?
This document uses PHP Chinese website manual Release
您可以使用該docker stats
命令實時流式傳輸容器的運行時指標(biāo)。該命令支持CPU,內(nèi)存使用情況,內(nèi)存限制和網(wǎng)絡(luò)IO度量標(biāo)準(zhǔn)。
以下是docker stats
命令的輸出示例
$ docker stats redis1 redis2 CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O redis1 0.07% 796 KB / 64 MB 1.21% 788 B / 648 B 3.568 MB / 512 KB redis2 0.07% 2.746 MB / 64 MB 4.29% 1.266 KB / 648 B 12.4 MB / 0 B
docker統(tǒng)計參考頁面有關(guān)于docker stats
命令的更多詳細(xì)信息。
Linux Containers依賴于控制組,這些組不僅跟蹤進(jìn)程組,還公開有關(guān)CPU,內(nèi)存和塊I / O使用情況的度量標(biāo)準(zhǔn)。您也可以訪問這些指標(biāo)并獲取網(wǎng)絡(luò)使用指標(biāo)。這與“純”LXC容器以及Docker容器有關(guān)。
控制組通過偽文件系統(tǒng)公開。在最近的發(fā)行版中,你應(yīng)該找到這個文件系統(tǒng)/sys/fs/cgroup
。在該目錄下,您將看到多個子目錄,稱為設(shè)備,冰柜,blkio等; 每個子目錄實際上對應(yīng)于不同的cgroup層次結(jié)構(gòu)。
在較早的系統(tǒng)上,控制組可能會安裝在/cgroup
,而沒有明確的層次結(jié)構(gòu)。在這種情況下,您不會看到子目錄,而是會在該目錄中看到一堆文件,并且可能會有一些與現(xiàn)有容器相對應(yīng)的目錄。
若要確定將控件組安裝在何處,可以運行:
$ grep cgroup /proc/mounts
您可以查看/proc/cgroups
系統(tǒng)已知的不同控制組子系統(tǒng),它們所屬的層次結(jié)構(gòu)以及它們包含的組數(shù)。
你也可以看看/proc/<pid>/cgroup
哪些控制組屬于一個進(jìn)程。控制組將顯示為相對于層次結(jié)構(gòu)安裝點根的路徑; 例如,/
意思是“這個過程沒有被分配到一個特定的組中”,而/lxc/pumpkin
意味著這個過程很可能是一個被命名為pumpkin
的容器的成員
對于每個容器,將在每個層次結(jié)構(gòu)中創(chuàng)建一個cgroup。在較舊版本的LXC userland工具的舊系統(tǒng)上,cgroup的名稱將是容器的名稱。隨著更新版本的LXC工具,cgroup將會lxc/<container_name>.
對于使用cgroup的Docker容器,容器名稱將是容器的完整ID或長ID。如果容器顯示為ae836c95b4c3 docker ps
,則其長ID可能類似于ae836c95b4c3c9e9179e0e91015512da89fdec91612f63cebae57df9a5444c79
。你可以用docker inspect
或查找docker ps --no-trunc
。
綜合考慮Docker容器的內(nèi)存指標(biāo),請看看/sys/fs/cgroup/memory/docker/<longid>/
。
對于每個子系統(tǒng)(內(nèi)存,CPU和塊I / O),您將找到一個或多個包含統(tǒng)計信息的偽文件。
memory.stat
內(nèi)存指標(biāo)可在“內(nèi)存”cgroup中找到。請注意,內(nèi)存控制組會增加一些開銷,因為它會對主機上的內(nèi)存使用情況進(jìn)行非常細(xì)致的記帳。因此,許多發(fā)行版默認(rèn)選擇不啟用它。一般來說,要啟用它,你所要做的就是添加一些內(nèi)核命令行參數(shù):cgroup_enable=memory swapaccount=1
。
度量標(biāo)準(zhǔn)位于偽文件memory.stat
。以下是它的樣子:
cache 11492564992rss 1930993664mapped_file 306728960pgpgin 406632648pgpgout 403355412swap 0pgfault 728281223pgmajfault 1724inactive_anon 46608384active_anon 1884520448inactive_file 7003344896active_file 4489052160unevictable 32768hierarchical_memory_limit 9223372036854775807hierarchical_memsw_limit 9223372036854775807total_cache 11492564992total_rss 1930993664total_mapped_file 306728960total_pgpgin 406632648total_pgpgout 403355412total_swap 0total_pgfault 728281223total_pgmajfault 1724total_inactive_anon 46608384total_active_anon 1884520448total_inactive_file 7003344896total_active_file 4489052160total_unevictable 32768
前半部分(不含total_
前綴)包含與cgroup內(nèi)進(jìn)程相關(guān)的統(tǒng)計信息,不包括子cgroup。下半部分(帶total_
前綴)也包含子cgroups。
一些指標(biāo)是“計量器”,即可以增加或減少的值(例如,交換cgroup成員使用的交換空間量)。其他一些是“計數(shù)器”,即只能上升的值,因為它們代表特定事件的發(fā)生(例如,pgfault,它表示自創(chuàng)建cgroup以來發(fā)生的頁面錯誤的數(shù)量;該數(shù)字永遠(yuǎn)不會減少)。
Metric | 描述 |
---|---|
cache | 此控制組的進(jìn)程使用的內(nèi)存量可以與塊設(shè)備上的塊精確關(guān)聯(lián)。當(dāng)你讀取和寫入磁盤上的文件時,這個數(shù)量會增加。如果您使用“常規(guī)”I / O(打開,讀取,寫入系統(tǒng)調(diào)用)以及映射文件(使用mmap),情況就會如此。它也解釋了tmpfs坐騎使用的內(nèi)存,但原因尚不清楚。 |
RSS | 與磁盤上的任何內(nèi)容不對應(yīng)的內(nèi)存量:堆棧,堆和匿名內(nèi)存映射。 |
mapped_file | 指示控制組中的進(jìn)程映射的內(nèi)存量。它不會告訴你有多少內(nèi)存被使用; 它會告訴你它是如何使用的。 |
pgfault,pgmajfault | 指示cgroup的進(jìn)程分別觸發(fā)“頁面錯誤”和“嚴(yán)重錯誤”的次數(shù)。當(dāng)進(jìn)程訪問不存在或受保護的部分虛擬內(nèi)存空間時,會發(fā)生頁面錯誤。如果進(jìn)程有問題并嘗試訪問無效地址(它將被發(fā)送一個SIGSEGV信號,通常使用著名的分段錯誤消息將其殺死),前者可能發(fā)生。當(dāng)進(jìn)程從已被換出的內(nèi)存區(qū)讀取或者對應(yīng)于映射文件時,后者可能發(fā)生:在這種情況下,內(nèi)核將從磁盤加載頁面,并讓CPU完成內(nèi)存訪問。當(dāng)進(jìn)程寫入寫時復(fù)制內(nèi)存區(qū)域時也會發(fā)生:同樣,內(nèi)核將搶占進(jìn)程,復(fù)制內(nèi)存頁面,并在頁面的進(jìn)程自己的副本上恢復(fù)寫入操作。內(nèi)核實際上必須從磁盤讀取數(shù)據(jù)時才會發(fā)生“重大”故障。當(dāng)它只需復(fù)制現(xiàn)有頁面或分配一個空白頁面時,它就是一個常規(guī)(或“次要”)錯誤。| |
swap | 此cgroup中進(jìn)程當(dāng)前使用的交換量。 |
active_anon,inactive_anon | 內(nèi)核已識別的匿名內(nèi)存數(shù)量分別處于活動狀態(tài)和非活動狀態(tài)?!澳涿眱?nèi)存是未鏈接到磁盤頁面的內(nèi)存。換句話說,這就是上述rss計數(shù)器的等價物。實際上,rss計數(shù)器的定義是active_anon + inactive_anon - tmpfs(其中,tmpfs是由此控制組裝載的tmpfs文件系統(tǒng)使用的內(nèi)存量)?,F(xiàn)在,“主動”和“非主動”之間有什么區(qū)別?頁面最初是“活動的”; 并定期將內(nèi)核掃描到內(nèi)存中,并將某些頁面標(biāo)記為“不活動”。每當(dāng)他們再次訪問時,他們立即被重新標(biāo)記為“活躍”。當(dāng)內(nèi)核幾乎內(nèi)存不足,并且需要時間換出磁盤時,內(nèi)核將交換“非活動”頁面。 |
active_file,inactive_file | 高速緩沖存儲器,具有與上述匿名存儲器相似的活動和非活動狀態(tài)。確切的公式是cache = active_file + inactive_file + tmpfs。內(nèi)核用于在活動和非活動集之間移動內(nèi)存頁的確切規(guī)則與用于匿名內(nèi)存的確切規(guī)則不同,但一般原則相同。請注意,當(dāng)內(nèi)核需要回收內(nèi)存時,從該池回收干凈(=未修改)頁面會更便宜,因為它可以立即回收(而匿名頁面和臟/修改頁面必須先寫入磁盤) 。 |
unevictable | 無法回收的內(nèi)存量; 一般來說,它會占用已被mlock“鎖定”的內(nèi)存。它通常被加密框架用來確保秘密密鑰和其他敏感材料永遠(yuǎn)不會換出到磁盤。 |
memory_limit,memsw_limit | 這些并不是真正的指標(biāo),但是提醒了應(yīng)用于此cgroup的限制。第一個表示該控制組的進(jìn)程可以使用的最大物理內(nèi)存量; 第二個表示RAM +交換的最大數(shù)量。 |
記錄頁面緩存中的內(nèi)存非常復(fù)雜。如果不同控制組中的兩個進(jìn)程都讀取同一文件(最終依靠磁盤上的相同塊),則相應(yīng)的內(nèi)存費用將在控制組之間分配。這很好,但這也意味著當(dāng)一個cgroup被終止時,它可能會增加另一個cgroup的內(nèi)存使用率,因為它們不再為這些內(nèi)存頁面分?jǐn)偝杀尽?/p>
cpuacct.stat
現(xiàn)在我們已經(jīng)介紹了內(nèi)存度量標(biāo)準(zhǔn),其他一切都會看起來非常簡單。CPU指標(biāo)將在cpuacct
控制器中找到。
對于每個容器,你會發(fā)現(xiàn)一個偽文件cpuacct.stat
,載有集裝箱的過程中積累的CPU使用率,之間分解user
和system
時間。如果您對區(qū)分不熟悉,user
是進(jìn)程直接控制CPU的時間(即執(zhí)行進(jìn)程代碼),并且system
是CPU代表這些進(jìn)程執(zhí)行系統(tǒng)調(diào)用的時間。
這些時間以1/100秒的刻度表示。實際上,它們是以“用戶jiffies”表示的。每秒有USER_HZ
“jiffies”,在x86系統(tǒng)上USER_HZ
是100。這用于精確地映射每秒調(diào)度器“ticks”的數(shù)量; 但隨著更高頻率調(diào)度的出現(xiàn)以及無滴答內(nèi)核的出現(xiàn),內(nèi)核滴答的數(shù)量不再相關(guān)。無論如何,它主要出于傳統(tǒng)和兼容性的原因。
塊I/O在blkio
控制器。不同的指標(biāo)分散在不同的文件中。而您可以在BLKIO控制器在內(nèi)核文檔中,下面列出了一些最相關(guān)的文件:
Metric | 描述 |
---|---|
blkio.sectors | 包含由cgroup的進(jìn)程成員逐個設(shè)備讀取和寫入的512字節(jié)扇區(qū)數(shù)。讀取和寫入被合并在一個計數(shù)器中。 |
blkio.io_service_bytes | 指示由cgroup讀取和寫入的字節(jié)數(shù)。它每個設(shè)備有4個計數(shù)器,因為對于每個設(shè)備,它區(qū)分同步I / O和異步I / O,以及讀取與寫入。 |
blkio.io_serviced | 不論其大小如何,執(zhí)行的I / O操作的數(shù)量。它也有每個設(shè)備4個計數(shù)器。 |
blkio.io_queued | 指示當(dāng)前為此cgroup排隊的I / O操作的數(shù)量。換句話說,如果cgroup沒有執(zhí)行任何I / O操作,則這將為零。請注意,相反情況并非如此。換句話說,如果沒有排隊的I / O,這并不意味著cgroup是空閑的(I / O方式)。它可以在其他靜態(tài)設(shè)備上進(jìn)行純同步讀取,因此可以立即處理它們,而無需排隊。此外,盡管找出哪個cgroup正在對I / O子系統(tǒng)施加壓力是有幫助的,但請記住它是一個相對數(shù)量。即使進(jìn)程組沒有執(zhí)行更多的I / O,其隊列大小也會因為其他設(shè)備的負(fù)載增加而增加。 |
網(wǎng)絡(luò)指標(biāo)不直接由控制組公開。有一個很好的解釋:網(wǎng)絡(luò)接口存在于網(wǎng)絡(luò)命名空間的上下文中。內(nèi)核可能會累積有關(guān)一組進(jìn)程發(fā)送和接收的數(shù)據(jù)包和字節(jié)的度量標(biāo)準(zhǔn),但這些度量標(biāo)準(zhǔn)不會很有用。您需要每個接口的度量標(biāo)準(zhǔn)(因為在本地lo
接口上發(fā)生的流量并不真正計數(shù))。但是由于單個cgroup中的進(jìn)程可能屬于多個網(wǎng)絡(luò)名稱空間,因此這些度量標(biāo)準(zhǔn)很難解釋:多個網(wǎng)絡(luò)名稱空間意味著多個lo
接口,可能有多個eth0
接口等; 所以這就是為什么沒有簡單的方法來收集控制組的網(wǎng)絡(luò)指標(biāo)。
相反,我們可以從其他來源收集網(wǎng)絡(luò)度量:
IPtables(或者說,iptables只是一個接口的netfilter框架)可以做一些嚴(yán)肅的會計。
例如,您可以設(shè)置一個規(guī)則來說明Web服務(wù)器上的出站HTTP流量:
$ iptables -I OUTPUT -p tcp --sport 80
沒有-j
或-g
標(biāo)志,所以規(guī)則將只計算匹配的數(shù)據(jù)包并轉(zhuǎn)到以下規(guī)則。
稍后,您可以通過以下方法檢查計數(shù)器的值:
$ iptables -nxvL OUTPUT
從技術(shù)上講,-n
不是必需的,但它將阻止iptables執(zhí)行DNS反向查找,在此場景中可能沒有用處。
計數(shù)器包括數(shù)據(jù)包和字節(jié)。如果您想為此類容器流量設(shè)置度量標(biāo)準(zhǔn),則可以執(zhí)行一個for
循環(huán)以iptables
在FORWARD
鏈中為每個容器IP地址(每個方向一個)添加兩條規(guī)則。這將只計量通過NAT層的流量; 您還必須添加通過用戶級代理的流量。
然后,您需要定期檢查這些計數(shù)器。如果你碰巧用collectd
,有一個不錯的插件若要自動化iptables計數(shù)器集合,請執(zhí)行以下操作。
因為每個容器都有一個虛擬以太網(wǎng)接口,所以您可能需要直接檢查該接口的TX和RX計數(shù)器。您將注意到,每個容器都與主機中的虛擬以太網(wǎng)接口相關(guān)聯(lián),名稱如下vethKk8Zqi
.不幸的是,找出哪個接口對應(yīng)于哪個容器是困難的。
但現(xiàn)在,最好的方法是從容器中檢查指標(biāo)。為了達(dá)到這個目的,你可以使用ip-netns magic在容器的網(wǎng)絡(luò)命名空間內(nèi)的主機環(huán)境中運行一個可執(zhí)行文件。
ip-netns exec
命令將允許您在當(dāng)前進(jìn)程可見的任何網(wǎng)絡(luò)名稱空間內(nèi)執(zhí)行任何程序(存在于主機系統(tǒng)中)。這意味著您的主機將能夠輸入您的容器的網(wǎng)絡(luò)名稱空間,但您的容器將無法訪問主機,也不能訪問它們的兄弟容器。盡管如此,容器將能夠“看到”并影響其子容器。
命令的確切格式是:
$ ip netns exec <nsname> <command...>
例如:
$ ip netns exec mycontainer netstat -i
ip netns
通過使用命名空間偽文件找到“mycontainer”容器。每個進(jìn)程屬于一個網(wǎng)絡(luò)名稱空間,一個PID名稱空間,一個mnt
名稱空間等,并且這些名稱空間在/proc/<pid>/ns/
下具體化。例如,PID 42的網(wǎng)絡(luò)名稱空間由偽文件/proc/42/ns/net
實現(xiàn)。
運行ip netns exec mycontainer ...
,它期望/var/run/netns/mycontainer
成為這些偽文件之一。(符號鏈接被接受。)
換句話說,要在容器的網(wǎng)絡(luò)命名空間中執(zhí)行命令,我們需要:
找出我們要調(diào)查的容器內(nèi)任何進(jìn)程的PID;
從創(chuàng)建一個符號鏈接/var/run/netns/<somename>
到/proc/<thepid>/ns/net
執(zhí)行 ip netns exec <somename> ....
請查閱枚舉Cgroups以了解如何查找要在其中測量網(wǎng)絡(luò)使用情況的容器中運行的進(jìn)程的cgroup。從那里,您可以檢查名為的偽文件tasks
,其中包含控件組(即容器中)的PID。選擇他們中的任何一個。
將所有內(nèi)容組合在一起,如果容器的“短ID”保存在環(huán)境變量中$CID
,然后你就可以這樣做:
$ TASKS=/sys/fs/cgroup/devices/docker/$CID*/tasks $ PID=$(head -n 1 $TASKS)$ mkdir -p /var/run/netns $ ln -sf /proc/$PID/ns/net /var/run/netns/$CID $ ip netns exec $CID netstat -i
請注意,每次您要更新指標(biāo)時運行一個新流程都相當(dāng)昂貴。如果您想要以高分辨率和/或通過大量容器收集度量標(biāo)準(zhǔn)(將單個主機上的容器想成1000個),則不需要每次都分配一個新進(jìn)程。
以下是如何從單個流程收集指標(biāo)。您必須使用C編寫公制收集器(或任何允許執(zhí)行低級別系統(tǒng)調(diào)用的語言)。你需要使用一個特殊的系統(tǒng)調(diào)用,setns()
它允許當(dāng)前進(jìn)程輸入任意的命名空間。然而,它需要一個打開的文件描述符到命名空間偽文件(記?。哼@是偽文件/proc/<pid>/ns/net
)。
然而,有一個問題:你不能保持這個文件描述符打開。如果這樣做,當(dāng)控制組的最后一個進(jìn)程退出時,命名空間不會被銷毀,并且其網(wǎng)絡(luò)資源(如容器的虛擬接口)將一直保留(或直到關(guān)閉該文件描述符)。
正確的方法是跟蹤每個容器的第一個PID,每次重新打開名稱空間偽文件。
有時,您并不關(guān)心實時度量集合,但是當(dāng)容器退出時,您想知道它使用了多少CPU、內(nèi)存等等。
Docker使它變得困難,因為它依賴于lxc-start
它,它會在它自己之后仔細(xì)清理,但它仍然是可能的。定期收集指標(biāo)通常更容易(例如,每隔一分鐘,使用collectd LXC插件)并依靠它來代替。
但是,如果您仍然希望在容器停止時收集統(tǒng)計數(shù)據(jù),下面為方法:
對于每個容器,啟動一個收集過程,并通過將其PID寫入cgroup的任務(wù)文件,將其移至要監(jiān)控的控制組。收集過程應(yīng)定期重新讀取任務(wù)文件以檢查它是否是控制組的最后一個過程。(如果您還想按前一節(jié)中的說明收集網(wǎng)絡(luò)統(tǒng)計信息,則還應(yīng)該將過程移至適當(dāng)?shù)木W(wǎng)絡(luò)名稱空間。)
當(dāng)容器退出時,lxc-start
會嘗試刪除控制組。它會失敗,因為控制組仍在使用中; 但沒關(guān)系?,F(xiàn)在您的過程應(yīng)該檢測到它是該組中剩下的唯一一個。現(xiàn)在是收集您需要的所有指標(biāo)的適當(dāng)時機!
最后,你的過程應(yīng)該移回到根控制組,并刪除容器控制組。刪除一個控制組,只是rmdir
是目錄。由于仍然包含文件,因此它對目錄不直觀; 但請記住這是一個偽文件系統(tǒng),所以通常的規(guī)則不適用。清理完成后,收集過程可以安全地退出。