06-docker网络模式

在这里插入图片描述

Docker网络

我们使用容器,不但是运行单机程序,当然是需要运行网络服务在容器中,那么如何配置docker的容器网络,基础网络配置,网桥配置。

docker 网络功能

docker的网络功能就是利用Linux的network namespace,network bridge,虚拟网络设备实现的。

在默认的情况下docker安装完毕后会生成网桥docker0,可以理解为一个虚拟的交换机,对两端的数据进行发送

docker的网络接口默认都是虚拟网络接口

docker容器网络在宿主机和容器内分别创建一个虚拟接口,让他们彼此通信

[root@docker-200 /www.yuchaoit.cn/harbor]#ifconfig docker0
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:3eff:feca:fa2b  prefixlen 64  scopeid 0x20<link>
        ether 02:42:3e:ca:fa:2b  txqueuelen 0  (Ethernet)
        RX packets 180132  bytes 9772747 (9.3 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 289156  bytes 448238750 (427.4 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@docker-200 /www.yuchaoit.cn/harbor]#

docker创建一个容器流程

  • 创建一对虚拟接口,分别放到本地主机和新容器中
  • 宿主机一端桥接到默认的docker0,且有一个唯一的名字
  • 另一端放入容器里,改名为eth0该接口只能在容器的命名空间里可见
  • 从网桥可用地段获取一个空闲的ip,分配给容器eth0,且默认路由桥接到宿主机网卡
  • 这些完后,容器可以使用eth0虚拟网卡和其他容器相连接
docker run 启动时候,若没有添加--net参数,默认使用bridge桥接模式
docker实际是通过iptables做了dnat规则

docker网络图解

首先,要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)来收发数据包,此外,如果不通子网之间需要进行通信,需要路由机制

Docker中网络接口默认都是虚拟接口,虚拟接口的优势是效率转发高

Docker 容器网络就利用了这项技术。它在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连通(这样的一对接口叫做 veth pair)。

在这里插入图片描述

接下来的部分将介绍在一些场景中,Docker所有的网络制定配置,以及通过Linux命令来进行调整,补充,甚至通过替换Docker默认网络配置

关于docker网络相关命令

下面是一个跟 Docker 网络相关的命令列表。

其中有些命令选项只有在 Docker 服务启动的时候才能配置,而且不能马上生效。
-b BRIDGE 或 --bridge=BRIDGE 指定容器挂载的网桥
--bip=CIDR 定制 docker0 的掩码
-H SOCKET... 或 --host=SOCKET... Docker 服务端接收命令的通道
--icc=true|false 是否支持容器之间进行通信
--ip-forward=true|false 请看下文容器之间的通信
--iptables=true|false 是否允许 Docker 添加 iptables 规则
--mtu=BYTES 容器网络中的 MTU
下面2个命令选项既可以在启动服务时指定,也可以在启动容器时指定。在 Docker 服务启动的时候指定则会成为默认值,后面执行 docker run 时可以覆盖设置的默认值。
--dns=IP_ADDRESS... 使用指定的DNS服务器
--dns-search=DOMAIN... 指定DNS搜索域
最后这些选项只有在 docker run 执行时使用,因为它是针对容器的特性内容。
-h HOSTNAME 或 --hostname=HOSTNAME 配置容器主机名
--link=CONTAINER_NAME:ALIAS 添加到另一个容器的连接
--net=bridge|none|container:NAME_or_ID|host 配置容器的桥接模式
-p SPEC 或 --publish=SPEC 映射容器端口到宿主主机
-P or --publish-all=true|false 映射容器所有端口到宿主主机

容器访问控制

容器的访问控制,主要是通过Linux上的iptables防火墙来进行管理和实现

iptables是Linux上默认的防火墙,在大部分的发行版中自带的。

容器访问外部网络

容器要想访问外部网络,需要本地系统的转发支持,在linux检查是否打开

$sysctl net.ipv4.ip_forward

net.ipv4.ip_forward = 1

如果为 0,说明没有开启转发,则需要手动打开。

$sysctl -w net.ipv4.ip_forward=1

如果在启动 Docker 服务的时候设定 --ip-forward=true, Docker 就会自动设定系统的 ip_forward 参数为 1。

容器之间访问

容器之间相互访问,需要两方面支持

容器的网络是否连接到互联网

默认情况下,所有容器都会被链接到docker0网桥上

要看本地系统的防火墙软件-iptables是否允许通过

1.Docker4种网卡模式(面试要问)

–net参数

--net=bridge 这个是默认值,连接到默认的网桥Docker0,这个模式给容器自动分配ip,且通过iptables的nat表和宿主机实现数据通信

