Most Docker developers know about networks. You create one, attach containers, they talk via container name. Simple. But there’s a hidden feature that makes blue-green deploys, rolling updates, and service discovery patterns trivial: network aliases.
Network aliases let a single container have multiple DNS names on the same network. You can use them to swap implementations without changing your app’s config.
The Problem They Solve
Imagine you have two versions of a database service: postgres-v1 and postgres-v2. Your app talks to them via hostname. You want to switch from v1 to v2 without changing the app’s connection string.
Normally, you’d have to:
- Update the app config to point to
postgres-v2 - Redeploy the app
- Risk downtime or bugs
With aliases, you can:
- Start
postgres-v2with an alias ofpostgres - Connections automatically route to v2
- No app config change needed
How Aliases Work
When you create a Docker network, the embedded DNS server tracks all connected containers. By default, it knows them by their container name. Aliases register additional names pointing to the same container.
Here’s the basic syntax:
$ docker network create mynet$ docker run --name db-v1 \ --network mynet \ --network-alias postgres \ postgres:15Now the container db-v1 is reachable as both db-v1 and postgres. Any container on mynet that resolves postgres gets the IP of db-v1.
Blue-Green Deploy Example
Here’s the real power. Suppose you’re running a production setup:
$ docker network create app-net
# Green deployment (current)$ docker run -d --name api-green \ --network app-net \ --network-alias api \ myapp:v1.2.3
# Frontend connects to 'api' (resolves to api-green)$ docker run -d --name frontend \ --network app-net \ -e API_HOST=api \ myfrontend:latestNow you want to deploy a new version. Start it as blue:
# Blue deployment (new)$ docker run -d --name api-blue \ --network app-net \ myapp:v2.0.0
# At this point, frontend still talks to green# Everything works, no downtimeOnce blue is healthy and tested, flip the alias:
# Remove the alias from green$ docker network disconnect mynet api-green$ docker run -d --name api-green-v1.2.3 \ --network app-net \ myapp:v1.2.3
# Add the alias to blue$ docker run -d --name api-blue \ --network app-net \ --network-alias api \ myapp:v2.0.0Now api resolves to api-blue. Frontend keeps the same config, but talks to v2. Zero downtime, instant rollback (flip back to green).
Docker Compose Example
In Compose, you define aliases in the service definition:
version: '3.8'
services: postgres-v1: image: postgres:14 networks: app-net: aliases: - db # Can resolve as 'db' - postgres-primary
api: image: myapp:latest depends_on: - postgres-v1 environment: DATABASE_URL: postgresql://postgres:5432/mydb networks: - app-net
networks: app-net:The api service can connect to postgres-v1 via the hostname db. If you later swap in postgres-v2 with the same aliases, no app changes needed.
Real-World Use Case: Canary Deployments
Here’s how a smart team uses aliases for canary deployments:
$ docker network create prod-net
# Stable release: 99% of traffic$ docker run -d --name api-prod-v1.5 \ --network prod-net \ --network-alias api-stable \ myapp:v1.5
# Canary: 1% of traffic$ docker run -d --name api-canary-v2.0 \ --network prod-net \ --network-alias api-canary \ myapp:v2.0
# Load balancer routes most requests to 'api-stable',# a small percentage to 'api-canary'$ docker run -d --name lb \ --network prod-net \ -p 80:8080 \ my-load-balancerYour load balancer knows about both aliases. It routes based on policy, gradually shifting traffic to the canary. If the canary has issues, you never promoted it to api-stable.
Practical Multi-Database Example
Here’s a more complex setup: a database migration scenario.
version: '3.8'
services: # Old database (being phased out) mysql-legacy: image: mysql:5.7 networks: app-net: aliases: - db-read # Backward compatible name environment: MYSQL_ROOT_PASSWORD: secret
# New database (replacing mysql) postgres-new: image: postgres:15 networks: app-net: aliases: - db-write # New name, but app will use it environment: POSTGRES_PASSWORD: secret
# App uses 'db-read' and 'db-write' app: build: . depends_on: - mysql-legacy - postgres-new environment: READ_DB_HOST: db-read WRITE_DB_HOST: db-write networks: - app-net
networks: app-net:As you migrate read queries to postgres, you just change which service has the db-read alias. No app code change.
Limitations and Gotchas
-
Aliases only work on custom networks: Bridge (default) and host networks don’t support aliases. You need to explicitly
docker network create. -
DNS isn’t load-balanced: If two containers have the same alias, DNS round-robins between them. This can surprise people.
-
Aliases are per-network: A container can have different aliases on different networks.
-
No layer 7 routing: Aliases resolve at DNS level. If you need smart routing (URL path, headers), use a load balancer.
Quick Checklist
- Create a custom Docker network for your services
- Use
--network-aliaswhen running containers - Or define
networks.*.aliasesin Compose - Test DNS:
docker run --rm --network mynet nicolaka/netshoot nslookup alias-name - Use aliases for blue-green deploys
- Use aliases for canary/staged rollouts
Aliases are underrated. They’re simple, powerful, and solve real deployment problems. Most teams don’t use them and end up redeploying apps for zero-downtime updates. Don’t be that team.