Docker 网络理论

Docker 容器网络,主要采用架构由三部分组成:CNM、Libnetwork、驱动。

CNM :

    Docker网络采用的设计规范时CNM(Container Network Model) :  CNM规定了Docker网络的基础组成要素:Sandbox、Endpoint、Network。
    容器包含 Endpoint 和 Sandbox 而 Sandbox 包含 Endpoint 然后 Endpoint 和 Network 对接
。Sandbox:提供了容器的虚拟网络栈,也即端口套接字、IP路由表、防火墙、DNS配置等内容。 主要用于隔离容器网络与宿主机网络,形成了完成独立的容器网络环境。
。Network,Docker内部的虚拟子网,网络内的参与者相互可见并能够进行通讯。 Docker的虚拟网路和宿主机网络存在隔离关系,主要目的是形成容器间的安全通讯环境。
。Endpoint,主要负责创建连接,
    

Libetwork

    是CNM 的标准实行,Libnetwork(Go语言开发)实现了CNM中定义的全部三个组件,此外它还实现了本地服务发现、基于Ingress容器负载均衡,以及网络控制层和管理层功能。

驱动

    如果说Libnetwork实现控制层和管理层功能,那么 驱动 就负责实现数据层。 驱动通过实现特定网络类型的方式扩展了Docker网络栈,例入桥接网络和覆盖网络。
    Docker内置了诺干驱动,通常被称为原生驱动或者本地驱动。比如Bridge Driver、Host Driver、Overlay Driver、MacLan Driver、None Driver等等。 第三方也可以编写Docker 网络驱动,这些驱动被叫做远程驱动,例入Calico、Contiv、Kuryr 以及Weave。每个驱动负责创建其上所有网络资源的创建和管理。
其中 Bridge 和 Overlay 在开发过程中使用频率较高
。Bridge,Docker容器的默认网络驱动,通过网桥来实现网络通讯。
。Overlay,借助 Docker 集群模块 Docker Swarm 搭建的跨 Docker Daemon 网络。
    
