docker容器使用內(nèi)存大小限制方法
前言
本文介紹如何通過docker運(yùn)行參數(shù)配置限制docker容器可以使用的內(nèi)存上限。docker容器默認(rèn)可以使用全部宿主機(jī)的所有內(nèi)存和 swap 分區(qū),比如宿主機(jī)的內(nèi)存是32G,則運(yùn)行一個(gè)docker容器最多可以分配到32G內(nèi)存,如果啟用了多個(gè)docker容器,則很快宿主機(jī)的內(nèi)存就耗盡了。
內(nèi)存限制相關(guān)參數(shù)如下:
選項(xiàng) | 描述 |
-m,--memory | 內(nèi)存限制,格式是數(shù)字加單位,單位可以為 b,k,m,g。最小為 4M |
--memory-swap | 內(nèi)存+交換分區(qū)大小總限制。格式同上。必須必-m設(shè)置的大 |
--memory-reservation | 內(nèi)存的軟性限制。格式同上 |
--oom-kill-disable | 是否阻止 OOM killer 殺死容器,默認(rèn)沒設(shè)置 |
--oom-score-adj | 容器被 OOM killer 殺死的優(yōu)先級(jí),范圍是[-1000, 1000],默認(rèn)為 0 |
--memory-swappiness | 用于設(shè)置容器的虛擬內(nèi)存控制行為。值為 0~100 之間的整數(shù) |
--kernel-memory | 核心內(nèi)存限制。格式同上,最小為 4M |
一、使用內(nèi)存限制
用戶內(nèi)存限制就是對容器能使用的內(nèi)存和交換分區(qū)的大小作出限制。使用時(shí)要遵循兩條直觀的規(guī)則:-m,--memory選項(xiàng)的參數(shù)最小為 4 M。--memory-swap不是交換分區(qū),而是內(nèi)存加交換分區(qū)的總大小,所以--memory-swap必須比-m,--memory大。在這兩條規(guī)則下,一般有四種設(shè)置方式。
你可能在進(jìn)行內(nèi)存限制的實(shí)驗(yàn)時(shí)發(fā)現(xiàn) docker run命令報(bào)錯(cuò):WARNING: Your kernel does not support swap limit capabilities, memory limited without swap.
這是因?yàn)樗拗鳈C(jī)內(nèi)核的相關(guān)功能沒有打開。按照下面的設(shè)置就行。
step 1:編輯 /etc/default/grub文件,將 GRUB_CMDLINE_LINUX一行改為 GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
step 2:更新 GRUB,即執(zhí)行 $ sudo update-grub
step 3: 重啟系統(tǒng)。
1. 不設(shè)置
如果不設(shè)置-m,--memory和--memory-swap,容器默認(rèn)可以用完宿舍機(jī)的所有內(nèi)存和 swap 分區(qū)。不過注意,如果容器占用宿主機(jī)的所有內(nèi)存和 swap 分區(qū)超過一段時(shí)間后,會(huì)被宿主機(jī)系統(tǒng)殺死(如果沒有設(shè)置--00m-kill-disable=true的話)。
2. 設(shè)置-m,--memory,不設(shè)置--memory-swap
給-m或--memory設(shè)置一個(gè)不小于 4M 的值,假設(shè)為 a,不設(shè)置--memory-swap,或?qū)?-memory-swap設(shè)置為 0。這種情況下,容器能使用的內(nèi)存大小為 a,能使用的交換分區(qū)大小也為 a。因?yàn)?Docker 默認(rèn)容器交換分區(qū)的大小和內(nèi)存相同。
如果在容器中運(yùn)行一個(gè)一直不停申請內(nèi)存的程序,你會(huì)觀察到該程序最終能占用的內(nèi)存大小為 2a。
比如$ docker run -m 1G ubuntu:16.04,該容器能使用的內(nèi)存大小為 1G,能使用的 swap 分區(qū)大小也為 1G。容器內(nèi)的進(jìn)程能申請到的總內(nèi)存大小為 2G。
3. 設(shè)置-m,--memory=a,--memory-swap=b,且b > a
給-m設(shè)置一個(gè)參數(shù) a,給--memory-swap設(shè)置一個(gè)參數(shù) b。a 時(shí)容器能使用的內(nèi)存大小,b是容器能使用的 內(nèi)存大小 + swap 分區(qū)大小。所以 b 必須大于 a。b -a 即為容器能使用的 swap 分區(qū)大小。
比如$ docker run -m 1G --memory-swap 3G ubuntu:16.04,該容器能使用的內(nèi)存大小為 1G,能使用的 swap 分區(qū)大小為 2G。容器內(nèi)的進(jìn)程能申請到的總內(nèi)存大小為 3G。
4. 設(shè)置-m,--memory=a,--memory-swap=-1
給-m參數(shù)設(shè)置一個(gè)正常值,而給--memory-swap設(shè)置成 -1。這種情況表示限制容器能使用的內(nèi)存大小為 a,而不限制容器能使用的 swap 分區(qū)大小。
這時(shí)候,容器內(nèi)進(jìn)程能申請到的內(nèi)存大小為 a + 宿主機(jī)的 swap 大小。
二、Memory reservation
這種 memory reservation 機(jī)制不知道怎么翻譯比較形象。Memory reservation 是一種軟性限制,用于節(jié)制容器內(nèi)存使用。給--memory-reservation設(shè)置一個(gè)比-m小的值后,雖然容器最多可以使用-m使用的內(nèi)存大小,但在宿主機(jī)內(nèi)存資源緊張時(shí),在系統(tǒng)的下次內(nèi)存回收時(shí),系統(tǒng)會(huì)回收容器的部分內(nèi)存頁,強(qiáng)迫容器的內(nèi)存占用回到--memory-reservation設(shè)置的值大小。
沒有設(shè)置時(shí)(默認(rèn)情況下)--memory-reservation的值和-m的限定的值相同。將它設(shè)置為 0 會(huì)設(shè)置的比-m的參數(shù)大 等同于沒有設(shè)置。
Memory reservation 是一種軟性機(jī)制,它不保證任何時(shí)刻容器使用的內(nèi)存不會(huì)超過--memory-reservation限定的值,它只是確保容器不會(huì)長時(shí)間占用超過--memory-reservation限制的內(nèi)存大小。
例如:
$ docker run -it -m 500M --memory-reservation 200M ubuntu:16.04 /bin/bash1
如果容器使用了大于 200M 但小于 500M 內(nèi)存時(shí),下次系統(tǒng)的內(nèi)存回收會(huì)嘗試將容器的內(nèi)存鎖緊到 200M 以下。
例如:
$ docker run -it--memory-reservation 1G ubuntu:16.04 /bin/bash1
容器可以使用盡可能多的內(nèi)存。--memory-reservation確保容器不會(huì)長時(shí)間占用太多內(nèi)存。
三、OOM killer
默認(rèn)情況下,在出現(xiàn) out-of-memory(OOM) 錯(cuò)誤時(shí),系統(tǒng)會(huì)殺死容器內(nèi)的進(jìn)程來獲取更多空閑內(nèi)存。這個(gè)殺死進(jìn)程來節(jié)省內(nèi)存的進(jìn)程,我們姑且叫它 OOM killer。我們可以通過設(shè)置--oom-kill-disable選項(xiàng)來禁止 OOM killer 殺死容器內(nèi)進(jìn)程。但請確保只有在使用了-m/--memory選項(xiàng)時(shí)才使用--oom-kill-disable禁用 OOM killer。如果沒有設(shè)置-m選項(xiàng),卻禁用了 OOM-killer,可能會(huì)造成出現(xiàn) out-of-memory 錯(cuò)誤時(shí),系統(tǒng)通過殺死宿主機(jī)進(jìn)程或獲取更改內(nèi)存。
下面的例子限制了容器的內(nèi)存為 100M 并禁止了 OOM killer:
$ docker run -it-m100M --oom-kill-disable ubuntu:16.04 /bin/bash1
是正確的使用方法。
而下面這個(gè)容器沒設(shè)置內(nèi)存限制,卻禁用了 OOM killer 是非常危險(xiǎn)的:
$ docker run -it--oom-kill-disable ubuntu:16.04 /bin/bash1
容器沒用內(nèi)存限制,可能或?qū)е孪到y(tǒng)無內(nèi)存可用,并嘗試時(shí)殺死系統(tǒng)進(jìn)程來獲取更多可用內(nèi)存。
一般一個(gè)容器只有一個(gè)進(jìn)程,這個(gè)唯一進(jìn)程被殺死,容器也就被殺死了。我們可以通過--oom-score-adj選項(xiàng)來設(shè)置在系統(tǒng)內(nèi)存不夠時(shí),容器被殺死的優(yōu)先級(jí)。負(fù)值更教不可能被殺死,而正值更有可能被殺死。
四、kernel-memory核心內(nèi)存限制
核心內(nèi)存和用戶內(nèi)存不同的地方在于核心內(nèi)存不能被交換出。不能交換出去的特性使得容器可以通過消耗太多內(nèi)存來堵塞一些系統(tǒng)服務(wù)。核心內(nèi)存包括:
- stack pages(棧頁面)
- slab pages
- socket memory pressure
- tcp memory pressure
可以通過設(shè)置核心內(nèi)存限制來約束這些內(nèi)存。例如,每個(gè)進(jìn)程都要消耗一些棧頁面,通過限制核心內(nèi)存,可以在核心內(nèi)存使用過多時(shí)阻止新進(jìn)程被創(chuàng)建。
核心內(nèi)存和用戶內(nèi)存并不是獨(dú)立的,必須在用戶內(nèi)存限制的上下文中限制核心內(nèi)存。
假設(shè)用戶內(nèi)存的限制值為 U,核心內(nèi)存的限制值為 K。有三種可能地限制核心內(nèi)存的方式:
- U != 0,不限制核心內(nèi)存。這是默認(rèn)的標(biāo)準(zhǔn)設(shè)置方式
- K < U,核心內(nèi)存時(shí)用戶內(nèi)存的子集。這種設(shè)置在部署時(shí),每個(gè) cgroup 的內(nèi)存總量被過度使用。過度使用核心內(nèi)存限制是絕不推薦的,因?yàn)橄到y(tǒng)還是會(huì)用完不能回收的內(nèi)存。在這種情況下,你可以設(shè)置 K,這樣 groups 的總數(shù)就不會(huì)超過總內(nèi)存了。然后,根據(jù)系統(tǒng)服務(wù)的質(zhì)量自有地設(shè)置 U。
- K > U,因?yàn)楹诵膬?nèi)存的變化也會(huì)導(dǎo)致用戶計(jì)數(shù)器的變化,容器核心內(nèi)存和用戶內(nèi)存都會(huì)觸發(fā)回收行為。這種配置可以讓管理員以一種統(tǒng)一的視圖看待內(nèi)存。對想跟蹤核心內(nèi)存使用情況的用戶也是有用的。
例如:
$ docker run -it -m 500M --kernel-memory 50M ubuntu:16.04 /bin/bash1
容器中的進(jìn)程最多能使用 500M 內(nèi)存,在這 500M 中,最多只有 50M 核心內(nèi)存。
$ docker run -it--kernel-memory 50M ubuntu:16.04 /bin/bash1
沒用設(shè)置用戶內(nèi)存限制,所以容器中的進(jìn)程可以使用盡可能多的內(nèi)存,但是最多能使用 50M 核心內(nèi)存。
五、驗(yàn)證
可以通過docker stats命令查看docker容器的內(nèi)存使用情況,來驗(yàn)證內(nèi)存設(shè)置是否生效。可以看到容器默認(rèn)可使用的最大內(nèi)存上限與宿主機(jī)內(nèi)存一致,設(shè)置--memory 1G參數(shù)后,最大可以使用的內(nèi)存被限制為1G。
docker stats
總結(jié)
到此這篇關(guān)于docker容器使用內(nèi)存大小限制的文章就介紹到這了,更多相關(guān)docker容器內(nèi)存大小限制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文教會(huì)你用Docker打包Python運(yùn)行環(huán)境
Docker提供了容器級(jí)別的資源隔離,由于Python的外部依賴管理中存在的問題,我們通常會(huì)使用virtualenv來對不同的項(xiàng)目創(chuàng)建其唯一的依賴環(huán)境,下面這篇文章主要給大家介紹了如何通過一篇文章教會(huì)你用Docker打包Python運(yùn)行環(huán)境的相關(guān)資料,需要的朋友可以參考下2022-05-05Linux Docker運(yùn)行springboot項(xiàng)目的步驟詳解
這篇文章主要介紹了Linux Docker運(yùn)行springboot項(xiàng)目的步驟詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01docker-compose啟動(dòng)的容器一直處于restarting狀態(tài)的問題解決
本文主要介紹了docker-compose啟動(dòng)的容器一直處于restarting狀態(tài)的問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-11-11docker打包鏡像后EasyExcel報(bào)錯(cuò),dockerfile缺少字體的解決
解決Docker打包鏡像后EasyExcel報(bào)錯(cuò)的問題:1. Dockerfile增加字體配置;2. 使用EasyExcel的write時(shí)添加"inMemory"參數(shù)為true,開啟內(nèi)存處理模式(不推薦,1W數(shù)據(jù)以內(nèi)可以考慮)2025-02-022025最新Docker國內(nèi)可用鏡像源倉庫地址分享
在使用Docker時(shí),您是否經(jīng)常遇到拉取鏡像緩慢或下載中斷的問題?特別是對于我們在國內(nèi)的開發(fā)者,網(wǎng)絡(luò)條件限制常常導(dǎo)致鏡像下載速度令人頭疼,為了讓您的開發(fā)工作更加順暢,小編特意收集并整理了2025年最新、可用的國內(nèi)Docker鏡像源地址,希望能大幅提升您的Docker下載速度2025-02-02Idea+docker通過dockerFile往華為云發(fā)布項(xiàng)目實(shí)踐
本文介紹了使用IntelliJ IDEA和Docker將Spring Boot項(xiàng)目部署到華為云上,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01Docker 數(shù)據(jù)持久化的三種方式小結(jié)
本文主要介紹了Docker 數(shù)據(jù)持久化的三種方式小結(jié),主要包括volume、bind mounts、tmpfs mounts這三種方式,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01