ulimit 與 容器


介紹

ulimit 可以設置當前進程以及其子進程的資源使用量,此處討論我們啟動的docker 容器的資源限制。

ulimit使用可以參考ulimit 使用docker run 參數介紹

列表如下:

選項 [options] 含義 例子
-a 顯示當前所有的 limit 信息。 ulimit – a;顯示當前所有的 limit 信息。
-c 最大的 core 文件的大小, 以 blocks 為單位。 ulimit – c unlimited; 對生成的 core 文件的大小不進行限制。
-d 進程最大的數據段的大小,以 Kbytes 為單位。 ulimit -d unlimited;對進程的數據段大小不進行限制。
-f 進程可以創建文件的最大值,以 blocks 為單位。 ulimit – f 2048;限制進程可以創建的最大文件大小為 2048 blocks。
-l 最大可加鎖內存大小,以 Kbytes 為單位。 ulimit – l 32;限制最大可加鎖內存大小為 32 Kbytes。
-m 最大內存大小,以 Kbytes 為單位。 ulimit – m unlimited;對最大內存不進行限制。
-n 可以打開最大文件描述符的數量。 ulimit – n 128;限制最大可以使用 128 個文件描述符。
-p 管道緩沖區的大小,以 Kbytes 為單位。 ulimit – p 512;限制管道緩沖區的大小為 512 Kbytes。
-s 線程棧大小,以 Kbytes 為單位。 ulimit – s 512;限制線程棧的大小為 512 Kbytes。
-t 最大的 CPU 占用時間,以秒為單位。 ulimit – t unlimited;對最大的 CPU 占用時間不進行限制。
-u 用戶最大可用的進程數。 ulimit – u 64;限制用戶最多可以使用 64 個進程。
-v 進程最大可用的虛擬內存,以 Kbytes 為單位。 ulimit – v 200000;限制最大可用的虛擬內存為 200000 Kbytes。

關於 -H(Hard) 和 -S(Soft)參數:
-S 可以理解為當前生效的配置值
-H 可以理解為最大配置值,只能由root用戶提升
參照鏈接,默認情況下ulimit的使用應該是等價於 -HS,也就是同時修改當前配置值和最大值。也就是說非root用戶在一個shell窗口內只能降低配置,而不能提升配置

各項參數在docker容器中對應值

當前窗口設置ulimit

首先測試在當前窗口下設置ulimit值,然后創建容器
我們此處最大打開文件數(系統默認值為1024),我們創建一個能打開1200個文件的容器

ulimit -Hn 258
docker run --rm -it --ulimit nofile=1200 -v /home/mao/Documents/test_ulimit:/ulimit daocloud.io/python:3-onbuild bash

可以看到容器創建成功,測試同時打開文件數量

確實能夠打開1200個文件句柄,看來運行環境下的ulimit對其不起作用

系統配置ulimit

設置沒有生效應該是很正常的現象,因為docker是一個CS架構的,我們當前窗口只是用於發送創建命令,而不是真正的執行者,真正的執行者是 Docker Daemon。因此,我們嘗試設置Docker Daemon的ulimit,

我們來設置系統參數
編輯 /etc/security/limits.conf,添加兩行

root    hard    nofile  900
*       hard    nofile  900
root    soft    nofile  900
*       soft    nofile  900

重啟系統,查看ulimit

