Docker 网络实现原理
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥 docker0),Docker启动一个容器时会据Docker网桥的段分配给容器一个?地址,称为cotainer-ip,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之问就能够通过容器的 container-TP 直接通信
Dogker网桥是宿主机虚拟出来的,并不是直实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法直接通过 Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run创建容器时候通过-p 或 -P 参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器
指定映射端口
docker run -id -P(大写) 容器id/名 #随机映射端口(从32768开始)
docker run -id -p(小写)端口:80 容器id/名 #指定映射端口
#指定的端口没有被服务占用,否则不生效
容器启动失败了怎么办
docker logs 容器id/名
docker inspect 容器/镜像id
#可以查看容器或者镜像的详细信息
获取容器的进程号
docker inspect -f '{{.State.Pid}}' 容器id/容器名
docker网络模式
docker网络的分类
- host:容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口
- container:创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围
- none:该模式拥有独自的网络命名空间,没有任何网络设置
- bridge:默认认为该模式,此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及iptables nat表配置与宿主机通信
- 自定义网络
网络模式详解
host模式
-
相当于vmware中的桥接模式,与宿主机在同一网络中,但没有独立ip地址。
-
docker使用了linux的namespaces技术来进行资源,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Natwork Namespace隔离网络等。
-
一个Net Namespace提供了一份独立的网络环境,包括网卡、路由、iptable规则等都与其他的network namespace隔离一个docker容器一般会分配一个独立的network namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的network namespace,而是和宿主机共用一个network namespace。容器将不会虚拟出自己的网卡、配置自己的ip等,而是使用宿主机的ip和端口。
container模式
这个模式指定新创新的容器和已经存在的一个容器共享一个network nameapace,而不是和宿主机共享,新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过io网卡设备通信
none模式
使用none模式,Docker容器拥有自己的network namespace,但是并不为Docker容器进行任何网络设置。也就是说,这个Docker容器没有网卡、IP、路由等信息。这种网络模式下容器只有io回环网络,没有其他网卡。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性
bridge模式
bridge模式是docker的默认网络模式,不用--net参数,就是bridge模式
相当于vmware中的nat模式,容器使用独立network namespaces,并连接到docker0虚拟网卡。通过docker0网桥以及iptables nat表配置与宿主机通信,此模式会成为每一个容器分配network namespace、设置ip等,并将一个主机上的Docker容器连接到一个虚拟网桥上。
- 当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机启动的docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连接在了一个二层网络中
- 从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址给容器使用,并设置docker的IP地址为容器的默认网关.在主机上创建一对虚拟网卡veth pair设备。veth设备总是成对出现的。它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth设备常用来来连接两个网络设备。
- docker将veth pair设备的一端放在新创建的容器中,并命令为veth0(容器的网卡),另一端放在主机中,以veth*这样类似的名字,并将这个网络设备加入到docker0网桥中,可以通过brcl1 show命令查看。
- 使用docker run -p时,docker实际上是在iptables做了DNAT规则,实际端口转发功能。可以使用iptables -t nat -vnl查看。
查看已有容器的网络模式
docker network ls或 docker network list
自定义网络
使用docker run创建docker容器时,可以用--nat或--network选项指定容器的网络模式
- host模式:使用--net=host指定
- none模式:使用--net=none指定
- container模式:使用--net=container:name or ID指定
- bridge模式:使用--net=bridge指定,默认设置,可省略
未创建自定义网络时,创建指定IP容器的测试
注意:创建指定IP的容器也需要基于docker网卡的IP网段
创建自定义docker网络
docker network create --subnet=172.66.0.0/16 --opt "com.docker.network.bridge.name"="docker1" mynetwork
再次创建指定IP的容器
Docker容器网络生产经验,docker的网络建议和宿主机的IP"对照”:
比如宿主机地址10.2.5.6,容器的地址就可以修改为172.5.6.x,这样方便在故障发生时,更容易定位故障节点位置。
删除自定义网络
如果想要删除自定义的网络,可以使用 docker network rm网络模式名称 进行删除,例如docker network rm mynetwork
删除网络模式前,需要先确保使用该网络模式创建的容器已退出(即已停止)。如果容器仍在运行,则该网络无法删除。
Docker容器网络生产经验
daemon.json 配置介绍
{
"graph": "/data/docker",
"storage-driver": "overlay2",
"insecure-registries": ["registry.access.redhat.com", "quay.io"],
"registry-mirrors": ["https://3u6mkfxb.mirror.aliyuncs.com"],
"bip": "172.24.38.1/24", #指定网桥的网段,这里不能写0,必须写1
"exec-opts": ["native. cgroupdriver= systemd"],
"live-restore": true
}
#配置项注意点:
● graph:该关键字未来将被弃用,可以采用"data-root" 替代。
● storage-driver:存储驱动,即分层文件系统。
● insecure-registries:不安全的docker registries, 即使用http协议推拉镜象。
● registry-mirrors:加速站点,一般可以使用阿里、网易云、docker中国 (https: //registry.docker-cn.com)的地址。
● bip:指定doccer bridge地址(不能以.0结尾),生产中建议采用172.xx.yy.1/24,其中xx. yy为宿主机ip后四位,方便定位问题。
● 若启动失败,查看/var/log/message 日志排错。
● live-restore:启用实时还原。
默认情况下,当Docker守护程序终止时,它将关闭正在运行的容器。从Docker Engine 1.12开始,您可以配置守护程序,以便在守护程序不可用时容器仍在运行。此功能称为实时还原。实时还原选项有助于减少由于守护程序崩溃,计划内的停机或升级而导致的容器停机时间。
#使用配置文件/etc/docker/daemon.json (没有时新建该文件)
vim /etc/docker/daemon.json
{
" insecure-registries": ["192.168.10.7:666"],
"registry-mirrors": ["https://3u6mkfxb.mirror.aliyuncs.com"],
"live-restore": true
}
Docker容器的资源控制
Docker通过Cgroup 来控制容器使用的资源配额,包括CPU、内存、磁盘三大方面,基本覆盖了常见的资源配额和使用量控制。Caroup 是ControlGroups的缩写,是Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(如 cpu、内存、磁盘,io等等)的机制,被LXC、docker等很多项目用于实现进程资源控制。Cgroup本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O或内存的分配控制等具体的资源管理是通过该功能来实现的。
- 资源限制:可以对任务使用的资源总额进行限制。
- 优先级分配:通过分配的cpu时间片数量以及磁盘IO带宽大小,实际上相当于控制了任务运行优先级。
- 资源统计:可以统计系统的资源使用量,如cpu时长,内存用量等。
- 任务控制: cgroup可以对任务 执行挂起、恢复等操作。
docker占用宿主机cpu的限制
cpu的使用率上限
Linux通过CFS (Completely Fair Scheduler,完全公平调度器)来调度各个进程对ceu的使用。CFS默认的调度周期是100ms 。我们可以设置每个容器进程的调度周期,以及在这个周期内各个容器最多能使用多少CPU时间。
使用--cpu-period 即可设置调度周期,使用--cpu-quota即可设置在每个周期内容器能使用的CPU时间。两者可以配合使用。CFS周期的有效范围是 1ms
1s,对应的--cpu-period 的数值范围是10001000000。而容器的CPU配额必须不小于1ms,即--cpu-quota的值必须>= 1000。而容器的CPU配额必须不小于1ms,即--cpu-quota的值必须>= 1000。
正常启用的cpu,测试使用上限
#正常创建容器(此时容器遵循默认的占用cpu资源规则)
[root@localhost ~]#docker run -id --name c1 centos:7
[root@localhost ~]#docker ps -a
[root@localhost ~]#docker exec -it c1 bash
[root@d6da0a6b999a /]# vi cpu.sh
#!/bin/bash
i=0
while true
do
let i++
done
[root@d6da0a6b999a /]# chmod +x cpu.sh
[root@d6da0a6b999a /]# ./cpu.sh
修改默认的容器时间分片上限规则,再次创建启动测试
创建容器时指定容器的cpu资源占用量上限
docker run -id --name c2 --cpu-quota 30000 centos:7
[root@localhost docker]#docker exec -it c2 bash
[root@10cfa036ff07 /]# vim cpu.sh
#!/bin/bash
i=0
while true
do
let i++
done
[root@10cfa036ff07 /]# vi cpu.sh
[root@10cfa036ff07 /]# chmod +x cpu.sh
[root@10cfa036ff07 /]# ./cpu.sh
多cpu分配容器的使用上限
[root@localhost ~]#docker exec -it c3 bash
[root@a1ce6948cdb6 /]# vi cpu.bash
#!/bin/bash
i=0
while true
do
let i++
done
[root@a1ce6948cdb6 /]# chmod +x ./cpu.bash
[root@a1ce6948cdb6 /]# ./cpu.bash
设置cpu资源的占用比
注意:该方式需要设置多个容器时才会生效
创建容器时可以使用选项 --cpu-shares 数值(该数值要为1024的倍数,1024代表一份,当个容器占用cpu的份额由自身分配的份数除于所有容器占用cpu的份数,就为该容器所占用cpu资源的百分比)
进行分配
[root@localhost ~]#docker run -id --name b1 --cpu-shares 2048 centos:7
[root@localhost ~]#docker run -id --name b2 --cpu-shares 1024 centos:7
[root@localhost ~]#docker run -id --name b3 --cpu-shares 1024 centos:7
开启三个终端,启动容器压测
#三个容器均为以下压测操作
#下载压测工具依赖环境
yum install -y epel-release
#下载压测工具
yum install -y stress
#进行四个线程压测
stress -c 4
#再开启一个终端查看测试结果
docker stats
由测试结果, 可以看到在cPU进行时间片分配的时候,容器b1比容器b2和b3多一倍的机会获得cpu的时间片。但分配的结果取决于当时主机和其他容器的运行状态,实际上也无法保证容器 b2和b3一定能获得cpu时间片
比如容器b2和b3的进程一直是空闲的,那么容器b1是可以获取比容器b2和b3更多的cpu时间片的。极端情况下,例如主机上只运行了一个容器,即使它的cpu份额只有50,它也可以独占整个主机的cpu资源。
Cgroups 只在容器分配的资源紧缺时,即在需要对容器使用的资源进行限制时,才会生效。因此,无法单纯根据某个容器的cpu 份额来确定有多少cpu资源分配给它,资源分配结果取决于同时运行的其他容器的CPU分配和容器中进程运行情况。
设置容器绑定指定的cpu
查看主机中的cpu编号
top
按数字“1”
进行绑核创建容器
docker run -id --name b4 --cpuset-cpus 2 centos:7
压力测试
yum install -y epel-release
yum insatll -y stress
stress -c 1
测试结果
内存使用的限制
限制容器可以使用的最大内存
m (或--memory=)选项用于限制容器可以使用的最大内存
docker run -itd --name d1 -m 512m centos:7 /bin/bash
docker stats
限制容器可用的swap 大小
#限制可用的swap 大小,--memory-swap
●强调一下, --memory-swap是必须要与 --memory(或-m)一起使用的。
●正常情况下, --memory-swap 的值包含容器可用内存和可用swap 。
●所以 -m 300m --memory-swap=1g 的含义为:容器可以使用300M 的物理内存,并且可以使用700M (1G - 300M)的swap。 设置为0或者不设置,则容器可以使用的 swap 大小为 -m 值的两倍。
如果 --memory-swap 的值和 -m 值相同,则容器不能使用swap。
如果 --memory-swap 值为 -1,它表示容器程序使用的内存受限,而可以使用的swap空间使用不受限制(宿主机有多少swap 容器就可以使用多少)。
#--memory-swap 的值包含容器可用内存和可用swap,减去-m的值才是可用swap的值。
#表示容器可以使用512M的物理内存,并且可以使用512M的swap。因为1g减去512m的物理内存,剩余值才是可用swap。
docker run -itd --name d2 -m 512m --memory-swap=1g centos:7 bash
#--memoryswap值和 -m 的值相同,表示容器无法使用swap
docker run -itd --name d3 -m 512m --memory-swap=512m centos:7 bash
# --memory-swap 的值设置为0或者不设置,则容器可以使用的 swap 大小为 -m 值的两倍。
docker run -itd --name d4 -m 512m centos:7 bash
# --memory-swap 值为 -1,它表示容器程序使用的内存受限,但可以使用的swap空间使用不受限制(宿主机有多少swap 容器就可以使用多少)。
docker run -itd --name d5 -m 512m --memory-swap=-1 centos:7 bash
对磁盘IO的配置控制(blkio)的限制
-
-device-read-bps:限制某个设备上的读速度bps ( 数据量),单位可以是kb、mb (M)或者gb。
-
--device-write-bps : 限制某个设备上的写速度bps ( 数据量),单位可以是kb、mb (M)或者gb。
该速度是指每秒钟进行读写操作1M,1G或者是1kb
-
--device-read-iops :限制读某个设备的iops (次数)
-
--device-write-iops :限制写入某个设备的iops ( 次数)
默认情况下容器的写速度
[root@localhost ~]#docker run -id --name e1 centos:7
[root@localhost ~]#docker exec -it e1 bash
[root@8657384cb483 /]# dd if=/dev/zero of=/opt/test.txt bs=10M count=5 oflag=direct
# oflag=direct 规避文件读写系统中所带来的缓存,避免影响测试结果
进行写速度限制的容器创建
[root@localhost ~]#docker run -it --name e3 --device-write-bps /dev/sda:1M centos:7 /bin/bash
[root@6c1b8bcf6b44 /]# dd if=/dev/zero of=/opt/test.out bs=10M count=5 oflag=direct
清除docker占用的磁盘空间
docker system prune -a 可用于清理磁盘,删除关闭的容器、无用的数据卷和网络。
docker system prune -a