这篇文章上次修改于 693 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
CentOS 版本:centos-release-7-2.1511.el7.centos.2.10.x86_64
Docker 版本:Docker version 19.03.12, build 48a66213fe
nginx 版本:1.19.1

问题描述

使用如下指令启动一个 nginx 容器: docker run -d --name nginx-test -p 80:80 nginx

然后运行 curl localhost,返回 curl: (56) Recv failure: Connection reset by peer,不管使用 localhost 还是 127.0.0.1 还是内网地址,返回都是连接被重置。

但进入容器内部是可以正常访问的:docker exec -t nginx-test curl -L http://localhost

尝试过的方法

  • 关闭 SELinux

    • vi /etc/selinux/config
    • SELINUX=disabled
    • reboot
  • 设置 ipv4 转发

    • vi /etc/sysctl.conf
    • net.ipv4.ip_forward=1
    • service network restart
  • 关闭防火墙或者放行相关端口

    • systemctl stop firewalld
  • 怀疑是该主机支持 ipv6,从而没有监听 ipv4 端口
  • 怀疑是 nginx 的问题

以上方法都未奏效,其中 ipv6 和 nginx 方向误导了我,浪费了不少时间。

问题解决

最后发现问题出在网桥上,Docker 默认的网桥 docker0 有问题,新建个网桥,让容器使用新建的网桥就好了。下面是具体操作过程:

  • 安装 bridge-utils:sudo yum intall bridge-utils
  • 停止 docker 服务:service docker stop
  • 添加网桥:brctl addbr br0
  • 添加 ip 字段:ip addr add 172.16.0.1/24 dev br0
  • 启用网桥 br0:ip link set dev br0 up
  • 查看网络 br0:ifconfig br0
  • 修改 docker 默认网桥:

    • vi /etc/docker/daemon.json
    • "bridge":"br0"
  • 重启 docker:service docker start
  • 此时查看网桥:brctl show,在没有挂载容器前,依旧是 8000.000000000000
  • 运行测试容器:docker run -d --name nginx-test -p 80:80 nginx
  • 查看网桥详情:docker network inspect bridge
  • 此时容器挂载在网桥上了,再次查看网桥 id:brctl show,发现已经变成 8000.xxxxxxxxxxxx,说明已经起作用
  • 进入测试容器内部,测试外网:

    • docker exec -it nginx-test sh
    • ping baidu.com

一些补充指令:

  • 安装 bridge-utils 工具包:sudo yum install bridge-utils
  • 查看网桥信息:brctl show
  • 创建网桥:

    • sudo brctl addbr br0
    • sudo ip addr add 172.16.0.1/24 dev br0
    • sudo ip link set dev br0 up
  • 删除网桥:

    • sudo ip link set dev br0 down
    • sudo brctl delbr br0
  • 重启网络:service network restart

参考资料