文章目录
🌟 前言
上一篇文章讲了容器的运行启动:【Docker 那些事儿】如何安全地进入到容器内部
本篇文章将继续承接上一篇,讲讲如何 停止、删除容器 和 对容器进行资源限制
1. 停止和删除容器
🍑 停止容器
在工作中,有时会需要将容器暂停,例如,要为容器文件系统做一个快照时。使用 docker pause 与 docker unpause 命令可以对容器进行暂停与激活操作,并且暂停状态的容器不会占用宿主机 CPU 资源。
当不再需要业务运行时,就要将容器关闭,这时可以使用 docker stop 命令。当遇到特殊情况而无法关闭容器时,还可以使用 docker kill 命令强制终止容器,示例代码如下:
以上示例使用 docker kill 命令强制终止了容器。
企业中通常有大量的容器需要操作,一个一个操作会浪费大量的人力及时间成本。在这种情况下,可以将 Docker 命令与正则表达式结合起来,实现对容器的批量操作。
首先查看运行状态容器的 ID 号,示例代码如下:
接着使用 正则表达式 根据运行状态容器的 ID 号关闭正在运行的容器,示例代码如下:
以上示例运用 docker stop 命令与正则表达式批量终止了运行中的容器,该命令还有另一种编写方式,示例代码如下:
另外,使用类似方法还可以对容器进行批量删除、启动等操作。
docker stop 与 docker kill 的区别如下👇
- docker stop 执行时,首先给容器发送一个TERM信号,让容器做一些退出前必须做的保护性、安全性操作,然后让容器自动停止运行,如果在一段时间内容器没有停止运行,再执行 kill -9 指令,强制终止容器。
- docker kill 执行时,不论容器是什么状态,在运行什么程序,直接执行 kill -9 指令,强制终止容器。
🍑 删除容器
容器以其轻量级的特点受人欢迎,通常一些容器使用不久就会闲置,长期积累会导致不必要的资源浪费,所以要及时清理无用的容器。
与 docker rmi 命令不同,docker rm 命令用于删除容器,下面将介绍删除容器的几种方法。
🍇 删除容器方法一
首先,查看所有容器及其状态,示例代码如下:
从以上示例中可以看到,目前宿主机中有三个处于终止状态的容器,以及一个处于运行状态的容器。
然后,结合正则与 docker rm 命令列出处于终止状态的容器并进行删除,示例代码如下:
以上示例使用 docker rm 命令结合正则表达式实现了批量删除容器,并回显删除的容器 ID。
最后,查看并确认容器已删除,示例代码如下:
从示例中可以看到,处于终止状态的容器已经被删除,运行状态的容器并没有被删除。
🍇 删除容器方法二
首先,查看所有容器及其状态,示例代码如下:
从以上示例中可以看到,宿主机中有三个处于终止状态的容器,以及一个处于运行状态的容器。
接着,使用 docker rm 命令结合正则表达式列出所有容器 ID 号并删除容器,示例代码如下:
从以上示例中可以看到,命令的执行时发生了报错,提示无法删除一个正在运行的容器,可以使用 -f 参数强制执行。
然后,查看当前容器状态,示例代码如下:
上述示例中可以看到,docker rm 命令结合正则表达式删除了三个终止状态的容器,运行中的容器没有被删除。
最后,根据报错提示在命令中添加一个 -f 参数,表示强制删除,示例代码如下:
从以上示例中可以看到,处于运行状态中的容器已经被删除。
🍇 删除容器方法三
首先,查看当前容器及其状态,示例代码如下:
接着,使用 docker rm 命令结合 docker ps -q -f status=exited 命名筛选出处于终止状态的容器 ID 号,并删除容器,示例代码如下:
上述示例中,命令已经执行成功。
最后,查看容器是否被删除,示例代码如下。
上述示例中可以看到,处于终止状态的容器都已经被删除。
🍇 删除容器方法四
从 Docker1.13 版本开始,用户可以使用 docker container prune 命令删除处于终止状态的容器。
首先,查看当前容器及其状态,示例代码如下:
接着,使用命令开始删除所有处于终止状态的容器,示例代码如下:
从以上示例中可以看到,当 docker container prune 命令执行之后,系统会向用户发出警告信息,并询问是否要继续。
docker container prune 会直接删除所有处于终止状态的容器,为了防止用户的误操作,将有用的容器删除,命令执行时会有警告信息与询问信息。
这时,如果确认要删除,可输入 “y” ,否则,输入 “n” 即可阻止命令执行。示例删除了所有处于终止状态的容器,命令执行成功之后返回一个释放内存的值。
最后,查看当前容器及其状态,示例代码如下:
从以上示例中可以看到,处于终止状态的容器已经被删除,而处于运行状态的容器并没有受到影响。
2. 容器资源限制
在默认情况下,Docker 没有对容器进行硬件资源的限制。使用 Dcoker 运行容器时,一台主机上可能会运行成百上千个容器,这些容器虽然相互隔离,但是在底层使用着相同的 CPU、内存和 磁盘 等资源。
如果不对容器使用的资源进行限制,那么容器对宿主机资源的消耗可能导致其他容器或进程不能够正常运行,严重时可能导致服务完全不可用。
本节将介绍如何对容器配置 CPU、内存、Block IO 等资源的限制。
🍑 限制容器内存资源
在 Linux 服务器上,如果内核检测到没有足够的内存(Memory)来执行重要的系统功能,内核会提示OOME(Out of Memory Error,内存溢出)并开始终止进程以释放内存,这称为 OOM 操作。
任何进程都有可能被终止,包括 Docker 和其他重要的应用程序。如果终止了系统关键进程,可能导致整个系统瘫痪。
设置限制内存上限虽然能保护主机,但是也可能会导致容器里的服务运行不畅。如果为服务设置的内存上限太小,服务在正常工作时可能出现资源不足;
如果设置过大,则会因为调度器算法浪费内存。因此,合理的做法是遵循以下原则。
- 为应用做内存压力测试,了解正常业务需求下内存的使用情况,然后再进入生产环境。
- 限制容器的内存使用上限。
- 尽量保持主机的资源充足,一旦通过监控发现资源不足,就进行扩容或者对容器进行迁移。
- 内存资源充足的情况下,尽量不要使用 Swap(交换分区),Swap 的使用会导致内存计算变得复杂,对调度器造成压力。
下面介绍Docker启动参数中的内存限制参数。
-m
,--memory
设置容器可使用的最大内存,最小值是4MB。
--memory-swap
设置容器可使用内存+Swap的最大值。
--memory-swapiness
默认情况下,用户可以设置一个0~100的值,代表允许内存与交换分区置换的比例。
--memory-reservation
设置一个内存使用的 soft limit(非强制性限制),如果 Docker 发现主机内存不足,会执行 OOM 操作。这个值必须小于 –memory 设置的值。
--kernel-memory
容器能够使用的内核内存的大小,最小值为 4MB。
--oom-kill-disable
设置是否在运行 OOM 时候终止容器进程。
宿主机会在内存不足时,随机关闭一些进程,而该参数会保护容器进程不被关闭。只有通过设置 -memory 限制容器内存,才可以使用该参数,否则容器会耗尽主机内存,而且导致主机应用被终止。
❗注:
--memory-swap
只有在设置了 -memory 时才有意义。
使用 Swap 允许容器在耗尽所有可用的内存时,将多余的内存需求写入磁盘。两者的关系如表所示。
以上两个参数默认值都为 -1,即对容器使用 内存 和 Swap 没有限制。
下面使用 progrium/stress 镜像来介绍如何为容器分配内存,该容器可以模拟进行压力测试。示例代码如下:
以上示例运行了一个容器,分配可用最大内存为 300MB,可用 Swap 为 100MB。
其中,–vm 1 参数表示启动一个内存工作线程
–vm-bytes 280M 参数表示每个线程分配 280MB 内存。
可以看到系统不断地给容器分配内存、释放内存,一直循环。由于使用的内存 380MB,在最大使用量(400MB)之内,容器正常运行。
下面测试内存使用超出限额的情况,实例代码如下:
从以上示例中可以看到,容器使用的内存超过了限额,容器里的进程被终止掉了,其中,signal 9 就是终止进程信号,最后容器退出。
如果在创建容器时仅指定 -m 参数,不设置 -memory-swap 参数,那么 -memory-swap 默认是 -m 的两倍,示例代码如下:
在以上示例中,容器最多使用 100MB 内存和 100MB Swap。
🍑 限制容器CPU资源
主机上的进程会通过时间分片机制使用 CPU。CPU 用频率来量化,也就是每秒执行的运算次数。为容器限制 CPU 资源并不是改变 CPU 的频率,而是改变每个容器能使用的 CPU 时间片。
理想状态下,CPU 应该一直处于运算状态,并且进程的计算量不会超过 CPU 的处理能力。
Docker 允许用户为每个容器设置一个数字,代表容器的 CPU share(共享),默认情况下每个容器的 share 值是 1000。这个 share 值是相对的,本身并不能代表任何确定的意义。当主机上有多个容器运行时,每个容器占用的 CPU 时间比例为它的 share 值在总额中的比例。
例如,主机上有两个一直使用 CPU 的容器(为了方便理解,不考虑主机上运行的其他进程),其 CPU share 都为 1000,那么两个容器 CPU 使用率都是 **50%**;
如果把其中一个容器的 share 值设置为 500,那么两者 CPU 的使用比为 2:1;如果删除 share 值为 1000 的容器,剩下来容器的 CPU 使用率将会是 **100%**。
Docker 为容器设置 CPU 资源限制的参数是 -c 或 –cpu-shares,其值是一个整数。运行两个容器 test01 与 test02,并设置 CPU 权重,示例代码如下:
以上示例中分别为 test01 与 test02 设置 CPU share 为 1000 与 2000。
接着,使用 docker stats 查看容器占用 CPU 情况,示例代码如下:
从以上示例中可以看到,两个容器 CPU 的使用占比约为 2:1,与先前设置的 share 值相吻合。
此时将 share 值为 2000 的 test02 容器暂停,再来查看 CPU 使用情况,示例代码如下:
设置 CPU 资源限制还可以使用 –cpuset-cpus 参数,它能够指定容器使用某一颗 CPU。这里使用 CPU 测试镜像 agileek/cpuset-test 进行测试,其功能是将 CPU 用满,示例代码如下:
使用宿主机 top 命令查看 CPU 使用情况,可以看到 CPU1 已经被占满,而 CPU0 没有受到影响,如图所示:
🍑 限制容器 Block IO
Block IO 表示磁盘的读写,Docker 可以用配置 bps(每秒读写的数据量)和 iops(每秒读写的次数)的方式限制容器对磁盘读写的带宽。
下面介绍限制 bps 与 iops 的参数。
--device-read-bps
限制读某个设备的bps。
--device-write-bps
限制写某个设备的bps。
--device-read-iops
限制读某个设备的iops。
--device-write-iops
限制写某个设备的iops。
默认情况下,所有容器对磁盘读写的带宽是相同的,通过配置 -blkio-weight 参数的值(10-1000)可以指定容器 Block IO 的优先级。–blkio-weight 与 -cpu-shares 类似,默认值都是 500。
下面运行的两个容器 test01 与 test02,其中,test01 读写磁盘的带宽是 test02 的两倍。
从以上示例中可以看到,容器 test01 的相对权重值是 800,而 test02 的相对权重值是 400,故 test01 读写磁盘的带宽是 test02 的两倍。
下面运行一个容器,限制其对 /dev/sda 写入的速率不高于 20MB/s。因为容器文件系统在宿主机的 /dev/sda 上,在容器中写文件相当于对宿主机的 /dev/sda 进行写入操作。
示例代码如下:
以上示例运行了一个 CentOS 容器,并限制其写 /dev/sda 的速率为 20MB/s。
下面通过命令查看该容器的写入速率,示例代码如下:
从以上示例中可以看到,设置了写入限制的容器,写入速率为 19.4MB/s,没有超过写入限制的 20MB/s。
作为对比,下面运行一个不限制写入速率的容器,示例代码如下:
以上示例中,一个不限制读写速率的容器,写入速率是 61.3MB/s。
其他参数使用方法与之类似,大家可以自己尝试做一下🤗。
3. 总结
这两篇文章,首先介绍了如何获取 Docker 帮助手册;然后通过大量的实验讲解了操作 Docker 容器的方法,包括进入、停止、删除容器等,以及容器各种状态之间如何转换;
最后介绍了 Docker 容器的资源限制,包括 限制内存、CPU、BLOCK IO 三种方法。
版权归原作者 Albert Edison 所有, 如有侵权,请联系我们删除。