Docker—基础之Linux Namespace
Docker
Docker通过namespace及cgroup等来提供容器的资源隔离与安全保障等
网络名称空间概念:为了支持网络协议栈的多个实例,linux在网络栈通过网络名称空间将独立的协议栈隔离到不同的网络名称空间。处于不同网络名称空间的网络栈是完全隔离的,彼此之间无法通信。通过对网络资源的隔离,就能在一个宿主机上虚拟多个不同的网络环境。
Docker正是利用网络名称空间特性,实现不同容器之间的网络隔离。Docker容器中各类网络栈都是Docker Daemon在启动时自动创建和配置的。
Veth设备:
由于网络名称空间代表一个独立的协议栈,所以他们是完全隔离的,彼此无法通信。
Veth设备对,注意:这里说的是设备对,即是成对出现的;其中一个作用就是打通了相互看不到的协议栈之间的壁垒,它像一条管子,将两个不同的网络名称空间连接起来实现通信。
在docker容器中,veth是连接容器与宿主机通信的重要桥梁,
网桥:
类似于二层交换机原理,利用MAC地址寻址,如果在MAC表存在,则转发,反之广播。
linux内核通过若干个网络桥接设备实现桥接,这个虚拟设备可以绑定若干个以太网接口设备,从而将它们桥接起来,这个网桥与其他的设备不同,最明显特性是它可以有一个IP地址。
Docker网络类型:
- host
- container模式(容器共享网络名称空间)
- none
- bridge
在bridge模式下,Docker启动会创建一个虚拟网桥Docker0,然后给Docker0分配一个子网。由Docker0创建的每一个容器,都会创建一个虚拟以太网设备(Veth设备对),一端关联Docker0,一端关联容器内部eth0,然后在Docker0所在的网段分配容器一个地址。
在同一台主机,不同容器之间通过即可Docker0桥接直接通信,不同主机需要映射宿主机端口,由宿主机网卡转发Docker0,然后转发容器通信。
查看宿主机网卡
[root@web ~]# ifconfig docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0 inet6 fe80::42:33ff:fe81:19b5 prefixlen 64 scopeid 0x20<link> ether 02:42:33:81:19:b5 txqueuelen 0 (Ethernet) RX packets 4408 bytes 255165 (249.1 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 5186 bytes 9931732 (9.4 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 10.0.4.8 netmask 255.255.252.0 broadcast 10.0.7.255 inet6 fe80::5054:ff:fe56:8b72 prefixlen 64 scopeid 0x20<link> ether 52:54:00:56:8b:72 txqueuelen 1000 (Ethernet) RX packets 7987346 bytes 1205279160 (1.1 GiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 7137417 bytes 1120316658 (1.0 GiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1 (Local Loopback) RX packets 776 bytes 99408 (97.0 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 776 bytes 99408 (97.0 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 veth99d1f16: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 # 连接不同namespace网络 inet6 fe80::5cd1:2aff:fef9:65d5 prefixlen 64 scopeid 0x20<link> ether 5e:d1:2a:f9:65:d5 txqueuelen 0 (Ethernet) RX packets 4392 bytes 315581 (308.1 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 5184 bytes 9931552 (9.4 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
当再启动一个容器,再次查看,可以看到又启动了一个veth设置
vethb50dc70: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::98cb:6cff:fe1b:b147 prefixlen 64 scopeid 0x20<link> ether 9a:cb:6c:1b:b1:47 txqueuelen 0 (Ethernet) RX packets 8 bytes 648 (648.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8 bytes 648 (648.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
进入容器查看,eth0 就是veth设备,他被命名为eth0,而且分配了IP地址。
[root@ad0c18fcb99c /]# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.3 netmask 255.255.0.0 broadcast 0.0.0.0 inet6 fe80::42:acff:fe11:3 prefixlen 64 scopeid 0x20<link> ether 02:42:ac:11:00:03 txqueuelen 0 (Ethernet) RX packets 14314 bytes 44963854 (42.8 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8786 bytes 588018 (574.2 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
查看容器网关
]# 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 # 指向docker0 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
docker启动会在linux以守护进程运行
]# ps -ef | grep docker root 1128 1 3 May11 ? 02:33:12 /usr/bin/dockerd root 1262 1128 0 May11 ? 00:37:17 containerd --config /var/run/docker/containerd/containerd.toml --log-level warn root 2494 1262 0 May11 ? 00:00:20 containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/34e4b348f161a741dbfe734561d5218addb793c74696b7bd10d517a5b6741751 -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/local/bin/containerd -runtime-root /var/run/docker/runtime-runc
通过pstree查看进程守护关系
├─dockerd(1128)─┬─containerd(1262)─┬─containerd-shim(2494)─┬─pause(2557) │ │ │ ├─{containerd-shim}(2517) │ │ │ ├─{containerd-shim}(2518) │ │ │ ├─{containerd-shim}(2519) │ │ │ ├─{containerd-shim}(2520) │ │ │ ├─{containerd-shim}(2521) │ │ │ ├─{containerd-shim}(2523) │ │ │ ├─{containerd-shim}(2524) │ │ │ └─{containerd-shim}(3789)
查看docker是如何管理容器的
启动容器
docker run -d docker.io/nginx
4892163d8ab1f27f3b5e13fd78c2307e8ceacfb0d6fd464214cb827c76de4d51
pstree查看进程关系
├─dockerd-current(18899)─┬─docker-containe(18908)─┬─docker-containe(16228)─┬─nginx(16247)─┬─nginx(16304) │ │ │ │ ├─nginx(16305) │ │ │ │ ├─nginx(16306) │ │ │ │ └─nginx(16307)
查看进程关系详情
]# ps -ef | grep 18899 # docker进程 root 16383 14276 0 10:48 pts/3 00:00:00 grep --color=auto 18899 root 18899 1 0 May14 ? 00:01:15 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt nativxy-path=/usr/libexec/docker/docker-proxy-current --init-path=/usr/libexec/docker/docker-init-current --seccomp-profile=/etc/docker/seccomp.json --selinux-enabled --log-driver=journald -ge-driver overlay2 root 18908 18899 0 May14 ? 00:00:37 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2minerd/containerd --shim docker-containerd-shim --runtime docker-runc --runtime-args --systemd-cgroup=true [root@web ~]# ps -ef | grep 18908 # 查看dontainerd进程 root 16228 18908 0 10:48 ? 00:00:00 /usr/bin/docker-containerd-shim-current 4892163d8ab1f27f3b5e13fd78c2307e8ceacfb0d6fd464214cb827c76de4d51 /var/run/docker/libcontainerd/480d6fd464214cb827c76de4d51 /usr/libexec/docker/docker-runc-current root 16412 14276 0 10:49 pts/3 00:00:00 grep --color=auto 18908 root 18908 18899 0 May14 ? 00:00:37 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2minerd/containerd --shim docker-containerd-shim --runtime docker-runc --runtime-args --systemd-cgroup=true [root@web ~]# ps -ef | grep 16228 # 可以看到由containerd启动了一个nginx的master进程 root 16228 18908 0 10:48 ? 00:00:00 /usr/bin/docker-containerd-shim-current 4892163d8ab1f27f3b5e13fd78c2307e8ceacfb0d6fd464214cb827c76de4d51 /var/run/docker/libcontainerd/480d6fd464214cb827c76de4d51 /usr/libexec/docker/docker-runc-current root 16247 16228 0 10:48 ? 00:00:00 nginx: master process nginx -g daemon off; root 16434 14276 0 10:49 pts/3 00:00:00 grep --color=auto 16228 [root@web ~]# ps -ef | grep 16247 # master启动了4个worker进程 root 16247 16228 0 10:48 ? 00:00:00 nginx: master process nginx -g daemon off; 101 16304 16247 0 10:48 ? 00:00:00 nginx: worker process 101 16305 16247 0 10:48 ? 00:00:00 nginx: worker process 101 16306 16247 0 10:48 ? 00:00:00 nginx: worker process 101 16307 16247 0 10:48 ? 00:00:00 nginx: worker process root 16465 14276 0 10:49 pts/3 00:00:00 grep --color=auto 16247
进入容器查看
root@4892163d8ab1:/# apt-get update root@4892163d8ab1:/# apt-get install procps # 安装ps命令 root@4892163d8ab1:/# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 02:48 ? 00:00:00 nginx: master process nginx -g daemon off; # PID为1的进程为nginx主进程 nginx 32 1 0 02:48 ? 00:00:00 nginx: worker process nginx 33 1 0 02:48 ? 00:00:00 nginx: worker process nginx 34 1 0 02:48 ? 00:00:00 nginx: worker process nginx 35 1 0 02:48 ? 00:00:00 nginx: worker process root 36 0 0 02:58 ? 00:00:00 bash root 405 36 0 03:08 ? 00:00:00 ps -ef
通过以上结果,由containerd启动了一个nginx的master进程,作为容器进程为1的主进程。