CONTENTS
1、数据卷volume
1.1 相关概念
(1)数据卷相关概念梳理
我们要知道docker镜像由多个只读层叠加而成,如果要修改运行的容器中的文件,那么就会将该文件从只读层复制到读写层,只读版本独立存在。这就是所谓的“写时复制”机制。
docker中文件存在于联合文件系统(UFS)中,不易于宿主机访问;荣期间数据共享不便;删除容器后数据会丢失。为了解决这些问题,“卷(volume)”就产生了。volume的初衷就是数据持久化。
“卷”是容器上一个或多个目录,此目录可绕过联合文件系统,与宿主机上某目录绑定。volume可以在运行容器时即完成创建与绑定操作。
(2)挂载卷的方式有“Bind mount volume”和“docker-managed volume”。它们与宿主机目录对应的关系如下图:
1.2 docker-managed volume
(1)这个是docker默认的管理卷,存放在/var/lib/docker/volumes目录下,数据卷的名称都是随机生成的。
(2)先清空容器并删除卷目录下的内容,然后我们简单运行WordPress和tomcat两个容器。
docker rm -f -v $( docker ps -a -q )
rm -rf *
docker images
docker run --name word -d wordpress:latest
docker run --name tomcat1 -d tomcat:v1
这时候我们查看在/var/lib/docker/volumes下只出现一个文件夹,而且是Wordpress的。原因就是只有Wordpress在dockerfile中声明了容器管理卷,所以我们运行WordPress的时候就会出现相关的卷。
如果在宿主机的目录下创建对应的文件,相应的容器中也会出现文件:
1.3 Bind mount volume
这可以指定宿主机的目录进行挂载。这个很常用,一是可以保存数据,二是可以共享数据。
(1)保存数据
下面我简单创建一个dockerfile,执行创建一个镜像。运行容器是指定目录挂载。观察在宿主机和容器目录上对应的数据。
vim dockerfile
FROM centos:latest
RUN touch /tmp/1.txt
RUN mkdir /data
VOLUME /data
CMD tail -f /tmp/1.txt
docker build -t test:v1 .
docker run --name test1 -v /data:/data -d test:v1
docker rm -f $( docker ps -a -q )
docker run --name test1 -v /data:/data -d test:v1
docker ps -a
cd /data/
touch {1..10}.txt
docker exec -it test1 /bin/bash
到容器下查看/data目录下观察:
(2)数据共享
这个其实很容易实现,只需要将容器的卷都绑定在宿主机同一个目录下即可实现共享。例如:我在运行一个容器test2,和test1一样执行宿主机的/data目录,以test2身份创建test2目录,然后test1登录,查看:
1.4 存储驱动
Docker存储驱动( storage driver )是Docker的核心组件,它是Docker实现分成镜像的基础
- device mapper ( DM ):性能和稳定性存在问题,不推荐生产环境使用
- btrfs: 社区实现了btrfs driver, 稳定性和性能存在问题
- overlayfs: 内核3. 18 overlayfs 进入主线,性能和稳定性优异,第一选择
我们主要考虑overlayfs,毕竟前面两个都不太推荐在生产环境中使用。下面观察下overlayfs的结构,由下而上:lower-->upper-->merged。merged上可以查看到lower和upper目录中的内容,在merged上修改下面两级目录下的内容并不会导致下面目录内容的变化,典型的写时复制机制。
如果内核不是overlayfs,可以修改:
2、资源限制
相关概念
- CGroup 是Control Groups 的缩写,是Linux内核提供的一种可以限制、记录、隔离进程组(process groups) 所使用的物力资源(如cpu memory i/o等等)的机制。2007 年进入Linux 2. 6. 24内核,CGroups 不是全新创造的,它将进程管理从cpuset 中剥离出来,作者是Google 的Paul Menage
- 默认情况下,如果不对容器做任何限制,容器能够占用当前系统能给容器提供的所有资源
- Docker限制可以从Memory、 CPU、 Block I/0 三个方面
- OOME: Out Of Memory Exception
一旦发生OOME, 任何进程都有可能被杀死,包括docker daemon在内
为此,Docker 调整了docker daemon 的OOM优先级,以免被内核关闭
2.1 内存限制
(1)内存限制的必要性
- 为应用做内存压力测试,理解正常业务需求下使用的内存情况,然后才能进入生产环境使用
- 一定要限制容器的内存使用上限
- 尽量保证主机的资源充足,一旦通过监控发现资源不足,就进行扩容或者对容器进行迁移
- 如果可以(内存资源充足的情况),尽量不要使用swap, swap 的使用会导致内存计算复杂,对调度器非常不友好。
(2)在docker启动参数中,和内存限制有关的包括(参数的值一般是内存大小,也就是一个正数,后面跟着内存单位b、k、m、g,分别对应bytes、KB、 MB、和GB) :
- -m --memory:容器能使用的最大内存大小,最小值为4m
- --memory-swap:容器能够使用的swap 大小
- --memory-swappiness:默认情况下,主机可以把容器使用的匿名页(anonymous page) swap 出来,可以设置一个0-100 之间的值,代表允许swap出来的比例
- --memory-reservation:设置一个内存使用的soft limit, 设置值小于 -m 设置
- --kernel-memory: 容器能够使用的kernel memory 大小,最小值为4m
- --oom-kill-disable:是否运行OOM的时候杀死容器。只有设置了-m, 才可以把这个选项设置为false,否则容器会耗尽主机内存,而且导致主机应用被杀死
关于--memory-swap和--memory参数说明:
2.2 CPU资源限制
Docker提供的CPU资源限制选项可以在多核系统上限制容器能利用哪些vCPU。而对容器最多能使用的CPU时间有两种限制方式:
- 一是有多个CPU密集型的容器竞争CPU时,设置各个容器能使用的CPU时间相对比例
- 二是以绝对的方式设置容器在每个调度周期内最多能使用的CPU时间
- --cpuset-cpus=" " 允许使用的CPU集,值可以为0-3, 0, 1
- -c,--cpu-shares=0 CPU共享权值(相对权重),默认值1024
- --cpuset-mems=" " 允许在上执行的内存节点(MEMs)
- --cpu-period=0 即可设置调度周期,CFS周期的有效范围是1ms ~ 1s,对应 --cpu-period的数值范围是1000~1000000
- --cpu-quota=0 设置在每个周期内容器能使用的CPU时间,容器的CPU配额必须不小于1ms, 即--cpu-quota的值必须 >= 1000,单位微秒
- --cpus 能够限制容器可以使用的主机CPU个数,并且还可以指定如1.5之类的小数
Example:
docker run -it -- cpu-period=50000 --cpu-quota=25000 ubuntu:16.04 /bin/bash
docker run -it --cpu-period=10000 --cpu-quota=20000 ubuntu:16.04 /bin/bash
2.3 测验
我们做个简单的压力测试,助于我们了解内存和CPU限制后面的选项作用。
docker run --name stress -it --rm -m 256m lorel/docker-stress-ng:latest stress -vm 2
docker run --name stress -it --rm --cpus 2 lorel/docker-stress-ng:latest stress --cpu 8
docker run --name stress -it --rm --cpuset-cpus 0 lorel/docker-stress-ng:latest stress --cpu 8
另外开一个shell,观察容器的资源占用状态:docker stats stress
完成今日份打卡!