目录
一、docker网络模式:
1、概述
docker的网络就是基于桥接模式实现的
桥接模式:用于连接两个不同网络段的设备,共享通信的一种方式
桥接设备:工作在OSI模型的二层,数据链路层,转发数据帧,基于Mac地址转发
类似于交换机,只能转发同一网段,通过泛洪广播来找目标设备mac地址。学习模式
2、docker网络实现原理:
桥接模式是一种网络模式,它在Docker中的工作方式可以分为以下几个步骤:
1、虚拟网络创建: 当您启动Docker守护进程时,Docker创建一个虚拟网络桥(通常称为Docker0)是一个虚拟的网络设备,类似于物理网络设备的交换机
2、分配唯一的ip地址 :每次您运行一个容器时,Docker分配一个唯一的IP地址给该容器
这个IP地址是在桥接模式网络的子网中
3、连接容器到桥接网络: 当容器启动时,Docker将容器的虚拟网络接口连接到虚拟网络桥上。其中一个端点位于容器,而另一个端点位于主机上
4、容器之间的通信: 如果有多个容器在相同的桥接网络上运行,他们可以通过各自的ip地址直接通信。Docker会自动在桥接网络上设置路由,使得容器可以与外部网络通信,而外部网络看到的是主机的IP地址
5、NAT(网络地址转换): 默认情况下,Docker使用NAT技术,将容器的私有IP地址映射到主机上的公共IP地址。这样,容器可以与外部通信,而外部网络看到的是主机的IP地址
问题:docker的网桥是宿主机虚拟出来的,并不是一个真正存在的网络设备,外部网络无法寻址找到。外部网络无法直接访问docker:0这个虚拟网桥分配给容器的IP地址
Docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,也就是无法直接访问容器ip访问容器
如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主机(端口映射)
即Docker run创建容器时用-p/-P启用,访问到的时候就通过宿主ip+容器端口来访问容器
给容器做端口映射:
-P:创建容器的时候,在宿主机和容器之间做一个端口映射。后不接数字代表随机分配一个端口给宿主机,容器的端口是不变的
-P32768开始
-P(大写):随机制定
-p 80:80(小写):指定端口
进入容器开启一下服务
实际上,docker是在宿主机和容器之间做了一个iptables的nat地址转换。
docker run -itd --name test1 -P nginx:1.22.0 /bin/bash
-p 80:80
前面80是宿主机的端口,后面是容器的端口80
docker run -itd --name test3 -p 80:80 nginx:1.22.0 /bin/bash
做端口映射时,宿主机的端口一定是未被占用
宿主机直接查看容器产生的日志:
docker run -itd --name test11 -p 456:80 nginx
必须是在run的时候不加/bin/bash
docker logs 容器名/容器id 查看全部日志
docker logs -f 容器名/容器id 尾部查看全部,动态查看
docker logs --tail=10 -f 容器名/容器id 尾部10条,动态查看
/bin/bash就是为了让容器后台有一个运行程序,保证容器不会退出
-d后台守护运行,但是时间一长容器自动退出
加/bin/bash就是容器的标准输出,docker logs日志捕获的是cmd和entrypoint标准输出。/bin/bash和捕获日志会冲突
3、docker的网络模式:
3.1、bridge模式:
在创建docker时不需要指定网络类型,默认就是bridge
docker run -itd --name test1 -p 4300:80 nginx:1.22.0
4300是宿主机的端口
80是nginx容器的端口
访问宿主机的ip+端口就等于访问nginx容器
使用 docker run -p 时,docker实际是在iptables做了DNAT规则,实现端口转发功能。
可以使用iptables -t nat -vnL 查看。
3.2、host模式:
容器将不会虚拟出自己的网卡,也没有自己的IP地址。全部使用宿主机的IP地址和端口
host:容器和宿主机共用一个网络命名空间
创建容器的时候指定网络模式:--network host
docker run -itd --name test1 --network host nginx:latest bin/bash
公用模式:如果是单个容器运行,可以使用host模式。容器的端口和宿主机端口公用一个,但是有多个容器,访问不了
3.3、container模式:
container:容器和容器之间共用一个网路命名空间
要想容器都起来必须后接/bin/bash
docker run -itd --name test1 --network host nginx:1.22.0 /bin/bash
创建一个test2和test1使用同一个ip和端口
docker run -itd --name test2 --network=container:test1 nginx:1.22.0 /bin/bash
容器中怎么启动服务:
cd /usr/bin
nginx 启动
nginx -s stop 停止
容器共用端口,但是不能同时启动。想要启动一个,其他容器必须关闭。
也就是说共用端口,只能使用一个
启动test1的nginx:
停止test1的nginx
nginx -s stop
3.4、none模式:
docker容器有自己的network-space,但是这个容器没有任何网络设置。
这个容器没有网卡,没有ip没有路由,只有lo回环网络。在none模式下,容器不可以联网(在工作中是用于容器功能测试用)
不能联网不能访问
封闭的网络能很好的保证容器的安全性。
docker run -itd --name test3 --network none nginx:1.22.0 /bin/bash
3.5、自定义网络模式:
我们可以给docker创建一个自己定义的网段
docker network ls
NETWORK ID:这个是docker网络唯一网络id
NAME:docker网络的名称
DRIVER:网络的驱动程序
SCOPE:
docker run -itd --name test6 --network bridge --ip 172.17.0.10 nginx:latest /bin/bash
在使用默认docker:0网桥时,创建容器是不能指定IP地址的,只能由docker网桥自动分配
除非用户自定义的网络才可以给容器自定义IP地址
创建自定义网络:
可以先自定义网络,再使用指定IP运行docker
docker network create --subnet=172.18.0.0/16 --opt "com.docker.network.bridge.name"="docker1" mynetwork
--opt "com.docker.network.bridge.name"="docker1":这里可以不加,但是网卡名称难以识别,系统会给你命名复杂名称
mynetwork:自定义网络的名称
有自定义网段之后,创建容器的时候就可以自定义IP地址了
docker run -itd --name nginx1 --network mynetwork --ip 172.18.0.10 nginx:latest /bin/bash
给容器自定义IP地址为 172.18.0.10
自定义IP地址,一定要先自定义网桥
4、docker网络总结:
docker的网络模式:
- bridge桥接模式:也是docker的默认模式,在创建时无需指定
- host模式:容器不会有自己的网络设备,但是可以和宿主机共享ip和端口
- container模式:容器和容器之间共享ip和端口
- none模式:也没有自己的网络设备,也没有网卡、ip。只有一个本地的回环地址。127.0.0.1。不能够联网的。相当于一个飞行模式,只能自己访问自己。一般用于测试容器的功能
- 自定义网络模式:创建容器时,默认使用docker0网桥是无法给容器定义IP地址的,自能自动分配,自定义网络在创建容器时,可以给容器指定IP地址
docker如何在创建容器时指定端口映射:
docker没有二次配置的机制,只能在创建的时候指定
-P(大写):随机指定端口
-p(小写):自定义指定端口
-p 32768:80 32768是宿主机的端口,后面80是容器的端口
docker容器外部查看日志
docker run -itd --name test11 -p 456:80 nginx
必须是在run的时候不加/bin/bash
docker logs 容器名/容器id 查看全部日志
docker logs -f 容器名/容器id 尾部查看全部,动态查看
docker logs --tail=10 -f 容器名/容器id 尾部10条,动态查看
/bin/bash就是为了让容器后台有一个运行程序,保证容器不会退出
-d后台守护运行,但是时间一长容器自动退出
加/bin/bash就是容器的标准输出,docker logs日志捕获的是cmd和entrypoint标准输出。/bin/bash和捕获日志会冲突
二、docker的数据管理:
1、数据卷
1.1、容器和宿主机之间进行数据共享:
数据卷:是一个供容器使用的特殊的目录,在容器中,和宿主机的目录进行映射,主机和宿主机之间都可以对目录中的文件进行修改,而且双方是同步生效。对镜像也没有影响。宿主机和容器之间实现数据迁移
MySQL 33066:3306
宿主机的目录和容器中的目录进行挂载(映射关系)
docker run -itd --name test1 -v /opt/test1:/opt/test centos:7 /bin/bash
test1是宿主机目录
test是容器目录
docker run -itd --name test2 -v /opt/test2:/opt/test:ro centos:7 /bin/bash
创建只读模式,容器里面只能读
容器里面的目录的文件只能看
1.2、容器和容器之间实现数据共享:
test1 test2 可以有一个或者多个映射目录,实现数据互传,数据同步
数据卷容器:只提供挂载点,让另一方来收集数据
docker run -itd --name test11 -v /opt/data1 -v /opt/data2 centos:7 /bin/bash
docker run -itd --volumes-from test11 --name test12 centos:7 /bin/bash
test11和test12 实现容器间数据共享
三、docker网络通信
1、容器互联:
实现两个容器之间网络通信
老版本方法:
第一个容器创建:
docker run -itd -P --name test111 centos:7 /bin/bash
第二个容器
docker run -itd -P --name test222 --link test111:test222 centos:7 /bin/bash
在centos容器中下载net-tools工具可以用Linux命令
yum -y install net-tools
要互ping要做映射
新版本都用network指定:
自定义网络实现网段互ping
docker run -itd -P --name test112 --network=mynetwork centos:7 /bin/bash
docker run -itd -P --name test113 --network=mynetwork centos:7 /bin/bash
同一网段中不用做映射就可以实现互ping
新版本建议使用
四、docker网络练习:
1、部署一个MySQL镜像,创建一个MySQL容器,用navicat实现可以直接访问容器的MySQL,MySQL宿主机:33066
MySQL容器:3306
2、创建一个数据卷。在宿主机可以看到容器内MySQL的日志文件
创建运行mysql容器,并建立数据卷:
docker run -itd --name mysql1 -v /opt/demo1:/opt/test -p 33066:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.20
本机MySQL远程登录测试:
navicat:
my.cnf配置文件拖出来修改
docker cp mysql1:/etc/mysql/my.cnf /opt
重启docker容器
docker restart mysql1
五、docker的资源控制:
对容器使用宿主机的资源进行限制
docker使用Linux自导的cgroup进行控制
Control groups,是Linux内核系统提供的一种可以限制,记录,隔离进程组所使用的物理资源的机制。
docker借助这个机制,来实现资源的控制
cgroup本身是提供将进程进行分组化管理的功能和接口的基础结构。分配控制的机制来实现资源控制。
其他的资源依然是隔离的
1、CPU资源控制:
Linux通过CFS(completely fair scheduler 完全公平调度器),通过这个调度器来调度各个进程对CPU的使用。CFS的调度周期为100ms。
我们也可以自定义容器的调度周期。以及在这个周期时间之内,各个容器能够使用CPU的调度时间。
--CPU-period 设置容器调度CPU的周期
--CPU-quota 设置每个周期内,容器可以使用CPU的时间
两者可以配合使用
cd /sys/fs/cgroup/cpu/docker/09103baf76369ad9f6a77576665c49b384b34d01ed1f09f1c6b091abfae27115
cpu.cfs_period_us: 表示 CFS 调度周期的长度,以微秒为单位。
在每个周期内,容器可以使用指定比例的 CPU 时间。默认情况下,cpu.cfs_period_us 的值是 100000(即 100 毫秒)。
cpu.cfs_quota_us: 表示容器在 cpu.cfs_period_us 周期内能够使用的 CPU 时间量,同样以微秒为单位。
它定义了一个相对于周期的配额。如果设置为 -1,表示没有限制。如果设置为正值,表示在周期内的配额。
例如,如果 cpu.cfs_quota_us 设置为 50000,那么容器在一个周期内最多可以使用 50 毫秒的 CPU 时间。
在 Linux 的 CFS 调度器中,cpu.cfs_period_us 参数定义了一个周期,
而这个周期实际上是用来调度任务(包括容器)的基本时间单位。
然而,具体的一次调度的时间是由调度器决定的,并且这个时间在一般情况下是动态变化的。
CFS的周期的有效范围:1ms-1s之间。则--cpu-period 1000-1000000
容器使用CPU的配额时间,必须大于1ms,--cpu-quota的值,必须是>=1000
cpu.cfs_quota_us:调度请求之后,根据配额,内核分配给容器使用CPU的时间
-1
如果配置是-1,那么容器在使用宿主机cpu的时间不做任何限制
cpu.rt_period_us
100000
CFS调度周期的长度,微秒,在每个周期内,容器可以使用指定比例的cpu时间,默认情况下都是100毫秒
CFS调度器,100毫秒就是定义了一个周期,在这个周期之内,调度任务(容器)的基本时间单位。
100毫秒一次调度容器请求cpu的资源。然后内核把cpu的资源分配给容器
查看容器的运行占用宿主机资源的情况
docker stats 容器名/id
查看容器内PID和宿主机的映射关系
docker top 容器名/id
1.1、对容器占用CPU的时间进行限制:
进行CPU压力测试
docker run -itd --name test1 centos:7 /bin/bash
docker exec -it test1 bash
vim /opt/cpu.sh
#!/bin/bash
i=0
while true
do
let i++
done
chmod +x /cpu.sh
./cpu.sh
top #可以看到这个脚本占了很多的cpu资源
设置50%的比例分配CPU使用时间上限
1、可以重新创建一个容器并设置限额
docker run -itd --name test6 --cpu-quota 50000 centos:7 /bin/bash
2、更改cpu.cfs_quota_us配置文件修改CPU使用时间
cd /sys/fs/cgroup/cpu/docker/3ed82355f81151c4568aaa6e7bc60ba6984201c119125360924bf7dfd6eaa42b/
echo 50000 > cpu.cfs_quota_us
默认是100000微秒,100毫秒对应的就是使用时间100%
改成50000微秒,就是50%
docker exec -it 3ed82355f811 /bin/bash
./cpu.sh
top #可以看到cpu占用率接近50%,cgroups对cpu的控制起了效果
在多核情况下,如果允许容器进程完全占用两个 CPU,
则可以将 cpu-period 设置为 100000( 即 0.1 秒), cpu-quota设置为 200000(0.2 秒)。
docker top test 查看容器内PID和宿主机的映射关系。
UID 是用户名。
PID 是进程在宿主系统上的 PID。
PPID 是进程在容器内部的 PID。
STIME 是进程的启动时间。
TTY 是终端类型和编号。
TIME 是进程的运行时间。
CMD 是进程的命令
1.2、设置CPU资源占用比( 设置多个容器时才有效 )
Docker 通过 --cpu-shares 指定 CPU 份额,默认值为1024,值为1024的倍数。
创建两个容器为 c1 和 c2,若只有这两个容器,设置容器的权重,使得c1和c2的CPU资源占比为1/3和2/3。
--cpu-shares 指定容器占用CPU的份额。默认权重1024,设置的值只能是1024的倍数。
docker run -itd --name c1 --cpu-shares 512 centos:7
docker run -itd --name c2 --cpu-shares 1024 centos:7
--cpu-shares是给每个容器使用cpu设置了相对的权重,权重高的,可以使用CPU的资源更多,但是,如果只有一个容器在运行,即便设置了权重,但是没有其他更高的权重来占用资源,权重低的容器依然不受限
分别进入容器,进行压力测试
yum install -y epel-release
yum install -y stress
#stress 是一个用于模拟系统负载的工具,它可以测试系统在高负载条件下的稳定性。
stress -c 4 #产生四个进程,每个进程都反复不停的计算随机数的平方根
#查看容器运行状态(动态更新)
docker stats
可以看到在 CPU 进行时间片分配的时候,容器 c2 比容器 c1 多一倍的机会获得 CPU 的时间片。
但分配的结果取决于当时主机和其他容器的运行状态, 实际上也无法保证容器 c1 一定能获得 CPU 时间片。
比如容器 c1 的进程一直是空闲的,那么容器 c2 是可以获取比容器 c1 更多的 CPU 时间片的。
极端情况下,例如主机上只运行了一个容器,即使它的 CPU 份额只有 50,它也可以独占整个主机的 CPU 资源。
Cgroups 只在容器分配的资源紧缺时,即在需要对容器使用的资源进行限制时,才会生效。
因此,无法单纯根据某个容器的 CPU 份额来确定有多少 CPU 资源分配给它,
资源分配结果取决于同时运行的其他容器的 CPU 分配和容器中进程运行情况。
1.3、设置容器绑定指定的CPU
#先分配虚拟机4个CPU核数
docker run -itd --name test7 --cpuset-cpus 1,3 centos:7 /bin/bash
#进入容器,进行压力测试
yum install -y epel-release
yum install stress -y
stress -c 4
#退出容器,执行 top 命令再按 1 查看CPU使用情况。
总结:对CPU的限制:
容器占用CPU的时间
容器占用CPU的权重比(要多个容器,才有效)
容器占用CPU的内核数(绑定指定的CPU内核给容器使用)
2、限制容器对内存的使用:
-m(--memory=) 选项用于限制容器可以使用的最大内存
docker run -itd --name test8 -m 512m centos:7 /bin/bash
docker stats
如果 --memory-swap 设置为 0 或者 不设置,则容器可以使用的 swap 大小为 -m 值的两倍。
如果 --memory-swap 的值和 -m 值相同,则容器不能使用 swap。
如果 --memory-swap 值为 -1,它表示容器程序使用的内存受限,
而可以使用的 swap 空间使用不受限制(宿主机有多少 swap 容器就可以使用多少)。
3、限制使用swap:
--memory-swap
docker run -itd --name test -m 512m --memory-swap=1g centos:7 /bin/bash
限制使用swap,必须和限制内存一起使用
--memory-swap 是必须要与 --memory 一起使用的。
设置swap有如下集中情况:
1、-m 512m --memory-swap=1g 那么容器实际上能够使用的swap空间是1g-512m=512m
2、如果不设置--memory-swap=1g,只有-m 512m,那么使用swap的空间是-m后面值的两倍也就是1024m
3、如果设置的--memory-swap的值和-m内存限制一样,容器不能使用swap空间 512-512=0
4、如果-m 512m --memory-swap=-1 设为-1则内存受限还是512m,但是容器使用swap空间不受限制
4、磁盘IO配额(了解):
限制容器在磁盘上的读速度:
--device-read-bps:
限制某个设备上的读速度bps(数据量),单位可以是kb、mb(M)或者gb。
例:docker run -itd --name test11 --device-read-bps /dev/sda:1M centos:7 /bin/bash
限制容器在磁盘上的写速度:
--device-write-bps :
限制某个设备上的写速度bps(数据量),单位可以是kb、mb(M)或者gb。
例:docker run -itd --name test12 --device-write-bps /dev/sda:1mb centos:7 /bin/bash
通过dd来验证写速度
dd if=/dev/zero of=test.out bs=1M count=10 oflag=direct
在使用dd获取空字符集是从文件系统的缓存当中输入,速度是比较快的,禁用文件系统缓存,直接把数据写入磁盘,可以更真实的测试设备的行,模拟直接写入物理设备的情况
限制容器读取的次数:
docker run -itd --name test --device-read-iops /dev/sda:100 centos:7 /bin/bash
限制读取操作每秒100次
限制容器写入的次数:
docker run -itd --name test --device-write-iops /dev/sda:50 centos:7 /bin/bash
限制写入的操作,每秒50次
5、清理docker占用的磁盘空间:
docker system prune -a
删除已经停止的容器
删除所有未被使用的网桥设备(docker1)
删除所有未被使用的镜像
删除创建容器时的缓存,以及无用的数据卷