| title | Master Docker Networks Using Docker Compose for Secure Multi-Tier Application Deployment |
|---|---|
| description | Learn how to securely deploy and manage a multi-tier application using Docker Compose with separate frontend and backend networks for isolation, service discovery, and load balancing. |
This configuration showcases a typical multi-tier application setup:
-
web-nginx(frontend) communicates withapp-umsover thefrontendnetwork, acting as a reverse proxy. -
app-umscommunicates withdb-mysqlover thebackendnetwork, ensuring that the database is securely isolated from the external environment. -
The separation of networks (
frontendandbackend) ensures that services only interact with those that they need to, providing both isolation and security. -
frontend: The
web-nginxandapp-umsservices are attached to this network, meaning these two services can communicate directly with each other. This network is typically used for communication between the reverse proxy (web-nginx) and the web application (app-ums). -
backend: Both the
app-umsanddb-mysqlservices are connected to this network. The backend network facilitates communication between the application (app-ums) and the database (db-mysql). Thedb-mysqlservice is not accessible fromweb-nginxbecause it is only attached to thebackendnetwork, providing a level of security by isolating the database from the external-facing services.
The networks provide an internal DNS-based service discovery mechanism, allowing services to communicate using service names instead of IP addresses. For example, app-ums can reach the db-mysql container by referring to it as db-mysql (via the DB_HOSTNAME environment variable).
name: ums-stack
services:
web-nginx:
image: nginx:latest
container_name: ums-nginx
ports:
- "8080:8080"
depends_on:
- app-ums
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
networks:
- frontend
app-ums:
image: ghcr.io/stacksimplify/usermgmt-webapp-v6:latest
ports:
- "8080"
deploy:
replicas: 2
depends_on:
- db-mysql
environment:
- DB_HOSTNAME=db-mysql
- DB_PORT=3306
- DB_NAME=webappdb
- DB_USERNAME=root
- DB_PASSWORD=dbpassword11
networks:
- frontend
- backend
db-mysql:
container_name: ums-mysqldb
image: mysql:8.0-bookworm
restart: always
environment:
MYSQL_ROOT_PASSWORD: dbpassword11
MYSQL_DATABASE=webappdb
ports:
- "3306:3306"
volumes:
- mydb:/var/lib/mysql
networks:
- backend
volumes:
mydb:
networks:
frontend:
backend:# Pull Docker Images and Start Containers
docker compose up -d
# List Docker Containers
docker compose ps# List Docker Networks
docker network ls
# Inspect specific Docker Network - FRONTEND
docker network inspect ums-stack_frontend
# Inspect specific Docker Network - BACKEND
docker network inspect ums-stack_backendweb-nginxacts as a reverse proxy, forwarding incoming requests from port 8080 of the host toapp-ums. Since both services share thefrontendnetwork,web-nginxcan resolve and accessapp-umsvia its container name (app-ums).
- Attached to the
frontendnetwork. - It forwards incoming traffic from the host's port 8080 to the
app-umsservice. Since bothweb-nginxandapp-umsare on the samefrontendnetwork,web-nginxcan reachapp-umsvia its container name. - No access to
db-mysql: Sinceweb-nginxis not connected to thebackendnetwork, it cannot directly communicate with the database service, ensuring the database remains isolated.
# Connect to web-nginx container
docker exec -it ums-nginx /bin/sh
# Alpine-based images: Install iputils
apk update
apk add iputils bind-tools
# Debian/Ubuntu-based images: Install iputils
apt-get update
apt-get install -y iputils-ping dnsutils
# Ping Services
ping web-nginx
ping app-ums
ping db-mysql
# Observation:
# 1. web-nginx and app-ums will work.
# 2. db-mysql will fail as there is NO ACCESS TO backend network.
# nslookup services
nslookup web-nginx
nslookup app-ums
nslookup db-mysql
# Observation:
# 1. web-nginx and app-ums will work.
# 2. db-mysql will fail as there is NO ACCESS TO backend network.
# dig
dig web-nginx
dig app-ums
dig db-mysql
# Observation:
# 1. web-nginx and app-ums will work.
# 2. db-mysql will fail as there is NO ACCESS TO backend network.app-umscommunicates withdb-mysqlusing the database hostnamedb-mysqland port3306. Both services are attached to thebackendnetwork, allowingapp-umsto resolvedb-mysqlvia DNS without exposing the database to the external network.
- Connected to both the
frontendandbackendnetworks. - This service can communicate with:
web-nginxover thefrontendnetwork.db-mysqlover thebackendnetwork using the environment variableDB_HOSTNAME=db-mysql.
app-umsscales to two replicas, meaning two instances of the application will be created. All replicas share the same networks and can accessdb-mysqlover the backend network.
# Connect to app-ums container (one of the replicas)
docker exec -it --user root ums-stack-app-ums-1 /bin/bash
# Debian/Ubuntu-based images: Install iputils
apt-get update
apt-get install -y iputils-ping dnsutils
# Ping Services
ping web-nginx
ping app-ums
ping db-mysql
# Observation:
# 1. web-nginx, app-ums, and db-mysql will work.
# 2. app-ums Service needs connectivity to both frontend and backend db.
# nslookup services
nslookup web-nginx
nslookup app-ums
nslookup db-mysql
# Observation:
# 1. web-nginx, app-ums, and db-mysql will work.
# 2. app-ums Service needs connectivity to both frontend and backend db.
# dig
dig web-nginx
dig app-ums
dig db-mysql
# Observation:
# 1. web-nginx, app-ums, and db-mysql will work.
# 2. app-ums Service needs connectivity to both frontend and backend db.- Attached only to the
backendnetwork. - Isolated from external services like
web-nginx, enhancing security by limiting access only toapp-ums, which is also on thebackendnetwork. - The database listens on port 3306, but only the
app-umsservice can access it internally via thebackendnetwork.
# Connect to db-mysql container
docker exec -it ums-mysqldb /bin/bash
# Debian/Ubuntu-based images: Install iputils
cat /etc/os-release
apt-get update
apt-get install -y iputils-ping dnsutils
# Oracle Image
cat /etc/os-release
microdnf install -y iputils bind-utils
# Ping Services
ping web-nginx
ping app-ums
ping db-mysql
# Observation:
# 1. app-ums and db-mysql will work.
# 2. web-nginx has NO ACCESS from db-mysql.
# nslookup services
nslookup web-nginx
nslookup app-ums
nslookup db-mysql
# Observation:
# 1. app-ums and db-mysql will work.
# 2. web-nginx has NO ACCESS from db-mysql.
# dig
dig web-nginx
dig app-ums
dig db-mysql
# Observation:
# 1. app-ums and db-mysql will work.
# 2. web-nginx has NO ACCESS from db-mysql.# Stop and Remove Containers
docker compose down -v
# Delete Docker Images
docker rmi $(docker images -q)- Isolation of Database:
db-mysqlis attached only to thebackendnetwork, isolating it from the external-facingweb-nginxservice for improved security. - No Host Networking: Services communicate internally via Docker networks, reducing exposure of services to the outside world.
- Each service in a Docker network can be accessed by its service name. Docker networks provide a built-in DNS service, making it easy to manage and scale multi-container applications.
Happy Dockerizing!