Docker - Container IP addresses mapping - docker

In Docker, I have 3 containers which are node, mysql and redis. When I run sudo iptables -t nat -L -n I can see those containers are running on different IP addresses like below
However, the IP addresses order for the services and the IP addresses (on some machine it's 172.23.0.x, on some machine it's 172.21.0.x) might be different every time I do docker-compose up --build so if I want the app works, I gotta config IP addresses for each service manually. Is there any way I can automatically map a fixed IP address for each service in the docker-compose.yml file? Thanks. Here's my docker-compose.yml file:
version: "3"
services:
universe:
build: .
working_dir: /usr/src
volumes:
- .:/usr/src
- /usr/src/node_modules/
ports:
- "3000:3000"
- "8000:8000"
restart: always
# Redis Alpine
redis:
image: redis:alpine
ports:
- "127.0.0.1:6379:6379"
# MySQL 5.7
mysql:
build:
context: ./docker/mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: database_name
MYSQL_USER: database_user
MYSQL_PASSWORD: database_password
volumes:
- /config/scripts:/docker-entrypoint-initdb.d
restart: always
ports:
- "127.0.0.1:3306:3306"

You can try this type of docker-compose.yml configuration with defining a network with bridge connection including subnet and gateway for that defined network.
version: "3"
services:
universe:
build: .
working_dir: /usr/src
volumes:
- .:/usr/src
- /usr/src/node_modules/
ports:
- "3000:3000"
- "8000:8000"
restart: always
networks:
vpcbr:
ipv4_address: 10.3.0.2
# Redis Alpine
redis:
image: redis:alpine
ports:
- "6379:6379"
networks:
vpcbr:
ipv4_address: 10.3.0.3
# MySQL 5.7
mysql:
build:
context: ./docker/mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: database_name
MYSQL_USER: database_user
MYSQL_PASSWORD: database_password
volumes:
- /config/scripts:/docker-entrypoint-initdb.d
restart: always
ports:
- "3306:3306"
networks:
vpcbr:
ipv4_address: 10.3.0.4
networks:
vpcbr:
driver: bridge
ipam:
config:
- subnet: 10.3.0.0/16
gateway: 10.3.0.1

In your Docker Compose setup as you’ve shown it, to communicate between containers, you can use the names of the services (universe, redis, mysql) as ordinary host names and they’ll resolve to the internal IP address of the container, whatever it happens to be.
Note that if you’re using the ports: option to remap a published port, you still need to connect to the internal port (the one on the right side of the colon). For instance you’d connect to mysql:3306 even if you specified a different external port mapping or not port mapping at all.
This doesn’t work from outside of Docker space; there you connect to the host’s DNS name or IP address with the published ports:, and the fact of Docker is totally hidden from you.

Related

Docker network configuration endpoints

I want to know how to configure correctly the backend endpoint.
I have a docker images that runs different containers:
Backend
Frontend
Nginx for backend
DB
From my understanding, since all containers are running on the same machine, I should be able to reach the backend with "host.docker.internal".
Indeed I can successfully do it on the local machine where Docker is running on.
By the way the frontend is not able to resolve the endpoint "host.docker.internal" if I try to make a request from another machine. Please note that I'm able to reach the frontend from another machine, it's just a matter of endpoint configuration.
Note that "192.168.1.11" is the IP of the machine where Docker is running, and "8888" it's the port where the frontend is.
Obviously I can succesfully make the requests from other machines too if I put the static IP address instead of "host.docker.internal". But the question is: since the React frontend application is served on Docker itself, shouldn't it be able to resolve the "host.docker.internal" endpoint?
Just for reference, here it is my docker compose:
version: "3.8"
services:
db: #mysqldb
image: mysql:5.7
container_name: ${DB_SERVICE_NAME}
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_USER: ${DB_USERNAME}
SERVICE_TAGS: dev
SERVICE_NAME: mysql
ports:
- $MYSQLDB_LOCAL_PORT:$MYSQLDB_DOCKER_PORT
volumes:
- ./docker-compose/mysql:/docker-entrypoint-initdb.d
networks:
- backend
mrmfrontend:
build:
context: ./mrmfrontend
args:
- REACT_APP_API_BASE_URL=$CLIENT_API_BASE_URL
- REACT_APP_BACKEND_ENDPOINT=$REACT_APP_BACKEND_ENDPOINT
- REACT_APP_FRONTEND_ENDPOINT=$REACT_APP_FRONTEND_ENDPOINT
- REACT_APP_FRONTEND_ENDPOINT_ERROR=$REACT_APP_FRONTEND_ENDPOINT_ERROR
- REACT_APP_CUSTOMER=$REACT_APP_CUSTOMER
- REACT_APP_NAME=$REACT_APP_NAME
- REACT_APP_OWNER=""
ports:
- $REACT_LOCAL_PORT:$REACT_DOCKER_PORT
networks:
- frontend
volumes:
- ./docker-compose/nginx/frontend:/etc/nginx/conf.d/
app:
build:
args:
user: admin
uid: 1000
context: ./MRMBackend
dockerfile: Dockerfile
image: backend
container_name: backend-app
restart: unless-stopped
working_dir: /var/www/
volumes:
- ./MRMBackend:/var/www
networks:
- backend
nginx:
image: nginx:alpine
container_name: backend-nginx
restart: unless-stopped
ports:
- 8000:80
volumes:
- ./MRMBackend:/var/www
- ./docker-compose/nginx/backend:/etc/nginx/conf.d/
networks:
- backend
- frontend
volumes:
db:
networks:
frontend:
driver: bridge
backend:
driver: bridge
The endpoint is configured in this way in the .env:
REACT_APP_BACKEND_ENDPOINT="http://host.docker.internal:8000"

