本专栏文章持续更新,新增内容使用蓝色表示。

环境介绍

开始之前,先介绍一下我的环境:

  • Kubernetes 集群(1 master + 2 worker)

  • Calico 网络插件

  • Docker 容器运行时

如果只是想了解 Docker 网络,只需安装 Docker 即可,无需搭建完整的 K8s 集群。

一、初始环境检查

1.1 查看初始网络状态

在安装 Docker 之前,建议先使用以下命令查看主机的网络接口情况,和后续进行对比。正常情况下,应该只能看到 lo、ens33 等基础网络接口。

ip a s

1.2 安装 Docker 后检查网络

安装  Docker 之后,再次运行 ip a s 命令,会出现一个新的网络接口(docker0 网桥)。

后续命令如果权限不够,可以加 sudo 提权,此处为了演示方便,直接切换到了 root 用户身份。

1.3 查看 Docker 网络列表

使用 docker network ls 命令列出 docker 当前网络:

# 需要 sudo 提权
docker network ls

从上图的输出结果中可以看到有三种不同的驱动,分别为 bridge、host、null。

安装 docker 之后这三种驱动就会创建出三个不同类型的网络。其中 bridge 是默认网络,创建容器时如果没有明确指定,都会自动加入这个网络。

二、 默认 Bridge 网络

使用 docker network inspect bridge 命令查看该网络的详细信息:

docker network inspect bridge

重点关注:Subnet 网段、Gateway 网关、Containers 列表(当前为空)。

2.1 创建测试容器

终端 1 - 创建并进入容器:

docker run -it --name apline0 --rm alpine sh

终端 2 - 观察网络变化:

# 查看新出现的 veth 接口
ip a s

# 再次检查 bridge 网络
docker network inspect bridge

使用 ip a s 命令查看网络接口信息时,可以发现多了一个 veth55d60a2@if3(名字可能不同)。

并且查看 bridge 网络信息,发现 Containers 属性里面多了 apline0 容器的信息。

2.2 分析网络接口对应关系

下面针对多出来的接口进行分析。

终端 2 - 在宿主机查看 veth 接口详情

ip -json address show dev veth55d60a2 | jq .

# 如果未安装 jq,可以使用以下命令。
# CentOS/RHEL
dnf install jq

# Ubuntu/Debian  
apt install jq

终端 1 - 在容器内部使用 ip a s 命令查看网络接口情况:

ip a s


注意:在我的环境中,由于使用了 Calico 网络插件的 IPIP 模式,会看到 tunl0@NONE 接口。如果只安装了 Docker,应该只会看到 lo 和 eth0 两个接口。

现在再来解释一下,@if 后面的数字含义:

宿主机视角 (Host)                 容器视角 (Container)
───────────────────────────────────────────────────
10: veth55d60a2@if3             3: eth0@if10
    ↑                                ↑
在宿主机是第10个接口             在容器内是第3个接口
对端是容器的第3个接口            对端是宿主机的第10个接口

这是一对 veth pair,就像"虚拟网线"的两端。

2.3 网络连通性测试

2.3.1 容器访问外部网络

终端 1 - 在 alpine0 容器内测试:

ping -c 2 baidu.com

在 bridge 网络模式下,容器可以访问外部网络。

2.3.2 宿主机与容器通信

终端 2 - 在宿主机测试:

ping -c 3 172.17.0.2  # 替换为 alpine0 的实际 IP

宿主机也可以直接 ping 通容器。

2.3.3 容器间通信测试

终端 3 - 创建第二个容器:

docker run -it --name apline1 --rm alpine sh

顺便验证一下@ifx的对应关系:

在 alpine1 容器内测试:

ping -c 2 172.17.0.2

既然 IP 可以 ping 通,那域名呢?

答案是不能,因为默认的 bridge 网络不支持容器间的自动 DNS 解析,这是它的主要限制之一。不过自定义的 bridge 模式支持域名解析。(第三部分介绍相关内容)

2.4 端口映射与外部访问

既然容器可以 ping 通外部网络,那外部网络能否 ping 通容器呢?

答案是需要通过端口映射。

创建一个名为 nginx-expose 的容器,将宿主机的 8080 端口和容器的 80 端口进行关联。

docker run -d --name nginx-expose --rm -p 8080:80 nginx

docker network inspect bridge | grep nginx-expose -C 5

此时 curl 宿主机的 8080 端口就可以看到 nginx 的欢迎页面。

在浏览器输入http://192.168.30.130:8080,也可以看到欢迎页面。

三、自定义 Bridge 网络

解决默认 bridge 网络的限制。

3.1 创建自定义网络

docker network create -d bridge mynet

docker network ls

使用以下命令查看自定义网络带来的变化:

ip a s

docker network inspect mynet

3.2 在自定义网络中测试

在自定义的 mynet 网络中创建两个容器,进行测试。

# 终端1
docker run -it --name alpine-mynet0 --hostname alpine-mynet0 --network mynet --rm alpine sh

# 终端2
docker run -it --name alpine-mynet1 --hostname alpine-mynet1 --network mynet --rm alpine sh

此处主要测试域名能否 ping 通:

答案是可以。

即使不指定主机名,也能通过容器名进行通信:

# 终端3
docker run -it --name alpine-mynet2 --network mynet --rm alpine sh

其余网络模式在下一篇介绍。


如有问题或建议,欢迎在评论区中留言~

更多推荐