--net=host 告诉docker不要将容器网络放在隔离的命名空间中,不要容器化容器内的网络,此时容器使用本地主机网络,他完全拥有本地主机接口和访问权限容器进程可以跟主机其他root进程一样可以打开范围端口,可以访问本地网络服务还可以让容器影响整个主机系统的事情,比如重启主机因此使用这个选项时要非常小心。

--net=container  container-->容器id
将新建容器的进程放到一个已经存在的网络栈中,新容器进程有自己的文件系统,但会和已存的容器共享ip地址和端口等网络资源。

--net=none 让docker容器不进行网络配置

查看docker的网络模式

查看当前docker已有的网络配置

[root@docker-200 ~]#docker network ls
NETWORK ID     NAME            DRIVER    SCOPE
6cb9ed4cc353   bridge          bridge    local
6d71aada2627   harbor_harbor   bridge    local
f3971eca0c0f   host            host      local
ff6208d689fb   none            null      local

查看docker0默认网桥

[root@docker-200 ~]#ifconfig docker0
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:3eff:feca:fa2b  prefixlen 64  scopeid 0x20<link>
        ether 02:42:3e:ca:fa:2b  txqueuelen 0  (Ethernet)
        RX packets 182668  bytes 9877642 (9.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 292481  bytes 473496962 (451.5 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@docker-200 ~]#

# 安装网桥管理工具
[root@docker-200 ~]#yum install bridge-utils -y

[root@docker-200 ~]#brctl show
bridge name    bridge id        STP enabled    interfaces
br-6d71aada2627        8000.02420be0d11c    no        veth074229e
docker0        8000.02423ecafa2b    no

查看端口映射与防火墙的关系

在这里插入图片描述

2.bridge模式

容器桥接网络原理

1. 当docker daemon第一次启动后,创建了一个虚拟的网桥,名字是docker0
2. 创建后,给这个网桥,默认分配一个子网,默认是172.17.0.1/16
3. 每创建一个容器,都自动创建一个veth设备对儿,一个关联docker0,另一端挂载容器里,叫做eth0,并且从网桥的地址段里,分配一个ip给容器,因此实现通信。
[root@docker-200 /etc/sysconfig/network-scripts]#docker inspect ff9|grep -i '"IPAddress"'
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2",

桥接网络模式特点

1. 同一个宿主机的容器可以相互连接,不同宿主机的不可以(iptables也不在一个机器么)
2.桥接模式的容器自动获取172.17.0.0/16网段的IP地址
[root@7dc8c7225862 /]# ifconfig |grep 172
        inet 172.17.0.5  netmask 255.255.0.0  broadcast 172.17.255.255
3.其他机器无法直接访问容器,需要通过端口映射。
4.每个容器映射到宿主机的端口,也唯一
5.容器可以借助宿主机的网络环境,访问其他机器。

桥接数据图

在这里插入图片描述

查看bridge模式详情

[root@docker-200 /etc/sysconfig/network-scripts]#docker network inspect bridge |jq
[
  {
    "Name": "bridge",
    "Id": "6cb9ed4cc353820c6753626de168b20dcf3d86ee3e6284318a98dac10d1a6864",
    "Created": "2022-08-27T22:02:43.680182817+08:00",
    "Scope": "local",
    "Driver": "bridge",
    "EnableIPv6": false,
    "IPAM": {
      "Driver": "default",
      "Options": null,
      "Config": [
        {
          "Subnet": "172.17.0.0/16",
          "Gateway": "172.17.0.1"
        }
      ]
    },
    "Internal": false,
    "Attachable": false,
    "Ingress": false,
    "ConfigFrom": {
      "Network": ""
    },
    "ConfigOnly": false,
    "Containers": {
      "bf84dad09ba34fd27dc3c743532c62227a104c38a8bc05cd89197f7507b7c12c": {
        "Name": "crazy_bartik",
        "EndpointID": "305fb33cef0514efb339ac3e7da0415c4bd382aab3b3db5923a7261a0d70ec80",
        "MacAddress": "02:42:ac:11:00:03",
        "IPv4Address": "172.17.0.3/16",
        "IPv6Address": ""
      },
      "d7ebdcb6d7fa45c8fc4e202bfb0bb049626166ff5e72453af69929e365ffc57e": {
        "Name": "infallible_cohen",
        "EndpointID": "51afb25f958f72f9c8c21b72779c3a36dab40953fdd74d58eb9b912a5e7cb4f7",
        "MacAddress": "02:42:ac:11:00:04",
        "IPv4Address": "172.17.0.4/16",
        "IPv6Address": ""
      },
      "ff9990f7e1f5fb14b486e59ad4087e9bf8ddd61a4d8cfdd5ff66b7036df75b08": {
        "Name": "gifted_hawking",
        "EndpointID": "c14577fa81212e1824bfcaccf45a85d5b85a64b81f02e35e41bfa08a8cbdd0ba",
        "MacAddress": "02:42:ac:11:00:02",
        "IPv4Address": "172.17.0.2/16",
        "IPv6Address": ""
      }
    },
    "Options": {
      "com.docker.network.bridge.default_bridge": "true",
      "com.docker.network.bridge.enable_icc": "true",
      "com.docker.network.bridge.enable_ip_masquerade": "true",
      "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
      "com.docker.network.bridge.name": "docker0",
      "com.docker.network.driver.mtu": "1500"
    },
    "Labels": {}
  }
]
[root@docker-200 /etc/sysconfig/network-scripts]#docker network inspect bridge |jq

基于busybox容器调试网络

默认其他镜像,都没有网络工具,要就自己定义
调试工具王者 busybox
[root@docker-200 /etc/sysconfig/network-scripts]#docker run -it busybox /bin/sh
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
5cc84ad355aa: Pull complete 
Digest: sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678
Status: Downloaded newer image for busybox:latest
/ # cd
~ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:05  
          inet addr:172.17.0.5  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:648 (648.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

~ # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0
~ # ping 10.0.0.200 -c 3
PING 10.0.0.200 (10.0.0.200): 56 data bytes
64 bytes from 10.0.0.200: seq=0 ttl=64 time=0.115 ms
64 bytes from 10.0.0.200: seq=1 ttl=64 time=0.079 ms
64 bytes from 10.0.0.200: seq=2 ttl=64 time=0.152 ms

--- 10.0.0.200 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.079/0.115/0.152 ms
~ # traceroute 10.0.0.200
traceroute to 10.0.0.200 (10.0.0.200), 30 hops max, 46 byte packets
 1  10.0.0.200 (10.0.0.200)  0.012 ms  0.010 ms  0.009 ms

若是遇见要自定义容器网段的需求

Docker服务默认会创建一个docker0网桥(其上有一个 docker0 内部接口),它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。

Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信,它还给出了 MTU(接口允许接收的最大传输单元),通常是 1500 Bytes,或宿主主机网络路由上支持的默认值。这些值都可以在服务启动的时候进行配置。

3.host模式

1. hosts启动的容器,没有自己的网卡,ip信息,直接用宿主机的
2. 但是除了network网络空间,其他如进程,文件系统,还是容器自己的
3.  通过参数 --network host 开启
4. host模式,没有端口映射功能
5.直接使用宿主机的网络环境,因此网络性能更高一筹。

host模式实战

1.看看宿主机端口
[root@docker-200 /www.yuchaoit.cn]#netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1021/sshd           
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      1254/master         
tcp6       0      0 :::22                   :::*                    LISTEN      1021/sshd           
tcp6       0      0 ::1:25                  :::*                    LISTEN      1254/master         
[root@docker-200 /www.yuchaoit.cn]#


2.运行容器
[root@docker-200 /www.yuchaoit.cn]#docker run -d --network host nginx

3.查看端口,进程,即可分析出host模式的原理

4. 访问容器nginx
10.0.0.200

5.修改容器内nginx页面
[root@docker-200 /www.yuchaoit.cn]#docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
c4364027e26b   nginx     "/docker-entrypoint.…"   2 minutes ago   Up 2 minutes             clever_bell
[root@docker-200 /www.yuchaoit.cn]#docker exec -it clever_bell bash


cat >/etc/apt/sources.list <<'EOF'
deb http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
EOF






6.更新容器内信息
apt update
root@docker-200:/# apt install iproute2 net-tools -y

查看容器内网络信息,而然看到的是宿主机的网络配置
ifconfig

在这里插入图片描述

4.container模式

在这里插入图片描述

实战

1.准备一个容器
[root@docker-200 /www.yuchaoit.cn]#docker run -it --name expose-80 -p 80:80 centos:7.6.1810 
[root@3739c811d393 /]# 
[root@3739c811d393 /]# curl 127.0.0.1
curl: (7) Failed connect to 127.0.0.1:80; Connection refused


2.再来一个容器
[root@docker-200 ~]#
[root@docker-200 ~]#docker run -d --name to_nginx --network container:expose-80 nginx
10e9d3472f7254db2e9790d4e01a97d617321e8226ef35dd8be763a2b5077ba4
[root@docker-200 ~]#
[root@docker-200 ~]#


3.宿主机测试
[root@docker-200 ~]#docker inspect -f '{{.Name}} - {{.NetworkSettings.IPAddress }}' $(docker ps -aq)
/to_nginx - 
/expose-80 - 192.168.2.2
[root@docker-200 ~]#

4.查看nginx结果
[root@docker-200 ~]#curl -I 192.168.2.2
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Sat, 27 Aug 2022 15:39:35 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
Connection: keep-alive
ETag: "61cb2d26-267"
Accept-Ranges: bytes

[root@docker-200 ~]#

5.None模式

这个模式正常几乎不用

6.自定义网络模式

1.例如自定义创建一个网桥,分配一个子网,使用该网桥的容器互相之间,可以直接通信

2.创建自定义网络语法
docke network create -d <mode> --subnet <CIDR>  --gateway <网关>  <自定义网络名字>

# 引用自定义网络
docker run --network <自定义网络名> <镜像名>

# 删除自定义网络
docker network rm <自定义网络名>

实践

1. 创建自定义网络
docker network create -d bridge --subnet 192.168.55.0/24  --gateway 192.168.2.1 www.yuchaoit.cn_net

2.查看自定义网络
[root@docker-200 ~]#docker network create -d bridge --subnet 192.168.55.0/24  --gateway  192.168.55.1  www.yuchaoit.cn_net
9e2641d14fcad4c5b0e4000a16df68affeb198476d5472a8d40665e34bd5e0cc


[root@docker-200 ~]#docker network ls
NETWORK ID     NAME                  DRIVER    SCOPE
2c43f9897ff2   bridge                bridge    local
6d71aada2627   harbor_harbor         bridge    local
f3971eca0c0f   host                  host      local
ff6208d689fb   none                  null      local
9e2641d14fca   www.yuchaoit.cn_net   bridge    local


3.查看网卡情况
[root@docker-200 ~]#ip addr show br-9e2641d14fca 
317: br-9e2641d14fca: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:1d:cc:79:81 brd ff:ff:ff:ff:ff:ff
    inet 192.168.55.1/24 brd 192.168.55.255 scope global br-9e2641d14fca
       valid_lft forever preferred_lft forever
[root@docker-200 ~]#

4.查看宿主机的网桥
[root@docker-200 ~]#brctl show
bridge name    bridge id        STP enabled    interfaces
br-6d71aada2627        8000.02420be0d11c    no        
br-9e2641d14fca        8000.02421dcc7981    no        
docker0        8000.02423ecafa2b    no    

5.创建容器,用自建的网桥

[root@docker-200 ~]#
[root@docker-200 ~]#docker run --name busybox_myself_net  -it --network www.yuchaoit.cn_net busybox /bin/sh
/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:C0:A8:37:02  
          inet addr:192.168.55.2  Bcast:192.168.55.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:11 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:946 (946.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # ping 10.0.0.200
PING 10.0.0.200 (10.0.0.200): 56 data bytes
64 bytes from 10.0.0.200: seq=0 ttl=64 time=0.264 ms
64 bytes from 10.0.0.200: seq=1 ttl=64 time=0.139 ms
^C
--- 10.0.0.200 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.139/0.201/0.264 ms
/ # 
/ # 
/ # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.55.1    0.0.0.0         UG    0      0        0 eth0
192.168.55.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
/ # 
/ # 
/ # traceroute 10.0.0.200
traceroute to 10.0.0.200 (10.0.0.200), 30 hops max, 46 byte packets
 1  10.0.0.200 (10.0.0.200)  0.014 ms  0.009 ms  0.008 ms
/ # 


6.再运行第二个容器,查看2个容器的网络连接性
docker run --name busybox2_myself_net  -it --network www.yuchaoit.cn_net busybox /bin/sh

7.容器之间可以通过主机名通信

ping  busybox2_myself_net  -c 2
ping  busybox_myself_net  -c 2

提取容器ip地址

1. 进入容器内部后
cat /etc/hosts
会显示自己以及(– link)软连接的容器IP

2.使用命令

docker inspect <container id>
或
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name_or_id


3.要获取所有容器名称及其IP地址只需一个命令。
docker inspect -f '{{.Name}} - {{.NetworkSettings.IPAddress }}' $(docker ps -aq)

如果使用docker-compose命令将是:

docker inspect -f '{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)

4.显示所有容器IP地址:
docker inspect --format='{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)

-----------------------------------------------------------------------------------------------

经验:可以考虑在 ~/.bashrc 中写一个 bash 函数:
function docker_ip() {
    sudo docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'  $1
}
function dockeriplist() {
    sudo docker inspect -f '{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)
}



执行docker_ip <container-ID>可以看到单个容器的IP

执行dockeriplist 可以列出所有的IP
Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