生產(chǎn)環(huán)境中監(jiān)控容器的運(yùn)行狀況十分重要,通過監(jiān)控我們可以隨時掌握容器的運(yùn)行狀態(tài),做到線上隱患和問題早發(fā)現(xiàn),早解決。
所以今天我就和你分享關(guān)于容器監(jiān)控的知識(原理及工具 cAdvisor)。
雖然傳統(tǒng)的物理機(jī)和虛擬機(jī)監(jiān)控已經(jīng)有了比較成熟的監(jiān)控方案,但是容器的監(jiān)控面臨著更大的挑戰(zhàn),因為容器的行為和本質(zhì)與傳統(tǒng)的虛擬機(jī)是不一樣的,總的來說,容器具有以下特性:
容器是短期存活的,并且可以動態(tài)調(diào)度
容器的本質(zhì)是進(jìn)程,而不是一個完整操作系統(tǒng)
由于容器非常輕量,容器的創(chuàng)建和銷毀也會比傳統(tǒng)虛擬機(jī)更加頻繁
Docker 容器的監(jiān)控方案有很多,除了 Docker 自帶的docker stats命令,還有很多開源的解決方案,例如 sysdig、cAdvisor、Prometheus 等,都是非常優(yōu)秀的監(jiān)控工具。
下面我們首先來看下,不借助任何外部工具,如何用 Docker 自帶的docker stats命令實現(xiàn)容器的監(jiān)控。
使用 docker stats 命令
使用 Docker 自帶的docker stats命令可以很方便地看到主機(jī)上所有容器的 CPU、內(nèi)存、網(wǎng)絡(luò) IO、磁盤 IO、PID 等資源的使用情況。下面我們可以具體操作看看。
首先在主機(jī)上使用以下命令啟動一個資源限制為 1 核 2G 的 nginx 容器:
$ docker run --cpus=1 -m=2g --name=nginx -d nginx
容器啟動后,可以使用docker stats命令查看容器的資源使用狀態(tài):
$ docker stats nginx
通過docker stats命令可以看到容器的運(yùn)行狀態(tài)如下:
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
f742a467b6d8 0.00% 1.387 MiB / 2 GiB 0.07% 656 B / 656 B 0 B / 9.22 kB 2
從容器的運(yùn)行狀態(tài)可以看出,docker stats命令確實可以獲取并顯示 Docker 容器運(yùn)行狀態(tài)。但是它的缺點也很明顯,因為它只能獲取本機(jī)數(shù)據(jù),無法查看歷史監(jiān)控數(shù)據(jù),沒有可視化展示面板。
因此,生產(chǎn)環(huán)境中我們通常使用另一種容器監(jiān)控解決方案 cAdvisor。
cAdvisor
cAdvisor 是谷歌開源的一款通用的容器監(jiān)控解決方案。cAdvisor 不僅可以采集機(jī)器上所有運(yùn)行的容器信息,還提供了基礎(chǔ)的查詢界面和 HTTP 接口,更方便與外部系統(tǒng)結(jié)合。所以,cAdvisor很快成了容器指標(biāo)監(jiān)控最常用組件,并且 Kubernetes 也集成了 cAdvisor 作為容器監(jiān)控指標(biāo)的默認(rèn)工具。
cAdvisor 的安裝與使用
下面我們以 cAdvisor 0.37.0 版本為例,演示一下 cAdvisor 的安裝與使用。
cAdvisor 官方提供了 Docker 鏡像,我們只需要拉取鏡像并且啟動鏡像即可。
由于 cAdvisor 鏡像存放在谷歌的 gcr.io 鏡像倉庫中,國內(nèi)無法訪問到。這里我把打好的鏡像放在了 Docker Hub。你可以使用 docker pull lagoudocker/cadvisor:v0.37.0 命令從 Docker Hub 拉取。
首先使用以下命令啟動 cAdvisor:
$ docker run \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:ro \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--volume=/dev/disk/:/dev/disk:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
--privileged \
--device=/dev/kmsg \
lagoudocker/cadvisor:v0.37.0
此時,cAdvisor 已經(jīng)成功啟動,我們可以通過訪問 http://localhost:8080 訪問到 cAdvisor 的 Web 界面。
cAdvisor 不僅可以監(jiān)控容器的資源使用情況,還可以監(jiān)控主機(jī)的資源使用情況。下面我們就先看下它是如何查看主機(jī)資源使用情況的。
使用 cAdvisor 查看主機(jī)監(jiān)控
訪問 http://localhost:8080/containers/ 地址,在首頁可以看到主機(jī)的資源使用情況,包含 CPU、內(nèi)存、文件系統(tǒng)、網(wǎng)絡(luò)等資源,如下圖所示。
使用 cAdvisor 查看容器監(jiān)控
如果你想要查看主機(jī)上運(yùn)行的容器資源使用情況,可以訪問 http://localhost:8080/docker/,這個頁面會列出 Docker 的基本信息和運(yùn)行的容器情況,如下圖所示。
在上圖中的 Subcontainers 下會列出當(dāng)前主機(jī)上運(yùn)行的所有容器,點擊其中一個容器即可查看該容器的詳細(xì)運(yùn)行狀態(tài),如下圖所示。
總體來說,使用 cAdvisor 監(jiān)控容器具有以下特點:
可以同時采集物理機(jī)和容器的狀態(tài)
可以展示監(jiān)控歷史數(shù)據(jù)
了解 Docker 的監(jiān)控工具,你是否想問,這些監(jiān)控數(shù)據(jù)是怎么來的呢?下面我就帶你了解一下容器監(jiān)控的原理。
監(jiān)控原理
我們知道 Docker 是基于 Namespace、Cgroups 和聯(lián)合文件系統(tǒng)實現(xiàn)的。其中 Cgroups 不僅可以用于容器資源的限制,還可以提供容器的資源使用率。無論何種監(jiān)控方案的實現(xiàn),底層數(shù)據(jù)都來源于 Cgroups。
Cgroups 的工作目錄為/sys/fs/cgroup,/sys/fs/cgroup目錄下包含了 Cgroups 的所有內(nèi)容。Cgroups包含很多子系統(tǒng),可以用來對不同的資源進(jìn)行限制。例如對CPU、內(nèi)存、PID、磁盤 IO等資源進(jìn)行限制和監(jiān)控。
為了更詳細(xì)的了解 Cgroups 的子系統(tǒng),我們通過 ls -l 命令查看/sys/fs/cgroup文件夾,可以看到很多目錄:
$ sudo ls -l /sys/fs/cgroup/
total 0
dr-xr-xr-x 5 root root 0 Jul 9 19:32 blkio
lrwxrwxrwx 1 root root 11 Jul 9 19:32 cpu -> cpu,cpuacct
dr-xr-xr-x 5 root root 0 Jul 9 19:32 cpu,cpuacct
lrwxrwxrwx 1 root root 11 Jul 9 19:32 cpuacct -> cpu,cpuacct
dr-xr-xr-x 3 root root 0 Jul 9 19:32 cpuset
dr-xr-xr-x 5 root root 0 Jul 9 19:32 devices
dr-xr-xr-x 3 root root 0 Jul 9 19:32 freezer
dr-xr-xr-x 3 root root 0 Jul 9 19:32 hugetlb
dr-xr-xr-x 5 root root 0 Jul 9 19:32 memory
lrwxrwxrwx 1 root root 16 Jul 9 19:32 net_cls -> net_cls,net_prio
dr-xr-xr-x 3 root root 0 Jul 9 19:32 net_cls,net_prio
lrwxrwxrwx 1 root root 16 Jul 9 19:32 net_prio -> net_cls,net_prio
dr-xr-xr-x 3 root root 0 Jul 9 19:32 perf_event
dr-xr-xr-x 5 root root 0 Jul 9 19:32 pids
dr-xr-xr-x 5 root root 0 Jul 9 19:32 systemd
這些目錄代表了 Cgroups 的子系統(tǒng),Docker 會在每一個 Cgroups 子系統(tǒng)下創(chuàng)建 docker 文件夾。這里如果你對 Cgroups 子系統(tǒng)不了解的話,不要著急,這里你只需要明白容器監(jiān)控數(shù)據(jù)來源于 Cgroups 即可。
監(jiān)控系統(tǒng)是如何獲取容器的內(nèi)存限制的?
下面我們以 memory 子系統(tǒng)(memory 子系統(tǒng)是Cgroups 眾多子系統(tǒng)的一個,主要用來限制內(nèi)存使用)為例,講解一下監(jiān)控組件是如何獲取到容器的資源限制和使用狀態(tài)的(即容器的內(nèi)存限制)。
我們首先在主機(jī)上使用以下命令啟動一個資源限制為 1 核 2G 的 nginx 容器:
$ docker run --name=nginx --cpus=1 -m=2g --name=nginx -d nginx
## 這里輸出的是容器 ID
51041a74070e9260e82876974762b8c61c5ed0a51832d74fba6711175f89ede1
注意:如果你已經(jīng)創(chuàng)建過名稱為 nginx 的容器,請先使用 docker rm -f nginx 命令刪除已經(jīng)存在的 nginx 容器。
容器啟動后,我們通過命令行的輸出可以得到容器的 ID,同時 Docker 會在/sys/fs/cgroup/memory/docker目錄下以容器 ID 為名稱創(chuàng)建對應(yīng)的文件夾。
下面我們查看一下/sys/fs/cgroup/memory/docker目錄下的文件:
$ sudo ls -l /sys/fs/cgroup/memory/docker
total 0
drwxr-xr-x 2 root root 0 Sep 2 15:12 51041a74070e9260e82876974762b8c61c5ed0a51832d74fba6711175f89ede1
-rw-r--r-- 1 root root 0 Sep 2 14:57 cgroup.clone_children
--w--w--w- 1 root root 0 Sep 2 14:57 cgroup.event_control
-rw-r--r-- 1 root root 0 Sep 2 14:57 cgroup.procs
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.failcnt
--w------- 1 root root 0 Sep 2 14:57 memory.force_empty
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.failcnt
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.max_usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.slabinfo
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.tcp.failcnt
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.tcp.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.tcp.max_usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.tcp.usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.max_usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.memsw.failcnt
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.memsw.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.memsw.max_usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.memsw.usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.move_charge_at_immigrate
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.numa_stat
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.oom_control
---------- 1 root root 0 Sep 2 14:57 memory.pressure_level
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.soft_limit_in_bytes
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.stat
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.swappiness
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.use_hierarchy
-rw-r--r-- 1 root root 0 Sep 2 14:57 notify_on_release
-rw-r--r-- 1 root root 0 Sep 2 14:57 tasks
可以看到 Docker 已經(jīng)創(chuàng)建了以容器 ID 為名稱的目錄,我們再使用 ls 命令查看一下該目錄的內(nèi)容:
$ sudo ls -l /sys/fs/cgroup/memory/docker/51041a74070e9260e82876974762b8c61c5ed0a51832d74fba6711175f89ede1
total 0
-rw-r--r-- 1 root root 0 Sep 2 15:21 cgroup.clone_children
--w--w--w- 1 root root 0 Sep 2 15:13 cgroup.event_control
-rw-r--r-- 1 root root 0 Sep 2 15:12 cgroup.procs
-rw-r--r-- 1 root root 0 Sep 2 15:12 memory.failcnt
--w------- 1 root root 0 Sep 2 15:21 memory.force_empty
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.failcnt
-rw-r--r-- 1 root root 0 Sep 2 15:12 memory.kmem.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.max_usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.slabinfo
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.tcp.failcnt
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.tcp.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.tcp.max_usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.tcp.usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:12 memory.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:12 memory.max_usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.memsw.failcnt
-rw-r--r-- 1 root root 0 Sep 2 15:12 memory.memsw.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.memsw.max_usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 15:21 memory.memsw.usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.move_charge_at_immigrate
-r--r--r-- 1 root root 0 Sep 2 15:21 memory.numa_stat
-rw-r--r-- 1 root root 0 Sep 2 15:13 memory.oom_control
---------- 1 root root 0 Sep 2 15:21 memory.pressure_level
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.soft_limit_in_bytes
-r--r--r-- 1 root root 0 Sep 2 15:21 memory.stat
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.swappiness
-r--r--r-- 1 root root 0 Sep 2 15:12 memory.usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.use_hierarchy
-rw-r--r-- 1 root root 0 Sep 2 15:21 notify_on_release
-rw-r--r-- 1 root root 0 Sep 2 15:21 tasks
由上可以看到,容器 ID 的目錄下有很多文件,其中 memory.limit_in_bytes 文件代表該容器內(nèi)存限制大小,單位為 byte,我們使用 cat 命令(cat 命令可以查看文件內(nèi)容)查看一下文件內(nèi)容:
$ sudo cat /sys/fs/cgroup/memory/docker/51041a74070e9260e82876974762b8c61c5ed0a51832d74fba6711175f89ede1/memory.limit_in_bytes
2147483648
這里可以看到memory.limit_in_bytes 的值為2147483648,轉(zhuǎn)換單位后正好為 2G,符合我們啟動容器時的內(nèi)存限制 2G。
通過 memory 子系統(tǒng)的例子,我們可以知道監(jiān)控組件通過讀取 memory.limit_in_bytes 文件即可獲取到容器內(nèi)存的限制值。了解完容器的內(nèi)存限制我們來了解一下容器的內(nèi)存使用情況。
$ sudo /sys/fs/cgroup/memory/docker/51041a74070e9260e82876974762b8c61c5ed0a51832d74fba6711175f89ede1/memory.usage_in_bytes
4259840
可以看到當(dāng)前內(nèi)存的使用大小為 4259840 byte,約為 4 M。了解了內(nèi)存的監(jiān)控。
下面我們來了解下網(wǎng)絡(luò)的監(jiān)控數(shù)據(jù)來源
網(wǎng)絡(luò)的監(jiān)控數(shù)據(jù)來源是從 /proc/{PID}/net/dev 目錄下讀取的,其中 PID 為容器在主機(jī)上的進(jìn)程 ID。下面我們首先使用 docker inspect 命令查看一下上面啟動的 nginx 容器的 PID,命令如下:
$ docker inspect nginx |grep Pid
"Pid": 27348,
"PidMode": "",
"PidsLimit": 0,
可以看到容器的 PID 為 27348,使用 cat 命令查看一下 /proc/27348/net/dev 的內(nèi)容
$ sudo cat /proc/27348/net/dev
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
eth0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
/proc/27348/net/dev 文件記錄了該容器里每一個網(wǎng)卡的流量接收和發(fā)送情況,以及錯誤數(shù)、丟包數(shù)等信息??梢娙萜鞯木W(wǎng)絡(luò)監(jiān)控數(shù)據(jù)都是定時從這里讀取并展示的。
總結(jié)一下,容器的監(jiān)控原理其實就是定時讀取 Linux 主機(jī)上相關(guān)的文件并展示給用戶。
結(jié)語
k8s后面使用metrics serve,cAdvisor 是提供底層數(shù)據(jù)的,metrics-server 底層數(shù)據(jù)來源是 cAdvisor
cAdvisor 是提供監(jiān)控數(shù)據(jù)的,Prometheus 是負(fù)責(zé)采集的數(shù)據(jù)的,這兩個作用是不一樣的,生產(chǎn)集群中一般都是 cAdvisor 配合 Prometheus 一起使用。
以上這篇Docker 容器監(jiān)控原理及 cAdvisor的安裝與使用說明就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。