Docker安装时,会自动安装一块Docker 网卡称为 docker0
$ ifconfig

 
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::42:23ff:feab:dd7e  prefixlen 64  scopeid 0x20<link>
        ether 02:42:23:ab:dd:7e  txqueuelen 0  (Ethernet)
        RX packets 6  bytes 452 (452.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 5  bytes 450 (450.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

2.桥接网络

    Docker 的bridge 网络采用内置的bridge驱动,而bridge的底层采用的是Linux内核中 Linux bridge技术。
    容器间的通信 bridge:

一、创建两个容器

$ docker container run -d --rm --name box1 busybox /bin/sh -c "while true; do sleep 3600; done”

Unable to find image 'busybox:latest' locally
Trying to pull repository docker.io/library/busybox ...
latest: Pulling from docker.io/library/busybox
7e5209d2300f: Pull complete
Digest: sha256:34c3559bbdedefd67195e766e38cfbb0fcabff4241dbee3f390fd6e3310f5ebc
Status: Downloaded newer image for docker.io/busybox:latest
019a0daed76f2c71ccb7879a259cc04eac9b60a826529c383f104ffa1ad12f3d

$ docker container run -d --rm --name box2 busybox /bin/sh -c "while true; do sleep 3600; done"
3325eedba7c2b16956b20d1eea968c74471e0fb42747fb73079f74bae460e16c
    查看容器
$ docker container ls

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
3325eedba7c2        busybox             "/bin/sh -c 'while..."   7 seconds ago       Up 6 seconds                            box2
019a0daed76f        busybox             "/bin/sh -c 'while..."   14 seconds ago      Up 13 seconds                           box1

$ docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
48bcb226d17e        bridge              bridge              local
3ea7c9283722        host                host                local
eee2e5b9cf19        none                null                local

$ docker network inspect bridge

[
    {
        "Name": "bridge",
        "Id": "48bcb226d17e09092378deb2c4e9a070edb64f5bc6e0b0378edd45f5f248a6f2",
        "Created": "2022-03-04T18:00:02.632533487+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,
        "Containers": {
            "019a0daed76f2c71ccb7879a259cc04eac9b60a826529c383f104ffa1ad12f3d": {
                "Name": "box1",
                "EndpointID": "8d09e83384eeeb6cb9fc31fadb1d9f39339ae4ccd6971dc790f60410797c6a07",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "3325eedba7c2b16956b20d1eea968c74471e0fb42747fb73079f74bae460e16c": {
                "Name": "box2",
                "EndpointID": "52c096c53b562a205a8880417cbba8fe0ff0fb1c0cbf3fd7fa67f828fbd72ac4",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/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": {}
    }
]

从此可以看出,两个容器都在一个叫docker0的Linux bridge上面,而docker0是docker默认安装添加上去的,可以证明: 容器相互之间可以拼通的。
而默认的 bridge网络是被映射到内核中为 docker0的 网桥上。
$ ip link show docker0

3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 02:42:23:ab:dd:7e brd ff:ff:ff:ff:ff:ff

Note: 你就可以把 bridge 和 docker0 当成 Linux 网桥的两个名字,两个都是代表同一个东西。docker 为了管理网络,又给 docker0 这个网桥取名为 bridge
Node:也可以通过 brctl 命令进行 bridge 连接接口查看( brctl  使用前需要安装, 对于CentOS, 可以通过  sudo  yum  install  -y  bridge-utils  安装. 对于Ubuntu, 可以通过  sudo  apt-get  install  -y  bridge-utils
$ brctl show

bridge name    bridge id        STP enabled    interfaces
docker0        8000.024223abdd7e    no        veth33f963f
                                              vethceb182f

从上面也可以确认两个接口进行通信。

2、容器对外通信

一、 查看路由

$ ip route

default via 172.19.79.253 dev eth0
169.254.0.0/16 dev eth0 scope link metric 1002
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.19.64.0/20 dev eth0 proto kernel scope link src 172.19.77.225
(个人理解:从此可以看出,如果是其他应用访问走的默认,如果docker就会走docker0接口,而经过桥接docker0其实意义上可以说是eth0 所以容器是可以访问外网。这里里面不得不提iptables转发)

二、端口转发

命令通过 -p
$ docker container run -d --rm --name -p8080:80 web nginx
    
效果
http://我的IP地址:8080/

端口映射
    如上效果图所示,容器内部开放端口为 80 ,该端口映射到了Docker主机的8080端口上,最终访问上面的IP地址所有流量都会转发到容器的80端口上面。
通过iptables命令可以更直观的感受
$ iptables -t nat -nvxL

Chain PREROUTING (policy ACCEPT 3 packets, 112 bytes)
    pkts      bytes target     prot opt in     out     source               destination         
    8398   514593 DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 3 packets, 112 bytes)
    pkts      bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 33 packets, 2300 bytes)
    pkts      bytes target     prot opt in     out     source               destination         
       0        0 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 35 packets, 2428 bytes)
    pkts      bytes target     prot opt in     out     source               destination         
       0        0 MASQUERADE  all  --  *      !br-43435188760c  172.18.0.0/16        0.0.0.0/0           
       0        0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           
       0        0 MASQUERADE  tcp  --  *      *       172.17.0.4           172.17.0.4           tcp dpt:80

Chain DOCKER (2 references)
    pkts      bytes target     prot opt in     out     source               destination         
       0        0 RETURN     all  --  br-43435188760c *       0.0.0.0/0            0.0.0.0/0           
       0        0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
       2      128 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 to:172.17.0.4:80
    tcp dpt:8080 to :172.17.0.4:80 刚刚好对应上面的效果。

3、自定义桥接bridge

$  docker network create -d bridge mybridge

43435188760ce70d58099ab5fe27b85fc07e2f5e14d6748e6532daa5749d4963

$ docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
48bcb226d17e        bridge              bridge              local
3ea7c9283722        host                host                local
43435188760c        mybridge            bridge              local
eee2e5b9cf19        none                null                local

$  docker network inspect mybridge

[
    {
        "Name": "mybridge",
        "Id": "43435188760ce70d58099ab5fe27b85fc07e2f5e14d6748e6532daa5749d4963",
        "Created": "2022-03-07T15:41:06.440007809+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

$  docker container run -d --rm --name box3 --network mybridge  busybox /bin/sh -c "while true; do sleep 3600; done”

2d7ce63d7e3f956564e684e343b7da2ae747e5679292c109096f619e73bce719

$ docker container ls

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
2d7ce63d7e3f        busybox             "/bin/sh -c 'while..."   9 seconds ago       Up 8 seconds                            box3
3325eedba7c2        busybox             "/bin/sh -c 'while..."   2 hours ago         Up 2 hours                              box2
019a0daed76f        busybox             "/bin/sh -c 'while..."   2 hours ago         Up 2 hours                              box1

$ docker container inspect box3

[
    {
        "Id": "2d7ce63d7e3f956564e684e343b7da2ae747e5679292c109096f619e73bce719",
        "Created": "2022-03-07T07:44:18.269363219Z",
        "Path": "/bin/sh",
        "Args": [
            "-c",
            "while true; do sleep 3600; done"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 6911,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2022-03-07T07:44:18.567776199Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:829374d342ae65a12f3a95911bc04a001894349f70783fda841b1a784008727d",
        "ResolvConfPath": "/var/lib/docker/containers/2d7ce63d7e3f956564e684e343b7da2ae747e5679292c109096f619e73bce719/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/2d7ce63d7e3f956564e684e343b7da2ae747e5679292c109096f619e73bce719/hostname",
        "HostsPath": "/var/lib/docker/containers/2d7ce63d7e3f956564e684e343b7da2ae747e5679292c109096f619e73bce719/hosts",
        "LogPath": "",
        "Name": "/box3",
        "RestartCount": 0,
        "Driver": "overlay2",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "journald",
                "Config": {}
            },
            "NetworkMode": "mybridge",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": true,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "docker-runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": null,
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DiskQuota": 0,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": -1,
            "OomKillDisable": false,
            "PidsLimit": 0,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0
        },
        "GraphDriver": {
            "Name": "overlay2",
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/fba5480131b3e84ac8abfa7905de44c4049dbe627139833b40ce38c39dcf8eb6-init/diff:/var/lib/docker/overlay2/98edee56f7a26a7781c93c13d5bbef9bbb9e8f32ad3c37201bc45c00bfb5a0a6/diff",
                "MergedDir": "/var/lib/docker/overlay2/fba5480131b3e84ac8abfa7905de44c4049dbe627139833b40ce38c39dcf8eb6/merged",
                "UpperDir": "/var/lib/docker/overlay2/fba5480131b3e84ac8abfa7905de44c4049dbe627139833b40ce38c39dcf8eb6/diff",
                "WorkDir": "/var/lib/docker/overlay2/fba5480131b3e84ac8abfa7905de44c4049dbe627139833b40ce38c39dcf8eb6/work"
            }
        },
        "Mounts": [],
        "Config": {
            "Hostname": "2d7ce63d7e3f",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "while true; do sleep 3600; done"
            ],
            "Image": "busybox",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "f967524cdbe0c5a0d70da4a45cde98bc250c28467678d7fe6de8fb38485d9788",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "/var/run/docker/netns/f967524cdbe0",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "",
            "Gateway": "",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "",
            "IPPrefixLen": 0,
            "IPv6Gateway": "",
            "MacAddress": "",
            "Networks": {
                "mybridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": [
                        "2d7ce63d7e3f"
                    ],
                    "NetworkID": "43435188760ce70d58099ab5fe27b85fc07e2f5e14d6748e6532daa5749d4963",
                    "EndpointID": "0e2fa562b7f2050eb84114356ac9882dbac340a675a32036b14040c0db35b035",
                    "Gateway": "172.18.0.1",
                    "IPAddress": "172.18.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:12:00:02"
                }
            }
        }
    }
]

$  docker network inspect mybridge

[
    {
        "Name": "mybridge",
        "Id": "43435188760ce70d58099ab5fe27b85fc07e2f5e14d6748e6532daa5749d4963",
        "Created": "2022-03-07T15:41:06.440007809+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "2d7ce63d7e3f956564e684e343b7da2ae747e5679292c109096f619e73bce719": {
                "Name": "box3",
                "EndpointID": "0e2fa562b7f2050eb84114356ac9882dbac340a675a32036b14040c0db35b035",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

通过上面操作就是已经建立好了自己的容器且指向自己创建的桥接。

记录上面没有使用过的命令

//容器连接第二个bridge
$ docker network connect bridge box3

//进入到容器 sh 里面
$ docker container exec -it box3 sh

//断开容器 bridge 连接
$ docker network disconnect bridge box3

//创建网络参数
$ docker network create —help


Usage:    docker network create [OPTIONS] NETWORK

Create a network

Options:
      --attachable             Enable manual container attachment
      --aux-address map        Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[])
  -d, --driver string          Driver to manage the Network (default "bridge")
      --gateway stringSlice    IPv4 or IPv6 Gateway for the master subnet
      --help                   Print usage
      --internal               Restrict external access to the network
      --ip-range stringSlice   Allocate container ip from a sub-range
      --ipam-driver string     IP Address Management Driver (default "default")
      --ipam-opt map           Set IPAM driver specific options (default map[])
      --ipv6                   Enable IPv6 networking
      --label list             Set metadata on a network (default [])
  -o, --opt map                Set driver specific options (default map[])
      --subnet stringSlice     Subnet in CIDR format that represents a network segment

//网络配置
$ docker container inspect --format '{{.NetworkSettings.IPAddress}}’ box2

172.17.0.3

引用文档

版权声明:本文为m0_37918421原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。