Connect to database from another container

Please help me if it's possible.
I need to start 2 applications with a single database.
I have 2 applications. First domain.com, 2-nd api.domain.com. Each application has docker-compose.yaml files.
domain.com - CMS
version: "3.8"
services:
web:
container_name: domain_web
build:
context: ./docker/php
dockerfile: Dockerfile
working_dir: /var/www/html
#command: composer install
volumes:
- ./:/var/www/html
- ./docker/php/app.conf:/etc/apache2/sites-available/000-default.conf
- ./docker/php/hosts:/etc/hosts
networks:
domain:
ipv4_address: 10.9.0.5
networks:
domain:
driver: bridge
ipam:
config:
- subnet: 10.9.0.0/16
gateway: 10.9.
volumes:
bel_baza:
api.domain.com - Laravel 5.6
version: "3.8"
services:
web:
container_name: api_domain_web
build:
context: ./docker/php
dockerfile: Dockerfile
working_dir: /var/www/html
# command: composer install
volumes:
- ./:/var/www/html
- ./docker/php/app.conf:/etc/apache2/sites-available/000-default.conf
- ./docker/php/hosts:/etc/hosts
networks:
api_domain:
ipv4_address: 10.15.0.5
db:
image: mysql:5.7
command: --default-authentication-plugin=mysql_native_password
restart: always
container_name: api_domain_db
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: domain
MYSQL_USER: user
MYSQL_PASSWORD: user
volumes:
- api_domain_baza:/var/lib/mysql
- ./docker/db:/docker-entrypoint-initdb.d
networks:
api_domain:
ipv4_address: 10.15.0.6
phpmyadmin:
image: phpmyadmin
restart: always
container_name: api_domain_pma
networks:
api_domain:
ipv4_address: 10.15.0.7
redis:
image: redis:3.0
container_name: api_domain_redis
networks:
api_domain:
ipv4_address: 10.15.0.10
networks:
api_domain:
driver: bridge
ipam:
config:
- subnet: 10.15.0.0/16
gateway: 10.15.0.1
volumes:
api_domain_baza:
api_domain started successfully.
I need to connect domain.com with database api_domain_db. For connecting host, I used IP address 10.15.0.6. First application not connected to the database from 2nd application.
What is my problem?
How I can connect domain.com with the database of 2nd application?
your problem is your are using separate docker compose applications for each application. And by default those applications can not access each other inner parts:
By default Compose sets up a single network for your app. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.
doc is here - https://docs.docker.com/compose/networking/
So it is like it creates separate network for each docker compose.
if you want them both to see each other inner part you can create external docker network as this:
docker network create --subnet 10.1.0.0/24 network_name
and then use that network in both docker compose like this:
networks:
default:
external:
name: network_name
services:
.....
if you need fixed IPs, you can define them as
app:
image: ...
networks:
default:
ipv4_address: 10.1.0.10

Services in docker compose not recognizing each other

