docker 进程守护(docker 进程管理)

docker 进程守护(docker 进程管理)p class f center p

大家好,我是讯享网,很高兴认识大家。




讯享网

 <p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2020%2F0129%2F78ce02ddj00q4tuqj001kc200sf00ixg00sf00ix.jpg&thumbnail=660x&quality=80&type=jpg"/><br/></p><p>  本文经授权转载自GitChat(ID:GitChat)</p><p>  作者 | 张晋涛</p><p>  责编 | 胡巍巍</p><p>  Docker 上手很容易,但如果将其应用于生产环境,则需要对它有更深入的理解。只有这样,才能确保应用符合我们的预期,或在遇到问题时可及时解决。所以,要想真正掌握 Docker 的核心知识,只靠网络上零散的信息往往是不够的,必须系统性地学习。</p><p>  容器,作为 Docker 的核心特性之一,是 Docker 使用者们无法回避的重要知识点。要想了解容器的核心原理,甚至自己动手写容器,不深入了解容器资源管理的相关的内容是绝对不行的。</p><p>  本文将以容器资源管理为主题,解决以下三个问题:</p><p>  哪些分配给容器的资源可被我们管理?</p><p>  容器实际使用了多少资源?</p><p>  如何对容器使用的资源进行管理?</p><p>  <strong>资源类型</strong></p><p>  对于第一个问题,当我们启动一个容器的时候,它可以使用一些系统资源,这与我们在物理机上启动程序基本是一致的。比如主要的几类:</p><p>  CPU</p><p>  内存</p><p>  网络</p><p>  I/O</p><p>  GPU</p><p>  这些系统资源是在我们启动容器时,需要考虑和可被我们管理的。比如,我们可以执行 docker run --help 查看 docker run 命令所支持的全部参数。现在 docker run 命令所支持的参数已超过 90 项,这里就不一一列出了。</p><p>  <strong>查看容器占用资源</strong></p><p>  <strong>docker stats</strong></p><p>  Docker 提供了一个很方便的命令 docker stats,可供我们查看和统计容器所占用的资源情况。</p><p>  我们仍然启动一个 Redis 容器作为示例。</p><p>  # 启动一个容器<br/>(MoeLove) ~ docker run -d redis<br/>c98c9831ee73e9b71719b404f5ecf3b408de0b69aec0f781e42dd28ada<br/># 查看其所占用资源的情况<br/>(MoeLove) ~ docker stats --no-stream $(docker ps -ql)<br/>CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS<br/>c98c9831ee73 amazing_torvalds 0.08% 2.613MiB / 15.56GiB 0.02% 3.66kB / 0B 0B / 0B 4<br/></p><p>  这里传递了一个 --no-stream 的参数,是因为 docker stats 命令默认是一个持续的动态流式输出(每秒一次),给它传递 --no-stream 参数后,它就只输出一次便会退出了。</p><p>  接下来我为你介绍下它输出内容的含义:</p><p>  Container ID:容器的 ID,也是一个容器生命周期内不会变更的信息。</p><p>  Name:容器的名称,如果没有手动使用 --name 参数指定,则 Docker 会随机生成一个,运行过程中也可以通过命令修改。</p><p>  CPU %:容器正在使用的 CPU 资源的百分比,这里面涉及了比较多细节,下面会详细说。</p><p>  Mem Usage/Limit:当前内存的使用及容器可用的最大内存,这里我使用了一台 16G 的电脑进行测试。</p><p>  Mem %:容器正在使用的内存资源的百分比。</p><p>  Net I/O:容器通过其网络接口发送和接受到的数据量。</p><p>  Block I/O:容器通过块设备读取和写入的数据量。</p><p>  Pids:容器创建的进程或线程数。</p><p>  <strong>docker top</strong></p><p>  除了上面提到的 docker stats 命令外,Docker 也提供了另一个比较简单的命令 docker top,与我们平时用的 ps 命令基本一致, 也支持 ps 命令的参数。</p><p>  (MoeLove) ~ docker top $(docker ps -ql)<br/>UID PID PPID C STIME TTY TIME CMD<br/>systemd+ 6275 6248 0 16:50 ? 00:00:24 redis-server *:6379<br/># 可以使用 ps 命令的参数<br/>(MoeLove) ~ docker top $(docker ps -ql) -o pid,stat,cmd<br/>PID STAT CMD<br/>6275 Ssl redis-server *:6379<br/></p><p>  <strong>管理容器的 CPU 资源</strong><br/></p><p>  在我们使用容器的时候,CPU 和内存是我们尤为关注的资源。不过,对于 CPU 资源的管理,涉及的内容会比较偏底层一些,有些涉及到了内核的 CPU 调度器,比如 CFS(Completely Fair Scheduler)等。</p><p>  我们可以先来查看下 Docker 提供了哪些控制 CPU 资源相关的参数。使用 docker run --help |grep CPU 即可查看。</p><p>  (MoeLove) ~ docker run --help |grep CPU<br/>--cpu-period int Limit CPU CFS (Completely Fair Scheduler) period<br/>--cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota<br/>--cpu-rt-period int Limit CPU real-time period in microseconds<br/>--cpu-rt-runtime int Limit CPU real-time runtime in microseconds<br/>-c, --cpu-shares int CPU shares (relative weight)<br/>--cpus decimal Number of CPUs<br/>--cpuset-cpus string CPUs in which to allow execution (0-3, 0,1)<br/></p><p>  这里暂时先不对参数的具体含义进行深入展开,我们直接以几个示例来分别进行说明,帮助大家理解。<br/></p><p>  <strong>默认无限制<br/></strong></p><p><blockquote>备注:我这里以一个 4 核 CPU 的电脑进行演示。</blockquote></p><p>  现在我们启动一个容器,我们以体积很小的 Alpine Linux 为例好了。</p><p>  (MoeLove) ~ docker run --rm -it alpine<br/>/ #<br/></p><p>  在另一个窗口,执行上面介绍的查看容器资源的命令:</p><p>  (MoeLove) ~ docker stats --no-stream $(docker ps -ql)<br/>CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS<br/>106a24399bc9 friendly_varahamihira 0.00% 1.047MiB / 15.56GiB 0.01% 5.01kB / 0B 1.67MB / 0B 1<br/></p><p>  可以看到,当前容器内没有过多的 CPU 消耗,且 PIDS 为 1,表示当前只有一个进程。</p><p>  现在我们回到刚才启动的容器,执行以下命令:</p><p>  sha256sum /dev/zero</p><p>  sha256sum 是一个用于计算和检查 SHA256 信息的命令行工具;</p><p>  /dev/zero 是 Linux 系统上一个特殊的设备,在读它时,它可以提供无限的空字符串(NULL 或者 0x00 之类的)。</p><p>  所以上面的命令,会让 sha256sum 持续地读 /dev/zero 产生的空串,并进行计算。这将迅速地消耗 CPU 资源。</p><p>  我们来看看此时容器的资源使用情况:</p><p>  (MoeLove) ~ docker stats --no-stream $(docker ps -ql)<br/>CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS<br/>106a24399bc9 friendly_varahamihira 100.59% 1.5MiB / 15.56GiB 0.01% 14.4kB / 0B 1.99MB / 0B 2<br/>(MoeLove) ~ docker top $(docker ps -ql) -o pid,c,cmd<br/>PID C CMD<br/>825 0 /bin/sh<br/>965 99 sha256sum /dev/zero<br/></p><p>  可以看到当前的 CPU 使用率已经在 100% 左右了。</p><p>  我们再新打开一个窗口,进入容器内,执行相同的命令:</p><p>  (MoeLove) ~ docker exec -it $(docker ps -ql) sh<br/>/ # sha256sum /dev/zero<br/></p><p>  查看容器使用资源的情况:<br/></p><p>  (MoeLove) ~ docker stats -- no-stream $(docker ps -ql)<br/>CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS<br/>f359d4ff6fc6 nice_zhukovsky 200.79% 1.793MiB / 15.56GiB 0.01% 4.58kB / 0B 0B / 0B 4<br/>(MoeLove) ~ docker top $(docker ps -ql) -o pid,c,cmd<br/>PID C CMD<br/>825 0 /bin/sh<br/>965 99 sha256sum /dev/zero<br/>1236 0 sh<br/>1297 99 sha256sum /dev/zero<br/></p><p>  可以看到现在两个进程,已经让两个 CPU 满负载运行了。这里需要额外说明的是,选择 sha256sum 作为示例,是因为它是单线程程序,每次启动一个 sha256sum 并不会消耗其他 CPU 核的资源。<br/></p><p>  由此可以得出的结论是,如果不对容器内程序进行 CPU 资源限制,其可能会消耗掉大量 CPU 资源,进而影响其他程序或者影响系统的稳定。</p><p>  <strong>分配 0.5 CPU</strong></p><p>  那接下来,我们对这个容器进行 CPU 资源的限制,比如限制它只可以使用 0.5 CPU。</p><p>  (MoeLove) ~ docker update --cpus "0.5" $(docker ps -ql)<br/>f359d4ff6fc6<br/></p><p>  我们可以重新启动一个容器,在 docker run 时,为它添加资源限制。<br/></p><p>  但我来给你介绍一种动态更改资源限制的办法,使用 docker update 命令。例如,在此例子中,我们使用如下命令,限制该容器只能使用 0.5 CPU。</p><p>  为了方便,我们直接关闭刚才的 sha256sum 进程,按 Ctrl+c 终止进程。然后重新运行该命令:</p><p>  # 终止进程<br/>/ # sha256sum /dev/zero<br/>^C<br/># 启动程序<br/>/ # sha256sum /dev/zero<br/></p><p>  查看资源占用情况:<br/></p><p>  (MoeLove) ~ docker stats -- no-stream $(docker ps -ql)<br/>CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS<br/>f359d4ff6fc6 nice_zhukovsky 49.87% 1.777MiB / 15.56GiB 0.01% 112kB / 0B 1.59MB / 0B 3</p><p>  (MoeLove) ~ docker top $(docker ps -ql) -o pid,c,cmd<br/>PID C CMD<br/>825 0 /bin/sh<br/>1236 0 sh<br/>7662 49 sha256sum /dev/zero<br/></p><p>  可以看到,该进程使用了 50% 左右的 CPU。我们接下来再启动另一个 sha256sum 的进程:<br/></p><p>  / # sha256sum /dev/zero<br/></p><p>  查看资源使用情况:<br/></p><p>  (MoeLove) ~ docker stats -- no-stream $(docker ps -ql)<br/>CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS<br/>f359d4ff6fc6 nice_zhukovsky 50.92% 1.891MiB / 15.56GiB 0.01% 113kB / 0B 1.59MB / 0B 4</p><p>  (MoeLove) ~ docker top $(docker ps -ql) -o pid,c,cmd<br/>PID C CMD<br/>825 0 /bin/sh<br/>1236 0 sh<br/></p><p>  可以看到,该容器整体占用了 50% 的 CPU,而其中的两个 sha256sum 进程则各占了 25%。<br/></p><p>  我们已经成功的按预期为它分配了 0.5 CPU。</p><p>  <strong>分配 1.5 CPU</strong></p><p>  接下来,重复上述步骤,但是为它分配 1.5 CPU,来看看它的实际情况如何。</p><p>  # 更新配置,使用 1.5 CPU<br/>(MoeLove) ~ docker update --cpus "1.5" $(docker ps -ql)<br/>f359d4ff6fc6<br/></p><p>  分别使用之前的两个窗口,执行 sha256sum /dev/zero 进行测试:<br/></p><p>  / # sha256sum /dev/zero<br/></p><p>  查看资源使用情况:<br/></p><p>  (MoeLove) ~ docker stats -- no-stream $(docker ps -ql)<br/>CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS<br/>f359d4ff6fc6 nice_zhukovsky 151.23% 2MiB / 15.56GiB 0.01% 122kB / 0B 1.59MB / 0B 4</p><p>  (MoeLove) ~ docker top $(docker ps -ql) -o pid,c,cmd<br/>PID C CMD<br/>825 0 /bin/sh<br/>1236 0 sh<br/>25167 77 sha256sum /dev/zero<br/>25211 74 sha256sum /dev/zero<br/></p><p>  可以看到,结果与我们的预期基本相符,150% 左右的 CPU,而两个测试进程,也差不多是平分了 CPU 资源。<br/></p><p>  <strong>指定可使用 CPU 核</strong></p><p>  可以使用 --cpuset-cpus 来指定分配可使用的 CPU 核,这里我指定为 0,表示使用第一个 CPU 核。</p><p>  (MoeLove) ~ docker update --cpus "1.5" --cpuset-cpus 0 $(docker ps -ql)<br/>f359d4ff6fc6<br/></p><p>  分别使用之前的两个窗口,执行 sha256sum /dev/zero 进行测试:<br/></p><p>  / # sha256sum /dev/zero<br/></p><p>  查看资源情况:<br/></p><p>  (MoeLove) ~ docker stats -- no-stream $(docker ps -ql)<br/>CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS<br/>f359d4ff6fc6 nice_zhukovsky 99.18% 1.988MiB / 15.56GiB 0.01% 221kB / 0B 1.59MB / 0B 4<br/>(MoeLove) ~ docker top $(docker ps -ql) -o pid,c,cmd<br/>PID C CMD<br/>825 0 /bin/sh<br/>1236 0 sh<br/>25119 50 sha256sum /dev/zero<br/>25164 48 sha256sum /dev/zero<br/></p><p>  可以看到,虽然我们仍然使用 --cpus 指定了 1.5 CPU,但由于使用 --cpuset-cpus 限制只允许它跑在第一个 CPU 上,所以这两个测试进程也就只能评分该 CPU 了。本文节选自专栏。<br/></p><p>  <strong>小结</strong></p><p>  通过上述的示例,我介绍了如何通过 --cpus 参数限制容器可使用的 CPU 资源;通过 --cpuset-cpus 参数可指定容器内进程运行所用的 CPU 核心;通过 docker update 可直接更新一个正在运行的容器的相关配置。</p><p>  现在我们回到前面使用 docker run --help | grep CPU,查看 Docker 支持的对容器 CPU 相关参数的选项:</p><p>  (MoeLove) ~ docker run --help |grep CPU<br/>--cpu-period int Limit CPU CFS (Completely Fair Scheduler) period<br/>--cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota<br/>--cpu-rt-period int Limit CPU real- time period in microseconds<br/>--cpu-rt-runtime int Limit CPU real- time runtime in microseconds<br/>-c, --cpu-shares int CPU shares (relative weight)<br/>--cpus decimal Number of CPUs<br/>--cpuset-cpus string CPUs in which to allow execution ( 0-3, 0, 1)<br/></p><p>  --cpus 是在 Docker 1.13 时新增的,可用于替代原先的 --cpu-period 和 --cpu-quota。这三个参数通过 cgroups 最终会实际影响 Linux 内核的 CPU 调度器 CFS(Completely Fair Scheduler, 完全公平调度算法)对进程的调度结果。<br/></p><p>  一般情况下,推荐直接使用 --cpus,而无需单独设置 --cpu-period 和 --cpu-quota,除非你已经对 CPU 调度器 CFS 有了足够多的了解,提供 --cpus 参数也是 Docker 团队为了可以简化用户的使用成本增加的,它足够满足我们大多数的需求。</p><p>  而 --cpu-shares 选项,它虽然有一些实际意义,但却不如 --cpus 来的直观,并且它会受到当前系统上运行状态的影响,为了不因为它给大家带来困扰,此处就不再进行介绍了。</p><p>  --cpu-rt-period 和 --cpu-rt-runtime 两个参数,会影响 CPU 的实时调度器。但实时调度器需要内核的参数的支持,并且配置实时调度器也是个高级或者说是危险的操作,有可能会导致各种奇怪的问题,此处也不再进行展开。</p><p>  管理容器的内存资源</p><p>  前面已经介绍了如何管理容器的 CPU 资源,接下来我们看看如何管理容器的内存资源。相比 CPU 资源来说,内存资源的管理就简单很多了。</p><p>  同样的,我们先看看有哪些参数可供我们配置,对于其含义我会稍后进行介绍:</p><p>  (MoeLove) ~ docker run -- help |egrep 'memory|oom'<br/>--kernel-memory bytes Kernel memory limit<br/>-m, --memory bytes Memory limit<br/>--memory-reservation bytes Memory soft limit<br/>--memory-swap bytes Swap limit equal to memory plus swap: '-1' to enable unlimited swap<br/>--memory-swappiness int Tune container memory swappiness (0 to 100) (default -1)<br/>--oom-kill-disable Disable OOM Killer<br/>--oom-score-adj int Tune host 's OOM preferences (-1000 to 1000)<br/></p><p>  <strong>OOM</strong><br/></p><p>  在开始进行容器内存管理的内容前,我们不妨先聊一个很常见,又不得不面对的问题:OOM(Out Of Memory)。</p><p>  当内核检测到没有足够的内存来运行系统的某些功能时候,就会触发 OOM 异常,并且会使用 OOM Killer 来杀掉一些进程,腾出空间以保障系统的正常运行。</p><p>  这里简单介绍下 OOM killer 的大致执行过程,以便于大家理解后续内容。</p><p>  内核中 OOM Killer 的代码,在 torvalds/linux/mm/oom_kill.c 可直接看到,这里以 Linux Kernel 5.2 为例。</p><p>  引用其中的一段注释:</p><p><blockquote>If we run out of memory, we have the choice between either killing a random task (bad), letting the system crash (worse).</blockquote><blockquote>OR try to be smart about which process to kill. Note that we don't have to be perfect here, we just have to be good.</blockquote></p><p>  翻译过来就是,当我们处于 OOM 时,我们可以有几种选择,随机地杀死任意的任务(不好),让系统崩溃(更糟糕)或者尝试去了解可以杀死哪个进程。注意,这里我们不需要追求完美,我们只需要变好(be good)就行了。</p><p>  事实上确实如此,无论随机地杀掉任意进程或是让系统崩溃,那都不是我们想要的。</p><p>  回到内核代码中,当系统内存不足时,out_of_memory() 被触发,之后会调用 select_bad_process() 函数,选择一个 bad 进程来杀掉。</p><p>  那什么样的进程是 bad 进程呢?总是有些条件的。select_bad_process() 是一个简单的循环,其调用了 oom_evaluate_task() 来对进程进行条件计算,最核心的判断逻辑是其中的 oom_badness()。</p><p>  unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,<br/>const nodemask_t *nodemask, unsigned long totalpages)<br/>{<br/>long points;<br/>long adj;</p><p>  if (oom_unkillable_task(p, memcg, nodemask))<br/>return 0;</p><p>  p = find_lock_task_mm(p);<br/>if (!p)<br/>return 0;</p><p>  /*<br/>* Do not even consider tasks which are explicitly marked oom<br/>* unkillable or have been already oom reaped or the are in<br/>* the middle of vfork<br/>*/<br/>adj = ( long)p-&gt;signal-&gt;oom_score_adj;<br/>if (adj == OOM_SCORE_ADJ_MIN ||<br/>test_bit(MMF_OOM_SKIP, &amp;p-&gt;mm-&gt;flags) ||<br/>in_vfork(p)) {<br/>task_unlock(p);<br/>return 0;<br/>}</p><p>  /*<br/>* The baseline for the badness score is the proportion of RAM that each<br/>* task's rss, pagetable and swap space use.<br/>*/<br/>points = get_mm_rss(p-&gt;mm) + get_mm_counter(p-&gt;mm, MM_SWAPENTS) +<br/>mm_pgtables_bytes(p-&gt;mm) / PAGE_SIZE;<br/>task_unlock(p);</p><p>  /* Normalize to oom_score_adj units */<br/>adj *= totalpages / 1000;<br/>points += adj;</p><p>  /*<br/>* Never return 0 for an eligible task regardless of the root bonus and<br/>* oom_score_adj (oom_score_adj can't be OOM_SCORE_ADJ_MIN here).<br/>*/<br/>return points &gt; 0 ? points : 1;<br/>}<br/></p><p>  而为了能够最快地进行选择,这里的逻辑也是尽可能的简单,除了明确标记不可杀掉的进程外,直接选择内存占用最多的进程。(当然,还有一个额外的 oom_score_adj 可用于控制权重)<br/></p><p>  这种选择的最主要的两个好处是:</p><p>  可以回收很多内存;</p><p>  可以避免缓解 OOM 后,该进程后续对内存的抢占引发后续再次的 OOM。</p><p>  我们将注意力再回到 Docker 自身,在生产环境中,我们通常会用 Docker 启动多个容器运行服务。当遇到 OOM 时,如果 Docker 进程被杀掉,那对我们的服务也会带来很大的影响。</p><p>  所以 Docker 在启动的时候默认设置了一个 -500 的 oom_score_adj 以尽可能地避免 Docker 进程本身被 OOM Killer 给杀掉。</p><p>  如果我们想让某个容器,尽可能地不要被 OOM Killer 杀掉,那我们可以给它传递 --oom-score-adj 配置一个比较低的数值。</p><p>  但是注意:不要通过 --oom-kill-disable 禁用掉 OOM Killer,或者给容器设置低于 dockerd 进程的 oom_score_adj 值,这可能会导致某些情况下系统的不稳定。除非你明确知道自己的操作将会带来的影响。</p><p>  <strong>管理容器的内存资源</strong></p><p>  介绍完了 OOM,相比你已经知道了内存耗尽所带来的危害,我们来继续介绍如何管理容器的内存资源。</p><p>  (MoeLove) ~ docker run -- help |grep 'memory'<br/>--kernel-memory bytes Kernel memory limit<br/>-m, --memory bytes Memory limit<br/>--memory-reservation bytes Memory soft limit<br/>--memory-swap bytes Swap limit equal to memory plus swap: '-1' to enable unlimited swap<br/>--memory-swappiness int Tune container memory swappiness (0 to 100) (default -1)<br/></p><p>  可用的配置参数有上述几个,我们通常直接使用 --memory 参数来限制容器可用的内存大小。我们同样使用几个示例进行介绍:<br/></p><p>  启动一个容器,并传递参数 --memory 10m 限制其可使用的内存为 10 m。</p><p>  (MoeLove) ~ docker run --rm -it --memory 10m alpine<br/>/ #<br/></p><p>  那我们如何验证它的可用内存大小是多少呢?在物理机上,我们通常使用 free 工具进行查看。但在容器环境内,它还是否生效呢?<br/></p><p>  / # free -m<br/>total used free shared buffers cached<br/>Mem: 15932 14491 1441 1814 564 3632<br/>-/+ buffers/cache: 10294 5637<br/>Swap: 8471 693 7778<br/></p><p>  很明显,使用 free 得到的结果是宿主机上的信息。当然,我们前面已经介绍了 docker stats 命令,我们使用它来查看当前的资源使用情况:<br/></p><p>  (MoeLove) ~ docker stats -- no-stream $(docker ps -ql)<br/>CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS<br/>e260e91874d8 busy_napier 0.00% 1.172MiB / 10MiB 11.72% 16.1kB / 0B<br/>0B / 0B 1<br/></p><p>  可以看到 MEM USAGE / LIMIT 那一列中的信息已经生效,是我们预期的样子。<br/></p><p>  那我们是否还有其他方式查看此信息呢?当然有:</p><p>  # 在容器内执行<br/>/ # cat /sys/fs/cgroup/memory/memory.limit_in_bytes<br/><br/></p><p>  或者可以在宿主机上执行以下命令:<br/></p><p>  (MoeLove) ~ cat /sys/fs/cgroup/memory/system.slice/docker-$(docker inspect --format '{{ .Id}}' $(docker ps -ql)).scope/memory.limit_in_bytes<br/><br/></p><p>  注意:以上命令在 Linux 5.2 内核下测试通过,不同版本之间目录结构略有差异。<br/></p><p>  <strong>更新容器内存资源限制</strong></p><p>  当容器运行一段时间,其中的进程使用的内存变多了,我们想允许容器使用更多内存资源,那要如何操作呢?</p><p>  我们仍然可以用前面介绍的 docker update 命令完成。</p><p>  比如使用如下命令,将可用内存扩大至 20m:</p><p>  (MoeLove) ~ docker update --memory 20m $(docker ps -ql)<br/>e260e91874d8<br/># 验证是否生效<br/>(MoeLove) ~ docker stats --no-stream $(docker ps -ql)<br/>CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS<br/>e260e91874d8 busy_napier 0.00% 1.434MiB / 20MiB 7.17% 35.3kB / 0B 0B / 0B 1<br/></p><p>  如果还不够,需要扩大至 100m 呢?<br/></p><p>  (MoeLove) ~ docker update --memory 100m $(docker ps -ql)<br/>Error response from daemon: Cannot update container e260e91874d8181b6d0078c7cd9ada2af35d630a7bef: Memory limit should be smaller than already set memoryswap limit, update the memoryswap at the same time<br/></p><p>  会发现这里有个报错信息。大意是 memory limit 应该比已经配置的 memoryswap limit 小,需要同时更新 memoryswap。<br/></p><p>  你可能会困惑,之前我们只是限制了内存为 10m,并且扩大至 20m 的时候是成功了的。为什么到 100m 的时候就会出错?</p><p>  这就涉及到了这些参数的特定行为了,我来为你一一介绍。</p><p>  <strong>内存限制参数的特定行为</strong></p><p>  这里的特定参数行为,主要是指我们前面使用的 --memory 和未介绍过的 --memory-swap 这两个参数。</p><p>  1. --memory 用于限制内存使用量,而 --memory-swap 则表示内存和 Swap 的总和。</p><p>  这解释了上面“Memory limit should be smaller than already set memoryswap limit”,因为 --memory-swap 始终应该大于等于 --memory (毕竟 Swap 最小也只能是 0 )。</p><p>  2. 如果只指定了 --memory 则最终 --memory-swap 将会设置为 --memory 的两倍。也就是说,在只传递 --memory 的情况下,容器只能使用与 --memory 相同大小的 Swap。</p><p>  这也解释了上面“直接扩大至 20m 的时候能成功,而扩大到 100m 的时候会出错”,在上述场景中只指定了 --memory 为 10m,所以 --memory-swap 就默认被设置成了 20m。</p><p>  3. 如果 --memory-swap 和 --memory 设置了相同值,则表示不使用 Swap。</p><p>  4. 如果 --memory-swap 设置为 -1 则表示不对容器使用的 Swap 进行限制。</p><p>  5. 如果设置了 --memory-swap 参数,则必须设置 --memory 参数。</p><p>  至此,我介绍了容器资源管理的核心内容,包括管理容器的 CPU 资源和内存资源。为容器进行合理的资源控制,有利于提高整体环境的稳定性,避免资源抢占或大量内存占用导致 OOM,进程被杀掉等情况。</p><p>  对 CPU 进行管理时,建议使用 --cpus,语义方面会比较清晰。如果是对 Linux 的 CPU 调度器 CFS 很熟悉,并且有强烈的定制化需求,这种情况下再使用 --cpu-period 和 --cpu-quota 比较合适。</p><p>  对内存进行管理时,有个 --memory-swappiness 参数也需要注意下,它可设置为 0~100 的百分比,与我们平时见到的 swappiness 行为基本一致,设置为 0 表示不使用匿名页面交换,设置为 100 则表示匿名页面都可被交换。如果不指定的话,它默认会从主机上继承。</p><p>  在本文中,关于在宿主机上查看容器的内存限制,我给出了一个命令:</p><p>  (MoeLove) ~ cat /sys/fs/cgroup/memory/system.slice/docker-$(docker inspect --format '{{ .Id}}' $(docker ps -ql)).scope/memory.limit_in_bytes<br/><br/></p><p>  本文节选自GitChat专栏,戳链接查看详情:https://gitbook.cn/m/mazi/comp/column?columnId=5d70cfdc4dcbfca46f</p><p>  【END】</p> 

讯享网
小讯
上一篇 2025-06-08 13:52
下一篇 2025-04-20 22:43

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/152351.html