docker 容器资源管理,你真的学会了吗英文(docker可以控制很多资
docker 容器资源管理,你真的学会了吗英文(docker可以控制很多资源,目前),本文通过数据整理汇集了docker 容器资源管理,你真的学会了吗英文(docker可以控制很多资源,目前)相关信息,下面一起看看。
作者|张金涛
编辑|胡玮炜
Docker很好用,如果应用到生产环境中,你需要对它有更深入的了解。这样才能保证应用达到我们的预期或者及时解决问题。所以要想真正掌握Docker的核心知识,光靠网上零散的信息往往是不够的,必须进行系统的学习。
容器作为Docker的核心特性之一,是Docker用户无法回避的重要知识点。如果你想了解容器的核心原理,甚至想自己写,是绝对不可能了解容器资源管理的相关内容的。
本文将围绕容器资源管理,解决以下三个问题
哪些分配给容器的资源可以由我们管理?容器实际使用了多少资源?如何管理容器使用的资源?
资源类型
对于第一个问题,当我们启动一个容器时,它可以使用一些系统资源,这和我们在物理机上启动一个程序基本是一样的。例如,主要类别
CPU网络I/OGPU这些系统资源需要我们在启动容器的时候考虑和管理。例如,我们可以执行docker run - help来查看docker run命令支持的所有参数。现在docker run命令支持的参数已经超过90个,这里就不一一列举了。
查看容器占用的资源
码头统计
Docker提供了一个方便的命令docker stats,它允许我们查看和统计容器所占用的资源。
我们仍然以Redis容器为例。
#启动一个容器(moe love)~ Docker Run-d Redis c 98 c 9831 e 73 e 9 b 71719 b 404 F5 ecf3 b 408 E0 b 69 AEC 0 f 781 e 42d 815575d 28 ada #检查它占用的资源(moe love)~ Docker stats-no-stream $(Docker PS-QL)容器ID名称CPU % MEM使用率/限制MEM % NET I/O块I/O pidsc 98 c 9831 ee 73 amazing _ Torvalds 0.08% 2
这里传递了一个参数-no-stream,因为docker stats命令在默认情况下是一个连续的动态流输出(每秒一次)。参数-no-stream传递给它后,它只会输出一次,然后退出。
接下来,我将向您介绍其输出的含义
容器ID:容器的ID,这也是在容器的生命周期中不会改变的信息。名称容器的名称。如果没有用- name参数手动指定,Docker会随机生成一个,也可以在运行过程中用命令修改。CPU%:容器正在使用的CPU资源的百分比,这个涉及到更多的细节,下面会详细描述。Mem Usage/Limit:当前的内存使用情况和容器中可用的最大内存。在这里,我用了一台16G的电脑进行测试。Mem%:容器正在使用的内存资源的百分比。Net I/O:容器通过其网络接口发送和接收的数据量。块I/O:容器通过块设备读写的数据量。Pids:容器创建的进程或线程的数量。码头顶部
除了上面提到的docker stats命令,docker还提供了另一个相对简单的命令docker top,和我们平时使用的ps命令基本相同,也支持ps命令的参数。
(moe love)~ docker top $(docker PS-QL)UID PID PPID C STIME TTY时间CMDsystemd 62756248016:50?00:00:24 redis-server :6379#可以使用ps命令的参数(moe love)~ Docker Top $(Docker PS-QL)-O PID,STAT,CMD PID STAT CMD 6275 SSL redis-server :6379
管理容器的CPU资源
当我们使用容器时,CPU和内存是我们特别关注的资源。对于CPU资源的管理,涉及的内容会低一些,有些涉及内核的CPU调度器,比如CFS(完全公平调度器)。
我们先来看看Docker提供了哪些参数来控制CPU资源。使用docker run - help |grep CPU查看。
(moe love)~ docker run-help | grep CPU- cpu-period int Limit CPU CFS(完全公平调度程序)period - cpu-quota int Limit CPU CFS(完全公平调度程序)quota - cpu-rt-period int Limit CPU实时周期以微秒计- cpu-rt-runtime int Limit CPU实时周期以微秒计-c,- cpu-shares int CPU shares(相对权重)-CPU的十进制数-CPU uset-允许执行的CPU字符串CPU(0-3,0,1)
参数的具体含义暂且不在此赘述。我们会直接用几个例子来解释,帮助你理解。
默认无限制
注意我将在这里用一台4核CPU计算机进行演示。
现在让我们开始一个容器。我们以Alpine Linux为例,它非常小。
(moe love)~ docker run-RM-it alpine/#
在另一个窗口中,执行命令以查看上述容器资源
(moe love)~ docker stats-no-stream $(docker PS-QL)容器ID名称CPU % MEM使用率/限制MEM %净I/O块I/O PID s106 a 24399 BC 9 friendly _ varahamihira 0.00% 1.047 MIB/15.56 gib 0.01% 5.01 kb/0B 1.67 MB/0B 1
如你所见,当前容器中没有过多的CPU消耗,PIDS为1,这意味着当前只有一个进程。
现在,让我们回到刚刚启动的容器,执行以下命令
sha256sum总和/发展/零
Sha256sum是一个命令行工具,用于计算和检查SHA256信息;/dev/zero是Linux系统上的一个特殊设备。读取时可以提供无限空字符串(NULL或0x00等。).所以上面的命令会 让sha256sum连续读取/dev/zero生成的空字符串,并进行计算。 这将很快消耗CPU资源。
让我们看看此时容器的资源使用情况
(moe love)~ docker stats-no-stream $(docker PS-QL)容器ID名称CPU % MEM使用率/限制MEM %净I/O块I/O PID s106 a 24399 BC 9 friendly _ varahamihira 100.59% 1.5 MIB/15.56 gib 0.01% 14.4 kb/0B 1.99 MB/0B 2(moe love)~ docker top $(docker PS-QL)-O PID,C,cmdPID C CMD8250
可以看出,目前的CPU利用率已经在100%左右。
让我们打开一个新窗口,进入容器,并执行相同的命令
(moe love)~ docker exec-it $(docker PS-QL)sh/# sha 256 sum/dev/zero
检查容器的资源使用情况
(moe love)~ docker stats-no-stream $(docker PS-QL)容器ID名称CPU % MEM使用率/限制MEM %净I/O块I/O PID SF 359 D4 ff 6 fc 6 nice _ zhukovsky 200.79% 1.793 MIB/15.56 gib 0.01% 4.58 kb/0B/0B 4(moe love)~ docker top $(docker PS-QL)-O PID,C,cmd PID C CMD8250 /bin
如您所见,这两个进程现在有两个CPU满负荷运行。这里需要注意的是,选择sha256sum作为例子是因为它是单线程程序,一次启动一个sha256sum不会消耗其他CPU核的资源。
可以得出结论,如果容器中的程序的CPU资源没有限制,可能会消耗大量的CPU资源,进而影响其他程序或者系统的稳定性。
0.5 CPU分配
接下来,我们对这个容器的CPU资源进行限制,比如它只能使用0.5的CPU。
(MoeLove) ~ docker更新-CPU ' 0.5 ' $(docker PS-QL)f 359d 4 ff 6 fc 6
我们可以重启一个容器,并在docker运行时为它添加资源限制。
让我向您展示一种动态改变资源限制的方法,使用docker update命令。例如,在这个例子中,我们使用下面的命令将容器限制为只有0.5 CPU。
为了方便起见,让我们关闭sha256sum进程,并按Ctrl+c来终止该进程。然后重新运行该命令
#终止进程/# sha256sum /dev/zero ^C# #启动程序/# sha256sum /dev/zero
检查资源占用情况
(moe love)~ docker stats-no-stream $(docker PS-QL)容器ID名称CPU % MEM使用率/限制MEM %净I/O块I/O pidsf 359 D4 ff 6 fc 6 nice _ zhukovsky 49.87% 1.777 MIB/15.56 gib 0.01% 112 kb/0B 1.59 MB/0B 3(moe love)~ docker top $(docker PS-QL)-O PID,C,cmdPID C CMD8250
如您所见,这个过程使用了大约50%的CPU。接下来让我们开始sha256sum的另一个过程
/# sha256sum /dev/zero
查看资源使用情况
(moe love)~ docker stats-no-stream $(docker PS-QL)容器ID名称CPU % MEM使用率/限制MEM %净I/O块I/O pidsf 359 D4 ff 6 fc 6 nice _ zhukovsky 50.92% 1.891 MIB/15.56 gib 0.01% 113 kb/0B 1.59 MB/0B 4(moe love)~ docker top $(docker PS-QL)-O PID,C,cmdPID C CMD8250
可以看到,容器整体占用了CPU的50%,而两个sha256sum进程各占25%。
我们已经成功地按预期给它分配了0.5个CPU。
1.5 CPU分配
接下来,重复上面的步骤,给它分配1.5个CPU,看看它实际上是如何工作的。
#更新配置使用1.5 CPU(moe love)~ Docker Update-CPU ' 1.5 ' $(Docker PS-QL)f 359d 4 ff 6fc 6
使用前面的两个窗口,执行sha256sum /dev/zero进行测试
/# sha256sum /dev/zero
查看资源使用情况
(moe love)~ docker stats-no-stream $(docker PS-QL)容器ID名称CPU % MEM使用率/限制MEM %净I/O块I/O pidsf 359 D4 ff 6 fc 6 nice _ zhukovsky 151.23% 2 MIB/15.56 gib 0.01% 122 kb/0B 1.59 MB/0B 4(moe love)~ docker top $(docker PS-QL)-O PID,C,cmd PID C cmd 8250/bin/bin
可以看到,结果基本符合我们的预期,大约150%的CPU,两个测试进程几乎平分了CPU资源。
指定可以使用CPU核心
您可以使用-CPU set-CPU来指定哪个CPU核心可以用于分配。在这里,我指定0,这意味着使用第一个CPU核心。
(MoeLove) ~ docker更新-CPU ' 1.5 '-CPU set-CPU 0 $(docker PS-QL)f 359d 4 ff 6 fc 6
使用前面的两个窗口,执行sha256sum /dev/zero进行测试
/# sha256sum /dev/zero
检查资源情况
(moe love)~ docker stats-no-stream $(docker PS-QL)容器ID名称CPU % MEM使用率/限制MEM %净I/O块I/O PID SF 359 D4 ff 6 fc 6 nice _ zhukovsky 99.18% 1.988 MIB/15.56 gib 0.01% 221 kb/0B 1.59 MB/0B 4(moe love)~ docker top $(docker PS-QL)-O PID,C,cmd PID C CMD8250
正如您所看到的,虽然我们仍然使用-CPU来指定1.5的CPU,两个测试进程只能对CPU进行评分,因为-CPU set-CPU限制只允许它在第一个CPU上运行。本文节选自专栏。
通过上面的例子,我介绍了如何通过CPU参数限制容器可以使用的CPU资源;- cpuset-cpus参数可以指定容器中要运行的进程所使用的CPU核心;Docker update可以直接更新正在运行的容器的相关配置。
现在让我们回到之前使用docker run - help | grep CPU来检查docker支持的与容器CPU相关的参数的选项
(moe love)~ docker run-help | grep CPU- cpu-period int Limit CPU CFS(完全公平调度程序)period - cpu-quota int Limit CPU CFS(完全公平调度程序)quota - cpu-rt-period int Limit CPU实时周期以微秒计- cpu-rt-runtime int Limit CPU实时周期以微秒计-c,- cpu-shares int CPU shares(相对权重)-CPU的十进制数-CPU uset-允许执行的CPU字符串CPU(0-3,0,1)
- cpu是在Docker 1.13中添加的,可以用来替换原来的- cpu-period和- cpu-quota。通过cgroups,这三个参数实际上会影响Linux内核中CPU调度器CFS(完全公平调度器)的调度结果。
一般情况下,建议直接使用- cpu,不要单独设置- cpu-period和- cpu-quota,除非你已经对cpu调度器CFS有足够的了解。提供-CPU参数也是Docker团队为了简化用户使用而增加的成本,足以满足我们的大部分需求。
而- cpu-shares选项,虽然有一定的实际意义,但不如- cpu直观,而且会受到当前系统运行状态的影响,为了不性病网给大家添麻烦,这里就不介绍了。
两个参数-CPU-RT-period和-CPU-RT-runtime会影响CPU的实时调度器。实时调度器需要内核参数的支持,配置实时调度器也是一个高级或者危险的操作,可能会导致各种奇怪的问题,这里就不展开了。
管理容器的内存资源。
描述了如何管理容器的CPU资源之后,让我们看看如何管理容器的内存资源。与CPU资源相比,内存资源的管理要简单得多。
同样,我们先来看看有哪些参数可供我们配置,稍后我会介绍它们的含义
(moe love)~ docker run-help | egrep ' memory | oom '-Kernel-Memory bytes Kernel Memory limit-m,-Memory bytes Memory limit-Memory-reservation bytes Memory soft limit-Memory-Swap bytes Swap limit等于Memory加swap: '-1 '启用无限制交换- memory-swappiness int Tune容器内存交换率(0到100)(默认值-1) - oom-kill-disable禁用oom黑仔- oom-score-adj int Tune主机的OOM首选项(-1000到1000)
伯父
在开始容器内存管理的内容之前,我们不妨先说一个我们不得不面对的很常见的问题OOM(内存不足)。
当内核检测到没有足够的内存运行系统的某些功能时,就会触发OOM异常,并且会使用OOM黑仔杀死一些进程,为系统的正常运行腾出空间。
下面简单介绍一下OOM killer的大致实现过程,以便大家了解后续内容。
OOM黑仔在内核中的代码可以直接在torvalds/linux/mm/oom_kill.c中看到,这里以linux内核5.2为例。
引用的注释之一
如果我们用完了内存,我们可以选择终止一个随机任务(糟糕),或者让系统崩溃(更糟糕)。
或者明智地选择终止哪个进程。注意,在这里我们不需要做到完美,我们只要做到优秀就可以了。
当我们在OOM时,我们可以有几种选择,随机杀死任何一个任务(坏的),使系统崩溃(更坏的)或者试图知道哪个进程可以被杀死。注意,我们这里不需要追求完美,只要优秀就好。
其实是真的,无论是随机杀死任何一个进程,还是让系统崩溃,那都不是我们想要的。
回到内核代码,当系统内存不足时,触发out_of_memory(),然后调用select_bad_process()函数,选择一个坏进程杀死。
什么样的过程是不好的过程?总有一些条件。Select_bad_process()是一个简单的循环,调用oom_evaluate_task()计算进程的条件,核心判断逻辑是oom_badness()。
unsignedlongoom _ bad ness(struct task _ struct p,struct mem_cgroup memcg,constnodemask_t nodemask,unsignedlong total pages){ long points;长的;if (oom_unkillable_task(p,memcg,node mask))return 0;p=find _ lock _ task _ mm(p);如果(!p)return 0;/ 甚至不要考虑被明确标记为oom 不可杀死或已经oom收割或正在vfork /adj=(long)p-signal-oom _ score _ adj;if(adj==OOM _ SCORE _ ADJ _ MIN | | test _ bit(MMF _ OOM _ SKIP,p-mm-flags)| | in _ vfork(p)){ task _ unlock(p);return0}/ 不良分数的基线是每个任务的rss、页面表和交换空间使用的RAM比例。/points=get _ MM _ RSS(p-MM)get _ MM _ counter(p-MM,MM _ SWAPENTS)MM _ pg tables _ bytes(p-MM)/PAGE _ SIZE;task _ unlock(p);/归一化为oom _ score _ adj units /adj =total pages/1000;点数=adj/ 无论根奖金和 oom_score_adj(此处oom_score_adj不能为OOM_SCORE_ADJ_MIN)如何,对符合条件的任务绝不返回0。/返点0?分1;}
为了尽快做出选择,这里的逻辑尽量简单。除了明确标记不能被杀死的进程,直接选择占用内存最多的进程。(还有一个额外的oom_score_adj可以用来控制权重)
该选项的两个主要优点是
可以回收大量内存;可以避免在OOM解除后,该进程后续对内存的抢占造成后续OOM。让我们把注意力转回Docker本身。在生产环境中,我们通常使用Docker启动多个容器来运行服务。当遇到OOM时,如果Docker进程被杀死,也会对我们的服务造成很大的影响。
,Docker在启动时默认设置了-500 oom_score_adj,以尽可能避免Docker进程本身被oom黑仔杀死。
如果我们希望一个容器尽可能不被OOM黑仔杀死,那么我们可以为它的delivery-oom-score-adj配置一个较低的值
注意,不要通过-oom - oom-kill-disable禁用OOM黑仔,或者将容器的oom_score_adj值设置为低于dockerd进程的值,这在某些情况下可能会导致系统的不稳定。除非你清楚的知道你操作的影响。
管理容器的内存资源。
在介绍完OOM之后,我们将继续介绍如何管理容器的内存资源,相比之下你已经知道内存耗尽带来的危害。
(moe love)~ docker run-help | grep ' memory '-Kernel-Memory bytes Kernel Memory limit-m,-Memory bytes Memory limit-Memory-reservation bytes Memory soft limit-Memory-Swap bytes Swap limit等于Memory加swap: '-1 '启用无限制交换- memory-swappiness int Tune容器内存交换率(0到100)(默认值-1)
有几个可用的配置参数。我们通常直接使用- memory参数来限制容器的可用内存大小。我们也用几个例子进行介绍
启动一个容器并传递参数- memory 10 m,将其可用内存限制为10 m。
(moe love)~ docker run-RM-it-memory 10m alpine/#
那么我们如何验证它的可用内存大小呢?在物理机上,我们通常使用免费工具进行检查。它在容器环境中仍然有效吗?
/# free -m总的已用空闲共享缓冲区缓存内存15932 14491 1441 1814 564 3632-/缓冲区/缓存内存10294 5637交换区8471 693 7778
很明显,使用free的结果就是主机上的信息。,我们在前面已经介绍了docker stats命令,我们使用它来查看当前的资源使用情况
(moe love)~ docker stats-no-stream $(docker PS-QL)容器ID名称CPU % MEM使用率/限制MEM %净I/O块I/O PID se 260 e 91874 D8 busy _ napier 0.00% 1.172 MIB/10 MIB 11.72% 16.1 kb/0B 0B/0B 1
您可以看到,“MEM使用/限制”列中的信息已经生效,这是我们所期望的。
我们还有其他方法查看这些信息吗?
#在容器中执行/# cat/sys/fs/cgroup/memory/memory . limit _ in _ bytes 10485760
或者,您可以在主机上执行以下命令
(moe love)~ cat/sys/fs/cgroup/memory/system . slice/docker-$(docker inspect-format ' { {。Id}}' $(docker ps -ql))。scope/memory . limit _ in _ bytes 10485760
注意以上命令是在Linux 5.2内核下测试的,不同版本之间目录结构略有不同。
更新容器内存资源限制
当容器运行一段时间后,其中的进程会使用更多的内存,我们希望允许容器使用更多的内存资源。我们做什么呢
我们仍然可以用前面介绍的docker update命令来完成。
例如,使用以下命令将可用内存扩展到20m:
(moe love)~ Docker Update-Memory 20m $(Docker PS-QL)e 260e 91874 D8 #验证是否生效(moe love)~ Docker Stats-No-Stream $(Docker PS-QL)container id name CPU % MEM使用率/限制MEM %净I/O块I/O PID se 260e 91874 D8 busy _ napier 0.00% 1.434 MIB/20mb 7.17% 35.3 kb/0B 0B/0B 1
如果不够,需要扩容到100m怎么办?
(moe love)~ docker update-memory 100m $(docker PS-QL)来自守护进程的错误响应无法更新container e 260e 91874d 8181 b 6d 0078 c 853487613907 CD 9 ada 2 af 35d 630 a 7 bef 204654982:memory limit应小于已设置的memory WAP限制,更新memory WAP
您会在这里发现一条错误消息。内存限制应该小于配置的memoryswap限制,并且需要更新memoryswap。
你可能会困惑。之前我们只把内存限制在10m,扩展到20m就成功了。为什么到了100m就出问题了?
这涉及到这些参数的具体行为。让我给你一一介绍。
限制内存参数的特定行为
这里的具体参数行为主要是指我们前面用到的两个参数——内存和未引入的——内存交换。
1.-memory用于限制内存使用,而- memory-Swap表示内存和交换的总和。
这就解释了上面的“内存限制应该小于总是设置的内存交换限制”,因为-memory-swap应该总是大于等于-memory(毕竟最小交换只能是0)。
2.如果只指定了- memory,那么最终- memory-swap将被设置为-memory的两倍。也就是说,在只传递-memory的情况下,容器只能使用与-memory大小相同的交换。
这也解释了上面的“直接扩展到20m可以成功,扩展到100m就会出错”。在上面的场景中,only-memory是10m,所以- memory-swap默认设置为20m。
3.如果- memory-Swap和- memory设置为相同的值,则意味着不使用交换。
4.如果- memory-Swap设置为-1,则意味着容器使用的交换不受限制。
5.如果设置了- memory-swap参数,则必须设置- memory参数。
至此,我已经介绍了容器资源管理的核心内容,包括管理容器的CPU资源和内存资源。对容器进行合理的资源控制,可以提高整个环境的稳定性,避免因资源抢占或大量内存占用而导致的OOM和进程杀戮。
管理CPU时,建议使用CPU,这样语义会更清晰。如果你熟悉Linux的CPU调度器CFS,并且有很强的定制需求,那么在这种情况下使用- cpu-period和- cpu-quota比较合适。
在管理内存时,有一个内存交换性参数需要注意。可以设置为0~100的百分比,与通常的交换行为基本一致。设置为0表示不使用匿名页面交换,设置为100表示可以交换匿名页面。如果未指定,默认情况下将从主机继承。
在本文中,我给出了一个关于在主机上查看容器内存限制的命令
(moe love)~ cat/sys/fs/cgroup/memory/system . slice/docker-$(docker inspect-format ' { {。Id}}' $(docker ps -ql))。scope/memory . limit _ in _ bytes 10485760
本文摘自GitChat专栏,戳链接查看详情https://gitbook.cn/m/mazi/comp/column?专栏Id=5d70cfdc4dc213091bfca46f
更多docker 容器资源管理,你真的学会了吗英文(docker可以控制很多资源,目前)相关信息请关注本站,本文仅仅做为展示!