【docker 笔记】docker 网络相关整理
2019-05-20 本文已影响3人
58bc06151329
文前说明
作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。
本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。
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 提供了用于开发的多种网络驱动。
- Libnetwork 作为一个网络代码库。
- 向上对 docker daemon 守护进程提供 API 接口,让其调用。
- 向下提供各种网络模式类型的接口和驱动。具体的实现就是通过 CNM 完成。
CNM 的组成
- CNM 主要由三个要素组成,sandbox(沙盒)、endpoint(接入端点)和 network(网络)。
- sandbox,一个沙盒可以有多个接入端点和多个网络。一个沙盒可以代表一个容器,里面包含了一个容器的网络栈所有信息,底层的技术实现是 Linux 的网络 Namespace。
- endpoint,一个接入端点可以对接一个沙盒和一个网络,实现方式可以是 veth pair、ovs 内部端口技术。一个接入端点只能存在一个沙盒中,不能同时存在多个沙盒里,就像交换机的接口,不能同时存在两个不同交换机里。给不同沙盒添加不同的接入端点,就能让沙盒接入不同的网络。
- network,一个网络由一组互相联通的接入端点组成,技术实现可以是 Linux bridge、vlan、vxlan 等等。一个网络可以包括多个接入端点。
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