• Docker容器端口暴露方式


    【Bridge 模式】

    Docker 进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的 Docker 容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。从 docker0 子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为 eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中。可以通过brctl show命令查看:

    1. [root@k8s-node01 ~]# brctl show
    2. bridge name bridge id STP enabled interfaces
    3. docker0 8000.02426b181b43 no vetha2bf9e3

    bridge 模式是 docker 的默认网络模式,使用docker run -p时,实际上是通过 iptables 做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。bridge模式如下图所示:

    1. [root@k8s-node01 ~]# iptables -t nat -nvL
    2. Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
    3. pkts bytes target prot opt in out source destination
    4. 2 470 KUBE-SERVICES all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */
    5. 1 60 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
    6. Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
    7. pkts bytes target prot opt in out source destination
    8. Chain OUTPUT (policy ACCEPT 2 packets, 152 bytes)
    9. pkts bytes target prot opt in out source destination
    10. 297 20227 KUBE-SERVICES all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */
    11. 0 0 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
    12. Chain POSTROUTING (policy ACCEPT 2 packets, 152 bytes)
    13. pkts bytes target prot opt in out source destination
    14. 442 29299 KUBE-POSTROUTING all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes postrouting rules */
    15. 0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
    16. 0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
    17. Chain DOCKER (2 references)
    18. pkts bytes target prot opt in out source destination
    19. 0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
    20. 0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80
    21. Chain KUBE-FIREWALL (0 references)
    22. pkts bytes target prot opt in out source destination
    23. 0 0 KUBE-MARK-DROP all -- * * 0.0.0.0/0 0.0.0.0/0
    24. Chain KUBE-KUBELET-CANARY (0 references)
    25. pkts bytes target prot opt in out source destination
    26. Chain KUBE-LOAD-BALANCER (0 references)
    27. pkts bytes target prot opt in out source destination
    28. 0 0 KUBE-MARK-MASQ all -- * * 0.0.0.0/0 0.0.0.0/0
    29. Chain KUBE-MARK-DROP (1 references)
    30. pkts bytes target prot opt in out source destination
    31. 0 0 MARK all -- * * 0.0.0.0/0 0.0.0.0/0 MARK or 0x8000
    32. Chain KUBE-MARK-MASQ (2 references)
    33. pkts bytes target prot opt in out source destination
    34. 0 0 MARK all -- * * 0.0.0.0/0 0.0.0.0/0 MARK or 0x4000
    35. Chain KUBE-NODE-PORT (1 references)
    36. pkts bytes target prot opt in out source destination
    37. Chain KUBE-POSTROUTING (1 references)
    38. pkts bytes target prot opt in out source destination
    39. 2 152 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0 mark match ! 0x4000/0x4000
    40. 0 0 MARK all -- * * 0.0.0.0/0 0.0.0.0/0 MARK xor 0x4000
    41. 0 0 MASQUERADE all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service traffic requiring SNAT */
    42. Chain KUBE-SERVICES (2 references)
    43. pkts bytes target prot opt in out source destination
    44. 0 0 KUBE-MARK-MASQ all -- * * !10.2.0.0/16 0.0.0.0/0 /* Kubernetes service cluster ip + port for masquerade purpose */ match-set KUBE-CLUSTER-IP dst,dst
    45. 0 0 KUBE-NODE-PORT all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
    46. 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 match-set KUBE-CLUSTER-IP dst,dst

    比如现在我们运行一个 busybox 容器

    1. [root@k8s-node01 ~]# docker run -tid --net=bridge --name docker_bri busybox top
    2. c7329745be212689b35800ceabea69f9fd4f9cc015948fff14fd6fbe1070ea50
    3. [root@k8s-node01 ~]# brctl show
    4. bridge name bridge id STP enabled interfaces
    5. docker0 8000.02426b181b43 no vetha2bf9e3
    6. vethf1b9d2e

    然后进入到容器内部去查看网络情况,这里我们需要使用到一个新的命令docker exec,用来进入容器内部,要记住我们要进行终端交互,所以要带上-it两个参数:

    1. [root@k8s-node01 ~]# docker exec -it docker_bri /bin/sh
    2. / # ifconfig -a
    3. eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
    4. inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0
    5. UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
    6. RX packets:0 errors:0 dropped:0 overruns:0 frame:0
    7. TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
    8. collisions:0 txqueuelen:0
    9. RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
    10. lo Link encap:Local Loopback
    11. inet addr:127.0.0.1 Mask:255.0.0.0
    12. UP LOOPBACK RUNNING MTU:65536 Metric:1
    13. RX packets:0 errors:0 dropped:0 overruns:0 frame:0
    14. TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
    15. collisions:0 txqueuelen:1000
    16. RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
    17. / # route -n
    18. Kernel IP routing table
    19. Destination Gateway Genmask Flags Metric Ref Use Iface
    20. 0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
    21. 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0

    可以通过ip link show命令查看到对应的 veth pair 对名称

    1. [root@k8s-node01 ~]# ip link show
    2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    4. 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    5. link/ether 00:0c:29:44:09:ce brd ff:ff:ff:ff:ff:ff
    6. 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    7. link/ether 02:42:6b:18:1b:43 brd ff:ff:ff:ff:ff:ff
    8. 4: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    9. link/ether 0a:9b:ca:3f:fc:c0 brd ff:ff:ff:ff:ff:ff
    10. 5: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default
    11. link/ether ce:34:a0:07:fd:88 brd ff:ff:ff:ff:ff:ff
    12. 9: vetha2bf9e3@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
    13. link/ether ae:94:ef:e4:4d:e2 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    14. 11: vethf1b9d2e@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
    15. link/ether 4a:4d:83:2c:70:7a brd ff:ff:ff:ff:ff:ff link-netnsid 1

    通过上面的命令可以验证我们前面提到的 bridge 模式原理。

    【自定义网络】

    另外我们可以通过自定义的 Docker 网络来连接多个容器,而不是使用--link命令,比如现在我们有一个新的容器想要和上面的 docker_bri 容器建立互连关系,之前我们可以使用 --link 命令:

    1. [root@k8s-node01 ~]# docker run -tid --link docker_bri --name docker_bri1 busybox top
    2. bd0a67e04610107b384c47f8cd530e5d92f7a97f41e586ab3eb57150ba27c133
    3. [root@k8s-node01 ~]# docker exec -it docker_bri1 /bin/sh
    4. / # ping docker_bri
    5. PING docker_bri (172.17.0.3): 56 data bytes
    6. 64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.142 ms
    7. 64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.087 ms
    8. ^C
    9. --- docker_bri ping statistics ---
    10. 2 packets transmitted, 2 packets received, 0% packet loss
    11. round-trip min/avg/max = 0.087/0.114/0.142 ms

    我们可以看到在新创建的容器上可以访问到我们连接的容器,但是反过来却不行了,因为--link是单方面的:

    1. [root@k8s-node01 ~]# docker exec -it docker_bri /bin/sh
    2. / # ping docker_bri1
    3. ping: bad address 'docker_bri1'
    4. / #

    这个时候我们可以通过自定义网络的方式来实现互联互通,首先创建一个自定义的网络:

    1. [root@k8s-node01 ~]# docker network create -d bridge my-net
    2. 7eee7c618ebcde272f087583f8ae0f50fca45c2d12ed9e65c951b5e5a5cc6399

    然后我们使用自定义的网络运行一个容器:

    1. [root@k8s-node01 ~]# docker run -it --rm --name busybox1 --network my-net busybox sh
    2. / #

    打开终端再运行一个容器:

    1. [root@k8s-node01 ~]# docker run -it --rm --name busybox2 --network my-net busybox sh
    2. / #

    然后我们通过 ping 来证明 busybox1 容器和 busybox2 容器建立了互联关系。 在 busybox1 容器输入以下命令:

    1. [root@k8s-node01 ~]# docker run -it --rm --name busybox1 --network my-net busybox sh
    2. / # ping busybox2
    3. PING busybox2 (172.18.0.3): 56 data bytes
    4. 64 bytes from 172.18.0.3: seq=0 ttl=64 time=2.050 ms
    5. 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.430 ms
    6. ^C
    7. --- busybox2 ping statistics ---
    8. 2 packets transmitted, 2 packets received, 0% packet loss
    9. round-trip min/avg/max = 0.430/1.240/2.050 ms
    10. / #

    用 ping 来测试连接 busybox2 容器,它会解析成 172.18.0.3。 同理在 busybox2 容器执行 ping busybox1,也会成功连接到:

    1. [root@k8s-node01 ~]# docker run -it --rm --name busybox2 --network my-net busybox sh
    2. / # ping busybox1
    3. PING busybox1 (172.18.0.2): 56 data bytes
    4. 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.106 ms
    5. 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.157 ms
    6. ^C
    7. --- busybox1 ping statistics ---
    8. 2 packets transmitted, 2 packets received, 0% packet loss
    9. round-trip min/avg/max = 0.106/0.131/0.157 ms
    10. / #

    这样,busybox1 容器和 busybox2 容器建立了互联关系,如果你有多个容器之间需要互相连接,推荐使用后面的 Docker Compose。

    【Host 模式】

    如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。 Host模式如下图所示

    docker host network

    使用 host 模式也很简单,只需要在运行容器的时候指定 --net=host 即可。

    【Container 模式】

    这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。 Container 模式如下图所示:

    docker container network

    在运行容器的时候指定 --net=container:目标容器名 即可。实际上我们后面要学习的 Kubernetes 里面的 Pod 中容器之间就是通过 Container 模式链接到 pause 容器上面的,所以容器直接可以通过 localhost 来进行访问。

    【None 模式】

    使用 none模式,Docker 容器拥有自己的 Network Namespace,但是并不为Docker 容器进行任何网络配置。也就是说这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。 None模式示意图如下所示:

    docker none network

    选择这种模式,一般是用户对网络有自己特殊的需求,不希望 docker 预设置太多的东西。

  • 相关阅读:
    3. 文档概述(Documentation Overview)
    k8s网络插件之Calico
    hackmyvm之gift
    携职教育:注意!2022年中级会计考试结束后别忘了做这些事!
    栈和队列的几道OJ题(数据结构、C语言、LeetCode)
    AngularJS实战之依赖注入与应用实践
    腾讯核心高级架构师汇总Java全栈知识点笔记,“吃透”后成功上岸!
    DPU网络开发SDK——DPDK(十四)
    怎么学编程效率高,编程练习网站编程软件下载,中文编程开发语言工具下载
    基于蚁群算法的车辆路径规划问题的研究附Matlab代码
  • 原文地址:https://blog.csdn.net/hedao0515/article/details/133849476