15.6.5 宿主机与外部网络通信

5. 宿主机与外部网络通信#

宿主机与外部网络通信决定了容器“出站访问”和“入站服务”的可达性。本节聚焦桥接网络下的默认行为、端口映射与防火墙协同,并给出可执行示例、排错步骤与练习。

一、原理草图:出站与入站流量路径

文章图片

二、出站通信验证(容器访问外网)
1)启动容器并测试 DNS 与外网连通:

# 1) 启动一个临时容器
docker run --rm -it --name net-test alpine:3.19 sh

# 2) 安装测试工具(示例为 Alpine)
apk add --no-cache curl bind-tools iproute2

# 3) DNS 解析
nslookup example.com

# 4) 出站访问
curl -I https://example.com

# 5) 查看默认路由
ip route

关键命令解释
- ip route:确认默认路由是否指向 docker0 网关
- nslookup:验证 DNS 是否可用
- curl -I:验证 HTTPS 出站是否可达

预期效果:能解析域名并返回 HTTP 200/301 状态码。

三、入站通信示例(外部访问容器服务)
1)在容器内启动 Web 服务并发布端口:

# 1) 启动 nginx 容器,将宿主机 8080 映射到容器 80
docker run -d --name web -p 8080:80 nginx:1.25

# 2) 查看端口映射
docker ps --format "table {{.Names}}\t{{.Ports}}"

# 3) 宿主机本地访问验证
curl -I http://127.0.0.1:8080

访问路径:外部客户端 → 宿主机 8080 → iptables DNAT → 容器 80
安全建议:限制绑定 IP

# 仅允许本机访问
docker run -d --name web-local -p 127.0.0.1:8081:80 nginx:1.25

四、宿主机与容器互通示例

# 1) 查看容器 IP
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web

# 2) 宿主机直连容器 IP
curl -I http://172.17.0.3

# 3) 容器访问宿主机(使用 docker0 网关)
docker exec -it web sh -c "apk add --no-cache curl && curl -I http://172.17.0.1"

五、iptables 规则检查与解释

# 查看 NAT 表规则(重点:DOCKER 链)
iptables -t nat -S | sed -n '1,120p'

# 查看是否存在 DNAT 规则
iptables -t nat -S | grep -i docker

关键规则说明
- MASQUERADE:容器出站 SNAT,转换为宿主机 IP
- DNAT:宿主机端口转发到容器端口

六、常见问题排查清单(含命令)

1)外部无法访问容器端口

# 检查端口是否映射
docker ps --format "table {{.Names}}\t{{.Ports}}"

# 检查容器服务是否监听 0.0.0.0
docker exec -it web ss -lntp

# 检查宿主机防火墙
firewall-cmd --list-ports
iptables -S | head -n 50

解决思路
- 若未监听 0.0.0.0,调整服务绑定地址
- 放行端口:

# firewalld 放行 8080
firewall-cmd --add-port=8080/tcp --permanent
firewall-cmd --reload

2)容器无法访问外网

# 容器内 DNS 检查
docker exec -it web cat /etc/resolv.conf

# 宿主机转发检查
sysctl net.ipv4.ip_forward

解决思路
- net.ipv4.ip_forward=1

sysctl -w net.ipv4.ip_forward=1
  • 检查 MASQUERADE 规则是否存在

3)端口冲突

# 查找占用端口的进程
ss -lntp | grep :8080

解决思路:更换映射端口或停止占用进程。

七、练习(含目标与验证)
1)练习一:仅允许本机访问
- 目标:容器服务只允许本机访问
- 操作:

docker run -d --name web-only-local -p 127.0.0.1:9090:80 nginx:1.25
  • 验证:
curl -I http://127.0.0.1:9090
# 远端访问应失败

2)练习二:模拟端口冲突排错
- 目标:识别并解决端口冲突
- 操作:

# 假设 8080 已被占用
docker run -d --name web-conflict -p 8080:80 nginx:1.25
  • 解决:
ss -lntp | grep :8080
docker run -d --name web-ok -p 8082:80 nginx:1.25

八、实践建议
- 记录端口映射清单与用途
- 优先使用反向代理统一入口,减少暴露端口
- 出口访问受控环境中,结合防火墙/安全组做策略收敛