I am trying to make a Confluence container communicate with a mysql container. They are both services that are launched in my docker-compose.yml
version: '2'
services:
db:
image: mysql:5.7
networks:
- confluencenet
volumes:
- ./mycustom.cnf:/etc/mysql/conf.d/my.cnf
restart: always
command: [mysqld, --character-set-server=utf8, --collation-server=utf8_bin, --default-storage-engine=INNODB, --max_allowed_packet=256M, --innodb_log_file_size=2GB, --transaction-isolation=READ-COMMITTED, --binlog_format=row]
environment:
MYSQL_DATABASE: bachelorarbeit_database
# So you don't have to use root, but you can if you like
MYSQL_USER: horizon
# You can use whatever password you like
MYSQL_PASSWORD: 1P#ssw0rt123
# Password for root access
MYSQL_ROOT_PASSWORD: P#ssw0rt
MYSQL_ROOT_USER: root
ports:
# <Port exposed> : < MySQL Port running inside container>
- '3306:3306'
confluence:
image: techgeeks/confluence-mysql-server
networks:
- confluencenet
build:
context: ./
args:
CONFLUENCE_VERSION: 7.4.0
container_name: confluence
volumes:
- confluencedata:/var/atlassian/confluence
ports:
- '8090:8090'
- '8091:8091'
volumes:
confluencedata:
external: false
postgresqldata:
external: false
networks:
confluencenet: {}
From my understanding, two docker services need to share the same network if they have to communicate with each other. They work seperately, I can connect to each from outside. However, the confluence instance cannot connect to the db service.
SQLState - 08S01
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
What did I do wrong putting the two in the same docker network?

How ports notation in docker compose service works?

in docker-compose.yml,
What is the difference between in following ports notations?
ports:
- "5000:5000"
resp:
ports:
- "8080"
or no ports at all.
For example in following docker-compose.yml, the mongodb service must be exposing a port to communicate with node service, but no port is specified
services:
node:
build:
context: .
dockerfile: node.dockerfile
ports:
- "3000:3000"
networks:
- nodeapp-network
depends_on:
- mongodb
mongodb:
image: mongo
networks:
- nodeapp-network
networks:
nodeapp-network:
driver: bridge
source: https://github.com/DanWahlin/NodeExpressMongoDBDockerApp
However in these docker-compose.yml, there are ports awlays specified with either 27017:27017 or 8080 notation.
services:
nginx:
container_name: nginx
image: ${DOCKER_ACCT}/nginx
build:
context: .
dockerfile: .docker/nginx.${APP_ENV}.dockerfile
links:
- node1:node1
- node2:node2
- node3:node3
ports:
- "80:80"
- "443:443"
networks:
- codewithdan-network
node1:
container_name: node-codewithdan-1
image: ${DOCKER_ACCT}/node-codewithdan
build:
context: .
dockerfile: .docker/node-codewithdan.${APP_ENV}.dockerfile
ports:
- "8080"
volumes:
- .:/var/www/codewithdan
working_dir: /var/www/codewithdan
env_file:
- ./.docker/env/app.${APP_ENV}.env
depends_on:
- mongo
- redis
networks:
- codewithdan-network
node2:
container_name: node-codewithdan-2
image: ${DOCKER_ACCT}/node-codewithdan
build:
context: .
dockerfile: .docker/node-codewithdan.${APP_ENV}.dockerfile
ports:
- "8080"
volumes:
- .:/var/www/codewithdan
working_dir: /var/www/codewithdan
env_file:
- ./.docker/env/app.${APP_ENV}.env
depends_on:
- mongo
- redis
networks:
- codewithdan-network
node3:
container_name: node-codewithdan-3
image: ${DOCKER_ACCT}/node-codewithdan
build:
context: .
dockerfile: .docker/node-codewithdan.${APP_ENV}.dockerfile
ports:
- "8080"
volumes:
- .:/var/www/codewithdan
working_dir: /var/www/codewithdan
env_file:
- ./.docker/env/app.${APP_ENV}.env
depends_on:
- mongo
- redis
networks:
- codewithdan-network
mongo:
container_name: mongo
image: ${DOCKER_ACCT}/mongo
build:
context: .
dockerfile: .docker/mongo.dockerfile
ports:
- "27017:27017"
env_file:
- ./.docker/env/mongo.${APP_ENV}.env
networks:
- codewithdan-network
redis:
container_name: redis
image: ${DOCKER_ACCT}/redis
build:
context: .
dockerfile: .docker/redis.${APP_ENV}.dockerfile
ports:
- "6379"
networks:
- codewithdan-network
networks:
codewithdan-network:
driver: bridge
source: https://github.com/DanWahlin/CodeWithDanDockerServices
Can you explain the difference?
Typical Docker containers run a long-running server listening on some TCP port. Other containers on the same Docker network can reach that container using the container’s name (docker run --name, container_name: directive) as a DNS name and the port the server is running on. In Docker Compose, Compose creates a Docker network per Compose YAML file, and also makes services available under their key in the YAML file. This works even if no ports: are specified.
So, for instance, if your docker-compose.yml file says
services:
mongo:
image: mongo
others:
env:
MONGODB_HOST: mongo
MONGODB_PORT: 27017
then the MongoDB container will be reachable on that host name and (default) port, even though it doesn’t explicitly have a ports:.
If you do declare a ports: then the container will be reachable from outside Docker space. If you only have one port it’s the port number of the server, and Docker picks the host port; this isn’t useful in most cases (but it’s guaranteed to not hit a port conflict). If you have two ports they’re the host port and internal service port. You can also specify a host IP address to bind(2) to.
Presence or absence of ports: doesn’t affect inter-dontainer communication. Always use the container’s name (or Docker-compose.yml service name) and the “internal” port number the server is listening on.
Either specify both ports (HOST:CONTAINER), or just the container port (an ephemeral host port is chosen). So in your case 8080 is container port
ports:
- "3000"
- "3000-3005"
- "8000:8000"
- "9090-9091:8080-8081"
- "49100:22"
- "127.0.0.1:8001:8001"
- "127.0.0.1:5000-5010:5000-5010"
- "6060:6060/udp"
From here
The ephemeral port range is configured by /proc/sys/net/ipv4/ip_local_port_range kernel parameter, typically ranging from 32768 to 61000.
Either way, you should be able to peek at what Docker has accomplished in your network stack by examining your NAT tables. from here
In docker compose by default no ports will be created in case they collide with already opened ports

