美文网首页docker
【docker 笔记】docker 网络相关整理

【docker 笔记】docker 网络相关整理

作者: 58bc06151329 | 来源:发表于2019-05-20 09:44 被阅读3次

    文前说明

    作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

    本文仅供学习交流使用,侵权必删。
    不用于商业目的,转载请注明出处。

    1. 概述

    • Docker 使用了 Linux 的 Namespaces 技术来进行资源隔离,如 PID Namespace 隔离进程, Mount Namespace 隔离文件系统,Network Namespace 隔离网络等。
    • 一个 Network Namespace 提供了一份独立的网络环境,包括网卡、路由、iptable 规则等都与其他的 Network Namespace 隔离。

    端口映射

    • Docker 容器默认无法与外部通信,需要在启动命令中加入 -P-p 参数允许通信。
    [root@localhost ]# docker run --name sdcvm-postgres -e POSTGRES_PASSWORD=engine -e POSTGRES_USER=engine -e POSTGRES_DB=engine -p 5433:5432 -v `pwd`/pgsql:/var/lib/pgsql -d sdcvm-postgres:lates
    
    • -P 会随机映射一个端口,开放内部服务端口。
    • 使用 docker port 可以查看端口情况。
    [root@localhost ~]# docker port 93517129873b
    5432/tcp -> 0.0.0.0:5433
    
    • -p 可以指定映射的本地端口,有 4 种格式。
    • 格式 1:-p <Local_Port>:<Container_Port>,映射指定端口。
    [root@localhost ]# docker run --name sdcvm-postgres 5433:5432 -d sdcvm-postgres:lates
    
    • 格式 2:-p <Local_IP>:<Local_Port>:<Container_Port>,映射指定地址的指定端口。
    [root@localhost ]# docker run --name sdcvm-postgres 127.0.0.1:5433:5432 -d sdcvm-postgres:lates
    
    • 格式 3:-p <Local_IP>::<Container_Port>,宿主机端口随机分配。
    [root@localhost ]# docker run --name sdcvm-postgres 127.0.0.1::5432 -d sdcvm-postgres:lates
    
    • 格式 4:在前三种格式的基础上指定传输协议。
    [root@localhost ]# docker run --name sdcvm-postgres 5433:5432/tcp -d sdcvm-postgres:lates
    

    端口暴露

    • Docker 中提供两种端口暴露的方式。
      • 在Dockerfile 中定义 EXPOSE 指令。
      • 在 docker run 命令中增加 --expose 参数。该参数可以接收范围值(例如 --expose=2000-3000)。
      • EXPOSE 指令与 --expose 参数都不依赖于宿主机。默认状态下,这些规则并不会使这些端口可以通过宿主机来访问。
      • EXPOSE 指令与 --expose 参数只提供所需信息的元数据。通过命令文档化端口的方式,有助于容器操作人员迅速确定服务启动命令。两种方式没有什么区别,生成的配置一致。
    "Config": {
               .....
                "ExposedPorts": {
                    "5432/tcp": {}
                },
                .....
    },
    "NetworkSettings": {
                ......
                "Ports": {
                    "5432/tcp": null
                },
               ......
    }
    
    • --expose 参数是属性附加属性,因此会在 EXPOSE 指令的基础上增加新的端口。

    容器互联

    • 容器互联是除端口映射外另一种可以与容器通信的方式。端口映射是宿主机与容器之间的通信,容器互联是容器与容器之间的通信。
      • 使用容器互联时,容器必须设置名称 --name 参数。默认 Docker 会随机生成词组。
      • 也可以通过 docker rename 命令重新设置命令,名称必须是唯一的。
      • 容器互联参数是 --link,使用 --link 创建的容器会使用容器的主机名和容器 ID 更新自己的 /etc/hosts 文件。
      • 通过 --link 会使得环境变量也发生变化。容器之前设置的环境变量会被 --link 的容器的环境变量所覆盖。

    2. 网络模型

    2.1 Libnetwork

    • Docker 从 1.7 开始,为了能更好的支持网络各种功能,独立创建了一个项目叫 Libnetwork。通过这个项目,Docker 希望统一容器这块的网络层标准。

    2.2 CNM(Container Network Model)

    • Libnetwork 是一个网络代码库。具体的实现模型是 CNM。
      • CNM 提供了用于开发的多种网络驱动。
    CNM 模型
    • Libnetwork 作为一个网络代码库。
      • 向上对 docker daemon 守护进程提供 API 接口,让其调用。
      • 向下提供各种网络模式类型的接口和驱动。具体的实现就是通过 CNM 完成。

    CNM 的组成

    • CNM 主要由三个要素组成,sandbox(沙盒)、endpoint(接入端点)和 network(网络)。
      • sandbox,一个沙盒可以有多个接入端点和多个网络。一个沙盒可以代表一个容器,里面包含了一个容器的网络栈所有信息,底层的技术实现是 Linux 的网络 Namespace。
      • endpoint,一个接入端点可以对接一个沙盒和一个网络,实现方式可以是 veth pair、ovs 内部端口技术。一个接入端点只能存在一个沙盒中,不能同时存在多个沙盒里,就像交换机的接口,不能同时存在两个不同交换机里。给不同沙盒添加不同的接入端点,就能让沙盒接入不同的网络。
      • network,一个网络由一组互相联通的接入端点组成,技术实现可以是 Linux bridge、vlanvxlan 等等。一个网络可以包括多个接入端点。
    CNM 组成

    CNM 的实现流程

    • 首先,驱动要注册自己到网络控制器里,控制器根据类型创建 network(网络)。
    • 其次,网络控制器在创建好的网络上创建 endpoint(接入端点)。
    • 最后,把容器连接到 endpoint(接入端点)。

    • 如果是删除销毁,那么顺序反过来即可。
    • CNM 让容器的网络使用更加简单,底层具体实现不需要关心。
      • 第三方网络插件只要提供了 network(网络)和 endpoint(接入端点)就能联通容器。
      • CNM 使容器与网络解耦,灵活性大大增强。

    3. 网络模式

    • 目前 Docker Libnetwork 支持多种驱动类型。
    • 通过 docker run 创建 Docker 容器时,可以通过 --net 选项指定容器的网络模式。
    参数 说明
    --net=bridge bridge 模式使用指定,默认设置。
    --net=host host 模式使用指定。
    --net=container:NAME_or_ID container 模式使用指定。
    --net=none none 模式使用指定。
    --net=overlay overlay 模式使用指定。

    3.1 bridge(网桥)模式

    • 是 Docker 的默认设置,也是最常用的网络连接方式,桥接网络可以让应用运行在一个隔离的网络中,网络中的容器可以互相访问,一般会将应用的端口映射出去,以便主机外的网络通过这个端口进行访问。
    • 当 Docker 进程启动时,会自动在宿主机上创建一个 docker0 虚拟网桥,默认分配网段172.17.0.0/16(也可以在 deamon.json 中配置),实际上是 Linux 的一个 bridge,可以理解为一个软件交换机,附加在其上的任何网卡之间都能自动转发数据包。
    [root@localhost ~]# ip addr
    .....
    5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:92:df:8d:3e brd ff:ff:ff:ff:ff:ff
        inet 172.16.0.1/16 scope global docker0
           valid_lft forever preferred_lft forever
        inet6 fe80::42:92ff:fedf:8d3e/64 scope link 
           valid_lft forever preferred_lft forever
    149: vethe46a37b@if148: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether ba:09:a9:6e:73:d7 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet6 fe80::b809:a9ff:fe6e:73d7/64 scope link 
           valid_lft forever preferred_lft forever
    
    • 创建一个容器时,容器从 docker0 中的子网分配一个 IP 地址(也可以使用 --ip 指定),并创建一对 veth 虚拟网络设备,一个设备在容器中作为容器的网卡名叫 eth0,另一个设备在宿主机上叫做名称为 vethXXX 并桥接在 docker0 上,可通过命令 brctl show 查看,通过这样的桥接方法宿主机上的所有容器都处于同一个二层网络中,这样使得容器与容器以及容器与宿主机之间能够互相通信。
    [root@localhost ~]# brctl show
    bridge name bridge id       STP enabled interfaces
    docker0     8000.024292df8d3e   no      vethe46a37b
    

    veth

    • Virtual ETHernet 的缩写,是一种虚拟网络设备。当它被创建以后,总是以两张虚拟网卡(Veth peer)形式成对出现,并且在一个网卡上的数据包可直接转发给另一个与之对应的网卡上,即使这两个网卡不在同一个 Namespace 中。

    容器间的通讯

    容器间的通信
    • 启动一个容器 Container 1,其 IP 地址为 172.17.0.2,默认网关为 172.17.0.1。网关地址是网桥 docker0 的地址。docker0 桥接的网卡是与容器对应的 veth(9c02e56) 网卡。
    • 启动一个容器 Container 2,其 IP 地址为 172.17.0.3,默认网关为 172.17.0.1。网关地址是网桥 docker0 的地址。docker0 桥接的网卡是与容器对应的 veth(b4963f3) 网卡。

    • 从容器 Container 1 中 ping 172.17.0.3(容器 Container 2),在容器 Container 1 里,根据路由规则,数据包从 eth0 转发至与之对应的 veth(9c02e56)上,该 veth 桥接在了 docker0上,此时数据包到达了 docker0,docker0 此时扮演交换机角色并广播 ARP 请求寻找 172.17.0.3 的 mac 地址,Container 2 的 veth(b4963f3)设备也桥接在 docker0 上,接收到 ARP 请求,发现自己是 172.17.0.3,将其 mac 地址回复给 Container 1,此时的容器 Container 1 就可以与容器 Container 2 进行通讯。

    容器与外部网络通讯

    容器与外部网络通讯

    宿主机与容器通讯

    宿主机与容器通讯

    外部访问容器

    • 默认情况,其他外部网络(宿主机以外)无法访问到容器内的端口,通常的做法是使用 -p 或者 -P 选项暴露容器中的端口到宿主机上,外部网络通过访问宿主机的端口从而访问到容器端口。

    3.2 host(主机)模式

    • 容器与主机共享同一网络 Namespace,网络协议栈、路由表、iptables 规则、网卡、IP、端口等等都是共享的。容器跟宿主机在同一网络视图下。直接使用宿主机的 IP 进行通信。网络流量和压力都是走的宿主机的网卡,性能会比较高。
    • 容器跟宿主机是共享一套网络机制,没有隔离,可能会引起网络资源与宿主机的竞争和冲突关系,规模小的场景,可以使用这种模式。

    3.3 container(容器)模式

    • 共享已存在的容器的网络 Namespace,此时这两容器共同使用同一网卡、主机名、IP 地址,容器间通讯可直接通过 lo 回环接口通讯,但是其他 Namespace 是隔离的。

    3.4 none 模式

    • Docker 提供的最简单的网络驱动模式。
    • 容器内的网络配置是空的,容器单独享用一个网络 Namespace,是一个封闭的网络环境。
    • 容器启动后无任何网络连接,看到的就是一个 lo 环回接口(loopback), 如果需要容器与外界互联,需要手动给容器配置网络接口、IP、路由等等,灵活性最强。

    3.5 overlay 模式

    • docker 1.8 新加入的一个网络模式,是跨主机多子网的网络方案。实现的机制是 vxlan 和 Linux bridge,不过使用这种模式需要安装 etcd、consul、zookeeper 这样的 KV 键值对数据存储系统来提供信息同步支持。

    3.6 macvlan 模式

    • macvlan 跟 overlay 一样是跨主机互联的驱动方案。
    • macvlan 是 Linux kernel 模块,原理是在宿主机物理网卡上虚拟出多个子网卡(同一物理网卡上配置多个 MAC 地址,即:多个 interface),通过不同的 MAC 地址在数据链路层(Data Link Layer)进行网络数据转发,是比较新的网络虚拟化技术,需要较新的内核支持(Linux kernel v3.9–3.19 and 4.0+)。
    • macvlan 最大的优点是性能极好。相比其他方案,macvlan 不需要创建 Linux bridge,直接通过以太 interface 连接到物理网络,另外 macvlan 还支持 802.1q trunk 等更为复杂的网络拓扑结构。
    • 需要注意的是。
      • macvlan 会独占主机的网卡,一个网卡只能创建一个 macvlan 网络。
      • 同一 macvlan 下的网络能通信,不同的 macvlan 网络之间不能(不同的 macvlan 网络不能在二层上通信,在三层可以通过网关进行通信)。
      • macvlan 网络的连通性和隔离性完全依赖 vlan,IP subnet 和路由,Docker 本身不做任何限制,用户可以像管理传统 vlan 网络那样管理 macvlan。

    4. 网络配置

    • docker daemon 命令中可以配置网络参数。
    [root@localhost ~]# docker daemon -help
    Command "daemon" is deprecated, and will be removed in Docker 1.16. Please run `dockerd` directly.
    Flag shorthand -h has been deprecated, please use --help
    Status: unknown shorthand flag: 'e' in -elp
    See 'dockerd --help'.
    
    Usage:  dockerd COMMAND
    
    A self-sufficient runtime for containers.
    
          --bip string                            Specify network bridge IP
      -b, --bridge string                         Attach containers to a network bridge
          --default-gateway ip                    Container default gateway IPv4 address
          --default-gateway-v6 ip                 Container default gateway IPv6 address
          --dns list                              DNS server to use (default [])
          --dns-opt list                          DNS options to use (default [])
          --dns-search list                       DNS search domains to use (default [])
      -H, --host list                             Daemon socket(s) to connect to (default [])
          --icc                                   Enable inter-container communication (default true)
          --ip ip                                 Default IP when binding container ports (default 0.0.0.0)
          --ip-forward                            Enable net.ipv4.ip_forward (default true)
          --ip-masq                               Enable IP masquerading (default true)
          --iptables                              Enable addition of iptables rules (default true)
          --ipv6                                  Enable IPv6 networking
          --userland-proxy                        Use userland proxy for loopback traffic (default true)
          --userland-proxy-path string            Path to the userland proxy binary
    ......
    
    • 容器中的主机名、DNS 配置信息通过系统配置文件 /etc/hosts/etc/resolv.conf/etc/hostname 维护。
      • /etc/resolv.conf 文件在创建容器时创建,并且与宿主机保持一致。
      • /etc/hosts 记录一些与容器相关的地址和名称信息。
      • /etc/hostname 记录主机名。
    • 当容器重启和终止后,修改会丢失。可以通过 -h--dns 在容器启动时写入文件。

    5. 网络的基本操作

    • 使用 docker run 命令的 --network 选项可以指定连接到的网络。
    操作 说明
    docker network connect 将容器连接到网络。
    docker network create 创建一个网络。
    docker network disconnect 断开容器与网络的连接。
    docker network inspect 显示详细信息。
    docker networs ls 显示网络列表。
    docker networs prune 删除所有未使用的网络。
    docker networs rm 删除一个或多个网络。

    5.1 连接网络

    • 将容器连接到网络。
    • 命令格式:docker network connect [OPTIONS] NETWORK CONTAINER
    参数 说明
    --alias 为容器添加网络范围别名
    --ip IPv4 网络地址。
    --ip6 IPv6 网络地址。
    --link 添加一个链接到其他容器。
    --link-local-ip 为容器添加本地地址链接。
    [root@localhost ]# docker network connect multi-host-network container1
    [root@localhost ]# docker network connect --ip 172.20.128.2 multi-host-network container2
    [root@localhost ]# docker network connect --link container1:c1 multi-host-network container2
    

    5.2 创建网络

    • 创建一个网络。
    • 命令格式:docker network create [OPTIONS] NETWORK
    操作 说明
    --attachable 启动手动附加。
    --aux-address 使用网络驱动程序辅助 IPv4 和 IPv6。
    --config-from 根据配置文件配置网络。
    -config-only 创建一个只配置网络的配置文件。
    --driver , -d 默认 bridge,管理网络的驱动程序。
    --gateway 设置网关。
    --ingress 创建 swarm routing-mesh 网络。
    --internal 限制网络的外部访问
    --ip-range 从定义的范围中分配 IP 地址。
    --ipam-driver IP 地址管理的驱动程序。
    --ipam-opt IP 地址管理驱动程序选项参数。
    --ipv6 启用 IPv6 网络。
    --label 设置元数据。
    --opt , -o 设置驱动程序特定选项。
    --scope 控制网络范围。
    --subnet 网段,CIDR 格式。
    [root@localhost ]# docker network create -d bridge my-bridge-network
    [root@localhost ]# docker network create --driver=bridge --subnet=192.168.0.0/16 br0
    [root@localhost ]# docker network create \
      --driver=bridge \
      --subnet=172.28.0.0/16 \
      --ip-range=172.28.5.0/24 \
      --gateway=172.28.5.254 \
      br0
    [root@localhost ]# docker network create -d overlay \
      --subnet=192.168.1.0/25 \
      --subnet=192.170.2.0/25 \
      --gateway=192.168.1.100 \
      --gateway=192.170.2.100 \
      --aux-address="my-router=192.168.1.5" --aux-address="my-switch=192.168.1.6" \
      --aux-address="my-printer=192.170.1.5" --aux-address="my-nas=192.170.1.6" \
      my-multihost-network
    
    • 创建自定义网络时,默认网络驱动程序(即网桥)可以传递的其他选项(用于 docker0 网桥的选项等效 docker daemon 进程的标志有以下几种)。
    docker0 选项 docker daemon 选项 说明
    com.docker.network.bridge.name - 创建 Linux网桥时要使用的网桥名称。
    com.docker.network.bridge.enable_ip_masquerade --ip-masq 启用 IP 伪装。
    com.docker.network.bridge.enable_icc --icc 启用或禁用容器间连接。
    com.docker.network.bridge.host_binding_ipv4 --ip 绑定容器端口时的默认 IP。
    com.docker.network.driver.mtu --mtu 设置容器网络的 MTU
    • 创建自定义网络时,任何网络驱动程序可以传递的其他选项(用于选项等效 docker daemon 进程的标志有以下几种)。
    选项 docker daemon 选项 说明
    --gateway - 网关。
    --ip-range --fixed-cidr IP 获取范围。
    --internal - 限制对网络的外部访问。
    --ipv6 --ipv6 开启 IPv6 网络。
    --subnet --bip 子网网段。
    [root@localhost ]# docker network create \
        -o "com.docker.network.bridge.host_binding_ipv4"="172.19.0.1" \
        simple-network
    

    5.3 断开网络

    • 断开容器与网络的连接。
    • 命令格式:docker network disconnect [OPTIONS] NETWORK CONTAINER
    操作 说明
    --force , -f 强制断开容器与网络之间的连接。
    [root@localhost ]# docker network disconnect multi-host-network container1
    

    5.4 显示详细信息

    • 显示详细信息。
    • 命令格式:docker network inspect [OPTIONS] NETWORK [NETWORK...]
    操作 说明
    --format , -f 使用给定的 GO 模板格式化输出。
    --verbose , -v 详细输出。

    5.5 显示网络列表

    • 显示网络列表
    • 命令格式:docker network ls [OPTIONS]
    操作 说明
    --filter , -f 提供筛选器值(例如 driver=bridge)
    --format 使用给定的 GO 模板格式化输出。
    --no-trunc 不截断输出。
    --quiet , -q 只输出网络 ID。
    [root@localhost ]# docker network ls --no-trunc
    NETWORK ID                                                         NAME                DRIVER           SCOPE
    18a2866682b85619a026c81b98a5e375bd33e1b0936a26cc497c283d27bae9b3   none                null             local
    c288470c46f6c8949c5f7e5099b5b7947b07eabe8d9a27d79a9cbf111adcbf47   host                host             local
    7b369448dccbf865d397c8d2be0cda7cf7edc6b0945f77d2529912ae917a0185   bridge              bridge           local
    95e74588f40db048e86320c6526440c504650a1ff3e9f7d60a497c4d2163e5bd   foo                 bridge           local
    63d1ff1f77b07ca51070a8c227e962238358bd310bde1529cf62e6c307ade161   dev                 bridge           local
    
    [root@localhost ]# sudo docker network ls
    NETWORK ID          NAME                DRIVER          SCOPE
    7fca4eb8c647        bridge              bridge          local
    9f904ee27bf5        none                null            local
    cf03ee007fb4        host                host            local
    78b03ee04fc4        multi-host          overlay         swarm
    

    Filtering

    • 当前支持的筛选器包括。
      • driver(驱动)
      • id(网络 ID)
      • label(label=<key> 或者 label=<key>=<value>)
      • name(网络名称)
      • scope(范围 swarm|global|local)
      • type(类型 custom|builtin)
    [root@localhost ]# docker network ls --filter driver=bridge
    NETWORK ID          NAME                DRIVER            SCOPE
    db9db329f835        test1               bridge            local
    f6e212da9dfd        test2               bridge            local
    

    Formatting

    • 格式化选项(--format)使用 GO 模板打印网络输出。
    • GO 模板的有效占位符如下所示。
    占位符 描述
    .ID 网络 ID。
    .Name 网络名称。
    .Driver 网络驱动。
    .Scope 范围(local、global)
    .IPv6 是否在网络上启用了 IPv6。
    .Internal 网络是否为内部网络。
    .Labels 分配给网络的所有标签。
    .Label 此网络的特定标签的值。(例如:{{.Label "project.version"}}
    .CreatedAt 创建网络的时间。
    [root@localhost ]# docker network ls --format "{{.ID}}: {{.Driver}}"
    afaaab448eb2: bridge
    d1584f8dc718: host
    391df270dc66: null
    

    5.6 删除未使用网络

    • 删除所有未使用的网络。
    • 命令格式:docker network prune [OPTIONS]
    操作 说明
    --filter 提供筛选器值(例如 until=)
    --force , -f 不提示确认。
    [root@localhost ]# docker network prune
    
    WARNING! This will remove all networks not used by at least one container.
    Are you sure you want to continue? [y/N] y
    Deleted Networks:
    n1
    n2
    

    5.7 删除网络

    • 删除一个或多个网络。
    • 命令格式:docker network rm NETWORK [NETWORK...]
    [root@localhost ]# docker network rm 3695c422697f my-network
    

    相关文章

      网友评论

        本文标题:【docker 笔记】docker 网络相关整理

        本文链接:https://www.haomeiwen.com/subject/fcyiaqtx.html