9.docker高级网络
9.1 网络通信基础
在网络通信中,两台主机的唯一标识为 IP 地址(V4/V6), (类似身份证号码) 基于 IP 地址实现全世界的网络互联。 计算机通信最初发展, 并未实现系统化与标准化, 不同厂商产出各自的网络来实现通信, 这样导致了计算机缺乏灵活性和可扩展性, 为了解决该问题,ISO(国际标准化组织)制定了一个国际标准 OSI(开放式通信系统互联参考模型), (IETF(国际互联网工程任务组)TCP/IP 模型) OSI 模型
9.2 局域网互联技术
9.2.1 以太网发展
1973 年, 美国加利福尼亚州的 Xerox 公司实现了最初的以太网(3Mbps) 1980 年, Xerox 与 DEC、Intel 实现了 10Mbps 以太网 1983 年, IEEE 标准委员会通过第一个 802.3 标准 1990 年, IEEE 通过了使用双绞线介质的以太网标准传输 10Mbps
9.2.2 局域网通信设备
集线器(HUB) , 物理层的设备
网桥又称桥接器,(Network Bridge), 数据链路层设备
交换机 Switch, 数据链路层设备(网管 snmp/telnet 与非网管)
9.2.3 局域网(二层)数据转发原理
192.168.1.10 向 192.168.1.11 发送邮件, 根据 OSI 七层模型, 数据转发是需要封装数据包(1500 字节/分片重组 MTU) 1. 192.168.1.10 查询本机的地址缓存表(arp -a), 是否有 IP 地址对应的 mac 地址, 如果有直接发送数据包,如果没有则发送 ARP 广播 2. 192.168.1.10 向网络发送 ARP 广播, 询问 192.168.1.11 的 MAC 地址是多少? 3. 在未隔离广播域的交换机上的端口都会接收到这个广播. 4. 192.168.1.11 接收到请求以后,比对目标网络地址, 是否是地址, 然后再回应给 192.168.1.10 5. 192.168.1.10 收到 mac 地址以后, 封装数据包,发送到交换机, 交换机根据目标 mac 转发数据到192.168.1.11
9.3 容器通信基础
在Linux系统中Namespace (> 2.6.x 内核版本) 主要用于资源的隔离。在有了Namespace功能之后,在Linux系统中就可以抽象出多个网络子系统,并且各子系统间都有自己的网络设备,协议栈等, 彼此之间互不影响。 如果相互隔离的Namespace之间需要通信时,则用veth-pair来做连接作为连接桥梁,使原本互不相干的容器之间能够相互通信。 根据网络连接的方式与规模,可分为“直接相连”、“Bridge 相连” 和 “OVS 相连”。下面会详细讲解几种模式的实现方式。
9.3.1 直接连接
直接相连是最简单的方式,一对 veth-pair 直接将两个 namespace 连接在一起。 #同一宿主机
9.3.1.1配置不同NS, 相同网段的直接连接互通
9.3.1.2 创建不同的Namespace
# 创建 namespace [root@docker01 ~]# ip netns a ns1 [root@docker01 ~]# ip netns a ns2
9.3.1.3 创建veth-pair(veth0/veth1)
#创建一对 veth-pair veth0 veth1
#创建 veth0 类型为 veth, 对端的地址为 veth1
[root@docker01 ~]# ip l a veth0 type veth peer name veth1
9.3.1.4 添加veth0/veth1至两个不同的NS
[root@docker01 ~]# ip l s veth0 netns ns1
[root@docker01 ~]# ip l s veth1 netns ns2
9.3.1.5 配置veth IP 地址
#给两个 veth0 veth1 配上 IP 并启用, 必须为一个网段 [root@docker01 ~]# ip netns exec ns1 ip a a 10.1.1.2/24 dev veth0 [root@docker01 ~]# ip netns exec ns1 ip l s veth0 up [root@docker01 ~]# ip netns exec ns2 ip a a 10.1.1.3/24 dev veth1 [root@docker01 ~]# ip netns exec ns2 ip l s veth1 up
9.3.1.6 测试veth 连通性
#从 veth0 ping veth1 [root@localhost ~]# ip netns exec ns1 ping 10.1.1.3 PING 10.1.1.3 (10.1.1.3) 56(84) bytes of data. 64 bytes from 10.1.1.3: icmp_seq=1 ttl=64 time=0.073 ms 64 bytes from 10.1.1.3: icmp_seq=2 ttl=64 time=0.068 ms --- 10.1.1.3 ping statistics --- 15 packets transmitted, 15 received, 0% packet loss, time 14000ms rtt min/avg/max/mdev = 0.068/0.084/0.201/0.032 ms
9.3.2 Linux Bridge连接
Linux Bridge 相当于一个网桥,可以中转两个namespace的流量。 如下图,两对 veth-pair 分别将两个 namespace 连到 Bridge 上。
9.3.2.1 配置不同NS, 相同网络通过网桥的互通
# 创建 namespace [root@docker01 ~]# ip netns a ns1 [root@docker01 ~]# ip netns a ns2
9.3.2.2 创建网桥br0
[root@docker01 ~]# ip l a br0 type bridge [root@docker01 ~]# ip l s br0 up 创建两对 veth-pair [root@docker01 ~]# ip l a veth01 type veth peer name br-veth0 [root@docker01 ~]# ip l a veth11 type veth peer name br-veth1
9.3.2.3 配置veth pair, 并且加入到独立的NS与相同的br0
9.3.2.3.1 #配置veth01的namespace为ns1, 设置br-veth0的桥接器为br0
[root@docker01 ~]# ip l s veth01 netns ns1 [root@docker01 ~]# ip l s br-veth0 master br0 [root@docker01 ~]# ip l s br-veth0 up
9.3.2.3.2 配置veth11的namespace为ns2, 设置br-veth1的桥接器为br0
[root@docker01 ~]# ip l s veth11 netns ns2 [root@docker01 ~]# ip l s br-veth1 master br0 [root@docker01 ~]# ip l s br-veth1 up
9.3.2.4 配置veth01与veth11 IP 地址
# 给两个 ns 中的 veth 配置 IP 并启用 [root@docker01 ~]# ip netns exec ns1 ip a a 11.1.1.2/24 dev veth01 [root@docker01 ~]# ip netns exec ns1 ip l s veth01 up [root@docker01 ~]# ip netns exec ns2 ip a a 11.1.1.3/24 dev veth11 [root@docker01 ~]# ip netns exec ns2 ip l s veth11 up
9.3.2.5 测试连通性
#veth01 ping veth11 [root@localhost ~]# ip netns exec ns1 ping 11.1.1.3 PING 11.1.1.3 (11.1.1.3) 56(84) bytes of data. 64 bytes from 11.1.1.3: icmp_seq=1 ttl=64 time=0.060 ms 64 bytes from 11.1.1.3: icmp_seq=2 ttl=64 time=0.105 ms --- 11.1.1.3 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 999ms rtt min/avg/max/mdev = 0.060/0.082/0.105/0.024 ms
9.3.3 通过OVS 连接
OVS 是第三方开源的 Bridge,功能比 Linux Bridge 要更强大
9.3.3.1 安装OVS
[root@localhost ~]# yum install wget openssl-devel \ python-sphinx gcc make python-devel openssl-devel kernel-devel graphviz kernel-debug-devel \ autoconf automake rpm-build redhat-rpm-config libtool python-twisted-core python-zope-interface \ PyQt4 desktop-file-utils libcap-ng-devel groff checkpolicy python-six selinux-policy-devel -y [root@localhost ~]# mkdir -p /root/rpmbuild/SOURCES [root@localhost ~]# cd /root/rpmbuild/SOURCES [root@localhost ~]# wget http://openvswitch.org/releases/openvswitch-2.9.2.tar.gz [root@localhost ~]# tar xvf openvswitch-2.9.2.tar.gz [root@localhost ~]# rpmbuild -bb --nocheck openvswitch-2.9.2/rhel/openvswitch-fedora.spec [root@localhost ~]# yum localinstall /root/rpmbuild/RPMS/x86_64/openvswitch-2.9.2-1.el7.centos.x86_64.rpm -y [root@demo SOURCES]# systemctl start openvswitch.service [root@demo SOURCES]# systemctl enable openvswitch.service
9.3.4 配置veth通过OVS连接通信
9.3.4.1 通过OVS命令创建一个bridge
[root@localhost ~]# ovs-vsctl add-br ovs-br
9.3.4.2 创建两对veth-pair
[root@localhost ~]# ip l a veth011 type veth peer name ovs-veth0
[root@localhost ~]# ip l a veth111 type veth peer name ovs-veth1
9.3.4.3 配置veth-pair添加到NS与OVS Bridge 中
#操作 veth011 #添加 veth011 到 ns1 [root@localhost ~]# ip l s veth011 netns ns1 #将 ovs-veth0 添加到 ovs-br 桥接器 [root@localhost ~]# ovs-vsctl add-port ovs-br ovs-veth0 [root@localhost ~]# ip l s ovs-veth0 up #操作 veth1 #添加 veth1 到 ns2 [root@localhost ~]# ip l s veth111 netns ns2 #将 ovs-veth1 添加到 ovs-br 桥接器 [root@localhost ~]# ovs-vsctl add-port ovs-br ovs-veth1 [root@localhost ~]# ip l s ovs-veth1 up
9.3.4.4 配置veth IP 地址
[root@localhost ~]# ip netns exec ns1 ip a a 12.1.1.2/24 dev veth011 [root@localhost ~]# ip netns exec ns1 ip l s veth011 up [root@localhost ~]# ip netns exec ns2 ip a a 12.1.1.3/24 dev veth111 [root@localhost ~]# ip netns exec ns2 ip l s veth111 up
9.3.4.5 测试连通性
# veth011 ping veth111 [root@localhost ~]# ip netns exec ns1 ping 12.1.1.3 PING 12.1.1.3 (12.1.1.3) 56(84) bytes of data. 64 bytes from 12.1.1.3: icmp_seq=1 ttl=64 time=0.311 ms 64 bytes from 12.1.1.3: icmp_seq=2 ttl=64 time=0.087 ms --- 12.1.1.3 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 999ms rtt min/avg/max/mdev = 0.087/0.199/0.311/0.112 ms
9.4 Docker0 网桥详解
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口) ,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和宿主机都在同一个物理网络。 Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信,它还给出了 MTU(接口允许接收的最大传输单元) ,以太网通常是 1500Bytes, 或宿主机网络路由上支持的默认值。这些值都可以在服务启动的时候进行配置。 --bip=CIDR -- IP 地址加掩码格式,例如 192.168.100.5/24 --mtu=BYTES -- 覆盖默认的 Docker mtu 配置 也可以在配置文件中配置 DOCKER_OPTS,然后重启服务。 由于目前 Docker 网桥是Linux 网桥,用户可以使用 brctl show 来查看网桥和端口连接信息。
9.4.1 查看docker0网桥
9.4.2 安装网络工具
#如果已经安装 Docker CE 则无需要再安装 [root@node-2 ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 [root@node-2 ~]# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo [root@node-2 ~]# yum install docker-ce-19.03.6 docker-ce-cli-19.03.6 containerd.io -y #安装网络查看工具 [root@node-2 ~]# yum install bridge-utils
9.4.3 查看网络
#查看系统网络接口
[root@node-2 ~]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen1000 link/ether 00:0c:29:14:38:91 brd ff:ff:ff:ff:ff:ff inet 192.168.91.136/24 brd 192.168.91.255 scope global noprefixroute ens32 valid_lft forever preferred_lft forever inet6 fe80::7dfd:e7a3:7683:20e7/64 scope link noprefixroute valid_lft forever preferred_lft forever 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:2f:4c:4a:2b brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever
9.4.4 查看网桥
[root@node-2 ~]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.02422f4c4a2b no
9.4.5 启动nginx demo容器
#运行 nginx demo [root@node-2 ~]# docker run --name nginx-demo -p 8081:80 -d nginx
9.4.6 获取容器进程id
[root@node-2 ~]# docker inspect -f '{{.State.Pid}}' nginx-demo 1370
9.4.7 查看命名空间
#系统所支持的网络命名空间(在内核中根据进程号隔离) [root@node-2 ~]# ll /proc/1370/ns/ total 0 lrwxrwxrwx 1 root root 0 Nov 6 11:51 ipc -> ipc:[4026532449] lrwxrwxrwx 1 root root 0 Nov 6 11:51 mnt -> mnt:[4026532447] lrwxrwxrwx 1 root root 0 Nov 6 11:50 net -> net:[4026532443] lrwxrwxrwx 1 root root 0 Nov 6 11:51 pid -> pid:[4026532450] lrwxrwxrwx 1 root root 0 Nov 6 11:51 user -> user:[4026531837] lrwxrwxrwx 1 root root 0 Nov 6 11:51 uts -> uts:[4026532448]
9.4.8 通过进程id 获取到网络命名空间
[root@demo ~]# ll /proc/1370/ns/net lrwxrwxrwx 1 root root 0 Mar 23 23:35 /proc/1370/ns/net -> net:[4026532443]
9.4.9 查看系统网络接口
#查看网络结构, 多了一块网卡 [root@node-2 ~]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen1000 link/ether 00:0c:29:14:38:91 brd ff:ff:ff:ff:ff:ff inet 192.168.91.136/24 brd 192.168.91.255 scope global noprefixroute ens32 valid_lft forever preferred_lft forever inet6 fe80::7dfd:e7a3:7683:20e7/64 scope link noprefixroute valid_lft forever preferred_lft forever 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:2f:4c:4a:2b brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:2fff:fe4c:4a2b/64 scope link valid_lft forever preferred_lft forever 5: veth7ebd9ef@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether b2:12:dc:e7:a5:17 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 fe80::b012:dcff:fee7:a517/64 scope link valid_lft forever preferred_lft forever
9.4.9.1 查看网卡桥接
[root@demo ~]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242c736b32f no veth7ebd9ef
9.4.9.2 查看Iptables
#iptables 存在有地址转换 [root@node-2 ~]# iptables -L -n -t nat Chain DOCKER (2 references) target prot opt source destination RETURN all -- 0.0.0.0/0 0.0.0.0/0 DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8081 to:172.17.0.2:80
9.5 创建 Docker 自定义网桥
Docker 自定义网桥 除了默认的 docker0 网桥,用户也可以指定网桥来连接各个容器。 在启动 Docker 服务的时候,使用 -b BRIDGE或--bridge=BRIDGE 来指定使用的网桥。 如果Docker服务已经运行,那需要先停止服务。
9.5.1 自定义网桥逻辑架构图
容器通过自定义的网桥bridge0访问外网
9.5.2 停止docker 服务
[root@node-2 ~]# service docker stop
9.5.3 建立自定义网桥bridge0
#设置bridge0网段为192.168.6.0/24 #添加网桥 [root@node-2 ~]# brctl addbr bridge0 #设置网桥 IP 地址段 [root@node-2 ~]# ip addr add 192.168.6.1/24 dev bridge0 #设置网桥状态 UP [root@node-2 ~]# ip link set dev bridge0 up
9.5.4 查看网络
#查看系统增加桥接器bridge0
[root@node-2 ~]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00:0c:29:14:38:91 brd ff:ff:ff:ff:ff:ff inet 192.168.91.136/24 brd 192.168.91.255 scope global noprefixroute ens32 valid_lft forever preferred_lft forever inet6 fe80::7dfd:e7a3:7683:20e7/64 scope link noprefixroute valid_lft forever preferred_lft forever 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:2f:4c:4a:2b brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:2fff:fe4c:4a2b/64 scope link valid_lft forever preferred_lft forever 6: bridge0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000 link/ether 12:e7:be:6c:aa:1c brd ff:ff:ff:ff:ff:ff inet 192.168.6.1/24 scope global bridge0 valid_lft forever preferred_lft forever inet6 fe80::10e7:beff:fe6c:aa1c/64 scope link tentative valid_lft forever preferred_lft forever
9.5.5 查看系统所有桥接器
[root@node-2 ~]# brctl show bridge name bridge id STP enabled interfaces bridge0 8000.000000000000 no docker0 8000.02422f4c4a2b no
9.5.6 查看网桥状态
[root@node-2 ~]# ip addr show bridge0 6: bridge0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000 link/ether 12:e7:be:6c:aa:1c brd ff:ff:ff:ff:ff:ff inet 192.168.6.1/24 scope global bridge0 valid_lft forever preferred_lft forever inet6 fe80::10e7:beff:fe6c:aa1c/64 scope link valid_lft forever preferred_lft forever
9.5.7 配置Docker使用新网桥bridge0
[root@node-2 ~]# cat /etc/docker/daemon.json { "bridge": "bridge0" } #完整配置 { "bridge": "bridge0", "registry-mirrors": ["https://plqjafsr.mirror.aliyuncs.com"], "data-root": "/data/docker", "storage-driver": "overlay2", "storage-opts": [ "overlay2.override_kernel_check=true", "overlay2.size=1G" ] }
9.5.8 重启docker 服务
#重载 [root@node-2 ~]# systemctl daemon-reload [root@node-2 ~]# service docker restart
9.5.8.1 启动容器
#启动一个已经退出的容器 [root@demo ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 400fb9f1f415 centos "/bin/bash" 27 hours ago Exited (1) 26 hours ago happy_lumiere #启动容器 [root@demo ~]# docker start 400fb9f1f415 #进入终端 [root@demo ~]# docker exec -it 400fb9f1f415 /bin/bash [root@400fb9f1f415 /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 7: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:c0:a8:06:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 192.168.6.2/24 brd 192.168.6.255 scope global eth0 valid_lft forever preferred_lft forever
9.5.9 运行容器,是否可以使用新网桥
9.5.9.1 重新运行容器
[root@node-2 ~]# docker run -it --name centos-d1 centos /bin/bash
9.5.9.2 使用 ping 测试网络连通性
/ # ping www.baidu.com PING www.baidu.com (163.177.151.109): 56 data bytes 64 bytes from 163.177.151.109: seq=0 ttl=127 time=9.102 ms 64 bytes from 163.177.151.109: seq=1 ttl=127 time=9.358 ms 64 bytes from 163.177.151.109: seq=2 ttl=127 time=9.284 ms
9.5.9.3 查看容器ip
#新容器使用bridge0网段192.168.6.0/24, docker0为172.17.0.0/16 网段 [root@node-2 ~]# docker run -ti centos / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 30: eth0@if31: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:c0:a8:06:03 brd ff:ff:ff:ff:ff:ff inet 192.168.6.3/24 brd 192.168.6.255 scope global eth0 valid_lft forever preferred_lft forever
9.5.9.4 查看系统Iptables 转发规则
MASQUERADE: 通过MASQUERADE自动实现SNAT,把192.168.6.0网段的地址, 转换发送到外网。 也就是说在自定义添加了网桥以后, docker 会自动添加网桥的网段到iptables SNAT 的规则中,实现容器启动以后能够自动的连接到外网。 [root@node-2 ~]# iptables -L -n -t nat ……….省略 Chain POSTROUTING (policy ACCEPT) target prot opt source destination MASQUERADE all -- 192.168.6.0/24 0.0.0.0/0
9.6 容器 None 网络模式添加网卡
Docker 的网络实现其实就是利用了 Linux 上的网络名字空间隔离技术和虚拟网络设备(veth pair)连接技术,实现容器对外部网络的访问。
9.6.1 创建容器流程回顾(桥接模式)
Docker 创建一个容器的时候,会执行如下操作:
创建一对虚拟接口(veth pair),分别放到本地主机和新容器中;
本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,比如veth65f9;
容器一端放到新容器中,并修改名字作为 eth0,这个接口只在容器的名字空间可见;
从网桥可用地址段中获取一个空闲地址分配给容器的 eth0,并配置默认路由到桥接网卡 veth65f9。
完成这些之后,容器就可以使用 eth0 虚拟网卡来连接其他容器和其他网络。
9.6.1.1 本案例实现的效果
为容器busybox容器添加自定义的网卡,容器可以通过网卡连接到外部网络。
9.6.2 操作过程
9.6.2.1 创建一个容器, 设置网络模式是none
#启动一个 /bin/bash 容器,指定 --net=none 参数。
[root@demo ~]# docker run -it --name=demo-none --net=none busybox
9.6.3 查看容器IP
#此时的容器是没有任何IP / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever
9.6.4 获取容器id
#在本地主机查找容器的进程 id [root@node-2 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 38078e9a638d busybox "sh" 13 minutes ago Up 13 minutes youthful_chandrasekhar
9.6.5 获取到容器的进程id
[root@node-2 ~]# docker inspect -f '{{.State.Pid}}' demo-none 13034
9.6.6 创建网络命名空间挂载点
[root@node-2 ~]# pid=13034 #创建网络空间挂载点(本地文件目录) [root@node-2 ~]# mkdir -p /var/run/netns #绑定网络命名空间到挂载点 [root@node-2 ~]# ln -s /proc/$pid/ns/net /var/run/netns/$pid
9.6.7 查看需要添加的桥接器的网段与桥接器名称
#检查桥接网卡的 IP 和子网掩码信息。 [root@node-2 ~]# ip addr show bridge0 6: bridge0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000 link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff inet 192.168.6.1/24 scope global bridge0 #容器网关地址 valid_lft forever preferred_lft forever inet6 fe80::10e7:beff:fe6c:aa1c/64 scope link valid_lft forever preferred_lft forever
9.6.8 建立veth-pair
namespace 之间需要通信,用 veth-pair 来做桥梁创建一对 “veth pair” 接口 A 和 B,绑定 A 到网桥 bridge0,并启用。 A 为: veth 接口(宿主机), B 为容器网卡 [root@node-2 ~]# ip link add A type veth peer name B #设置 A veth 桥接到 bridge0 [root@node-2 ~]# brctl addif bridge0 A #启动 veth A [root@node-2 ~]# ip link set A up
9.6.9 设置网络与ip
#将B放到容器的网络命名空间,命名为 eth10,启动它并配置一个可用 IP(桥接网段)和默认网关。 #添加网卡 B 到网络命名空间 13034 [root@node-2 ~]# ip link set B netns $pid #设置容器网卡的名称为 eth10 [root@node-2 ~]# ip netns exec $pid ip link set dev B name eth10 #设置网卡的状态为 up [root@node-2 ~]# ip netns exec $pid ip link set eth10 up #设置容器网卡的 ip 地址 [root@node-2 ~]# ip netns exec $pid ip addr add 192.168.6.100/24 dev eth10 #设置默认路由 [root@node-2 ~]# ip netns exec $pid ip route add default via 192.168.6.1
9.6.9.1 查看容器ip
#查看容器是否有 eth10 / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 20: eth10@if21: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue qlen 1000 link/ether 8e:6b:02:17:36:0a brd ff:ff:ff:ff:ff:ff inet 192.168.6.100/24 scope global eth10 valid_lft forever preferred_lft forever
9.6.9.2 查看宿主机网桥
[root@node-2 ~]# brctl show bridge name bridge id STP enabled interfaces bridge0 8000.1651b5e3adba no A docker0 8000.02422f4c4a2b no
9.6.9.3 查看系统网卡
[root@node-2 ~]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00:0c:29:14:38:91 brd ff:ff:ff:ff:ff:ff inet 192.168.91.136/24 brd 192.168.91.255 scope global noprefixroute ens32 valid_lft forever preferred_lft forever inet6 fe80::7dfd:e7a3:7683:20e7/64 scope link noprefixroute valid_lft forever preferred_lft forever 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:2f:4c:4a:2b brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:2fff:fe4c:4a2b/64 scope link valid_lft forever preferred_lft forever 6: bridge0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 16:51:b5:e3:ad:ba brd ff:ff:ff:ff:ff:ff inet 192.168.6.1/24 scope global bridge0 valid_lft forever preferred_lft forever inet6 fe80::10e7:beff:fe6c:aa1c/64 scope link valid_lft forever preferred_lft forever 21: A@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master bridge0 state UP group default qlen 1000 link/ether 16:51:b5:e3:ad:ba brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 fe80::1451:b5ff:fee3:adba/64 scope link valid_lft forever preferred_lft forever
9.7 运行容器 IP 添加地址
#拉取镜像 CentOS
[root@ demo ~]# docker pull centos
9.7.1 运行容器
#前台运行centos
[root@demo ~]# docker run --name=centos-IP1 -it centos /bin/bash
9.7.2 获取到容器启动进程号
[root@ demo ~]# docker inspect -f '{{.State.Pid}}' centos-IP1 13575
9.7.3 容器修改之前的ip
[root@95d78806950d /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 28: eth0@if29: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:c0:a8:06:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 192.168.6.3/24 brd 192.168.6.255 scope global eth0 valid_lft forever preferred_lft forever
9.7.4 创建容器网络命名空间挂载点
[root@ demo ~]# pid=13575 #无法直接操作必须要有网络空间挂载点 [root@demo ~]# ip netns exec $pid ip a Cannot open network namespace "13575": No such file or directory [root@ demo ~]# mkdir -p /var/run/netns #创建网络空间挂载点 [root@ demo ~]# ln -s /proc/$pid/ns/net /var/run/netns/$pid #查看现在容器 IP [root@ demo ~]# ip netns exec $pid ip a
9.7.5 设置容器新IP
#设置容器的ip 地址 [root@ demo ~]# ip netns exec $pid ip addr add 192.168.6.10/24 dev eth0
9.7.6 容器内部检验IP
#检验新的ip 地址是否添加
[root@ demo ~]# ip netns exec $pid ip a
9.8 总结 Docker 实现原理
1)底层硬件支撑, 也可以用虚拟机运行Docker。 2)在硬件或虚拟机内安装支持容器运行的操作系统 3) Docker 通过NS、Cgroups与OverlayFs 技术实现容器的加载启动. 4)容器通过利用系统中的Docker0网桥与外部网络互通。