Can't to connect to postgres container

I define postgres server in docker-compose.yml:
db:
image: postgres:9.5
expose:
- 5432
Then in another docker container I tried to connect to this postgres container. But it gives an error with warning:
Is the server running on host "db" (172.22.0.2) and accepting
data-service_1 | TCP/IP connections on port 5432?
Why container can't to connect to another by provided information (host="db" and port=5432)?
PS
Full docker-compose.yml:
version: "2"
services:
data-service:
build: .
depends_on:
- db
ports:
- "50051:50051"
db:
image: postgres:9.5
depends_on:
- data-volume
environment:
- POSTGRES_USER=cobrain
- POSTGRES_PASSWORD=a
- POSTGRES_DB=datasets
ports:
- "8000:5432"
expose:
- 5432
volumes_from:
- data-volume
# - container:postgres9.5-data
restart: always
data-volume:
image: busybox
command: echo "I'm data container"
volumes:
- /var/lib/postgresql/data
Solution #1. Same file.
To be able to access the db container, you have to define your other containers in context of docker-compose.yml. When containers are started, each container gets all other containers mapped in /etc/hosts.
Just do
version: '2'
services:
web:
image: your/image
db:
image: postgres:9.5
If you do not wish to put your other containers into the same docker-compose.yml, there are other solutions:
Solution #2. IP
Do docker inspect <name of your db container> and look for IPAddress directive in the result listing. Use that IPAddress as host to connect to.
Solution #3. Networks
Make your containers join same network. For that, under each service, define:
services:
db:
networks:
- myNetwork
Don't forget to change db for each container you are starting.
I usually go with the first solution during development. I use apache+php as one container and pgsql as another one, a separate DB for every project. I do not start more than one setting of docker-compose.yml, so in this case defining both containers in one .yml config is perfect.
the depends on is not correct. i would try to use other paramters like LINKS and environment:
version: "2"
services:
data-service:
build: .
links:
- db
ports:
- "50051:50051"
volumes_from: ["db"]
environment:
DATABASE_HOST: db
db:
image: postgres:9.5
environment:
- POSTGRES_USER=cobrain
- POSTGRES_PASSWORD=a
- POSTGRES_DB=datasets
ports:
- "8000:5432"
expose:
- 5432
#volumes_from:
#- data-volume
# - container:postgres9.5-data
restart: always
data-volume:
image: busybox
command: echo "I'm data container"
volumes:
- /var/lib/postgresql/data
this one works for me (not postgres but mysql)

Resources