I'm in the process of creating a docker-compose config which maintains:
a node.js server, and
a separate postgres server.
Tutorials emphasise that postgres port 5432 must be exposed or forwarded so that the node container can access it: facilitated in the below docker-compose.yml.
version: "3.7"
services:
db:
container_name: db
image: postgres:alpine
ports:
- "5010:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: verysecretpass
POSTGRES_DB: pg-dev
server:
container_name: dashboard-api
build: .
volumes:
- .:/server
ports:
- "5000:5000"
This produces the below docker ps output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0d790cd4929e server_server "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 0.0.0.0:5000->5000/tcp dashboard-api
818296c1fc02 postgres:alpine "docker-entrypoint.s…" 7 minutes ago Up 4 minutes 0.0.0.0:5010->5432/tcp pg
In the above state, node gets ECONN REFUSED when attempting to connect with this url: postgres://postgres:verysecretpass#db:5010/pg-dev
Yet, the same connection string can connect when using 5432 instead of 5010.
In fact, using 5432, connection succeeds even when pg container has no port configuration whatsoever. The below docker ps output reflects no-port-config state in which node container can happily connect:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
76da96c15c05 server_server "docker-entrypoint.s…" 7 seconds ago Up 7 seconds 0.0.0.0:5000->5000/tcp dashboard-api
51c221ac2c54 postgres:alpine "docker-entrypoint.s…" 8 seconds ago Up 7 seconds 5432/tcp db
Why does this work? What am I missing here?
Using:
Docker version 20.10.0, build 7287ab3
docker-compose version 1.27.4, build 40524192
Unless otherwise configured, the services in a docker-compose document are automatically added to a network. There's no need to expose ports in this network.
If you want to expose ports on a container to the outside world, you will need to explicitly map these as you did. This however does not change anything for communication between services in the same network. If you have no reason to access the database from outside the network (e.g. inspect data using a DB tool on your own machine), you don't have to map / expose any ports of the db container.
Related
I am running docker-compose by creating 2 app, redis and simple node server, and docker-compose.yml is like this
version: '3'
services:
redis-server:
image: redis:latest
ports:
- "6379:6379"
volumes:
- ./data/redis:/data
node-server:
build: .
ports:
- "4001:8081"
when I run the command docker-compose.yml it create 2 contaiers and the log says app is running on post 4001
also when I run dokcer ps I see these containers
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1c6872205ba3 redis:latest "docker-entrypoint.s…" 13 seconds ago Up 12 seconds 0.0.0.0:6379->6379/tcp node_app_redis-server_1
9401443ab8c9 node_app_node-server "docker-entrypoint.s…" 13 seconds ago Up 12 seconds 5001/tcp, 0.0.0.0:4001->8081/tcp node_app_node-server_1
but still can't visit the app on http://localhost:4001/
as what #Nabil suggested, I wasn't exposing port 8081 in my index.js, so my app was listing on a different post than what is specified on docker-compose.yml file
so
------to reproduce the error-----
app.listen(4001, ()=>{
console.log(`app is running on post 4001`)
})
where it should be port 8081 like this (error gone)
app.listen(8081, ()=>{
console.log(`app is running on post 8081`)
})
by doing this I am able to visit my on lcoalhost:4001
when i run docker ps i am seeing port 80 unmapped on the apphub-ui container, i am expecting it to be mapped to 4200, which i also see. I dont understand why 80/tcp is present, it is creating connection refused issues in my app.
Here is the docker ps output
docker ps 10s +59%
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
22cb2b9c28d4 swimlane/apphub-ui:latest "/usr/bin/reefer -t …" 20 seconds ago Up 17 seconds 80/tcp, 0.0.0.0:80->4200/tcp apphub_apphub-ui_1
19a78f93bfe7 swimlane/apphub-api:latest "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 0.0.0.0:3000->3000/tcp apphub_apphub-api_1
7b3478e2dcd5 mongo:3.6 "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 0.0.0.0:27017->27017/tcp apphub_mongo_1
My docker-compose file is as follows
version: '3.6'
volumes:
mongo:
services:
mongo:
image: mongo:3.6
ports:
- 27017:27017
volumes:
- mongo:/data/db
apphub-api:
image: swimlane/apphub-api:latest
ports:
- 3000:3000
depends_on:
- mongo
apphub-ui:
image: swimlane/apphub-ui:latest
ports:
- 80:4200
depends_on:
- apphub-api
environment:
- APPHUB_API_HOST=apphub-api
My app runs fine if i change the mapped ports for the ui feature to 4200:4200, and i dont see the stray unmapped 80
I'm having the feeling that you want to map the port 4200 on your host to the port 80 of your container. If that's the case, you should switch the values. i.e.
ports:
- 4200:80
Note: am new to docker/swarm.
I've created a WordPress/mysql containers in a docker swarm mode running on Azure as per https://docs.docker.com/compose/wordpress/.
The cluster was created as per https://docs.docker.com/docker-for-azure/
here is my dockerfile:
======================
version: '3.3'
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
db_data: {}
=======================
as per official documentation, I can publish ports using --published flag, however, I need to know how to include that in Dockerfile.
Running apps
You can now start creating containers and services.
$ docker run hello-world
You can run websites too. Ports exposed with --publish are automatically exposed through the platform load balancer:
$ docker service create --name nginx --publish published=80,target=80 nginx
Once up, find the DefaultDNSTarget output in either the AWS or Azure portals to access the site.
Using docker ps, I can see that it is listening on 0.0.0.0:8000->80, however, without a service, it will not automatically create an azure load balance rule to the container.
swarm-manager000000:~/compose$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8c94587acd97 wordpress:latest "docker-entrypoint.s…" 10 minutes ago Up 10 minutes 0.0.0.0:8000->80/tcp compose_wordpress_1
aff61e0022a8 mysql:5.7 "docker-entrypoint.s…" 10 minutes ago Up 10 minutes 3306/tcp, 33060/tcp compose_db_1
5d2fdb3d75c4 docker4x/l4controller-azure:18.09.2-ce-azure1 "loadbalancer run --…" 2 hours ago Up 2 hours editions_controller
d5f0a8a91f66 docker4x/meta-azure:18.09.2-ce-azure1 "metaserver -iaas_pr…" 2 hours ago Up 2 hours 10.0.0.4:9024->8080/tcp meta-azure
93c6571b6ee6 docker4x/guide-azure:18.09.2-ce-azure1 "/entry.sh" 2 hours ago Up 2 hours editions_guide
b6cad5676b10 docker4x/logger-azure:18.09.2-ce-azure1 "python /server.py" 2 hours ago Up 2 hours 0.0.0.0:514->514/udp editions_logger
d2a74fe21751 docker4x/agent-azure:18.09.2-ce-azure1 "supervisord --confi…" 2 hours ago Up 2 hours agent
swarm-manager000000:~/compose$
If, for example, I tried to create a service that is mapped to a new image i.e: nginx. this will immediately create an inbound rule in the Azure load balancer.
$ docker service create --name nginx --publish published=80,target=80 nginx
Please advise of how to map the service to the existing WordPress container, or how to update the Dockerfile to create the service and use --published.
Thanks
I have no experience that maps the docker service to an existing container. As I know, it just does the same in the swarm as docker run command. You can take a look at the description of them.
If you really like to map the service to a container, I suggest the AKS than Docker Swarm in Azure, it's more manageable to you for the service and container. It can map the service to the container no matter it's existing one or creates a new one.
For the issue to publish the port. You can achieve it by using the parameter --publish in the docker run command like this:
docker run -d -p 80:80 my_image
Or you can do it in the compose file like this:
ports:
- "8000:80"
But you cannot publish the port in the Dockerfile, you just can tell the container which port the application listen to by using EXPOSE. Take a look at Expose vs publish: Docker port commands explained simply, then you will know it.
I'm using this docker-compose config for running a classic nodejs app + mysql + redis:
version: '3'
services:
app:
container_name: app
restart: always
build:
context: ./app/
depends_on:
- db
- redis
- elasticsearch
links:
- db
- redis
- elasticsearch
ports:
- "127.0.0.1:${APP_PORT}:${APP_PORT}"
environment:
- "PORT=${APP_PORT}"
- "MYSQL_PORT=${MYSQL_PORT}"
- "REDIS_PORT=${REDIS_PORT}"
redis:
container_name: redis
image: "redis:3-alpine"
restart: always
ports:
- "127.0.0.1:${REDIS_PORT}:6379"
db:
container_name: db
image: mariadb:10.0.30
restart: always
volumes:
- "${MYSQL_DATA_LOCATION}/data:/var/lib/mysql:delegated"
- "${MYSQL_DATA_LOCATION}/my.cnf:/etc/mysql/my.cnf:ro"
ports:
- "127.0.0.1:${MYSQL_PORT}:3306"
environment:
- "MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}"
- "MYSQL_USER=${MYSQL_USER}"
- "MYSQL_PASSWORD=${MYSQL_PASSWORD}"
- "MYSQL_DATABASE=${MYSQL_DATABASE}"
I'm also using a .env file containing the following values:
APP_PORT=5000
MYSQL_PORT=3306
REDIS_PORT=6379
And I start the application with
docker-compose up -d
Everything runs fine this way. I can change the mysql port without error, but if I change the redis port to something else than the original port, I have the following error in the app, when I use this config:
redis.createClient({host: 'redis', port: process.env.REDIS_PORT });
I get the following message:
Error: Redis connection to redis:5555 failed - connect ECONNREFUSED 172.18.0.3:5555
Whereas the connection between the db and the app works correctly :s
In docker ps I can see that the machine started with the expected config:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9c594c6d98b8 nginx:mainline-alpine "nginx -g 'daemon of…" 33 seconds ago Up 39 seconds 0.0.0.0:2000->80/tcp webproxy
62d1f917d7ff app "npm run docker-debug" 36 seconds ago Up 42 seconds 127.0.0.1:5000->5000/tcp, 127.0.0.1:9222->9222/tcp app
7c982d543a7d mariadb:10.0.30 "docker-entrypoint.s…" 39 seconds ago Up 45 seconds 127.0.0.1:4000->3306/tcp db
9dd13967b37d redis:3 "docker-entrypoint.s…" 39 seconds ago Up 44 seconds 127.0.0.1:5555->6379/tcp redis
I can see here that the db is mapped from 4000 to 3306, which works, but the redis mapping from 5555 to 6379 is ignored. And if I manually change the port in the app connection to port 6379, it does work...
Is there something missing in my configuration ?
the redis is running inside the container on port 6379 period (if you dont change the port in its config). On your host you map port 5555 to redis container 6379. All services in docker-compose are visible to each other and you dont even need to EXPOSE those ports to host. In your app settings if you access the redis by redis://redis:6379 will work or with the exposed port redis://HOST_IP:5555 will work too
After I carry out docker-compose up, it starts the containers.
when I do docker ps I get the below, which tells me that the containers are running. However when I do docker network inspect bridge the result shows me that there are no containers part of the docker0 bridge.
When I then carry out docker run meanchat_myserver it actually does show up on docker0 and I am also getting the data that the server is running on port 3000.
Which I don't get by using docker-compose.
What am I doing wrong here?
I am reading that when I use docker0 I can only refer to IP's to connect to other containers and not the name. Can I assume the ip's don't change on the containers and that this works without issue on deploying the app in production?
02cf08b1c3da d57f06ba9c68 "npm start" 33 minutes ago Up 33 minutes 4200/tcp meanchat_client_1
e257063c9e21 meanchat_myserver "npm start" 33 minutes ago Up 33 minutes 3000/tcp meanchat_myserver_1
02441c2e43f5 e114a298eabd "npm start" About an ago Up 33 minutes 0.0.0.0:80->80/tcp meanchat_nginx_1
88d9841d2553 mongo "docker-entrypoint..." 3 hours ago Up 3 hours 27017/tcp meanchat_mongo_1
compose
version: '3'
services:
# Build the container using the client Dockerfile
client:
build: ./
# This line maps the contents of the client folder into the container.
volumes:
- ./:/usr/src/app
myserver:
build: ./express-server
volumes:
- ./:/usr/src/app
depends_on:
- mongo
nginx:
build: ./nginx
# Map Nginx port 80 to the local machine's port 80
ports:
- "80:80"
# Link the client container so that Nginx will have access to it
mongo:
environment:
- AUTH=yes
- MONGO_INITDB_ROOT_USERNAME=superAdmin
- MONGO_INITDB_ROOT_PASSWORD=admin123
- MONGO_INITDB_DATABASE=d0c4ae452a5c
image: mongo
volumes:
- /var/mongodata/data:/data/db
By default Compose sets up a single network for your app.
For more detail, refer this link.
This means containers with compose won't be located in default bridge network by default.
You can check which network the containers with compose are using with the command.
docker inspect $container_name -f "{{.NetworkSettings.Networks}}"
However, If you want containers to be in default bridge network, you can use network_mode.
services:
service_name:
# other options....
network_mode: bridge