一、Docker网络基础扫盲

刚开始玩Docker的时候,总觉得容器之间能互相访问是理所当然的,直到某天发现服务A死活调不通服务B,才意识到网络配置是个大坑。Docker默认提供了几种网络模式:

  1. bridge:默认模式,容器通过虚拟网桥docker0通信
  2. host:直接使用宿主机网络栈
  3. none:完全隔离的网络环境
  4. overlay:跨主机的容器网络方案

举个实际例子,当你用默认bridge网络启动两个容器时:

# 启动两个nginx容器(技术栈:Docker CLI)
docker run -d --name nginx1 nginx:alpine
docker run -d --name nginx2 nginx:alpine

# 尝试在nginx1中ping nginx2
docker exec nginx1 ping nginx2  # 会报"Name or service not known"

这里的问题在于:默认bridge网络下的容器只能通过IP互通,无法使用容器名称作为主机名解析。这就是最常见的初级坑之一。

二、典型网络问题排查三板斧

2.1 检查容器基础连通性

遇到网络问题首先执行"体检三部曲":

# 1. 检查容器IP分配(技术栈:Docker + Linux命令)
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx1

# 2. 测试基础网络连通性
docker exec nginx1 ping 172.17.0.3  # 替换为nginx2的实际IP

# 3. 检查端口映射情况
docker port nginx1  # 查看端口绑定情况

2.2 自定义网络实战

解决前文提到的名称解析问题,最优雅的方式是创建自定义网络:

# 创建自定义bridge网络
docker network create mynet

# 将容器接入自定义网络
docker run -d --name nginx3 --network mynet nginx:alpine
docker run -d --name nginx4 --network mynet nginx:alpine

# 现在可以直接用容器名通信了
docker exec nginx3 ping nginx4  # 成功!

自定义网络的优势在于:

  • 自动DNS解析
  • 更好的隔离性
  • 支持网络别名(alias)等高级功能

2.3 防火墙与路由排查

如果跨主机通信失败,可能需要检查这些:

# 查看iptables规则(技术栈:Linux网络)
sudo iptables -L -n --line-numbers

# 检查路由表
route -n

# 典型问题案例:当Docker容器无法访问外网时
sudo iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j MASQUERADE

三、高级网络问题解决方案

3.1 容器与宿主机服务互通

假设宿主机运行着MySQL,容器需要连接它:

# 错误示范:直接连接localhost
docker run --rm mysql mysql -h localhost -u root  # 失败!

# 正确做法1:使用host.docker.internal(Docker 18.03+)
docker run --rm mysql mysql -h host.docker.internal -u root

# 正确做法2:使用宿主机真实IP
docker run --rm mysql mysql -h 192.168.1.100 -u root

3.2 多容器复杂组网

通过docker-compose实现复杂网络拓扑:

# docker-compose.yml(技术栈:Docker Compose)
version: '3'
services:
  web:
    image: nginx
    networks:
      - frontend
      - backend

  db:
    image: mysql
    networks:
      - backend

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true  # 禁止外部访问

这种配置实现了:

  • web服务可同时访问内外网
  • 数据库仅限内部访问
  • 网络分层清晰

四、疑难杂症处理手册

4.1 诡异的端口占用问题

有时会出现"端口已被占用"但实际没服务监听的情况:

# 检查端口占用真相(技术栈:Linux系统命令)
sudo ss -tulnp | grep 80

# Docker特定检查
docker ps --format "table {{.Names}}\t{{.Ports}}"

# 终极解决方案:重启docker服务
sudo systemctl restart docker

4.2 容器间通信延迟高

当容器间TCP通信出现异常延迟时:

# 检查网络延迟(技术栈:Linux网络工具)
docker exec -it container1 ping container2

# 使用更专业的tcptraceroute
docker exec -it container1 tcptraceroute container2 80

# 可能的原因:
# 1. 错误的MTU设置
# 2. 防火墙规则过多
# 3. 网络驱动不兼容

4.3 DNS解析故障

容器内DNS解析失败的修复步骤:

# 检查容器DNS配置
docker exec -it nginx cat /etc/resolv.conf

# 临时解决方案:指定DNS服务器
docker run --dns 8.8.8.8 --rm alpine ping baidu.com

# 永久解决方案:修改docker守护进程配置
# /etc/docker/daemon.json
{
  "dns": ["8.8.8.8", "114.114.114.114"]
}

五、最佳实践与经验总结

经过多年踩坑,总结出这些黄金法则:

  1. 生产环境永远使用自定义网络
  2. 跨主机通信优先考虑overlay网络
  3. 慎用--network=host模式,它会带来安全隐患
  4. 定期检查iptables规则,Docker会自动修改它们
  5. 复杂项目使用docker-compose管理网络拓扑

记住:Docker网络问题的排查就像破案,需要:

  • 先确认案发现场(网络现状)
  • 寻找蛛丝马迹(日志、配置)
  • 重现犯罪过程(最小复现)
  • 实施抓捕(修复方案)

只要按照这个方法论,再诡异的网络问题也能水落石出。