[root@localhost ~]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31087
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 900
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kby![](https://images2018.cnblogs.com/blog/1117030/201806/1117030-20180621162543780-1252623657.png)
tes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 31087
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
[root@localhost ~]# docker run --rm -it --ulimit nofile=1200 -v /home/mao/Documents/test_ulimit:/ulimit daocloud.io/python:3-onbuild bash

但是創建容器依舊成功,在容器內運行正常,能夠打開1200個文件。

這就很奇怪了,我們來看看進程的限制

[root@localhost Documents]# ps aux | grep docker
root       1142  0.4  1.0 503536 83648 ?        Ssl  17:03   0:02 /usr/bin/dockerd
root       1432  0.2  0.2 236876 22672 ?        Ssl  17:03   0:01 docker-containerd --config /var/run/docker/containerd/containerd.toml
root       2751  0.0  0.2 176752 16684 pts/0    Sl+  17:07   0:00 docker run --rm -it --ulimit nofile=1200 -v /home/mao/Documents/test_ulimit:/ulimit daocloud.io/python:3-onbuild bash
root       2764  0.0  0.0   7640  3188 ?        Sl   17:07   0:00 docker-containerd-shim -namespace moby -workdir /var/lib/docke /containerd/daemon/io.containerd.runtime.v1.linux/moby/ca96469d3d0325f370312f76181a0054b2eb76a11961498fbb83677c1ca6afe7 -address /var/run/docker/containerd/docker-containerd.sock -containerd-binary /usr/bin/docker-containerd -runtime-root /var/run/docker/runtime-runc
root       2868  0.0  0.0 112708   972 pts/1    S+   17:12   0:00 grep --color=auto docker
[root@localhost Documents]# cat /proc/1142/limits
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
Max file size             unlimited            unlimited            bytes
Max data size             unlimited            unlimited            bytes
Max stack size            8388608              unlimited            bytes
Max core file size        unlimited            unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             unlimited            unlimited            processes
Max open files            65536                65536                files
Max locked memory         65536                65536                bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       31087                31087                signals
Max msgqueue size         819200               819200               bytes
Max nice priority         0                    0
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us
[root@localhost Documents]# cat /proc/2764/limits
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
Max file size             unlimited            unlimited            bytes
Max data size             unlimited            unlimited            bytes
Max stack size            8388608              unlimited            bytes
Max core file size        unlimited            unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             unlimited            unlimited            processes
Max open files            65536                65536                files
Max locked memory         65536                65536                bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       31087                31087                signals
Max msgqueue size         819200               819200               bytes
Max nice priority         0                    0
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us

我們設置的900限制並沒有生效,后來想了想,看到這篇文章,原因可能是系統守護進程是先啟動的docker服務,然后才讀取的limits.conf參數,因此這個參數設置並沒有生效。

調整docker.service

既然是系統服務的原因,那么我們就去調整系統服務參數

查看 /lib/systemd/system/docker.service

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target docker.socket firewalld.service
Wants=network-online.target
Requires=docker.socket

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd://
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=1048576
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity
# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
# restart the docker process if it exits prematurely
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s

[Install]
WantedBy=multi-user.target

在這個文件中我們可以看到系統的打開文件最大值為1048576,我們可以試試創建相應的容器
嘗試運行docker run -d --name=b1 --ulimit nofile=1048576 busybox top,成功運行
嘗試運行docker run -d --name=b2 --ulimit nofile=1048577 busybox top,報錯:

但是這個參數是否真的有效呢?
使用了這個參數之后,我們查看 /proc/pid/limits,可以看到容器進程的limits確實被限制到了這個范圍內。但是這個參數僅僅是docker run 的默認參數,你依然可以通過--ulimit參數超出這個限制。
比如我在docker.service中設置LimitNOFILE=990,但是我們仍然可以創建--ulimit nofile=1200的容器。

這個時候就出現了一個奇怪的現象:

[root@localhost system]# vi docker.service
[root@localhost system]# systemctl daemon-reload
[root@localhost system]# systemctl restart docker
[root@localhost system]# docker run --rm -it --ulimit nofile=1200 -v /home/mao/Documents/test_ulimit:/ulimit daocloud.io/python:3-onbuild bash
root@bd021ea0b5db:/usr/src/app#

然后重新啟動一個shell

[root@localhost ~]# ps aux | grep docker
root       2835  1.0  0.8 544764 65920 ?        Ssl  17:49   0:00 /usr/bin/dockerd
root       2840  1.1  0.2 301292 21608 ?        Ssl  17:49   0:00 docker-containerd --config /var/run/docker/containerd/containerd.toml
root       2949  1.5  0.2 176752 18664 pts/0    Sl+  17:49   0:00 docker run --rm -it --ulimit nofile=1200 -v /home/mao/Documents/test_ulimit:/ulimit daocloud.io/python:3-onbuild bash
root       2965  0.1  0.0   7512  2704 ?        Sl   17:49   0:00 docker-containerd-shim -namespace moby -workdir /var/lib/docke /containerd/daemon/io.containerd.runtime.v1.linux/moby/bd021ea0b5dba32f14b27af41177251d6e5742f739e8fcfe54116c55b272c19c -address /var/run/docker/containerd/docker-containerd.sock -containerd-binary /usr/bin/docker-containerd -runtime-root /var/run/docker/runtime-runc
root       3074  0.0  0.0 112704   968 pts/1    S+   17:49   0:00 grep --color=auto docker
[root@localhost ~]# cat /proc/2965/limits
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
Max file size             unlimited            unlimited            bytes
Max data size             unlimited            unlimited            bytes
Max stack size            8388608              unlimited            bytes
Max core file size        unlimited            unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             unlimited            unlimited            processes
Max open files            990                  990                  files
Max locked memory         65536                65536                bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       31087                31087                signals
Max msgqueue size         819200               819200               bytes
Max nice priority         0                    0
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us

可以看到雖然它的容器進程的limits限制是990,但是我們創建的容器的ulimit卻依然可以達到1200
在容器中進行測試:

root@bd021ea0b5db:/ulimit# ulimit -n
1200
root@bd021ea0b5db:/ulimit# python test_fh.py
open 1 file descriptors
open 2 file descriptors
open 3 file descriptors
...
open 1195 file descriptors
open 1196 file descriptors
open 1197 file descriptors
Traceback (most recent call last):
  File "test_fh.py", line 9, in <module>
OSError: [Errno 24] Too many open files: 'file1197'

看來真的可以同時打開1200個文件,這一點很奇怪。可能是容器的隔離機制做的很好的原因。

另外一個問題是這個1048576是從哪里來的呢,我從Ubuntu16.04的docker.service中看到的這個值,但是centos7中打開看到的卻是“infinity”,但是創建容器的時候參數最大還是只能為1048576。
因此我認為這是系統中的一個最大值,但是這個最大值是否有效呢?
我們可以查看 /etc/sysctl.conf,看到一個參數 fs.file-max=786960。創建了一個--ulimit nofile=1048576 的容器,在其中打開文件,最終發現創建文件數量達到70萬左右的時候就會報錯退出了,因此,/etc/sysctl.conf中的值才是真正的系統限制。

其他參數

順便測一下docker.service中的其他設置,中設置

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.

LimitFSIZE=666666
LimitCPU=666666
LimitDATA=666666
LimitSTACK=666666
LimitCORE=666666
LimitRSS=666666
LimitMEMLOCK=666666
LimitNPROC=666666
LimitNOFILE=666666
LimitMEMLOCK=666666
LimitLOCKS=666666

重啟docker服務后,運行容器

[root@localhost system]# docker run --rm -it  busybox sh
/ # ulimit -a
-f: file size (blocks)             1302
-t: cpu time (seconds)             666666
-d: data seg size (kb)             651
-s: stack size (kb)                651
-c: core file size (blocks)        1302
-m: resident set size (kb)         651
-l: locked memory (kb)             651
-p: processes                      666666
-n: file descriptors               666666
-v: address space (kb)             unlimited
-w: locks                          666666
-e: scheduling priority            0
-r: real-time priority             0
/ # exit

可以看到這些默認參數均生效了。

結論

docker的ulimit參數在docker.service中創建,作用於默認容器。創建容器時可以通過--ulimit參數來修改,可以超過設置的值。但是一旦設置之后,無法在容器內提升。

ulimit參數存在一個上限,這個上限是由系統決定的,實際使用過程中也有一個上限,這個上限是由sysctl命令控制的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM