名称: docker-compose-networking 用户可调用: false 描述: 使用当配置Docker Compose中的网络和服务通信时,包括桥接网络、覆盖网络、服务发现和服务间通信。 允许工具: [Bash, Read]
Docker Compose 网络配置
掌握 Docker Compose 中的网络配置和服务通信模式,用于构建安全、可扩展的多容器应用程序。
默认桥接网络
Docker Compose 自动为 compose 文件中的所有服务创建一个默认桥接网络:
version: '3.8'
services:
frontend:
image: nginx:alpine
ports:
- "80:80"
# 可以使用服务名称作为主机名到达后端
backend:
image: node:18-alpine
command: node server.js
# 从前端可通过主机名 'backend' 访问
database:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: secret
# 从后端可通过主机名 'database' 访问
在此设置中:
- 所有服务可以使用服务名称作为主机名进行通信
- 前端可以到达后端在
http://backend:3000 - 后端可以到达数据库在
postgres://database:5432 - 只有前端的端口 80 暴露给主机
自定义桥接网络
定义自定义网络以实现服务隔离和分段:
version: '3.8'
services:
frontend:
image: nginx:alpine
networks:
- frontend-network
ports:
- "80:80"
api:
image: node:18-alpine
networks:
- frontend-network
- backend-network
environment:
DATABASE_URL: postgresql://db:5432/app
database:
image: postgres:15-alpine
networks:
- backend-network
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: app
volumes:
- db-data:/var/lib/postgresql/data
cache:
image: redis:7-alpine
networks:
- backend-network
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
frontend-network:
driver: bridge
backend-network:
driver: bridge
internal: true
volumes:
db-data:
redis-data:
网络隔离:
- 前端只能到达 API
- 前端不能直接到达数据库或缓存
- API 可以到达所有服务
- 后端网络是内部的(无外部访问)
网络别名
配置多个主机名以进行服务发现:
version: '3.8'
services:
web:
image: nginx:alpine
networks:
public:
aliases:
- website
- www
- web-server
internal:
aliases:
- web-internal
api:
image: node:18-alpine
networks:
public:
aliases:
- api-server
- backend
internal:
aliases:
- api-internal
depends_on:
- database
database:
image: postgres:15-alpine
networks:
internal:
aliases:
- db
- postgres
- primary-db
environment:
POSTGRES_PASSWORD: secret
networks:
public:
driver: bridge
internal:
driver: bridge
internal: true
服务可以通过其任何别名访问:
http://website,http://www,http://web-server都到达 web 服务postgresql://db:5432,postgresql://postgres:5432都到达数据库
静态 IP 地址
为需要稳定网络的服务分配固定 IP 地址:
version: '3.8'
services:
loadbalancer:
image: nginx:alpine
networks:
app-network:
ipv4_address: 172.28.1.10
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
app-1:
image: myapp:latest
networks:
app-network:
ipv4_address: 172.28.1.11
environment:
APP_ID: "1"
app-2:
image: myapp:latest
networks:
app-network:
ipv4_address: 172.28.1.12
environment:
APP_ID: "2"
app-3:
image: myapp:latest
networks:
app-network:
ipv4_address: 172.28.1.13
environment:
APP_ID: "3"
database:
image: postgres:15-alpine
networks:
app-network:
ipv4_address: 172.28.1.20
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks:
app-network:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.28.0.0/16
gateway: 172.28.1.1
volumes:
pgdata:
外部网络
连接到在 Compose 外部创建的现有 Docker 网络:
version: '3.8'
services:
api:
image: node:18-alpine
networks:
- app-network
- shared-network
environment:
DATABASE_URL: postgresql://db:5432/app
database:
image: postgres:15-alpine
networks:
- app-network
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks:
app-network:
driver: bridge
shared-network:
external: true
name: company-shared-network
volumes:
pgdata:
首先创建外部网络:
docker network create company-shared-network
docker compose up -d
主机网络模式
使用主机网络以获得最大性能(仅限 Linux):
version: '3.8'
services:
high-performance-app:
image: myapp:latest
network_mode: "host"
environment:
BIND_ADDRESS: "0.0.0.0"
PORT: "8080"
# 不需要端口映射 - 直接使用主机的网络堆栈
monitoring:
image: prometheus:latest
network_mode: "host"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.listen-address=0.0.0.0:9090'
volumes:
prometheus-data:
注意:主机网络绕过 Docker 网络隔离,通常用于监控工具或高吞吐量应用程序。
服务发现和 DNS
配置 DNS 解析和服务发现:
version: '3.8'
services:
api:
image: node:18-alpine
networks:
- app-network
dns:
- 8.8.8.8
- 8.8.4.4
dns_search:
- company.local
extra_hosts:
- "legacy-api.company.local:192.168.1.100"
- "auth-service.company.local:192.168.1.101"
environment:
DATABASE_HOST: database.company.local
database:
image: postgres:15-alpine
networks:
app-network:
aliases:
- database.company.local
- db.company.local
hostname: primary-database
domainname: company.local
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks:
app-network:
driver: bridge
driver_opts:
com.docker.network.bridge.name: br-company-app
volumes:
pgdata:
链接容器(遗留)
虽然 links 已弃用,但理解它有助于迁移遗留配置:
version: '3.8'
services:
# 现代方法 - 使用网络代替
web:
image: nginx:alpine
networks:
- app-network
depends_on:
- api
api:
image: node:18-alpine
networks:
- app-network
depends_on:
- database
environment:
# 使用服务名称作为主机名
DATABASE_URL: postgresql://database:5432/app
database:
image: postgres:15-alpine
networks:
- app-network
environment:
POSTGRES_PASSWORD: secret
networks:
app-network:
driver: bridge
多网络架构
具有多个隔离网络的复杂应用程序:
version: '3.8'
services:
nginx:
image: nginx:alpine
networks:
- public
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- frontend
- api
frontend:
image: react-app:latest
networks:
- public
- frontend-tier
environment:
API_URL: http://api:3000
api:
image: node-api:latest
networks:
- frontend-tier
- backend-tier
environment:
DATABASE_URL: postgresql://postgres:5432/app
REDIS_URL: redis://cache:6379
QUEUE_URL: amqp://rabbitmq:5672
depends_on:
- database
- cache
- queue
worker:
image: node-worker:latest
networks:
- backend-tier
environment:
DATABASE_URL: postgresql://postgres:5432/app
QUEUE_URL: amqp://rabbitmq:5672
depends_on:
- database
- queue
deploy:
replicas: 3
database:
image: postgres:15-alpine
networks:
- backend-tier
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
cache:
image: redis:7-alpine
networks:
- backend-tier
command: redis-server --appendonly yes
volumes:
- redis-data:/data
queue:
image: rabbitmq:3-management-alpine
networks:
- backend-tier
- management
ports:
- "15672:15672" # 管理界面
environment:
RABBITMQ_DEFAULT_USER: admin
RABBITMQ_DEFAULT_PASS: secret
volumes:
- rabbitmq-data:/var/lib/rabbitmq
monitoring:
image: prometheus:latest
networks:
- management
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
networks:
public:
driver: bridge
frontend-tier:
driver: bridge
internal: true
backend-tier:
driver: bridge
internal: true
management:
driver: bridge
volumes:
pgdata:
redis-data:
rabbitmq-data:
prometheus-data:
网络分段:
- 公共: 面向互联网的服务(nginx, 前端)
- 前端层: 前端和 API 通信
- 后端层: API, 工作者, 数据库, 缓存, 队列
- 管理: 监控和管理工具
端口发布策略
控制服务如何暴露端口:
version: '3.8'
services:
# 短语法 - 主机:容器
web:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
networks:
- public
# 长语法,指定协议
api:
image: node:18-alpine
ports:
- target: 3000
published: 3000
protocol: tcp
mode: host
networks:
- app-network
# 随机主机端口
app:
image: myapp:latest
ports:
- "3000" # Docker 分配随机主机端口
networks:
- app-network
# 绑定到特定主机接口
admin:
image: admin-panel:latest
ports:
- "127.0.0.1:8080:80" # 仅可从本地主机访问
networks:
- admin-network
# UDP 协议
dns:
image: bind9:latest
ports:
- "53:53/udp"
- "53:53/tcp"
networks:
- dns-network
# 端口范围
streaming:
image: rtmp-server:latest
ports:
- "1935:1935"
- "8080-8089:8080-8089"
networks:
- streaming-network
networks:
public:
app-network:
admin-network:
internal: true
dns-network:
streaming-network:
容器通信模式
请求-响应模式
version: '3.8'
services:
gateway:
image: nginx:alpine
networks:
- frontend
ports:
- "80:80"
volumes:
- ./nginx-gateway.conf:/etc/nginx/nginx.conf:ro
service-a:
image: service-a:latest
networks:
- frontend
- backend
environment:
SERVICE_B_URL: http://service-b:8080
DATABASE_URL: postgresql://db:5432/service_a
service-b:
image: service-b:latest
networks:
- frontend
- backend
environment:
DATABASE_URL: postgresql://db:5432/service_b
database:
image: postgres:15-alpine
networks:
- backend
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
volumes:
pgdata:
发布-订阅模式
version: '3.8'
services:
publisher:
image: publisher:latest
networks:
- messaging
environment:
REDIS_URL: redis://redis:6379
depends_on:
- redis
subscriber-1:
image: subscriber:latest
networks:
- messaging
environment:
REDIS_URL: redis://redis:6379
SUBSCRIBER_ID: "1"
depends_on:
- redis
subscriber-2:
image: subscriber:latest
networks:
- messaging
environment:
REDIS_URL: redis://redis:6379
SUBSCRIBER_ID: "2"
depends_on:
- redis
redis:
image: redis:7-alpine
networks:
- messaging
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
messaging:
driver: bridge
driver_opts:
com.docker.network.bridge.enable_icc: "true"
volumes:
redis-data:
网络故障排除配置
启用调试和监控:
version: '3.8'
services:
app:
image: myapp:latest
networks:
app-network:
aliases:
- primary-app
cap_add:
- NET_ADMIN
- NET_RAW
debug:
image: nicolaka/netshoot:latest
networks:
- app-network
command: sleep infinity
cap_add:
- NET_ADMIN
- NET_RAW
stdin_open: true
tty: true
database:
image: postgres:15-alpine
networks:
app-network:
aliases:
- db
environment:
POSTGRES_PASSWORD: secret
networks:
app-network:
driver: bridge
driver_opts:
com.docker.network.bridge.enable_ip_masquerade: "true"
com.docker.network.driver.mtu: "1500"
ipam:
driver: default
config:
- subnet: 172.28.0.0/16
调试命令:
# 进入调试容器
docker compose exec debug bash
# 测试连通性
ping app
curl http://app:8080/health
# 检查 DNS 解析
nslookup app
dig app
# 网络扫描
nmap -p- app
# 路由追踪
traceroute app
# 监控流量
tcpdump -i eth0 -n
IPv6 网络
启用 IPv6 支持:
version: '3.8'
services:
web:
image: nginx:alpine
networks:
- ipv6-network
ports:
- "80:80"
api:
image: node:18-alpine
networks:
ipv6-network:
ipv6_address: 2001:db8:1::10
database:
image: postgres:15-alpine
networks:
ipv6-network:
ipv6_address: 2001:db8:1::20
environment:
POSTGRES_PASSWORD: secret
networks:
ipv6-network:
driver: bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.28.0.0/16
- subnet: 2001:db8:1::/64
何时使用此技能
使用 docker-compose-networking 当您需要:
- 为多容器应用程序配置自定义网络拓扑
- 实施网络分段和服务隔离
- 设置服务发现和服务间通信
- 设计具有前端/后端分离的安全网络架构
- 配置服务的静态 IP 地址
- 连接到外部 Docker 网络
- 实现复杂的微服务通信模式
- 排除网络连接问题
- 配置 DNS 解析和主机名别名
- 设置发布-订阅或消息队列架构
- 启用 IPv6 网络
- 通过主机网络优化网络性能
- 配置端口发布和暴露策略
最佳实践
-
使用自定义网络进行隔离:始终创建自定义网络,而不是仅依赖默认网络,以获得更好的安全性和组织性。
-
实施网络分段:将前端、后端和数据层分离到不同的网络中,以限制攻击面。
-
使用内部网络:将后端网络标记为
internal: true,以防止外部访问敏感服务,如数据库。 -
优先使用服务名称而非 IP:使用 Docker 的内置 DNS 和服务名称,而不是硬编码 IP 地址,以提高可维护性。
-
配置健康检查:实施健康检查,确保服务在路由流量之前准备就绪。
-
使用网络别名:为服务定义有意义的别名,以支持多种命名约定和更轻松的迁移。
-
除非必要,避免主机网络:默认使用桥接网络;主机网络应仅用于特定的性能要求。
-
记录网络架构:清楚地注释您的网络设计,并记录哪些服务可以相互通信。
-
明智使用 Depends_on:将
depends_on与健康检查结合使用,确保服务以正确的顺序启动。 -
实施最小权限:只暴露绝对需要从 Docker 网络外部访问的端口。
-
使用环境变量配置 URL:通过环境变量配置服务端点,以便在不同环境之间灵活配置。
-
测试网络隔离:定期验证服务只能通过预期的网络路径通信。
-
配置适当的 MTU:根据您的网络基础设施设置 MTU 值,以避免分片问题。
-
为共享资源使用外部网络:当多个 Compose 项目需要通信时,使用外部网络而不是重复服务。
-
监控网络性能:使用工具如
docker stats和专用监控容器来跟踪网络使用情况和识别瓶颈。
常见陷阱
-
公开所有服务:不要为只应内部访问的服务发布端口;使用网络而不是端口发布。
-
硬编码 IP 地址:除非绝对必要,避免静态 IP 地址;依赖服务发现。
-
仅使用默认网络:不创建自定义网络会错过适当的隔离机会。
-
忽略网络模式:为您的用例使用错误的网络模式(桥接 vs 主机 vs 覆盖)可能导致连接或性能问题。
-
缺少网络依赖:未正确配置
depends_on可能导致服务在尝试连接到不可用服务时失败。 -
过度使用主机网络:不必要地使用
network_mode: host会破坏容器隔离和可移植性。 -
不使用内部网络:未将后端网络标记为内部,会暴露数据库和敏感服务。
-
混合网络模式:在使用
network_mode: host时尝试发布端口或连接到网络会导致配置错误。 -
循环网络依赖:创建形成循环的网络依赖关系会阻止容器正常启动。
-
忽略 DNS 配置:未正确配置 DNS 可能导致容器化应用程序中的名称解析失败。
-
子网冲突:使用与主机或其他 Docker 网络冲突的 IP 范围会导致路由问题。
-
不测试网络策略:假设网络隔离有效而不测试,可能会留下安全漏洞。
-
暴露管理界面:发布管理端口(如 RabbitMQ、Redis、PostgreSQL)而没有身份验证或 IP 限制。
-
使用链接而非网络:已弃用的
links功能应替换为现代网络配置。 -
忽略网络驱动选项:未配置驱动选项如 MTU 或 IP 伪装,可能导致生产中的微妙连接问题。
资源
官方文档
网络故障排除
- Nicolaka Netshoot - 网络故障排除容器
- Docker 网络检查