I have two services, web and helloworld. The following is my docker-compose YAML file:
version: "3"
services:
helloworld:
build: ./hello
volumes:
- ./hello:/usr/src/app
ports:
- 5001:80
web:
build: ./web
volumes:
- ./web:/usr/share/nginx/html
ports:
- 5000:80
depends_on:
- helloworld
Inside the index.html in web, I made a button that opens http://helloworld when clicked on. However, my button ends up going to helloworld.com instead of the correct service. Both services work fine when I do localhost:5001 and localhost:5000. Am I missing something?
Docker's embedded DNS for service discovery is for container-to-container networking. For connections from outside of docker (e.g. from your browser) you need to publish the port (e.g. 5000 and 5001 in your file) and connect to that published port.
To use the container-to-container networking, you would need the DNS lookup to happen inside of the web container and the connection to go from web to helloworld, instead of from your browser to the container.
Edit: from your comment, you may find a reverse proxy helpful. Traefik and nginx-proxy are two examples out there. You can configure these to forward to containers by hostname or by a virtual path, and in your situation, I think path based routing would be easier. The resulting compose file would look something like:
version: "3"
services:
traefik:
image: traefik
command: --docker --docker.watch
volumes:
- /var/lib/docker.sock:/var/lib/docker.sock
ports:
- 8080:80
helloworld:
build: ./hello
volumes:
- ./hello:/usr/src/app
labels:
- traefik.frontend.rule=PathPrefixStrip:/helloworld
- traefik.port=80
web:
build: ./web
volumes:
- ./web:/usr/share/nginx/html
labels:
- traefik.frontend.rule=PathPrefixStrip:/
- traefik.port=80
The above is all untested off the top of my head configuration, but should get you in the right direction. With the PathPrefixStrip rule, you can make a link in web to "/helloworld" which will go to the other container. And since the link doesn't have a hostname or port, it will go to the same traefik hostname/port you are already using.
Related
I have a VPS with nginx-proxy container, and I create some wordpress website with phpmyadmin service. If I want to create another site with this definition I got "same port" problem.
Ok, I can change the port to 2998 and it works fine but I need to add a new open port to my VPS. I don't want to add or change the port for each site.
Now:
example-a.com:2999 -> example-a phpmyadmin login page
examlpe-b.com:2998 -> example-b phpymadmin login page
Is there a way to direct me to the appropriate container by domain address?
example-a.com:2999 -> example-a phpmyadmin login page
examlpe-b.com:2999 -> example-b phpymadmin login page
My nginx proxy definition
networks:
nginx-proxy:
external: false
name: nginx-reverse-proxy
default:
name: nginx-reverse-proxy-default
version: '2'
services:
nginx-proxy:
build:
context: .nginx-proxy
dockerfile: Dockerfile
container_name: nginx-proxy
ports:
- 80:80
- 443:443
restart: always
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- .nginx-proxy/certs:/etc/nginx/certs:ro
- .nginx-proxy/vhost.d:/etc/nginx/vhost.d
- .nginx-proxy/dhparam:/etc/nginx/dhparam
- /usr/share/nginx/html
networks:
- nginx-proxy
nginx-proxy-acme:
image: nginxproxy/acme-companion
container_name: nginx-proxy-acme
restart: always
volumes_from:
- nginx-proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- .nginx-proxy/certs:/etc/nginx/certs:rw
- .nginx-proxy-acme/acme:/etc/acme.sh
And this is my wordpress site definition
version: "3.9"
volumes:
database_volume: {}
x-logging:
&default-logging
driver: json-file
options:
max-size: '1m'
max-file: '3'
services:
web:
build:
context: ./.docker
dockerfile: Dockerfile_web
container_name: test_web
ports:
- '3000:80'
volumes:
- ./wp:/var/www
depends_on:
- database
- php
restart: always
logging: *default-logging
database:
image: mariadb:latest
container_name: test_database
environment:
MYSQL_USER: wp
MYSQL_PASSWORD: wp
MYSQL_DATABASE: wp
MYSQL_ROOT_PASSWORD: wp
volumes:
- ./database_volume:/var/lib/mysql
expose:
- 3306
restart: always
logging: *default-logging
php:
build:
context: ./.docker
dockerfile: Dockerfile_php
container_name: test_php
working_dir: /var/www/
volumes:
- ./wordpress:/var/www
restart: always
logging: *default-logging
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: test_phpmyadmin
links:
- database:db
ports:
- '2999:80'
restart: always
logging: *default-logging
What you want is not possible, but you probably don't actually want it. It becomes clear once you think through what you want to configure, and what would happen if a user would go to either URL:
you have configured example-a.com to point to your IP
you have configured example-b.com to point to your IP
you have configured your nginx-proxy container to listen on ports 80 and 443
you want to configure your WordPress containers to both listen on port 2999
you, or rather the acme-companion, have configured your nginx container to forward HTTP requests that ask for host example-a.com to go to the container for example A with port 2999, and requests that ask for example-b.com to go to container B with port 2999
Now, you can see right away that you have two things attempting to listen on the same network interface with port 2999 - that doesn't work, and it can't, because who would handle picking up incoming requests before the request is parsed to find out which host it wanted ? Container A can't accept the request and, if it's meant for B, hand the request over - A doesn't know about B.
So if you think about a user sending a request to example-a.com:2999, what really happens is that a request goes to <yourip>:2999, just like if a user goes to example-b.com:2999, it will end up going to <yourip>:2999.
How can that problem be solved ? By having a third container C that accepts user requests, looks into the request, and based on whether they wanted container A or B, hands the request over to A or B.
Here is the great thing: you already have that! Container C is really your nginx container, which is listening on port 80/443. So if your users go to example-a.com without providing a port, it will go to 80 or 443 (depending on whether they used http or https). Then, nginx will analyze the request, and send it to the correct container. For this, it doesn't really matter what port A and B listen on, because to the outside world, it looks like they are listening on 80/443.
So the real answer is that while you can't combine custom ports with virtual hosts and use the same port for multiple containers (other than 80/443), you don't actually NEED custom ports in the first place! If you just configure your containers with the default ports, users can use both https://example-a.com and https://example-b.com and it will 'just work'™
I am trying to access a docker container from another container using localhost address.
The compose file is pretty simple. Both containers ports are exposed.
There are no problems when building.
In my host machine I can successfully execute curl http://localhost:8124/ and get a response.
But inside the django_container when trying the same command I get Connection refused error.
I tried adding them in the same network, still result didn't change.
Well if I try to execute with the internal ip of that container like curl 'http://172.27.0.2:8123/' I get the response.
Is this the default behavior? How can I reach clickhouse_container using localhost?
version: '3'
services:
django:
container_name: django_container
build: ./django
ports:
- "8007:8000"
links:
- clickhouse:clickhouse
volumes:
- ./django:/usr/src/run
command: bash /usr/src/run/run.sh
clickhouse:
container_name: clickhouse_container
build: ./clickhouse
ports:
- "9001:9000"
- "8124:8123"
- "9010:9009"
So with this line here - "8124:8123" you're mapping the port of clickhouse container to localhost 8124. Which allows you to access clickhouse from localhost at port 8124.
If you want to hit clickhouse container from within the dockerhost network you have to use the hostname for the container. This is what I like to do:
version: '3'
services:
django:
hostname: djano
container_name: django
build: ./django
ports:
- "8007:8000"
links:
- clickhouse:clickhouse
volumes:
- ./django:/usr/src/run
command: bash /usr/src/run/run.sh
clickhouse:
hostname: clickhouse
container_name: clickhouse
build: ./clickhouse
ports:
- "9001:9000"
- "8124:8123"
- "9010:9009"
If you make the changes like I have made above you should be able to access clickhouse from within the django container like this curl http://clickhouse:8123.
As in #Billy Ferguson's answer, you can visit using localhost in host machine just because: you define a port mapping to route localhost:8124 to clickhouse:8123.
But when from other container(django), you can't. But if you insist, there is a ugly workaround: share host's network namespace with network_mode, but with this the django container will just share all network of host.
services:
django:
hostname: djano
container_name: django
build: ./django
ports:
- "8007:8000"
links:
- clickhouse:clickhouse
volumes:
- ./django:/usr/src/run
command: bash /usr/src/run/run.sh
network_mode: "host"
It depends of config.xml settings. If in config.xml <listen_host> 0.0.0.0</listen_host> you can use clickhouse-client -h your_ip --port 9001
I'm trying to pass redis url to docker container but so far i couldn't get it to work. I did a little research and none of the answers worked for me.
version: '3.2'
services:
redis:
image: 'bitnami/redis:latest'
container_name: redis
hostname: redis
expose:
- 6379
links:
- api
api:
image: tufanmeric/api:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
- proxy
environment:
- REDIS_URL=redis
depends_on:
- redis
deploy:
mode: global
labels:
- 'traefik.port=3002'
- 'traefik.frontend.rule=PathPrefix:/'
- 'traefik.frontend.rule=Host:api.example.com'
- 'traefik.docker.network=proxy'
networks:
proxy:
Error: Redis connection to redis failed - connect ENOENT redis
You can only communicate between containers on the same Docker network. Docker Compose creates a default network for you, and absent any specific declaration your redis container is on that network. But you also declare a separate proxy network, and only attach the api container to that other network.
The single simplest solution to this is to delete all of the network: blocks everywhere and just use the default network Docker Compose creates for you. You may need to format the REDIS_URL variable as an actual URL, maybe like redis://redis:6379.
If you have a non-technical requirement to have separate networks, add - default to the networks listing for the api container.
You have a number of other settings in your docker-compose.yml that aren't especially useful. expose: does almost nothing at all, and is usually also provided in a Dockerfile. links: is an outdated way to make cross-container calls, and as you've declared it to make calls from Redis to your API server. hostname: has no effect outside the container itself and is usually totally unnecessary. container_name: does have some visible effects, but usually the container name Docker Compose picks is just fine.
This would leave you with:
version: '3.2'
services:
redis:
image: 'bitnami/redis:latest'
api:
image: tufanmeric/api:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- REDIS_URL=redis://redis:6379
depends_on:
- redis
deploy:
mode: global
labels:
- 'traefik.port=3002'
- 'traefik.frontend.rule=PathPrefix:/'
- 'traefik.frontend.rule=Host:api.example.com'
- 'traefik.docker.network=default'
I have application in c# 'web_dotnet' in one container which downloads data from php service 'web_php' in second container. But what is url for php service? Url 'http://web_php:80' from c# service doesn't work. That is mine docker-compose.yml:
version: '3.5'
services:
web_php:
image: php:7.2.2-apache
container_name: my_php_container
volumes:
- ./php/:/var/www/html/
ports:
- 3000:80
networks:
- mynet
web_dotnet:
build: .
container_name: my_dotnet_container
ports:
- 2000:80
networks:
- mynet
networks:
mynet:
name: xyz_net
driver: bridge
First, you can simplify you file, removing unnecessary network declaration and port exposing. docker-compose creates default user-defined bridge network for you and links all services to it - no need to do it manually. Also inside network all ports are being exposed to services automatically.
Second, remove container_name. You are confusing yourself. Services get their host names equal to service names by default.
version: '3.5'
services:
web_php:
image: php:7.2.2-apache
volumes:
- ./php/:/var/www/html/
web_dotnet:
build: .
Now, after all useless stuff is cleaned, just call web_php:80 from web_dotnet.
After, if you would like to access web_dotnet ** from outside** docker-compose, then you add ports directive to make it visible from host.
I'm trying to split legacy system combined from hbase and php module into two separated containers with the following docker-compose file:
version: '2'
services:
php:
image: my-legacy-php
volumes:
- ~/workspace/php:/workspace/php
ports:
- "80:80"
links:
- hbase
hbase:
image: dajobe/hbase
hostname: hbase-docker
ports:
- "43590-44000:43590-44000"
- "8085:8085"
- "2181:2181"
- "8080:8080"
- "16010:16010"
- "9095:9095"
- "9090:9091"
- "16020:16020"
- "16030:16030"
- "60000:60000"
volumes:
- ~/workspace/hbase-docker/data:/data
I'm using a public hbase-docker image which using port 9090 for thrift while my legacy php module expect to connect via port 9091. I've tried to 'map' or 'forward' within the docker-compose.yml file "9090:9091" without lack. I also tried the expose attribute of docker-compose but it doesn't takes two ports (only one which is exposed to the other containers). How do I make that append?
I want that the listening port 9090 of hbase container will appear as 9091 from the php container (inside)
One of the possible solutions is: Building your own image, with dajobe/hbase as the base image, but modifying the hbase configs and ports exposed using EXPOSE to match your requirements, And then use that image in your compose file.
But this would require you have build and managing the image by yourself.
The solution is to put both services on the same docker network.
Specifically, add this to your docker-compose.yml:
networks:
app_net:
driver: bridge
Then, in each service's config be sure to include:
networks:
- app_net
Finally (and you've already done this), be sure that the correct port mapping is included in the config for hbase:
ports:
- "9090:9091"