摘要:標簽空格分隔資源管理內存磁盤注該文作者是,原文是。如果你運行命令,你自己可以看到這個結構當我們想管理資源的時候,這個方法提供了很大的靈活性,因為我們可以分別的管理每個組。
標簽(空格分隔): Docker 資源管理 內存 CPU 磁盤 I/O
注:該文作者是 Marek Goldmann,原文是 Resource management in Docker。
在這篇博客文章中,我想談談 Docker 容器資源管理的話題,我們往往不清楚它是怎樣工作的以及我們能做什么不能做什么。我希望你讀完這篇關于資源管理的博客文章之后,可以幫助你更容易理解這些。
注意:我們假設你在一個 systemd 可用的系統上運行了 Docker。如果你是使用 RHEL/CentOS 7+ 或 Fedora 19+,systemd 肯定可用,但是請注意在不同的 systemd 版本之間可能配置選項會有改變。有疑問時,使用你所工作的系統的 systemd 的 man pages。
目錄預覽
1. 基礎概念Docker 使用 cgroups 歸類運行在容器中的進程。這使你可以管理一組進程的資源,可想而知,這是非常寶貴的。
如果你運行一個操作系統,其使用 systemd 管理服務。每個進程(不僅僅是容器中的進程)都將被放入一個 cgroups 樹中。如果你運行 systemd-cgls 命令,你自己可以看到這個結構:
$ systemd-cgls ├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 22 ├─machine.slice │ └─machine-qemux2drhel7.scope │ └─29898 /usr/bin/qemu-system-x86_64 -machine accel=kvm -name rhel7 -S -machine pc-i440fx-1.6,accel=kvm,usb=off -cpu SandyBridge -m 2048 ├─system.slice │ ├─avahi-daemon.service │ │ ├─ 905 avahi-daemon: running [mistress.local │ │ └─1055 avahi-daemon: chroot helpe │ ├─dbus.service │ │ └─890 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation │ ├─firewalld.service │ │ └─887 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid │ ├─lvm2-lvmetad.service │ │ └─512 /usr/sbin/lvmetad -f │ ├─abrtd.service │ │ └─909 /usr/sbin/abrtd -d -s │ ├─wpa_supplicant.service │ │ └─1289 /usr/sbin/wpa_supplicant -u -f /var/log/wpa_supplicant.log -c /etc/wpa_supplicant/wpa_supplicant.conf -u -f /var/log/wpa_supplica │ ├─systemd-machined.service │ │ └─29899 /usr/lib/systemd/systemd-machined [SNIP]
當我們想管理資源的時候,這個方法提供了很大的靈活性,因為我們可以分別的管理每個組。盡管這篇博客文章著重與容器,同樣的原則也適用于其他的進程。
1.1 測試說明注意:如果你想知道更多關于 systemd 的知識,我強烈推薦 RHEL 7 的 Resource Management and Linux Containers Guide 。
在我的例子中,我將使用 stress 工具來幫助我生成容器的一些負載,因此我可以實際看到資源的申請限制。我使用這個 Dockerfile 創建了一個名為 stress 的定制的 Docker 鏡像:
FROM fedora:latest RUN yum -y install stress && yum clean all ENTRYPOINT ["stress"]1.2 關于資源報告工具的說明
你使用這個工具來報告如 top, /proc/meminfo 等等 cgroups 不知道的使用情況。這意味著你將報告關于這臺主機的信息,盡管我們在容器中運行著它們。我發現了一篇很好來自于 Fabio Kung 的關于這個主題的文章。讀一讀它吧。
因此,我們能做什么?
如果你想快速發現在該主機上哪個容器(或是最近的任何 systemd 服務)使用最多資源,我推薦 systemd-cgtop 命令:
$ systemd-cgtop Path Tasks %CPU Memory Input/s Output/s / 226 13.0 6.7G - - /system.slice 47 2.2 16.0M - - /system.slice/gdm.service 2 2.1 - - - /system.slice/rngd.service 1 0.0 - - - /system.slice/NetworkManager.service 2 - - - - [SNIP]
這個工具能立刻給你一個快速預覽什么運行在系統上。但是如果你想得到關系使用情況的更詳細信息(比如,你需要創建一個好看的圖表),你將去分析 /sys/fs/cgroup/…? 目錄。我將向你展示去哪里能找到我們將討論的每個資源的有用文件(看下面的 CGroups fs 段落)。
2. CPUDocker 能夠指定(通過運行命令的 -c 開關)給一個容器的可用的 CPU 分配值。這是一個相對權重,與實際的處理速度無關。事實上,沒有辦法說一個容器應該只獲得 1Ghz CPU。記住。
默認,每個新的容器將有 1024 shares 的 CPU,當我們多帶帶講它的時候,這個值并不意味著什么。但是如果我們啟動兩個容器并且兩個都將使用 100% CPU,CPU 時間將在這兩個容器之間平均分割,因為它們兩個都有同樣的 CPU shares(為了簡單起見,我假設它們沒有任何進程在運行)。
如果我們設置容器的 CPU shares 是 512,相對于另外一個容器,它將使用一半的 CPU 時間。但這不意味著它僅僅能使用一半的 CPU 時間。如果另外一個容器(1024 shares 的)是空閑的 - 我們的容器將被允許使用 100% CPU。這是需要注意的另外一件事。
限制是僅僅當它們應該被執行的時候才會強制執行。CGroups 不限制進程預先使用(比如,不允許它們允許的更快,即使它們有空余資源)。相反它提供了它盡可能提供的,以及它僅僅在必需的時候限制(比如,當太多的進程同時大量使用 CPU)。
當然,這很難說清楚(我想說的是這不可能說清楚的)多少資源應該被分配給你的進程。這實際取決于其他進程的行為和多少 shares 被分配給它們。
2.1 示例:管理一個容器的 CPU 分配正如我在前面提到的,你可以使用 -c 開關來分配給運行在容器中的所有進程的 shares 值。
因為在我的機器上我有 4 核,我將使用 4 壓測:
$ docker run -it --rm stress --cpu 4 stress: info: [1] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
如果你想以相同的方式啟動兩個容器,兩個都將使用 50% 左右的 CPU。但是當我們修改其中一個容器的 shares 時,將發生什么?
$ docker run -it --rm -c 512 stress --cpu 4 stress: info: [1] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
正如你所看到的,CPU 在兩個容器之間是以這樣的方式分割了,第一個容器使用了 60% 的 CPU,另外一個使用了 30% 左右。這似乎是預期的結果。
2.2 Attaching containers to cores注:丟失的 10% CPU 被 GNOME,Chrome 和我的音樂播放器使用了。
除了限制 CPU 的 shares(股份,相當于配額的意思),我們可以做更多的事情,我們可以把容器的進程固定到特定的處理器(core)。為了做到這個,我們使用 docker run 命令的 --cpuset 開關。
為了允許僅在第一個核上執行:
docker run -it --rm --cpuset=0 stress --cpu 1
為了允許僅在第一個和第二個核上執行:
docker run -it --rm --cpuset=0,1 stress --cpu 2
你當然可以混合使用選項 --cpuset 和 -c。
2.3 變更一個正在運行的容器的分配值注意:Share enforcement 僅僅發生在當進程運行在相同的核上的時候。這意味著如果你把一個容器固定在第一個核,而把另外一個容器固定在另外一個核,兩個都將使用各自核的 100%,即使它們有不同的 CPU shares 設置(再一次,我假設僅僅有兩個容器運行在主機上)。
有可能改變一個正在運行的容器的 shares(或是任何進程)。你可以直接與 cgroups 文件系統交互,但是因為我們有 systemds,我們可以通過它來為我們管理。
為了這個目的,我們將使用 systemctl 命令和 set-property 參數。使用 docker run 命令新的容器將有一個 systemd scope,自動分配到其內的所有進程都將被執行。為了改變容器中所有進程的 CPU share,我們僅僅需要在 scope 內改變它,像這樣:
$ sudo systemctl set-property docker-4be96b853089bc6044b29cb873cac460b429cfcbdd0e877c0868eb2a901dbf80.scope CPUShares=512
注意:添加 --runtime 暫時的改變設置。否則,當主機重起的時候,這個設置會被記住。
把默認值從 1024 變更到 512。你可以在下面看到結果。這一變化發生在記錄的中間。請注意 CPU 使用率。在 systemd-cgtop 中 100% 意味著滿額使用了一核,并且這是正確的,因為我綁定了兩個容器在相同的核上。
2.4 CGroups fs注意:為了顯示所有的屬性,你可以使用 systemctl show docker-4be96b853089bc6044b29cb873cac460b429cfcbdd0e877c0868eb2a901dbf80.scope 命令。為了列出所有可用的屬性,請看下 man systemd.resource-control。
你可以在 /sys/fs/cgroup/cpu/system.slice/docker-$FULL_CONTAINER_ID.scope/ 下面發現指定容器的關于 CPU 的所有信息,例如:
$ ls /sys/fs/cgroup/cpu/system.slice/docker-6935854d444d78abe52d629cb9d680334751a0cda82e11d2610e041d77a62b3f.scope/ cgroup.clone_children cpuacct.usage_percpu cpu.rt_runtime_us tasks cgroup.procs cpu.cfs_period_us cpu.shares cpuacct.stat cpu.cfs_quota_us cpu.stat cpuacct.usage cpu.rt_period_us notify_on_release
2.5 概要重述注意:關于這些文件的更多信息,請移步 RHEL Resource Management Guide 查看。
需要記住的一些事項:
CPU share 僅僅是一個數字 - 與 CPU 速度無關
新容器默認有 1024 shares
在一臺空閑主機上,低 shares 的容器仍可以使用 100% 的 CPU
如果你想,你可以把容器固定到一個指定核
3. 內存現在讓我看下限制內存。
第一件事需要注意的是,默認一個容器可以使用主機上的所有內存。
如果你想為容器中的所有進程限制內存,使用 docker run 命令的 -m 開關即可。你可以使用 bytes 定義它的值或是(k, m 或 g)。
3.1 示例:管理一個容器的內存分配你可以像這樣使用 -m 開關:
$ docker run -it --rm -m 128m fedora bash
為了顯示限制的實際情況,我將再次使用我的 stress 鏡像??紤]一下的運行:
$ docker run -it --rm -m 128m stress --vm 1 --vm-bytes 128M --vm-hang 0 stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress 工具將創建一個進程,并嘗試分配 128MB 內存給它。它工作的很好,但是如果我們使用的比實際分配給容器的更多,將發生什么?
$ docker run -it --rm -m 128m stress --vm 1 --vm-bytes 200M --vm-hang 0 stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
它照樣正常工作,是不是很奇怪?是的,我同意。
我們將在 libcontainer 源碼 找到解釋(cgroups 的 Docker 接口)。我們可以看到源碼中默認的 memory.memsw.limit_in_bytes 值是被設置成我們指定的內存參數的兩倍,當我們啟動一個容器的時候。memory.memsw.limit_in_bytes 參數表達了什么?它是 memory 和 swap 的總和。這意味著 Docker 將分配給容器 -m 內存值以及 -m swap 值。
當前的 Docker 接口不允許我們指定(或者是完全禁用它)多少 swap 應該被使用,所以我們現在需要一起使用它。
有了以上信息,我們可以再次運行我們的示例。這次我們嘗試分配超過我們分配的兩倍內存。它將使用所有的內存和所有的 swap,然后玩完了。
$ docker run -it --rm -m 128m stress --vm 1 --vm-bytes 260M --vm-hang 0 stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd stress: FAIL: [1] (415) <-- worker 6 got signal 9 stress: WARN: [1] (417) now reaping child worker processes stress: FAIL: [1] (421) kill error: No such process stress: FAIL: [1] (451) failed run completed in 5s
如果你嘗試再次分配比如 250MB(--vm-bytes 250M),它將工作的很好。
警告:如果你不通過 -m 開關限制內存,swap 也被不會被限制1。
不限制內存將導致將導致一個容器可以很容易使得整個系統不可用的問題。因此請記住要一直使用 -m 參數2。
3.2 CGroups fs你可以在 /sys/fs/cgroup/memory/system.slice/docker-$FULL_CONTAINER_ID.scope/ 下面發現關于內存的所有信息,例如:
$ ls /sys/fs/cgroup/memory/system.slice/docker-48db72d492307799d8b3e37a48627af464d19895601f18a82702116b097e8396.scope/ cgroup.clone_children memory.memsw.failcnt cgroup.event_control memory.memsw.limit_in_bytes cgroup.procs memory.memsw.max_usage_in_bytes memory.failcnt memory.memsw.usage_in_bytes memory.force_empty memory.move_charge_at_immigrate memory.kmem.failcnt memory.numa_stat memory.kmem.limit_in_bytes memory.oom_control memory.kmem.max_usage_in_bytes memory.pressure_level memory.kmem.slabinfo memory.soft_limit_in_bytes memory.kmem.tcp.failcnt memory.stat memory.kmem.tcp.limit_in_bytes memory.swappiness memory.kmem.tcp.max_usage_in_bytes memory.usage_in_bytes memory.kmem.tcp.usage_in_bytes memory.use_hierarchy memory.kmem.usage_in_bytes notify_on_release memory.limit_in_bytes tasks memory.max_usage_in_bytes
4. 塊設備(磁盤)注意:想了解關于這些文件的更多信息,請移步到 RHEL Resource Management Guide, memory section。
對于 塊設備,我們可以考慮兩種不同類型的限制:
讀寫速率
可寫的空間 (定額)
第一個是非常容易實施的,但是第二個仍未解決。
4.1 限制讀寫速率注意:我假設你正在使用 devicemapper storage 作為 Docker 的后端。使用其他后端,任何事情都將不是確定的。
Docker 沒有提供任何的開關來定義我們可以多快的讀或是寫數據到塊設備中。但是 CGroups 內建了。它甚至通過 BlockIO* 屬性暴露給了 systemd。
為了限制讀寫速率我們可以分別使用 BlockIOReadBandwidth 和 BlockIOWriteBandwidth 屬性。
默認 bandwith 是沒有被限制的。這意味著一個容器可以使得硬盤”熱“,特別是它開始使用 swap 的時候。
4.2 示例:限制寫速率讓我測試沒有執行限制的速率:
$ docker run -it --rm --name block-device-test fedora bash bash-4.2# time $(dd if=/dev/zero of=testfile0 bs=1000 count=100000 && sync) 100000+0 records in 100000+0 records out 100000000 bytes (100 MB) copied, 0.202718 s, 493 MB/s real 0m3.838s user 0m0.018s sys 0m0.213s
花費了 3.8秒來寫入 100MB 數據,大概是 26MB/s。讓我們嘗試限制一點磁盤的速率。
為了能調整容器可用的 bandwitch,我們需要明確的知道容器掛載的文件系統在哪里。當你在容器里面執行 mount 命令的時候,你可以發現它,發現設備掛載在 root 文件系統:
$ mount /dev/mapper/docker-253:0-3408580-d2115072c442b0453b3df3b16e8366ac9fd3defd4cecd182317a6f195dab3b88 on / type ext4 (rw,relatime,context="system_u:object_r:svirt_sandbox_file_t:s0:c447,c990",discard,stripe=16,data=ordered) proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) tmpfs on /dev type tmpfs (rw,nosuid,context="system_u:object_r:svirt_sandbox_file_t:s0:c447,c990",mode=755) [SNIP]
在我們的示例中是 /dev/mapper/docker-253:0-3408580-d2115072c442b0453b3df3b16e8366ac9fd3defd4cecd182317a6f195dab3b88。
你也可以使用 nsenter 得到這個值,像這樣:
$ sudo /usr/bin/nsenter --target $(docker inspect -f "{{ .State.Pid }}" $CONTAINER_ID) --mount --uts --ipc --net --pid mount | head -1 | awk "{ print $1 }" /dev/mapper/docker-253:0-3408580-d2115072c442b0453b3df3b16e8366ac9fd3defd4cecd182317a6f195dab3b88
現在我們可以改變 BlockIOWriteBandwidth 屬性的值,像這樣:
$ sudo systemctl set-property --runtime docker-d2115072c442b0453b3df3b16e8366ac9fd3defd4cecd182317a6f195dab3b88.scope "BlockIOWriteBandwidth=/dev/mapper/docker-253:0-3408580-d2115072c442b0453b3df3b16e8366ac9fd3defd4cecd182317a6f195dab3b88 10M"
這應該把磁盤的速率限制在 10MB/s,讓我們再次運行 dd:
bash-4.2# time $(dd if=/dev/zero of=testfile0 bs=1000 count=100000 && sync) 100000+0 records in 100000+0 records out 100000000 bytes (100 MB) copied, 0.229776 s, 435 MB/s real 0m10.428s user 0m0.012s sys 0m0.276s
可以看到,它花費了 10s 來把 100MB 數據寫入磁盤,因此這速率是 10MB/s。
4.3 限制磁盤空間注意:你可以使用 BlockIOReadBandwidth 屬性同樣的限制你的讀速率
正如我前面提到的,這是艱難的話題,默認你每個容器有 10GB 的空間,有時候它太大了,有時候不能滿足我們所有的數據放在這里。不幸的是,我們不能為此做點什么。
我們能做的唯一的事情就是新容器的默認值,如果你認為一些其他的值(比如 5GB)更適合你的情況,你可以通過指定 Docker daemon 的 --storage-opt來實現,像這樣:
docker -d --storage-opt dm.basesize=5G
你可以調整一些其他的東西,但是請記住,這需要在后面重起你的 Docker daemon,想了解更多的信息,請看這里。
4.4 CGroups fs你可以在 /sys/fs/cgroup/blkio/system.slice/docker-$FULL_CONTAINER_ID.scope/ 目錄下發現關于塊設備的所有信息,例如:
$ ls /sys/fs/cgroup/blkio/system.slice/docker-48db72d492307799d8b3e37a48627af464d19895601f18a82702116b097e8396.scope/ blkio.io_merged blkio.sectors_recursive blkio.io_merged_recursive blkio.throttle.io_service_bytes blkio.io_queued blkio.throttle.io_serviced blkio.io_queued_recursive blkio.throttle.read_bps_device blkio.io_service_bytes blkio.throttle.read_iops_device blkio.io_service_bytes_recursive blkio.throttle.write_bps_device blkio.io_serviced blkio.throttle.write_iops_device blkio.io_serviced_recursive blkio.time blkio.io_service_time blkio.time_recursive blkio.io_service_time_recursive blkio.weight blkio.io_wait_time blkio.weight_device blkio.io_wait_time_recursive cgroup.clone_children blkio.leaf_weight cgroup.procs blkio.leaf_weight_device notify_on_release blkio.reset_stats tasks blkio.sectors
總結注意:想了解關于這些文件的更多信息,請移步到 RHEL Resource Management Guide, blkio section。
正如你所看到的,Docker 容器的資源管理是可行的。甚至非常簡單。唯一的事情就是我們不能為磁盤使用設置一個定額,這有一個上游問題列表 -- 跟蹤它并且評論。
希望你發現我的文章對你有用。
這在技術上是不正確的; 這有限度, 但是它設置的值在我們當前運行的系統是不可達的。 例如在我的筆記本上 16GB 的內存值是 18446744073709551615,這是 ~18.5 exabytes…??
或者是使用 MemoryLimit 屬性。??
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/26333.html
摘要:本文將以多主機網絡環境為基礎,探討如何利用內置編排工具模式對各主機上的容器加以管理。在本文中,我們將立足于臺主機與在負載均衡之上部署應用程序容器,同時將其接入一套覆蓋網絡。管理節點會利用負載均衡以將服務公布至集群之外。 本文將以多主機網絡環境為基礎,探討如何利用內置編排工具 Docker Swarm模式對各主機上的容器加以管理。 Docker Engine – Swarm模式 在...
摘要:分別進行配置和測試。也就是說對于開發和部署來說,使用可以更快速的交付和部署應用環境。更便捷的應用更新管理。使用鏡像創建并啟動一個容器。執行用戶指定的應用程序。執行完畢后,容器被終止。 Docker是為應用的開發和部署提供的一站式容器解決方案,它能幫助開發者高效快速的構建應用,實現Build,Ship and Run Any App, Anywhere,從而達到一次構建,到處運行的目的。...
摘要:資源官網資源資源版本的安裝參考這個資源安裝參考這個資源阿里云開發者平臺資源阿里云鏡像加速器資源中文版資源參考學習安裝時間第步卸載舊版本的手工刪除里面有圖象容器卷和網絡現在的名字叫第步安裝第步安裝官方的 資源01: Docker官網資源02: Docker Store資源03: Ubuntu版本的Docker安裝(參考這個)資源04: Docker-compose安裝(參考這個) 資源...
閱讀 2805·2019-08-30 15:55
閱讀 2853·2019-08-30 15:53
閱讀 2289·2019-08-26 13:47
閱讀 2551·2019-08-26 13:43
閱讀 3153·2019-08-26 13:33
閱讀 2794·2019-08-26 11:53
閱讀 1789·2019-08-23 18:35
閱讀 795·2019-08-23 17:16