Docker存储与网络
一、Docker存储
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
docker存储volume #环境 centos7.4 , Docker version 17.12.0-ce docker volume创建、备份、nfs存储 #docker volume 数据存容器内,删容器即销毁全部数据 要保留的数据(数据持久化),需存储在容器外 docker volume是文件或目录,mount到docker容器中使用 docker volume bind muount #挂载任意目录或文件 Volumes #固定路径的目录,docker管理 tmpfs mounts #存放宿主机内存中 image docker volume 官网文档地址 https://docs.docker.com/storage/volumes/ #bind muount实例 #docker挂载文件或目录到容器 #创建目录及文件 mkdir -p /data/test1 echo 'docker volume'>/data/test1/test.txt #创建容器,-v 挂载目录(默认读写权限) docker run -dit --name busybox1 -v /data/test1:/data/test1 busybox #查看 docker exec busybox1 cat /data/test1/test.txt #修改文件后,在查看本地是否更改 docker exec busybox1 echo my files>>/data/test1/test.txt docker exec busybox1 cat /data/test1/test.txt cat /data/test1/test.txt 为保证Dockerfile可移植,构建镜像不能使用bind muount #tmpfs mounts # 使用--tmpfs docker run -dit --name tmpfs-test --tmpfs /app busybox #Volumes #不指定挂载目录,默认目录/var/lib/docker/volumes//_data/ #docker volumes可管理,官方推荐 #使用Volumes #不指定挂载目录,自动创建 volumes/<ID号>/_data/ docker run -dit --name busybox2 -v /data/test busybox #在容器创建目文件 docker exec busybox2 touch /data/test/test2.txt #在宿主机查看文件路径 find /var/lib/docker/volumes -name test2.txt docker inspect busybox2 |grep Source #docker volume命令管理 #创建volume docker volume create volume-test1 #查看参数 docker inspect volume-test1 #使用volume docker run -dit --name busybox3 -v volume-test1:/volume busybox #查看 docker inspect -f {{.Mounts}} busybox3 #查看docker数据卷 docker volume ls #删除没使用的数据卷(谨慎使用) docker volume prune Bind mounts和volumes都通过-v或--volume挂载,tmpfs使用--tmpfs 三种都可以使用--mount挂载,格式更清晰,官方推荐使用 #docker volume 数据共享 挂载相同目录 使用volume container #数据卷容器 volume container # --volumes-from 容器名,就会传递容器的挂载目录(volume参数传递) #创建容器busybox4(不需要启动) mkdir -p /data/test2 echo 'busybox4'>/data/test2/test.txt docker create --name busybox4 -v /data/test2:/data/test2 busybox # --volumes-from 使用其它容器的volume docker run -dit --name busybox5 --volumes-from busybox4 busybox #查看 docker exec busybox5 cat /data/test2/test.txt #挂载多个 数据卷容器 docker run -dit --name busybox6 --volumes-from busybox4 --volumes-from busybox1 busybox docker exec busybox6 ls /data/ #查看 #docker volume 备份 备份volume挂载目录 使用容器--volumes-from备份 #使用数据卷容器备份busybox4的volumes docker run --rm --volumes-from busybox4 -v $(pwd):/backup busybox \ tar cvf /backup/backup.tar /data/test2/ . 以上docker volume实例,全部在单台docker主机 docker集群环境,需要使用共享存储、分布式存储 #docker volume使用NFS存储 #NFS服务端,配置nfs共享 yum install nfs-utils rpcbind -y mkdir -p /data/nfs/docker echo "/data/nfs *(rw,no_root_squash,sync)">>/etc/exports exportfs -r systemctl start rpcbind nfs-server systemctl enable rpcbind nfs-server showmount -e localhost #nfs客户端 yum install -y nfs-utils rpcbind #创建volume 连接 172.16.50.43:/data/nfs docker volume create --driver local \ --opt type=nfs \ --opt o=addr=172.16.50.43,rw \ --opt device=:/data/nfs \ volume-nfs #查看 docker volume ls docker volume inspect volume-nfs #容器使用volume-nfs docker run -dit --name busybox7 -v volume-nfs:/nfs busybox #查看 docker inspect -f {{.Mounts}} busybox7 df -h |grep /data/nfs #volume目录/var/lib/docker/volumes/volume-nfs/_data自动挂载到了nfs服务上 #容器创文件测试 docker exec busybox7 touch /nfs/testfiles.txt #使用volume driver 可实现更多的backend #删除测试容器,volume docker rm -f -v tmpfs-test busybox{1,2,3,4,5,6,7} #-f 强制删除,-v 删除volume docker volume prune
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
[root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1fb916fb0e13 6a "sh" 2 hours ago Created hello2 9fb1ff8de577 6a "sh" 2 hours ago Up 7 minutes hello [root@localhost ~]# docker start 1 1 [root@localhost ~]# docker stats CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 9fb1ff8de577 0.00% 56KiB / 993MiB 0.01% 648B / 0B 0B / 0B 0 ^C [root@localhost ~]# docker update -m 500m --memory-swap -1 9f 9f [root@localhost ~]# docker stats CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 9fb1ff8de577 0.00% 56KiB / 500MiB 0.01% 648B / 0B 0B / 0B 0 CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 9fb1ff8de577 0.00% 56KiB / 500MiB 0.01% 648B / 0B 0B / 0B 0 CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 9fb1ff8de577 0.00% 56KiB / 500MiB 0.01% 648B / 0B 0B / 0B 0 CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 9fb1ff8de577 0.00% 56KiB / 500MiB 0.01% 648B / 0B 0B / 0B 0 ———————————————— 版权声明:本文为CSDN博主「cakincqm」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/chengqiuming/article/details/78987167
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1.停止正在运行的docker: systemctl stop docker 2.创建文件夹:mkdir -p /xxx/disk (xxx/disk为新磁盘目录名) 3.移动/var/lib/docker/目录到新目录中: mv /var/lib/docker /xxx/disk/ ###(假设新磁盘空间多的话 先copy -r /var/lib/docker . 一份) 4.软连接/disk/docker到/var/lib/里: ln -s /xxx/disk/docker /var/lib/ 5.启动docker: systemctl start docker
1.将数据从宿主机挂载到容器中的三种方式
Docker提供三种方式将数据从宿主机挂载到容器中:
•volumes:Docker管理宿主机文件系统的一部分(/var/lib/docker/volumes 会在这个目录下创建相应的存储目录)。保存数据的最佳方式。(默认模式)
•bind mounts:将宿主机上的任意位置的文件或者目录挂载到容器中。
•tmpfs:挂载存储在主机系统的内存中,而不会写入主机的文件系统。如果不希望将数据持久存储在任何位置,可以使用tmpfs,同时避免写入容器可写层提高性能。
2.Volume
步骤一:管理卷: # docker volume create nginx-vol 创建一个名为nginx-vol的存储卷 # docker volume ls 查看所有的逻辑卷 # docker volume inspect nginx-vol 查看该卷的详细信息 步骤二:用卷创建一个容器: # docker run -d --name=nginx-test --mount type=volume(默认是volume,可以省略),src=nginx-vol,dst=/usr/share/nginx/html nginx #新版 建议使用 ,更通用 # docker run -d --name=nginx-test -v nginx-vol:/usr/share/nginx/html nginx #老版本使用 步骤三 清理: # docker stop nginx-test 停容器 # docker rm nginx-test 删容器 # docker volume rm nginx-vol 删除卷 注意: 1.如果没有指定卷,自动创建。 2.建议使用--mount,更通用。 参考网址:https://docs.docker.com/engine/admin/volumes/volumes/#start-a-container-with-a-volume
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
[root@docker01 docker]# docker volume create nginx-vol nginx-vol [root@docker01 docker]# docker volume ls #/var/lib/docker/volumes/nginx-vol/_data <---> nginx-vol数据目录 DRIVER VOLUME NAME local nginx-vol [root@docker01 docker]# docker run -d --name=nginx-test --mount src=nginx-vol,dst=/usr/share/nginx/html nginx:1.15 a332324e37f451cc1ab985546c00d2341230de057cddee036f37ed4c6e94bc8f [root@docker01 docker]# docker ps -l #查看最近一个产生的容器 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a332324e37f4 nginx:1.15 "nginx -g 'daemon of…" 18 seconds ago Up 12 seconds 80/tcp nginx-test [root@docker01 docker]# [root@docker01 docker]# docker container inspect a332324e37f4 | grep -C 3 _data #查看匹配语句的前后三行 { "Type": "volume", "Name": "nginx-vol", "Source": "/var/lib/docker/volumes/nginx-vol/_data", "Destination": "/usr/share/nginx/html", "Driver": "local", "Mode": [root@docker01 docker]# ls /var/lib/docker/volumes/nginx-vol/_data 50x.html index.html #/usr/share/nginx/html下面的数据 挂载到了宿主机 [root@docker01 docker]# [root@docker01 docker]# docker container inspect a332324e37f4 | grep IPAddress "SecondaryIPAddresses": null, "IPAddress": "172.17.0.4", "IPAddress": "172.17.0.4", [root@docker01 docker]# curl 172.17.0.4 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> [root@docker01 docker]# vim /var/lib/docker/volumes/nginx-vol/_data/index.html [root@docker01 docker]# cat /var/lib/docker/volumes/nginx-vol/_data cat: /var/lib/docker/volumes/nginx-vol/_data: 是一个目录 [root@docker01 docker]# cat /var/lib/docker/volumes/nginx-vol/_data/index.html hello world [root@docker01 docker]# curl 172.17.0.4 hello world [root@docker01 docker]#
3.Bind Mounts
用卷创建一个容器: # docker run -d -it --name=nginx-test --mount type=bind,src=/app/wwwroot,dst=/usr/share/nginx/html nginx #新版本 # docker run -d -it --name=nginx-test -v /app/wwwroot:/usr/share/nginx/html nginx #老版本 /app/wwwroot 宿主机的目录,会用/app/wwwroot的内容覆盖掉/usr/share/nginx/html 验证绑定: # docker inspect nginx-test 清理: # docker stop nginx-test # docker rm nginx-test 注意: 1.如果源文件/目录(宿主机上没有这个目录)没有存在,不会自动创建,会抛出一个错误。 2.如果挂载目标在容器中非空目录,则该目录现有内容将被隐藏。 #src=/app/wwwroot里面的内容 将覆盖 dst=/usr/share/nginx/html的内容 https://docs.docker.com/engine/admin/volumes/bind-mounts/#start-a-container-with-a-bind-mount
4.小结
Volume特点: 多个运行容器之间共享数据。 当容器停止或被移除时,该卷依然存在。 多个容器可以同时挂载相同的卷。 当明确删除卷时,卷才会被删除。 将容器的数据存储在远程主机或其他存储上 将数据从一台Docker主机迁移到另一台时,先停止容器,然后备份卷的目录(/var/lib/docker/volumes/) Bind Mounts特点: 从主机共享配置文件到容器。默认情况下,挂载主机/etc/resolv.conf到每个容器,提供DNS解析。 在Docker主机上的开发环境和容器之间共享源代码。例如,可以将Maven target目录挂载到容器中,每次在Docker主机上构建Maven项目时,容器都可以访问构建的项目包。 当Docker主机的文件或目录结构保证与容器所需的绑定挂载一致时
二、Docker网络
我们在使用docker run创建Docker容器时,可以用--net选项指定容器的网络模式,Docker有以下5种网络模式:
下面分别介绍一下Docker的各个网络模式。
1 host模式
格式:
docker run -it --name myubuntu --net=host ubuntu /bin/bash
众所周知,Docker使用了Linux的Namespaces技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
例如,我们在10.10.101.105/24的机器上用host模式启动一个含有web应用的Docker容器,监听tcp80端口。当我们在容器中执行任何类似ifconfig命令查看网络环境时,看到的都是宿主机上的信息。而外界访问容器中的应用,则直接使用10.10.101.105:80即可,不用任何NAT转换,就如直接跑在宿主机中一样。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
•-–net=host容器不会获得一个独立的network namespace,而是与宿主机共用一个。这就意味着容器不会有自己的网卡信息,而是使用宿主机的。容器除了网络,其他都是隔离的。 [root@docker01 docker]# docker run -it --net=host busybox / # 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 inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 00:0c:29:56:32:aa brd ff:ff:ff:ff:ff:ff inet 192.168.1.10/24 brd 192.168.1.255 scope global ens33 valid_lft forever preferred_lft forever inet6 fe80::8f4:8fc3:786b:527f/64 scope link valid_lft forever preferred_lft forever 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue link/ether 02:42:ec:33:a2:25 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:ecff:fe33:a225/64 scope link valid_lft forever preferred_lft forever 5: veth7a3a6c5@if4: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 link/ether a6:d1:6f:39:28:8b brd ff:ff:ff:ff:ff:ff inet6 fe80::a4d1:6fff:fe39:288b/64 scope link valid_lft forever preferred_lft forever 7: veth3d53b29@if6: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 link/ether ba:f7:ab:f4:e9:33 brd ff:ff:ff:ff:ff:ff inet6 fe80::b8f7:abff:fef4:e933/64 scope link valid_lft forever preferred_lft forever 9: vethc841c0a@if8: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 link/ether 1e:48:38:75:54:ee brd ff:ff:ff:ff:ff:ff inet6 fe80::1c48:38ff:fe75:54ee/64 scope link valid_lft forever preferred_lft forever / #
2 container模式
格式:
docker run -it --name myubuntu --net=container:NAME_OR_ID ubuntu /bin/bash
在理解了host模式后,这个模式也就好理解了。这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
•container–net=container:Name/ID与指定的容器使用同一个network namespace,具有同样的网络配置信息,两个容器除了网络,其他都还是隔离的。 [root@docker01 docker]# docker run -it --name bs1 busybox / # 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 12: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:11:00:05 brd ff:ff:ff:ff:ff:ff inet 172.17.0.5/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever / # 开另一个窗口 [root@docker01 ~]# docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 61af36f47fbf busybox "sh" 31 seconds ago Up 25 seconds bs1 [root@docker01 ~]# docker run -it --name bs2 --net=container:61af36f47fbf busybox #网络一样 / # 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 12: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:11:00:05 brd ff:ff:ff:ff:ff:ff inet 172.17.0.5/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever / #
3 none模式
格式:
docker run -it --name myubuntu --net=none ubuntu /bin/bash
这个模式和前两个不同。在这种模式下,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
•-–net=none获取独立的network namespace,但不为容器进行任何网络配置,需要我们手动配置。 [root@docker01 docker]# docker run -it --net=none busybox / # 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 / #
4 bridge模式
bridge模式是Docker默认的网络设置,此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的Docker容器连接到一个虚拟网桥上。下面着重介绍一下此模式。
4.1 bridge模式的拓扑
当Docker server启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。接下来就要为容器分配IP了,Docker会从RFC1918所定义的私有IP网段中,选择一个和宿主机不同的IP地址和子网分配给docker0,连接到docker0的容器就从这个子网中选择一个未占用的IP使用。如一般Docker会使用172.17.0.0/16这个网段,并将172.17.42.1/16分配给docker0网桥(在主机上使用ifconfig命令是可以看到docker0的,可以认为它是网桥的管理接口,在宿主机上作为一块虚拟网卡使用)。单机环境下的网络拓扑如下,主机地址为10.10.101.105/24。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
[root@docker01 ~]# ifconfig br-36766c64e493: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.18.0.1 netmask 255.255.0.0 broadcast 172.18.255.255 inet6 fe80::42:37ff:fea2:3f9d prefixlen 64 scopeid 0x20<link> ether 02:42:37:a2:3f:9d txqueuelen 0 (Ethernet) RX packets 6 bytes 1231 (1.2 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 29 bytes 2108 (2.0 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 br-9cdfea34f9cd: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.19.0.1 netmask 255.255.0.0 broadcast 172.19.255.255 inet6 fe80::42:63ff:fe56:f9b9 prefixlen 64 scopeid 0x20<link> ether 02:42:63:56:f9:b9 txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 inet6 fe80::42:ecff:fe33:a225 prefixlen 64 scopeid 0x20<link> ether 02:42:ec:33:a2:25 txqueuelen 0 (Ethernet) RX packets 46244 bytes 2600005 (2.4 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 49929 bytes 173907794 (165.8 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.1.10 netmask 255.255.255.0 broadcast 192.168.1.255 inet6 fe80::8f4:8fc3:786b:527f prefixlen 64 scopeid 0x20<link> ether 00:0c:29:56:32:aa txqueuelen 1000 (Ethernet) RX packets 440988 bytes 602710620 (574.7 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 244878 bytes 22083517 (21.0 MiB) 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 1000 (Local Loopback) RX packets 124 bytes 21089 (20.5 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 124 bytes 21089 (20.5 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 veth3d53b29: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::b8f7:abff:fef4:e933 prefixlen 64 scopeid 0x20<link> ether ba:f7:ab:f4:e9:33 txqueuelen 0 (Ethernet) RX packets 22 bytes 3316 (3.2 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 36 bytes 2954 (2.8 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 veth523916d: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::d8a5:7aff:fe29:bc3e prefixlen 64 scopeid 0x20<link> ether da:a5:7a:29:bc:3e txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 16 bytes 1312 (1.2 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 veth7a3a6c5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::a4d1:6fff:fe39:288b prefixlen 64 scopeid 0x20<link> ether a6:d1:6f:39:28:8b txqueuelen 0 (Ethernet) RX packets 6 bytes 1231 (1.2 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 29 bytes 2108 (2.0 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 vethc841c0a: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::1c48:38ff:fe75:54ee prefixlen 64 scopeid 0x20<link> ether 1e:48:38:75:54:ee txqueuelen 0 (Ethernet) RX packets 13 bytes 1901 (1.8 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 28 bytes 1996 (1.9 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 vethca5575e: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::c057:f1ff:fe10:aed7 prefixlen 64 scopeid 0x20<link> ether c2:57:f1:10:ae:d7 txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 16 bytes 1312 (1.2 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 vethe529e61: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::70f0:1eff:fed8:344d prefixlen 64 scopeid 0x20<link> ether 72:f0:1e:d8:34:4d txqueuelen 0 (Ethernet) RX packets 2666 bytes 180649 (176.4 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3300 bytes 19520939 (18.6 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 [root@docker01 docker]# docker pull busybox Using default tag: latest latest: Pulling from library/busybox Image docker.io/library/busybox:latest uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/ e2334dd9fee4: Downloading latest: Pulling from library/busybox e2334dd9fee4: Pull complete Digest: sha256:a8cf7ff6367c2afa2a90acd081b484cbded349a7076e7bdf37a05279f276bc12 Status: Downloaded newer image for busybox:latest docker.io/library/busybox:latest [root@docker01 docker]# docker run -it busybox / # 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 10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:11:00:05 brd ff:ff:ff:ff:ff:ff inet 172.17.0.5/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever / #
Docker完成以上网络配置的过程大致是这样的:
1. 在主机上创建一对虚拟网卡veth pair设备。veth设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth设备常用来连接两个网络设备。
2. Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0。另一端放在主机中,以veth65f9这样类似的名字命名,并将这个网络设备加入到docker0网桥中,可以通过brctl show命令查看。
3. 从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。
网络拓扑介绍完后,接着介绍一下bridge模式下容器是如何通信的。
4.2 bridge模式下容器的通信
在bridge模式下,连在同一网桥上的容器可以相互通信(若出于安全考虑,也可以禁止它们之间通信,方法是在DOCKER_OPTS变量中设置--icc=false,这样只有使用--link才能使两个容器通信)。 容器也可以与外部通信,我们看一下主机上的Iptable规则,可以看到这么一条 -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE 这条规则会将源地址为172.17.0.0/16的包(也就是从Docker容器产生的包),并且不是从docker0网卡发出的,进行源地址转换,转换成主机网卡的地址。这么说可能不太好理解,举一个例子说明一下。
假设主机有一块网卡为eth0,IP地址为10.10.101.105/24,网关为10.10.101.254。从主机上一个IP为172.17.0.1/16的容器中ping百度(180.76.3.151)。
IP包首先从容器发往自己的默认网关docker0,包到达docker0后,也就到达了主机上。然后会查询主机的路由表,发现包应该从主机的eth0发往主机的网关10.10.105.254/24。接着包会转发给eth0,并从eth0发出去(主机的ip_forward转发应该已经打开)。
这时候,上面的Iptable规则就会起作用,对包做SNAT转换,将源地址换为eth0的地址。这样,在外界看来,这个包就是从10.10.101.105上发出来的,Docker容器对外是不可见的。 那么,外面的机器是如何访问Docker容器的服务呢?我们首先用下面命令创建一个含有web应用的容器,将容器的80端口映射到主机的80端口。 docker run -d --name web -p 80:80 fmzhen/simpleweb 然后查看Iptable规则的变化,发现多了这样一条规则: -A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.5:80 此条规则就是对主机eth0收到的目的端口为80的tcp流量进行DNAT转换,将流量发往172.17.0.5:80,也就是我们上面创建的Docker容器。所以,外界只需访问10.10.101.105:80就可以访问到容器中得服务。 除此之外,我们还可以自定义Docker使用的IP地址、DNS等信息,甚至使用自己定义的网桥,但是其工作方式还是一样的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
[root@docker01 docker]# docker run -it --name bs4 busybox / # 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 17: eth0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:11:00:05 brd ff:ff:ff:ff:ff:ff inet 172.17.0.5/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever / # 容器 ---> 外网 eth0@if18 ---> 宿主机vethxxx(随机字符串) ---> 宿主机docker0 ---SNAT---> 宿主机ens33 --->外界 容器 <---- 外网 eth0@if18 <--- 宿主机vethxxx(随机字符串) <--- 宿主机docker0 <---DNAT--- 宿主机ens33 <---外界 [root@docker01 ~]# ifconfig br-36766c64e493: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.18.0.1 netmask 255.255.0.0 broadcast 172.18.255.255 inet6 fe80::42:37ff:fea2:3f9d prefixlen 64 scopeid 0x20<link> ether 02:42:37:a2:3f:9d txqueuelen 0 (Ethernet) RX packets 6 bytes 1231 (1.2 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 26 bytes 1982 (1.9 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 inet6 fe80::42:ecff:fe33:a225 prefixlen 64 scopeid 0x20<link> ether 02:42:ec:33:a2:25 txqueuelen 0 (Ethernet) RX packets 41 bytes 5874 (5.7 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 57 bytes 4586 (4.4 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.1.10 netmask 255.255.255.0 broadcast 192.168.1.255 inet6 fe80::8f4:8fc3:786b:527f prefixlen 64 scopeid 0x20<link> ether 00:0c:29:56:32:aa txqueuelen 1000 (Ethernet) RX packets 145613 bytes 201043013 (191.7 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 71781 bytes 6554643 (6.2 MiB) 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 1000 (Local Loopback) RX packets 124 bytes 21089 (20.5 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 124 bytes 21089 (20.5 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 veth3d53b29: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::b8f7:abff:fef4:e933 prefixlen 64 scopeid 0x20<link> ether ba:f7:ab:f4:e9:33 txqueuelen 0 (Ethernet) RX packets 22 bytes 3316 (3.2 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 33 bytes 2828 (2.7 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 veth523916d: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::d8a5:7aff:fe29:bc3e prefixlen 64 scopeid 0x20<link> ether da:a5:7a:29:bc:3e txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 16 bytes 1312 (1.2 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 veth5a8ff4b: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::6854:20ff:fec2:43fa prefixlen 64 scopeid 0x20<link> ether 6a:54:20:c2:43:fa txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8 bytes 656 (656.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 veth7a3a6c5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::a4d1:6fff:fe39:288b prefixlen 64 scopeid 0x20<link> ether a6:d1:6f:39:28:8b txqueuelen 0 (Ethernet) RX packets 6 bytes 1231 (1.2 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 26 bytes 1982 (1.9 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 vethc841c0a: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::1c48:38ff:fe75:54ee prefixlen 64 scopeid 0x20<link> ether 1e:48:38:75:54:ee txqueuelen 0 (Ethernet) RX packets 13 bytes 1901 (1.8 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 25 bytes 1870 (1.8 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 [root@docker01 ~]# route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface default gateway 0.0.0.0 UG 100 0 0 ens33 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-36766c64e493 192.168.1.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33 [root@docker01 ~]# [root@docker01 ~]# yum -y install bridge-utils [root@docker01 ~]# brctl show bridge name bridge id STP enabled interfaces br-36766c64e493 8000.024237a23f9d no veth523916d docker0 8000.0242ec33a225 no veth3d53b29 veth5a8ff4b veth7a3a6c5 vethc841c0a [root@docker01 ~]# [root@docker01 ~]# iptables-save #NAT转发规则 # Generated by iptables-save v1.4.21 on Sat May 2 16:33:20 2020 *filter :INPUT ACCEPT [521:43254] :FORWARD DROP [0:0] :OUTPUT ACCEPT [393:50826] :DOCKER - [0:0] :DOCKER-ISOLATION-STAGE-1 - [0:0] :DOCKER-ISOLATION-STAGE-2 - [0:0] :DOCKER-USER - [0:0] -A FORWARD -j DOCKER-USER -A FORWARD -j DOCKER-ISOLATION-STAGE-1 -A FORWARD -o br-36766c64e493 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -o br-36766c64e493 -j DOCKER -A FORWARD -i br-36766c64e493 ! -o br-36766c64e493 -j ACCEPT -A FORWARD -i br-36766c64e493 -o br-36766c64e493 -j ACCEPT -A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -o docker0 -j DOCKER -A FORWARD -i docker0 ! -o docker0 -j ACCEPT -A FORWARD -i docker0 -o docker0 -j ACCEPT -A DOCKER -d 172.17.0.3/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT -A DOCKER-ISOLATION-STAGE-1 -i br-36766c64e493 ! -o br-36766c64e493 -j DOCKER-ISOLATION-STAGE-2 -A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2 -A DOCKER-ISOLATION-STAGE-1 -j RETURN -A DOCKER-ISOLATION-STAGE-2 -o br-36766c64e493 -j DROP -A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP -A DOCKER-ISOLATION-STAGE-2 -j RETURN -A DOCKER-USER -j RETURN COMMIT # Completed on Sat May 2 16:33:20 2020 # Generated by iptables-save v1.4.21 on Sat May 2 16:33:20 2020 *nat :PREROUTING ACCEPT [9:1909] :INPUT ACCEPT [9:1909] :OUTPUT ACCEPT [8:602] :POSTROUTING ACCEPT [8:602] :DOCKER - [0:0] -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER -A POSTROUTING -s 172.18.0.0/16 ! -o br-36766c64e493 -j MASQUERADE -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE -A POSTROUTING -s 172.17.0.3/32 -d 172.17.0.3/32 -p tcp -m tcp --dport 80 -j MASQUERADE -A DOCKER -i br-36766c64e493 -j RETURN -A DOCKER -i docker0 -j RETURN -A DOCKER ! -i docker0 -p tcp -m tcp --dport 88 -j DNAT --to-destination 172.17.0.3:80 COMMIT # Completed on Sat May 2 16:33:20 2020 [root@docker01 ~]#
5.用户自定义模式
用户可以通过Docker网络驱动器或其他的网络驱动器自定义网络。你可以将许多容器连接到同一个网络上,一旦连接到了自定义的网络上,容器之间就可以通过对方的IP地址和主机名来进行通信了。
如果容器连接到了用户自定义的网络上,容器的/etc/hosts文件会加入在同一个网络中的其他所有容器的IP地址。
由于容器有可能随时改变/etc/hosts文件,容器中的程序可能会读取到不完整的甚至空的/etc/hosts文件。通常重新读取可以解决这个问题。
重要:自定义网络与默认的bridge原理一样,但自定义网络具备内部DNS发现,可以通过容器名或者主机名容器之间网络通信。后面介绍的lnmp就用到了该模式
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
[root@docker01 ~]# docker network ls #常用的网络模式查看 NETWORK ID NAME DRIVER SCOPE dcfaf483d096 bridge bridge local 884bc10989a5 host host local 30612ce6f04d none null local [root@docker01 ~]# docker network create test_net #创建一个自定义的网络 36766c64e4930212b3e1eeff0df8417f930b28140619720b5d87c9e393695d25 [root@docker01 ~]# docker network ls NETWORK ID NAME DRIVER SCOPE dcfaf483d096 bridge bridge local 884bc10989a5 host host local 30612ce6f04d none null local 36766c64e493 test_net bridge local [root@docker01 ~]# docker run -it --name bs3 --net=test_net busybox / # 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 15: eth0@if16: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0 valid_lft forever preferred_lft forever / #