容器互联 #
容器互联概述 #
为什么需要容器互联? #
text
┌─────────────────────────────────────────────────────┐
│ 容器互联需求 │
├─────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Web │────→│ API │────→│Database │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ 需要解决: │
│ - 容器如何发现彼此 │
│ - 容器如何通信 │
│ - 如何处理容器IP变化 │
│ - 如何实现负载均衡 │
│ │
└─────────────────────────────────────────────────────┘
容器互联方式 #
方式一:使用–link(已弃用) #
bash
# 创建数据库容器
docker run -d --name db mysql:8.0
# 使用--link连接
docker run -d --name web --link db:database nginx
# 在web容器中可以通过database访问db
docker exec web ping database
注意: --link已被弃用,推荐使用自定义网络。
方式二:使用自定义网络(推荐) #
bash
# 创建网络
docker network create mynetwork
# 运行容器
docker run -d --name db --network mynetwork mysql:8.0
docker run -d --name web --network mynetwork nginx
# 通过容器名通信
docker exec web ping db
方式对比 #
text
┌─────────────────────────────────────────────────────┐
│ --link vs 自定义网络 │
├─────────────────────────────────────────────────────┤
│ │
│ --link: │
│ ✗ 已弃用 │
│ ✗ 只能单向连接 │
│ ✗ 需要重启容器更新 │
│ ✗ 不支持动态管理 │
│ │
│ 自定义网络: │
│ ✓ 推荐方式 │
│ ✓ 双向通信 │
│ ✓ 动态连接/断开 │
│ ✓ 自动DNS解析 │
│ ✓ 支持网络别名 │
│ │
└─────────────────────────────────────────────────────┘
服务发现 #
DNS解析 #
bash
# 创建网络
docker network create app-network
# 运行服务
docker run -d --name db --network app-network mysql:8.0
docker run -d --name redis --network app-network redis:alpine
docker run -d --name app --network app-network myapp
# 容器内DNS解析
docker exec app nslookup db
docker exec app nslookup redis
# 通过服务名连接
docker exec app ping -c 3 db
docker exec app ping -c 3 redis
网络别名 #
bash
# 设置网络别名
docker run -d \
--name db \
--network app-network \
--network-alias mysql \
--network-alias database \
mysql:8.0
# 通过任意别名访问
docker run --rm --network app-network alpine ping mysql
docker run --rm --network app-network alpine ping database
docker run --rm --network app-network alpine ping db
Docker Compose服务发现 #
yaml
version: '3.8'
services:
web:
image: nginx
networks:
- frontend
depends_on:
- app
app:
image: myapp
networks:
- frontend
- backend
environment:
- DB_HOST=db
- REDIS_HOST=redis
depends_on:
- db
- redis
db:
image: mysql:8.0
networks:
- backend
redis:
image: redis:alpine
networks:
- backend
networks:
frontend:
backend:
容器间通信 #
HTTP通信 #
bash
# 创建网络
docker network create web-network
# 运行API服务
docker run -d \
--name api \
--network web-network \
-p 8000:8000 \
myapi
# 运行Web服务
docker run -d \
--name web \
--network web-network \
-e API_URL=http://api:8000 \
myweb
# Web可以通过http://api:8000访问API
数据库连接 #
yaml
# docker-compose.yml
version: '3.8'
services:
app:
image: myapp
environment:
- DB_HOST=db
- DB_PORT=3306
- DB_NAME=mydb
- DB_USER=root
- DB_PASSWORD=root
depends_on:
- db
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=mydb
Redis连接 #
yaml
version: '3.8'
services:
app:
image: myapp
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
depends_on:
- redis
redis:
image: redis:alpine
负载均衡 #
使用Nginx负载均衡 #
yaml
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- app1
- app2
- app3
app1:
image: myapp
networks:
- app-network
app2:
image: myapp
networks:
- app-network
app3:
image: myapp
networks:
- app-network
networks:
app-network:
nginx.conf配置 #
nginx
upstream backend {
server app1:8000;
server app2:8000;
server app3:8000;
}
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Docker Swarm负载均衡 #
bash
# 创建服务并扩展
docker service create \
--name web \
--replicas 3 \
--publish 80:80 \
nginx
# Swarm自动负载均衡
服务依赖 #
depends_on #
yaml
version: '3.8'
services:
web:
image: nginx
depends_on:
- app
- db
app:
image: myapp
depends_on:
- db
db:
image: mysql:8.0
健康检查依赖 #
yaml
version: '3.8'
services:
web:
image: nginx
depends_on:
db:
condition: service_healthy
db:
image: mysql:8.0
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
等待脚本 #
bash
#!/bin/bash
# wait-for.sh
host="$1"
shift
cmd="$@"
until nc -z "$host" 3306; do
echo "Waiting for $host..."
sleep 1
done
echo "$host is available"
exec $cmd
yaml
# docker-compose.yml
services:
app:
image: myapp
command: ["./wait-for.sh", "db:3306", "npm", "start"]
depends_on:
- db
网络安全 #
网络隔离 #
yaml
version: '3.8'
services:
web:
image: nginx
networks:
- frontend
ports:
- "80:80"
app:
image: myapp
networks:
- frontend
- backend
db:
image: mysql:8.0
networks:
- backend
networks:
frontend:
backend:
internal: true # 隔离外部访问
访问控制 #
bash
# 创建隔离网络
docker network create --internal isolated-network
# 只有特定容器可以访问
docker run -d --name db --network isolated-network mysql
docker run -d --name app --network isolated-network myapp
调试技巧 #
测试连通性 #
bash
# 使用ping测试
docker exec app ping -c 3 db
# 使用curl测试HTTP
docker exec app curl -I http://api:8000
# 使用nc测试端口
docker exec app nc -zv db 3306
# 使用telnet测试
docker exec app telnet db 3306
查看DNS解析 #
bash
# 查看DNS配置
docker exec app cat /etc/resolv.conf
# 使用nslookup
docker exec app nslookup db
# 使用dig
docker exec app dig db
抓包分析 #
bash
# 在容器内抓包
docker exec app tcpdump -i eth0 port 3306
# 使用netshoot容器
docker run --rm --net container:app nicolaka/netshoot tcpdump -i eth0
小结 #
本节学习了Docker容器互联的方法:
- 容器互联的两种方式
- 服务发现和DNS解析
- 容器间通信配置
- 负载均衡实现
- 服务依赖管理
- 网络安全配置
下一步 #
接下来,让我们学习 Compose基础,了解Docker Compose的基本使用。