目录
六、创建私有仓库
七、Docker资源限制
7.1、CPU使用率
7.2、CPU共享比例
7.3、CPU周期限制
7.4、CPU核心限制
7.5、CPU 配额控制参数的混合案例
7.6、内存限制
7.7、Block IO 的限制
7.8、限制bps 和iops
8、Docker数据持久化
8.1、数据持久化介绍
8.2、Volume的基本使用
8.2.1、管理卷
8.2.2、创建使用指定卷的容器
8.2.3、清理卷
8.3、Bind Mounts的基本使用
8.3.1 使用卷创建一个容器
8.3.2、验证绑定
8.3.3、清理
8.4、数据卷容器
8.4.1、数据卷容器概述
8.4.2、创建数据卷容器
六、创建私有仓库
仓库(Repository)是集中存放镜像的地方。
仓库注册服务器才是存放仓库具体的服务器(Registry),每个服务器上都可以放置多个仓库,而每个仓库下可以放置多个镜像,每个镜像上可以运行多个容器,每个容器上可以跑一个应用或应用组。
仓库自身可以分为:公共仓库和私有仓库
安装docker后,可以通过官方提供的registry镜像部署一套本地的私有仓库环境
[root@localhost ~]# mkdir -p /opt/data/registry
[root@localhost ~]# docker run -d --restart=always -p 5000:5000 -v /opt/data/registry:/tmp/registry registry
Unable to find image 'registry:latest' locally
latest: Pulling from library/registry
79e9f2f55bf5: Pull complete
0d96da54f60b: Pull complete
5b27040df4a2: Pull complete
e2ead8259a04: Pull complete
3790aef225b9: Pull complete
Digest: sha256:169211e20e2f2d5d115674681eb79d21a217b296b43374b8e39f97fcf866b375
Status: Downloaded newer image for registry:latest
f5b026b082957e416f2facf2fb8739ee5002d31e44ffa05c71eff08c588b0f1f
[root@localhost ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f5b026b08295 registry "/entrypoint.sh /etc…" 17 seconds ago Up 16 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp hardcore_cori
准备测试镜像
[root@localhost ~]# docker run -d -p 800:80 nginx #将宿主机800端口映射给容器的业务端口
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
a2abf6c4d29d: Pull complete
a9edb18cadd1: Pull complete
589b7251471a: Pull complete
186b1aaa4aa6: Pull complete
b4df32aa5a72: Pull complete
a0bcbecc962e: Pull complete
Digest: sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Status: Downloaded newer image for nginx:latest
bc0698d60239d036f737d18370a81eb84a0a7f69ec536a8b208118aace4fa79a
[root@localhost ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bc0698d60239 nginx "/docker-entrypoint.…" 7 seconds ago Up 6 seconds 0.0.0.0:800->80/tcp, :::800->80/tcp zealous_darwin
宿主机(192.168.2.118)访问8000端口测试:
[root@localhost ~]# docker logs bc0698d60239 #查看日志
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2023/08/02 03:56:56 [notice] 1#1: using the "epoll" event method
2023/08/02 03:56:56 [notice] 1#1: nginx/1.21.5
2023/08/02 03:56:56 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2023/08/02 03:56:56 [notice] 1#1: OS: Linux 3.10.0-1160.92.1.el7.x86_64
2023/08/02 03:56:56 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2023/08/02 03:56:56 [notice] 1#1: start worker processes
2023/08/02 03:56:56 [notice] 1#1: start worker process 32
2023/08/02 03:56:56 [notice] 1#1: start worker process 33
2023/08/02 03:56:56 [notice] 1#1: start worker process 34
2023/08/02 03:56:56 [notice] 1#1: start worker process 35
192.168.2.1 - - [02/Aug/2023:03:58:40 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.188" "-"
2023/08/02 03:58:40 [error] 34#34: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 192.168.2.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.2.118:800", referrer: "http://192.168.2.118:800/"
192.168.2.1 - - [02/Aug/2023:03:58:40 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://192.168.2.118:800/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.188" "-"
将修改过的nginx镜像做标记封装,准备上传到私有仓库
[root@localhost ~]# docker tag nginx 192.168.2.118:5000/nginx-test
[root@localhost ~]# docker push 192.168.2.118:5000/nginx-test
Using default tag: latest
The push refers to repository [192.168.2.118:5000/nginx-test]
Get "https://192.168.2.118:5000/v2/": http: server gave HTTP response to HTTPS client
[root@localhost ~]# cat /etc/docker/daemon.json
{
"registry-mirrors":[ "https://nyakyfun.mirror.aliyuncs.com" ],"insecure-registries":["192.168.2.118:5000"]
}
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl restart docker
将镜像上传到私有仓库
[root@localhost ~]# docker push 192.168.2.118:5000/nginx-test
Using default tag: latest
The push refers to repository [192.168.2.118:5000/nginx-test]
d874fd2bc83b: Pushed
32ce5f6a5106: Pushed
f1db227348d0: Pushed
b8d6e692a25e: Pushed
e379e8aedd4d: Pushed
2edcec3590a4: Pushed
latest: digest: sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3 size: 1570
从私有仓库中下载镜像到本地
[root@localhost ~]# docker rmi 192.168.2.118:5000/nginx-test
Untagged: 192.168.2.118:5000/nginx-test:latest
Untagged: 192.168.2.118:5000/nginx-test@sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 19 months ago 141MB
registry latest b8604a3fe854 20 months ago 26.2MB
[root@localhost ~]# docker pull 192.168.2.118:5000/nginx-test
Using default tag: latest
latest: Pulling from nginx-test
Digest: sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
Status: Downloaded newer image for 192.168.2.118:5000/nginx-test:latest
192.168.2.118:5000/nginx-test:latest
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 19 months ago 141MB
192.168.2.118:5000/nginx-test latest 605c77e624dd 19 months ago 141MB
registry latest b8604a3fe854 20 months ago 26.2MB
七、Docker资源限制
Docker容器技术底层是通过Cgroup(Control Group 控制组)实现容器对物理资源使用的限制,限制的资源包括CPU、内存、磁盘三个方面。基本覆盖了常见的资源配额和使用量控制。
Cgroup 是Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源的机制,被LXC及Docker等很多项目用于实现进程的资源控制。
Cgroup 是提供将进程进行分组化管理的功能和接口的基础结构,Docker中I/O 或内存的分配控制等具体的资源管理功能都是通过Cgroup功能来实现的。这些具体的资源管理功能称为Cgroup子系统,以下是对几大子系统的介绍。
- blkio:限制块设备的输入输出控制。如:磁盘、光盘、USB等。
- cpu:限制CPU资源的访问
- cpuacct:产生Cgroup 任务的CPU资源报告。
- cpuset:限制分配单独的cpu 和内存资源。
- devices:允许或拒绝对设备的访问。
- freezer:暂停和恢复Cgroup 任务。
- memory:设置每个Cgroup 的内存限制以及产生内存资源报告。
- net_cls:用于标记每个网络包。
- ns:命名空间子系统。
- perf_event:增加了对每group 的监测跟踪的能力,可以监测属于某个特定的group 的所有线程以及运行在特定CPU 上的线程。
centos-7-x86_64.tar提取链接:https://pan.baidu.com/s/155YCVkJr6rXKf7VP-ZXFwQ?pwd=e12x
提取码:e12x
使用下面的Dockerfile 来创建一个基于CentOS的stress工具镜像。
[root@localhost ~]# cat centos-7-x86_64.tar.gz | docker import - centos:7
sha256:bd0569f5d7da160cecb1437baf48b28d31a303777785053f4189ff1af97e7342
[root@localhost ~]# mkdir stress
[root@localhost ~]# cd stress
[root@localhost stress]# vim Dockerfile
FROM centos:7
MAINTAINER crushlinux "crushlinux@163.com"
RUN yum -y install wget
RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum -y install stress
[root@localhost stress]# docker build -t centos:stress .
[+] Building 48.6s (8/8) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 288B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/centos:7 0.0s
=> [1/4] FROM docker.io/library/centos:7 0.0s
=> [2/4] RUN yum -y install wget 31.9s
=> [3/4] RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo 1.8s
=> [4/4] RUN yum -y install stress 14.1s
=> exporting to image 0.7s
=> => exporting layers 0.6s
=> => writing image sha256:4907ba4a7a63ba68cab027bcc5191665bad0898ad7229435b528e364e154d399 0.0s
=> => naming to docker.io/library/centos:stress
7.1、CPU使用率
在CentOS7中可以通过修改对应的Cgroup配置文件cpu.cfs_quota_us的值来实现,直接执行echo命令将设定值导入到文件中就会立即生效。
例如将容器ddb8e55d1c09的CPU使用设置为20000,设置CPU的使用率限定为20%。
[root@localhost ~]# docker run -itd centos:stress /bin/bash
ddb8e55d1c094fe9734994ffe3a61fafebf2237eded6ebffa507f61d32921010
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ddb8e55d1c09 centos:stress "/bin/bash" 9 seconds ago Up 8 seconds dazzling_euclid
[root@localhost ~]# echo "20000" >
/sys/fs/cgroup/cpu,cpuacct/docker/ddb8e55d1c094fe9734994ffe3a61fafebf2237eded6ebffa507f61d32921010/cpu.cfs_quota_us
7.2、CPU共享比例
当多个容器任务运行时,很难计算CPU的使用率,为了使容器合理使用CPU资源,可以通过--cpu-shares选项设置容器按比例共享CPU资源,这种方式还可以实现CPU使用率的动态调整。
命令中的--cpu-shares 选项值不能保证可以获得1 个vcpu 或者多少GHz 的CPU 资源,仅仅只是一个弹性的加权值。
默认情况下,每个docker容器的cpu份额都是1024。单独一个容器的份额是没有意义的。只有在同时运行多个容器时,容器的CPU加权的效果才能体现出来。例如,两个容器A、B的CPU份额分别为1000和500,在CPU进行时间片分配的时候,容器A比容器B多一倍的机会获得CPU的时间片。但分配的结果取决于当时主机和其他容器的运行状态,实际上也无法保证容器A一定能获得CPU时间片。比如容器A的进程一直是空闲的,那么容器B 是可以获取比容器A更多的CPU时间片的。极端情况下,比如说主机上只运行了一个容器,即使它的CPU份额只有50,它也可以独占整个主机的CPU资源。
Cgroups 只在容器分配的资源紧缺时,也就是说在需要对容器使用的资源进行限制时才会生效。因此无法单纯根据某个容器的CPU份额来确定有多少CPU 资源分配给它,资源分配结果取决于同时运行的其他容器的CPU分配和容器中进程运行情况。
换句话说,可以通过cpu shares可以设置容器使用CPU的优先级,比如启动了两个容器及运行查看CPU使用百分比。
[root@localhost ~]# docker run -tid --name cpu512 --cpu-shares 512 centos:stress stress -c 10
b2d3e64065f09a683e352722d187c097e2b4bf161a4cc08444a304700a101e23
[root@localhost ~]# docker run -tid --name cpu1024 --cpu-shares 1024 centos:stress stress -c 10
5c59dc0f47d3f6bde8003d8b6f684e6fc8268ef792d282e1c335abbbcc3edfa8
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5c59dc0f47d3 centos:stress "stress -c 10" 10 seconds ago Up 8 seconds
cpu1024
b2d3e64065f0 centos:stress "stress -c 10" About a minute ago Up About a minute cpu512
ddb8e55d1c09 centos:stress "/bin/bash" 53 minutes ago Up 53 minutes dazzling_euclid
bc0698d60239 nginx "/docker-entrypoint.…" 4 hours ago Exited (0) 2 hours ago zealous_darwin
f5b026b08295 registry "/entrypoint.sh /etc…" 4 hours ago Up About an hour 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp hardcore_cori
[root@localhost ~]# docker exec -it b2d3e64065f0 /bin/bash
[root@b2d3e64065f0 /]# top
top - 03:31:32 up 5:48, 0 users, load average: 19.89, 12.06, 5.18
Tasks: 14 total, 11 running, 3 sleeping, 0 stopped, 0 zombie
%Cpu(s): 99.9 us, 0.1 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3861080 total, 1333692 free, 350952 used, 2176436 buff/cache
KiB Swap: 2097148 total, 2097148 free, 0 used. 3107816 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9 root 20 0 7260 96 0 R 14.3 0.0 1:00.20 stress
11 root 20 0 7260 96 0 R 14.3 0.0 0:59.15 stress
12 root 20 0 7260 96 0 R 14.3 0.0 1:00.03 stress
15 root 20 0 7260 96 0 R 14.3 0.0 1:01.25 stress
13 root 20 0 7260 96 0 R 14.0 0.0 0:59.02 stress
16 root 20 0 7260 96 0 R 14.0 0.0 1:01.54 stress
8 root 20 0 7260 96 0 R 12.7 0.0 0:59.61 stress
10 root 20 0 7260 96 0 R 12.7 0.0 0:59.41 stress
7 root 20 0 7260 96 0 R 12.3 0.0 1:00.28 stress
14 root 20 0 7260 96 0 R 12.3 0.0 0:59.47 stress
1 root 20 0 7260 644 548 S 0.0 0.0 0:00.03 stress
23 root 20 0 11772 1804 1448 S 0.0 0.0 0:00.01 bash
39 root 20 0 11772 1808 1448 S 0.0 0.0 0:00.01 bash
55 root 20 0 51864 1920 1408 R 0.0 0.0 0:00.00 top
[root@localhost ~]# docker exec -it 5c59dc0f47d3 /bin/bash
[root@5c59dc0f47d3 /]# top
top - 03:34:52 up 5:51, 0 users, load average: 20.41, 16.06, 8.10
Tasks: 13 total, 11 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3861080 total, 1338616 free, 345936 used, 2176528 buff/cache
KiB Swap: 2097148 total, 2097148 free, 0 used. 3112744 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
11 root 20 0 7260 92 0 R 30.9 0.0 1:56.49 stress
12 root 20 0 7260 92 0 R 28.2 0.0 1:55.71 stress
16 root 20 0 7260 92 0 R 28.2 0.0 1:57.39 stress
14 root 20 0 7260 92 0 R 27.6 0.0 1:53.74 stress
13 root 20 0 7260 92 0 R 25.2 0.0 1:57.68 stress
7 root 20 0 7260 92 0 R 24.9 0.0 1:55.63 stress
8 root 20 0 7260 92 0 R 24.9 0.0 1:55.41 stress
9 root 20 0 7260 92 0 R 24.9 0.0 1:54.88 stress
15 root 20 0 7260 92 0 R 24.9 0.0 1:59.09 stress
10 root 20 0 7260 92 0 R 24.6 0.0 1:56.37 stress
1 root 20 0 7260 640 548 S 0.0 0.0 0:00.01 stress
17 root 20 0 11772 1808 1448 S 0.0 0.0 0:00.04 bash
33 root 20 0 51860 1924 1408 R 0.0 0.0 0:00.00 top
开启了10 个stress 进程,目的是充分让系统资源变得紧张。只有这样竞争资源,设定的资源比例才可以显现出来。如果只运行一个进行,会自动分配到空闲的CPU,这样比例就无法看出来。由于案例的环境不一样,可能导致上面两张图中占用CPU 百分比会不同,但是从cpu share 来看两个容器总比例一定会是1:2。
7.3、CPU周期限制
docker 提供了--cpu-period、--cpu-quota 两个参数控制容器可以分配到的CPU 时钟周期。
- --cpu-period 是用来指定容器对CPU的使用要在多长时间内做一次重新分配。
- --cpu-quota 是用来指定在这个周期内,最多可以有多少时间用来跑这个容器。与--cpu-shares 不同的是:这种配置是指定一个绝对值,而且没有弹性在里面,容器对CPU 资源的使用绝对不会超过配置的值。
cpu-period 和cpu-quota 的单位为微秒(μs)。cpu-period 的最小值为1000 微秒,
最大值为1 秒(10^6 μs),默认值为0.1 秒(100000 μs)。cpu-quota 的值默认为-1,
表示不做控制。cpu-period、cpu-quota 这两个参数一般联合使用。
举个例子,如果容器进程需要每1 秒使用单个CPU 的0.2 秒时间,可以将cpu-period 设置为1000000(即1 秒),cpu-quota 设置为200000(0.2 秒)。当然,在多核情况下,如果允许容器进程需要完全占用两个CPU,则可以将cpu-period 设置为100000(即0.1 秒),cpu-quota 设置为200000(0.2 秒)。
[root@localhost ~]# docker run -it --cpu-period 10000 --cpu-quota 20000 centos:stress /bin/bash
[root@aa6136f8cb7b /]# cat /sys/fs/cgroup/cpu/cpu.cfs_period_us
10000
[root@aa6136f8cb7b /]# cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
20000
7.4、CPU核心限制
多核CPU的服务器Docker还可以控制容器运行限定使用哪些CPU内核,可以使用--cpuset-cpus选项来使某些程序独享CPU核心,以便提高其处理速度,对应的Cgroup文件为/sys/fs/cgroup/cpuset/docker/容器ID号/cpuset.cpus。选项后直接跟参数0、1、2……表示第1个内核,第2个内核,第3个内核,与/proc/cpuinfo中的标号相同。
如果服务器有16个核心,那么CPU编号为0~15,使新建容器绑定第1~4的核心使用:
[root@localhost ~]# docker run -itd --cpuset-cpus 0,1,2,3 centos:stress /bin/bash
7f26046560e1f1e1d91dfe3d16bded32d37ffcaef964725a68eaf16b99722fa7
或
[root@localhost ~]# docker run -itd --cpuset-cpus 0-3 centos:stress /bin/bash
1b69dabb453be291dcd87dbeca4f15f6761c0868feae0d53ea80097fbbd210b6
那么该容器内的进程只会在0,1,2,3的CPU上运行。
通过下面指令也可以看到容器中进程与CPU 内核的绑定关系,可以认为达到了绑定CPU 内核的目的。
[root@localhost ~]# docker exec 1b69dabb453b taskset -c -p 1
pid 1's current affinity list: 0-3 #容器内部第一个进程编号一般为1
尽量使用绑定内核的方式分配CPU资源给容器进程使用,然后在配合--cpu-shares选项动态调整CPU使用资源的比例。
7.5、CPU 配额控制参数的混合案例
通过--cpuset-cpus 指定容器A 使用CPU 内核0,容器B 只是用CPU 内核1。在主机上只有这两个容器使用对应CPU 内核的情况,它们各自占用全部的内核资源,--cpu-shares 没有明显效果。
--cpuset-cpus、--cpuset-mems 参数只在多核、多内存节点上的服务器上有效,并且必须与实际的物理配置匹配,否则也无法达到资源控制的目的。
在系统具有多个CPU 内核的情况下,需要通过cpuset-cpus 为容器CPU 内核才能比较方便地进行测试。
用下列命令创建测试用的容器:
[root@localhost ~]# docker run -itd --name cpu3 --cpuset-cpus 3 --cpu-shares 512 centos:stress stress -c 1
004cb93f1d76e4b30e001ad7b2afc51dfcedef818970edcf0763aba56a45cea2
[root@localhost ~]# docker exec -it 004cb93f1d76 /bin/bash
[root@004cb93f1d76 /]# top
top - 03:57:24 up 6:14, 0 users, load average: 5.43, 15.35, 15.68
Tasks: 4 total, 2 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s): 8.0 us, 0.1 sy, 0.0 ni, 91.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3861080 total, 1396020 free, 291912 used, 2173148 buff/cache
KiB Swap: 2097148 total, 2097148 free, 0 used. 3170028 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7 root 20 0 7260 96 0 R 100.0 0.0 1:18.70 stress
1 root 20 0 7260 436 352 S 0.0 0.0 0:00.01 stress
8 root 20 0 11772 1800 1444 S 0.0 0.0 0:00.01 bash
24 root 20 0 51880 1872 1388 R 0.0 0.0 0:00.00 top
[root@localhost ~]# docker run -itd --name cpu4 --cpuset-cpus 3 --cpu-shares 1024 centos:stress stress -c 1
8998d47911ade2227fe71fce69a125be34a5714868cb7d4fbf3fe40a9fae4164
[root@localhost ~]# docker exec -it 8998d47911ad /bin/bash
[root@8998d47911ad /]# top
top - 04:00:08 up 6:16, 0 users, load average: 2.03, 9.50, 13.38
Tasks: 4 total, 2 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s): 24.8 us, 0.0 sy, 0.0 ni, 74.7 id, 0.0 wa, 0.0 hi, 0.5 si, 0.0 st
KiB Mem : 3861080 total, 1383908 free, 302924 used, 2174248 buff/cache
KiB Swap: 2097148 total, 2097148 free, 0 used. 3158056 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7 root 20 0 7260 92 0 R 66.4 0.0 0:48.96 stress
1 root 20 0 7260 432 352 S 0.0 0.0 0:00.01 stress
8 root 20 0 11772 1804 1448 S 0.0 0.0 0:00.01 bash
24 root 20 0 51852 1912 1408 R 0.0 0.0 0:00.00 top
上面的centos:stress 镜像安装了stress 工具,用来测试CPU 和内存的负载。通过在两个容器上分别执行stress -c 1 命令,将会给系统一个随机负载,产生1 个进程。这个进程都反复不停的计算由rand() 产生随机数的平方根,直到资源耗尽。
观察到宿主机上的CPU 试用率,第三个内核的使用率接近100%,并且一批进程的CPU 使用率明显存在2:1 的使用比例的对比。
7.6、内存限制
与操作系统类似,容器可使用的内存包括两部分:物理内存和swap。Docker 通过下面两组参数来控制容器内存的使用量。
- -m 或--memory:设置内存的使用限额,例如100M, 1024M。
- --memory-swap:设置内存swap 的使用限额。
当执行如下命令:
其含义是允许该容器最多使用200M 的内存和300M 的swap。
[root@localhost ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 293601280 bytes
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 293601280 bytes
- --vm 1:启动1 个内存工作线程。
- --vm-bytes 280M:每个线程分配280M 内存。
默认情况下,容器可以使用主机上的所有空闲内存。与CPU 的cgroups 配置类似,docker 会自动为容器在目录/sys/fs/cgroup/memory/docker/<容器的完整长ID>中创建相应cgroup 配置文件。
因为280M 在可分配的范围(300M)内,所以工作线程能够正常工作,其过程是:
- 分配280M 内存。
- 释放280M 内存。
- 再分配280M 内存。
- 再释放280M 内存。
- 一直循环......
如果让工作线程分配的内存超过300M,分配的内存超过限额,stress 线程报错,容器退出。
[root@localhost ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 380M
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 398458880 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: FAIL: [1] (416) <-- worker 7 got signal 9
stress: WARN: [1] (418) now reaping child worker processes
stress: FAIL: [1] (422) kill error: No such process
stress: FAIL: [1] (452) failed run completed in 0s
7.7、Block IO 的限制
默认情况下,所有容器能平等地读写磁盘,可以通过设置--blkio-weight 参数来改变容器block IO 的优先级。
--blkio-weight 与--cpu-shares 类似,设置的是相对权重值,默认为500。在下面的例子中,容器A 读写磁盘的带宽是容器B 的两倍。
[root@localhost ~]# docker run -it --name container_A --blkio-weight 600 centos:stress /bin/bash
[root@9a1ade37e4a2 /]# cat /sys/fs/cgroup/blkio/blkio.weight
600
[root@9a1ade37e4a2 /]# cat /sys/fs/cgroup/blkio/blkio.weight[root@localhost ~]#
[root@localhost ~]# docker run -it --name container_B --blkio-weight 300 centos:stress /bin/bash
[root@82d39cad4b92 /]# cat /sys/fs/cgroup/blkio/blkio.weight
300
7.8、限制bps 和iops
如果在一台服务器上进行容器的混合部署,那么会存在同时几个程序写磁盘数据的情况,这时可以通过--device-write-iops选项来限制每秒写io次数来限制制定设备的写速度。相应的还有--device-read-iops选项可以限制读取IO的速度,但是这种方法只能限制设备,而不能限制分区,相应的Cgroup写配置文件为/sys/fs/cgroup/blkio/容器ID/ blkio.throttle.write_iops_device。
- bps 是byte per second,每秒读写的数据量。
- iops 是io per second,每秒IO 的次数。
可通过以下参数控制容器的bps 和iops:
- --device-read-bps,限制读某个设备的bps
- --device-write-bps,限制写某个设备的bps
- --device-read-iops,限制读某个设备的iops
- --device-write-iops,限制写某个设备的iops
下面的示例是限制容器写/dev/sda 的速率为5 MB/s。
[root@localhost ~]# docker run -it --device-write-bps /dev/sda:5MB centos:stress /bin/bash
[root@f4b37691fa4d /]# dd if=/dev/zero of=test bs=1M count=100 oflag=direct
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 20.006 s, 5.2 MB/s
通过dd 测试在容器中写磁盘的速度。因为容器的文件系统是在host /dev/sda 上的,在容器中写文件相当于对宿主机/dev/sda 进行写操作。另外,oflag=direct 指定用direct
IO 方式写文件,这样--device-write-bps 才能生效。
结果表明,bps 5.2 MB/s 在限速5MB/s 左右。作为对比测试,如果不限速,结果如下:
[root@localhost ~]# docker run -it centos:stress /bin/bash
[root@d324fcfe3cbb /]# dd if=/dev/zero of=test bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 0.0527029 s, 2.0 GB/s
8、Docker数据持久化
8.1、数据持久化介绍
在Docker中若要想实现容器数据的持久化(所谓的数据持久化即数据不随着Container的结束而销毁),需要将数据从宿主机挂载到容器中。目前Docker提供了三种不同的方式将数据从宿主机挂载到容器中。
(1)Volumes:Docker会管理宿主机文件系统的一部分资源,默认位于 /var/lib/docker/volumes 目录中;(最常用的方式)
[root@localhost ~]# docker run -it -v /opt/ centos /bin/bash
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
a1d0c7532777: Already exists
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest
[root@630ab274dcd8 /]# touch /opt/test.txt
[root@630ab274dcd8 /]# ls /opt/
test.txt
[root@localhost ~]# ls /var/lib/docker/volumes/3e75601aeaa96d13807f38d22fd13666db6ead38af2ce543a249e5515d497bca/_data/
test.txt
目前所有Container的数据都保存在/var/lib/docker/volumes/目录下边,由于没有在创建时指定卷,所以Docker帮我们默认创建许多匿名(就上面这一堆很长ID的名字)卷。
(2)bind mounts:意为着可以指定存储在宿主机系统的任意位置;(比较常用的方式)
但是bind mounts在不同的宿主机系统之间是不可移植的,比如Windows和Linux的存储结构是不一样的,bind mount所指向的host目录也不能一样。这也是为什么bind mount不能出现在Dockerfile中的原因,因为会导致Dockerfile无法移植。
(3)tmpfs:挂载存储在宿主机系统的内存中,而不会写入宿主机的文件系统;(一般都不会用的方式)
8.2、Volume的基本使用
8.2.1、管理卷
创建一个自定义容器卷
[root@localhost ~]# docker volume create nginx-data
nginx-data
查看所有容器卷
[root@localhost ~]# docker volume ls
DRIVER VOLUME NAME
local nginx-data
查看指定容器卷详情信息
[root@localhost ~]# docker volume inspect nginx-data
[
{
"CreatedAt": "0001-01-01T00:00:00Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/nginx-data/_data",
"Name": "nginx-data",
"Options": null,
"Scope": "local"
}
]
8.2.2、创建使用指定卷的容器
有了自定义容器卷,我们可以创建一个使用这个数据卷的容器
[root@localhost ~]# docker run -d -it --name=nginx -p 800:80 -v nginx-data:/usr/share/nginx/html nginx
67a5acf397730011f702127cd7d5001f3c87d12060ed2b0e7bf2015c0d8ba94e
[root@localhost ~]# docker exec -it nginx /bin/bash
root@67a5acf39773:/# ls /usr/share/nginx/html/
50x.html index.html
选项-v代表挂载数据卷,这里使用自定数据卷nginx-data,并且将数据卷挂载到 /usr/share/nginx/html (这个目录是yum安装nginx的默认网页目录)。如果没有通过-v指定,那么Docker会默认帮我们创建匿名数据卷进行映射和挂载。
注意:
- 数据卷下无文件,显示容器对应目录下的文件
- 数据卷下有文件,显示数据卷原有文件,并将容器对应目录的文件隐藏,显示数据卷文件
可以看到网页目录下有两个默认页面,这时我们可以查看宿主机文件系统的数据
[root@localhost ~]# ls /var/lib/docker/volumes/nginx-data/_data/
50x.html index.html
可以看到容器里面的两个默认页面,由此可知Volume帮我们做了类似于一个软链接的功能。在容器里边的改动,我们可以在宿主机里感知,而在宿主机里面的改动,在容器里边可以感知到。
如果我们手动stop并且remove当前nginx容器,我们会发现容器卷里面的文件还在,并没有随着容器被删除掉。
[root@localhost ~]# docker stop nginx
nginx
[root@localhost ~]# docker rm nginx
nginx
[root@localhost ~]# ls /var/lib/docker/volumes/nginx-data/_data/
50x.html index.html
所以在数据卷里边的东西是可以持久化的。如果下次还需要创建一个nginx容器,那么时候复用当前数据卷里面文件的。
[root@localhost ~]# docker run -d -it --name=nginx2 -p 801:80 -v nginx-data:/usr/share/nginx/html nginx
6741a1c3ea19a45333e0330191c023bc3e04bfad85498edd4c160e0871996ea7
[root@localhost ~]# docker exec -it nginx2 /bin/bash
root@6741a1c3ea19:/# ls /usr/share/nginx/html/
50x.html index.html
此外,我们还可以启动多个nginx容器实例,共享同一个数据卷。数据卷的复用性和扩展性较强的。
8.2.3、清理卷
如果不再使用自定义数据卷了,那么可以手动清理掉:
[root@localhost ~]# docker volume rm -f nginx-data
nginx-data
[root@localhost ~]# docker volume ls
DRIVER VOLUME NAME
8.3、Bind Mounts的基本使用
8.3.1 使用卷创建一个容器
[root@localhost ~]# docker run -d -it --name=nginx -p 800:80 -v /wwwroot:/usr/share/nginx/html nginx
0bc4e5c1975bb7fff3d8e5886e78c6711de7204ba7a09cddb24c410421c53f23
这里指定了将宿主机上的 /wwwroot 目录(如果没有会自动创建)挂载到 /usr/share/nginx/html (这个目录是yum安装nginx的默认网页目录)。
docker挂载的默认权限是读写(rw),用户也可以通过ro指定为只读
[root@localhost ~]# docker run -d -it --name=nginx2 -p 801:80 -v /wwwroot:/usr/share/nginx/html:ro nginx
0aba96663db35032504213f6aab44424e88d2e0a2e39592e3f1c94ae23e35269
[root@localhost ~]# docker exec -it nginx /bin/bash
root@0bc4e5c1975b:/# ls /usr/share/nginx/html/
可以看到,与volumes不同,bind mounts的方式会隐藏掉被挂载目录里面的内容(如果非空的话),这里是/usr/share/nginx/html 目录下的内容被隐藏掉了,因此我们看不到。
但是,我们可以将宿主机上的文件随时挂载到容器中:
新建一个index.html,并在容器中查看
[root@localhost ~]# echo "test html" > /wwwroot/index.html
[root@localhost ~]# docker exec -it nginx /bin/bash
root@0bc4e5c1975b:/# ls /usr/share/nginx/html/
index.html
8.3.2、验证绑定
[root@localhost ~]# docker inspect nginx
"HostConfig": {
"Binds": [
"/wwwroot:/usr/share/nginx/html"
],
8.3.3、清理
[root@localhost ~]# docker stop nginx
nginx
[root@localhost ~]# docker rm nginx
nginx
[root@localhost ~]# ls /wwwroot/
index.html
同volumes一样,当我们清理掉容器之后,挂载目录里面的文件仍然还在,不会随着容器的结束而消失,从而实现数据持久化。
8.4、数据卷容器
8.4.1、数据卷容器概述
用户需要在容器之间共享一些持续性更新的数据时,可以使用数据卷容器。数据容器也是一个普通的容器。里边带有设置好的数据卷,专门提供给其他容器挂载使用。 通过--volumes-from 数据卷容器名来实现。
8.4.2、创建数据卷容器
[root@localhost ~]# docker run -it -v /dbdata:/dbdata --name=dbdata centos /bin/bash
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
a1d0c7532777: Already exists
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest
[root@36cd7b069c08 /]# exit
exit
//创建一个数据卷容器,并在其中创建一个数据卷挂载到/dbdata
进入test1容器创建文件测试
[root@localhost ~]# docker run -it --volumes-from dbdata --name test1 centos /bin/bash
[root@e06b68cbae34 /]# ls
bin dev home lib64 media opt root sbin sys usr
dbdata etc lib lost+found mnt proc run srv tmp var
[root@e06b68cbae34 /]# touch dbdata/crushlinux
[root@e06b68cbae34 /]# ls
bin dev home lib64 media opt root sbin sys usr
dbdata etc lib lost+found mnt proc run srv tmp var
[root@e06b68cbae34 /]# ls dbdata/
crushlinux
[root@e06b68cbae34 /]# exit
exit
//在test1容器的/dbdata目录创建测试文件
进入test2容器验证结果
[root@localhost ~]# docker run -it --volumes-from dbdata --name test2 centos /bin/bash
[root@bbaf174a1aa9 /]# ls
bin dev home lib64 media opt root sbin sys usr
dbdata etc lib lost+found mnt proc run srv tmp var
[root@bbaf174a1aa9 /]# ls dbdata/
crushlinux
说明:
- 可以多次使用--volume-from参数从多个容器挂载多个目录。也可以从其他已经挂载了数据卷的容器来挂载数据卷(类似传递)。
- 再次强调:如果删除了挂载的容器,数据卷不会被自动删除。如果要删除容器的时候同时删除数据卷,需加上-v参数。