一、当Docker容器突然"失联"时该怎么办

作为一名常年和Docker打交道的运维人员,我最怕听到开发同事说:"我的容器怎么连不上数据库了?"这种网络问题就像家里的Wi-Fi突然断连,让人抓狂。但别担心,今天我们就来聊聊如何像侦探一样,一步步揪出Docker网络问题的真凶。

首先我们得明白,Docker的网络是个"套娃"系统。容器有自己的网络空间,宿主机又有自己的网络配置,中间还隔着防火墙、路由表这些"门卫"。比如最近我遇到一个典型情况:某个Python服务容器突然无法访问Redis容器,但昨天还好好的。

# 技术栈:Python + Docker
# 测试网络连接的示例代码
import redis
import socket

try:
    # 尝试连接Redis容器
    r = redis.Redis(host='redis-container', port=6379)
    print(r.ping())  # 应该返回True
except Exception as e:
    print(f"连接失败: {e}")
    
# 检查基础网络
try:
    socket.create_connection(('redis-container', 6379), timeout=3)
    print("端口可达")
except socket.error as e:
    print(f"端口不可达: {e}")

二、排查网络问题的"三板斧"

1. 先看看容器是不是还活着

就像医生先检查病人的脉搏一样,我们得确认容器状态:

# 查看容器状态
docker ps -a | grep "my-container"

# 检查容器日志
docker logs --tail 50 my-container

2. 进入容器内部做网络诊断

有时候需要在容器内部"把脉":

# 进入容器内部
docker exec -it my-container /bin/bash

# 在容器内执行(假设是基于Alpine的镜像)
ping redis-container
nc -zv redis-container 6379
traceroute redis-container

3. 检查Docker网络配置

Docker的网络配置就像城市的道路规划,出了问题谁都到不了目的地:

# 查看网络列表
docker network ls

# 检查容器连接的网络
docker inspect my-container | grep Network

# 查看网络详情
docker network inspect my-bridge-network

三、那些年我们踩过的网络坑

案例1:跨容器通信失败

上周我们的Java服务突然无法访问MongoDB容器,排查后发现:

# 原来两个容器不在同一个网络
docker network connect my-network mongodb-container
docker network connect my-network java-app-container

# 技术栈:Java + MongoDB
// Java连接代码示例
MongoClient mongoClient = new MongoClient("mongodb-container");
System.out.println("连接状态:" + mongoClient.getDatabase("admin").runCommand(new BasicDBObject("ping", 1)));

案例2:端口映射失灵

Nginx容器映射了80端口却无法访问,原因是:

# 发现宿主机端口被占用
netstat -tulnp | grep :80

# 解决方案是修改映射或释放端口
docker run -p 8080:80 nginx

案例3:DNS解析异常

Node.js服务突然无法解析内部域名,原来是:

# 检查容器的resolv.conf
docker exec -it nodejs-container cat /etc/resolv.conf

# 解决方案是自定义DNS
docker run --dns 8.8.8.8 --dns 8.8.4.4 my-node-app

四、高级网络问题排查武器库

当基础方法不管用时,我们需要更专业的工具:

1. 使用tcpdump抓包

# 在宿主机上抓取容器网络流量
tcpdump -i docker0 -nn -vvv

# 或者在容器内抓包
docker exec -it my-container tcpdump -i eth0 -nn -vvv

2. 检查iptables规则

Docker会生成复杂的iptables规则:

iptables -L -n -v --line-numbers
iptables -t nat -L -n -v

3. 使用conntrack跟踪连接

conntrack -L | grep 6379  # 查看Redis连接状态

五、防患于未然的网络配置建议

  1. 明确网络驱动选择:根据场景选bridge、host还是overlay
  2. 合理规划子网:避免IP冲突,比如:
    docker network create --subnet=172.28.0.0/16 my-net
    
  3. 善用网络别名:让容器通过友好名称通信
    docker run --net=my-net --name=web --network-alias=frontend nginx
    
  4. 做好端口管理:使用明确的端口映射
    docker run -p 192.168.1.100:8080:80 nginx
    

六、不同场景下的网络方案选择

  1. 开发环境:简单的bridge网络就够了
  2. 微服务架构:考虑使用自定义bridge或overlay网络
  3. 生产集群:可能需要结合Kubernetes的CNI插件

比如我们的Go微服务就采用了自定义网络:

// 技术栈:Golang + Docker
func main() {
    resp, err := http.Get("http://user-service:8080/api")
    if err != nil {
        log.Fatalf("服务调用失败: %v", err)
    }
    defer resp.Body.Close()
    // ...处理响应
}

七、常见问题速查手册

  1. 现象:容器无法访问外网

    • 检查:docker exec -it container ping 8.8.8.8
    • 解决:可能是DNS配置问题或防火墙阻止
  2. 现象:容器间无法通信

    • 检查:是否在同一网络,防火墙规则
    • 解决:docker network connect或检查安全组
  3. 现象:端口映射无效

    • 检查:宿主机端口是否占用,SELinux状态
    • 解决:更换端口或systemctl stop firewalld

八、终极解决方案:重建网络环境

当所有方法都无效时,可以尝试:

# 停止Docker服务
systemctl stop docker

# 清理网络配置
ip link delete docker0
iptables -F
iptables -t nat -F

# 重新启动
systemctl start docker

记住,这就像网络问题的"核按钮",慎用!

总结

Docker网络问题就像迷宫,但只要掌握了正确的路线图,总能找到出口。关键是要有系统地排查:从容器内部到宿主机,从基础连接到高级配置。建议平时多积累典型问题的解决方案,建立自己的排查清单。遇到问题时,保持耐心,像剥洋葱一样一层层分析,真相总会水落石出。