首页 > 其他分享 >Docker基础知识 (25) - Docker 容器资源限制和监控

Docker基础知识 (25) - Docker 容器资源限制和监控

时间:2023-02-05 18:55:17浏览次数:46  
标签:25 容器 -- CPU 基础知识 内存 memory Docker docker


在默认情况下,Docker 是不对运行的容器进行资源限制的。在生产环境中,如果不对单一容器进行资源限制,宿主(主机)的资源用完后会导致系统出错甚至系统崩溃。因为在生产环境通常会部署几十个、甚至几百个容器,这些容器都共同使用宿主(主机)的 CPU、内存、磁盘等资源,当某一个容器占用宿主(主机)的资源过多,会导致其它容器无法正常运行、甚至服务崩溃等,因此在创建容器的时候需要进行资源限制。

 

1. 资源限制的概念

    Docker 对容器的资源限制类似于使用 VirtualBox 创建的虚拟机,VirtualBox 创建一台虚拟机时指定 CPU、内存等参数,虚拟机在运行的过程中只能使用参数指定内的宿主机资源。
    
    Docker 也是使用了类似的方法对容器进行资源限制,Docker 利用 cgroup 功能限制每个容器能使用的宿主(主机)资源,这些限制条件可以在执行 docker run 命令时进行配置。

    在进行 Docker 资源限制时,一些功能需要得到宿主(主机)的内核支持,在 Docker 服务器上执行 docker info 命令可以查看相关支持,格式如下:

        $ docker info

            
            Client:
             Context: default
             Debug Mode: false
             Plugins:
              app: Docker App (Docker Inc., v0.9.1-beta3)
              buildx: Build with BuildKit (Docker Inc., v0.5.1-docker)
              scan: Docker Scan (Docker Inc., v0.21.0)

            Server:
             Containers: 4
              Running: 4
              Paused: 0
              Stopped: 0
             Images: 15
             Server Version: 20.10.7
             Storage Driver: overlay2
              Backing Filesystem: extfs
              Supports d_type: true
              Native Overlay Diff: true
              userxattr: false
             Logging Driver: json-file
             Cgroup Driver: cgroupfs
             Cgroup Version: 1
             Plugins:
              Volume: local
              Network: bridge host ipvlan macvlan null overlay
              Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
             Swarm: inactive
             Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
             Default Runtime: runc
             Init Binary: docker-init
             containerd version: 1c90a442489720eec95342e1789ee8a5e1b9536f
             runc version: v1.1.4-0-g5fd4c4d
             init version: de40ad0
             Security Options:
              apparmor
              seccomp
               Profile: default
             Kernel Version: 5.15.0-58-generic
             Operating System: Ubuntu 20.04.5 LTS
             OSType: linux
             Architecture: x86_64
             CPUs: 2
             Total Memory: 1.93GiB
             Name: Tom-Ubuntu20
             ID: NTDR:PPOJ:PJG3:QFLF:UYVG:OIRR:7AIK:Q4KR:COOV:AOLT:DMW6:SEME
             Docker Root Dir: /var/lib/docker
             Debug Mode: false
             Registry: https://index.docker.io/v1/
             Labels:
             Experimental: false
             Insecure Registries:
              192.168.0.3
              127.0.0.0/8
             Registry Mirrors:
              https://docker.mirrors.ustc.edu.cn/
              https://hub-mirror.c.163.com/
              https://reg-mirror.qiniu.com/
             Live Restore Enabled: false

    如果宿主(主机)内核中禁用了某些功能,会在结尾输出警告,根据需要调整宿主(主机)的系统配置。
    
    Docker 对容器的资源限制主要是限制内存和 CPU。


2. Docker 容器的内存限制

    Docker 的内存限制分为两种:

        (1) 硬性的内存限制,也就是允许容器使用指定的内存大小;
        (2) 非硬性的内存限制,即容器可以使用尽可能多的内存,直到内核检测到主机上的内存不够用;

    一般情况下使用硬性内存限制。在指定容器内存大小时,使用正整数,后面跟上 b(字节)、k(千字节)、m(兆字节)和 g(千兆字节)作为单位后缀。

    1) OOM (Out Of Memory) 优先级的机制

        在产生了 OOM 时,Docker 会尝试调整 Docker 守护程序上的 OOM 的优先级来减轻这些风险,以便它比系统上的其他进程更不可能被杀死,但是容器的 OOM 优先级没有调整的话,这会使单个容器被杀死的可能性比 Docker 守护进程或其他系统进程被杀死的可能性会更大,不推荐通过在守护进程或容器上手动设置 –oom-score-adj 为极端负数,或通过在容器上设置 –oom-kill-disable 来跳过这些安全的措施。

        /proc/PID/oom_score_adj: 范围为 -1000 到 1000,值越高越容易被宿主机 kill 掉,如果将该值设置为 -1000,则进程永远不会被宿主机 kernel kill。

        /proc/PIDJoom_adj: 范围为 -17 到 +15,取值越高越容易被干掉,如果是 -17,则表示不能被 kill,该设置参数的存在是为了和旧版本的 Linux 内核兼容。

        /proc/PID/oom_score:这个值是系统综合进程的内存消耗量、CPU 时间 (utime + stime)、存活时间 (utime - stime) 和 oom_adj 计算出的进程得分,消耗内存越多得分越高,越容易被宿主(主机)kernel 强制杀死。

        –oom-score-adj:宿主机内核对进程使用的内存进行评分,评分最高的将被宿主(主机)内核 kill 掉(取值范围为 -1000 到 1000,越低越不会被 kill 掉),可以指定一个容器的评分为较低的负数,但会影响内核的正常工作,不推荐手动指定;

        –oom-kill-disable:在设置了 -m 选项时使用,对某个容器关闭 OOM 机制,无论是否出现内存溢出现象,该容器都不会被 kill 掉。如果不设置 -m 选项,主机在产生 OOM 时也还是会 kill 到进程。除了 MySQL 这一类特别重要的容器,一般也不会指定。


    2)内存限制的参数

        (1) -m 或 –memory 参数

            可以指定容器能使用的最大内存,如果设置了此参数,则运行容器启动时最低内存大小为 6M (早期 Docker 版本最小限制为 4M)。

            $ docker images

                REPOSITORY   TAG              IMAGE ID       CREATED         SIZE
                python       3.8-gunicorn     4686d50df7e6   2 weeks ago     993MB
                python       3.8              da8341a525e8   2 weeks ago     913MB
                php          7.4-fpm-mysqli   87fcda7d7f83   3 weeks ago     632MB
                nginx        latest           605c77e624dd   13 months ago   141MB
                php          7.4-fpm          854be5bd67a6   13 months ago   460MB
                mariadb      10.4             3ceee7cde5e0   15 months ago   401MB

            $ docker run -it --rm -m 2m mariadb:10.4 /bin/bash

                docker: Error response from daemon: Minimum memory limit allowed is 6MB.
                See 'docker run --help'.

                注:如果容器存在,自动移除已存在的容器,再创建新容器。

            $ docker run -it --rm -m 6m mariadb:10.4 /bin/bash

                root@7a3849e45f1f:/# exit
                exit


        (2) --memory-swap 参数

            可以指定容器能使用的交换分区大小,该参数必须和物理内存限制同时存在才可使用,并且设定值不同也有不同的效果。

            a) 当设置值大于物理内存时
 
                如果想要容器内可以使用交换分区,则设定值要大于物理内存大小,容器中的 swap 交换分区可用大小为交换分区设定值减去物理内存设定值(所得值大于 0),例如容器物理内存限制为 512m,要想使用 100m 的交换分区,则启动容器时交换分区的设定值为 612m。

                $ docker run -it --rm --memory-swap 30m mariadb:10.4 /bin/bash

                    docker: Error response from daemon: You should always set the Memory limit when using Memoryswap limit, see usage.
                    See 'docker run --help'.

                $ docker run -it --rm -m 512m --memory-swap 612m mariadb:10.4 /bin/bash

                    root@c9ceb920eae6:/# exit
                    exit


            b) 当设置值为 0 或等于物理内存时

                当值为 0 时,这时就可以忽略这个参数设置的,也就是不使用交换分区。

                $ docker run -it --rm -m 512m --memory-swap 0 mariadb:10.4 /bin/bash

                    root@bdc0b5f7d4d9:/# exit
                    exit

                $ docker run -it --rm -m 512m --memory-swap 512m mariadb:10.4 /bin/bash

                    root@aa0aeb40125a:/# exit
                    exit


            c) 当设置值为 unset 时

                当宿主(主机)开启了 swap 功能,并且 --memory-swap 设定值为 unset,即启动容器时未添加 --memory-swap 参数,则表示容器可使用的交换分区大小为2倍的物理内存大小;我们将容器的物理内存设定为 512m,不添加 --memory-swap 参数时,容器能使用的交换分区大小为 1g。

                $ docker run -it --rm -m 512m mariadb:10.4 /bin/bash
            
                    root@31e868d0dd49:/# exit
                    exit


            d) 当设置值为 -1 时

                当宿主(主机)开启了 swap 功能,并且容器 --memory-swap 设定值为 -1,表示容器可以使用宿主(主机)的 swap 最大空间。

                $ docker run -it --rm -m 512m --memory-swap -1 mariadb:10.4 /bin/bash

                    root@3687aa4f055c:/# exit
                    exit


        (3) --memory-swappiness 参数
  
            可以设置容器使用交换分区的倾向性,取值范围为 0-100,0 表示只有在物理内存不足的情况下才会使用交换分区,值越高表示越倾向于使用交换分区,取值为 100 时表示优先使用交换分区。

        (4) --kernel-memory 参数

            可以指定容器可以使用的最大内核内存大小,由于内核内存与用户空间内存是相互隔离的,无法直接与用户空间内存进行交换,因此内核内存不足的容器可能会阻塞宿主机资源,这时就会对主机和其它容易及服务进程产生影响,在生产中不要设置容器的内核内存大小。

        (5) --memory-reservation 参数

            可以指定小于物理内存值的软限制,当 Docker 检测到宿主(主机)上的内存不足时会激活该限制。如果使用该参数时,设定值必须低于 -m 指定的物理内存才能使其优先,并且因为该参数是软限制,因而不能保证容器不超过设置的限制,但容器能使用的最大内存不会超过物理内存设定值。

 

    3) 内存限制的验证

        下载压力测试的镜像来验证容器的内存限制,可以执行 docker run lorel/docker-stress-ng -help 命令来查看压测镜像的使用帮助。

            $ docker run lorel/docker-stress-ng

                Unable to find image 'lorel/docker-stress-ng:latest' locally
                latest: Pulling from lorel/docker-stress-ng
                Image docker.io/lorel/docker-stress-ng:latest uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/
                c52e3ed763ff: Pulling fs layer
                a3ed95caeb02: Downloading
                7f831269c70e: Download complete
                latest: Pulling from lorel/docker-stress-ng
                Image docker.io/lorel/docker-stress-ng:latest uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/
                c52e3ed763ff: Pull complete
                a3ed95caeb02: Pull complete
                7f831269c70e: Pull complete
                Digest: sha256:c8776b750869e274b340f8e8eb9a7d8fb2472edd5b25ff5b7d55728bca681322
                Status: Downloaded newer image for lorel/docker-stress-ng:latest
                stress-ng, version 0.03.11

                Usage: stress-ng [OPTION [ARG]]

                    ...
                
                Example: stress-ng --cpu 8 --io 4 --vm 2 --vm-bytes 128M --fork 4 --timeout 10s

                Note: Sizes can be suffixed with B,K,M,G and times with s,m,h,d,y            

            $ docker run -it lorel/docker-stress-ng /bin/bash stress-ng --cpu 8 --io 4 --vm 2 --vm-bytes 128M --fork 4 --timeout 10s

                stress-ng: info: [1] dispatching hogs: 8 cpu, 4 fork, 4 iosync, 2 vm
                stress-ng: info: [1] successful run completed in 10.10s


        (1) 内存大小硬限制

            a) 不限制物理内存

                使用下载的压测镜像来创建一个容器,利用 -vm 指定 2 个工作进程,并设置每个工作进程最多允许使用 256M 的内存,并且宿主(主机) 也不限制当前容器的最大内存。

                $ docker run -it -d --name test-m1 lorel/docker-stress-ng --vm 2 --vm-bytes 256M

                    0b5e0b9ac76bd195ca7321a0006332e5746c7f0601377c129ed0643605d9b205

                $ docker ps

                    CONTAINER ID   IMAGE                    COMMAND                   ...      NAMES
                    0b5e0b9ac76b   lorel/docker-stress-ng   "/usr/bin/stress-ng …"            test-m1

                $ docker stats test-m1

                    CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT    MEM %     NET I/O       BLOCK I/O     PIDS
                    0b5e0b9ac76b   test-m1   200.49%   513.9MiB / 1.93GiB   26.01%    3.45kB / 0B   4.52MB / 0B   5


            b) 限制物理内存

                使用 -m 或者 –memory 选项来指定容器的最大使用内存。

                $ docker run -it -d --name test-m2 -m 512m lorel/docker-stress-ng --vm 2 --vm-bytes 256M

                    b5b18a32e7a4aca499e4e628c6a4557c193efff8f6570cf30214c8906dce9a78

                $ docker stats test-m2

                    CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT   MEM %     NET I/O       BLOCK I/O     PIDS
                    b5b18a32e7a4   test-m2   185.50%   480MiB / 512MiB     93.75%    2.82kB / 0B   1.19GB / 0B   5


            c) 宿主(主机)验证 cgroups

                宿主(主机)对容器的资源限制主要是利用 Docker 的 cgroup 功能来实现的,可以在 /sys/fs/cgroup/memory/docker/ 目录下找到对应容器ID,容器ID 目录下的 memory.limit_in_bytes 文件中记录了宿主机对容器的内存资源限制;memory.limit_in_bytes 文件中的值是将容器内存转化为字节,所以一般数值会很大;可以使用命令来编辑这个文件的数值,从而修改了物理内存大小的限制。

                    $ ls /sys/fs/cgroup/memory/docker/97d050912cc6daaacad3fb5e46cc23e654d94b6a7de374ae5c6c8b5d037c9b06

                        ...

                    $ cat /sys/fs/cgroup/memory/docker/97d050912cc6daaacad3fb5e46cc23e654d94b6a7de374ae5c6c8b5d037c9b06/memory.limit_in_bytes

                        268435456

                    $ echo "268435456/1024/1024" | bc

                        256

                注:可以通过文本编辑工具编辑文件里的内存限制值的,但是是在原有的基础上添加内存限制,如果修改值小于原有的内存的话是会报出 "write error: Device or resource busy"

        (2) 内存大小软限制

            内存的软限制是需要使用到 --memory-reservation 参数,这个参数设置的作用不是很大,设置了后使用 docker stats 查看时 “MEM USAGE / LIMIT” 的值还是在设置的最大内存值附件波动。

                $ docker run -it -d --name test-m3 --memory-reservation 128m lorel/docker-stress-ng --vm 2 --vm-bytes 256M

                    6b6ae66eedb90813e03c332826273787e3ad1d683fc66b5e142d4f31e94ab356

                $ docker stats test-m3

                    CONTAINER ID  NAME     CPU %    MEM USAGE / LIMIT   MEM %    NET I/O      BLOCK I/O    PIDS
                    6b6ae66eedb9  test-m3  29.69%   255.1MiB / 1.93GiB  12.91%   3.28kB / 0B  8.77GB / 0B  5

            容器内存设置软限制,也可以修改 /sys/fs/cgroup/memory/docker/容器 ID/memory.soft_limit_in_bytes 文件,可以增加或者减少。

        (3) 关闭 OOM 机制

            在 Docker 运行容器时会受到 OOM 机制的影响的,可以创建一个容器来验证 cgroup 的功能,会发现默认是开启 OOM 机制的,这时当宿主机出现 OOM 时会出现被 kill 掉的情况,需要关闭OOM机制的话是需要添加 --oom-kill-disable 参数的。

                $ docker run -it -d --name test-m4 --oom-kill-disable lorel/docker-stress-ng --vm 2 --vm-bytes 256M

                    025a4068bd30b56477f565e5d3fe91c5560c3ed8455fcffbe505380244b5fad4

                $ cat /sys/fs/cgroup/memory/docker/025a4068bd30b56477f565e5d3fe91c5560c3ed8455fcffbe505380244b5fad4/memory.oom_control

                    oom_kill_disable 1
                    under_oom 0
                    oom_kill 0

            如果关闭 OOM 机制的话从而会影响宿主机的正常工作,这个参数基本上是不会去添加的,除非一些特殊的情况。

        (4) 交换分区限制

            当启动一个容器设置的内存是 256m,没有添加 --memory-swap 参数时,这时验证 cgroup 时 memory.memsw.limit_in_bytes 文件的值是默认设置的内存的 2 倍;当我们希望能使用 128m 的交换分区,则需要设置 --memory-swap 参数的值为 386m,设置完后再查看 memory.memsw.limit_in_bytes 文件时,这时就已经是设定的 384m。

                $ docker run -it -d --name test-m5 -m 256m lorel/docker-stress-ng --vm 2 --vm-bytes 256M

                    65accefe365bee2f75376feb25331fd5619c392f637877fec08cacc0793a2519

                $ cat /sys/fs/cgroup/memory/docker/65accefe365bee2f75376feb25331fd5619c392f637877fec08cacc0793a2519/memory.memsw.limit_in_bytes

                    536870912

                $ echo "536870912/1024/1024" | bc

                    512               

                $ docker run -it -d --name test-m6 -m 256m --memory-swap 386m lorel/docker-stress-ng --vm 2 --vm-bytes 256M

                    7d87de9559e0b49761fe25aae7bc440a7349598580c67a0088024f0f0ca281f3

                 $ cat /sys/fs/cgroup/memory/docker/7d87de9559e0b49761fe25aae7bc440a7349598580c67a0088024f0f0ca281f3/memory.memsw.limit_in_bytes

                    404750336

                $ echo "404750336/1024/1024" | bc

                    386                 

            注: 这个 --memory-swap 参数设置的值比设置的的物理内存小的话是会报错的。


3. Docker 容器的 CPU 限制

    在默认的情况下,每个容器对宿主(主机) CPU 周期的访问权限是没有限制的,但是可以设置各种约束来限制给定容器访问宿主(主机)CPU 的周期,大多数的用户使用使用的默认的 CFS 调度的方式,在 Docker 1.13 版本以及更高的版本,是还可以配置实时的优先级。

    1) 容器 CPU 限制的参数

        (1) --cpus 参数:在 Docker1.13 版本及后面的版本才开始使用的,也就是替代了之前版本中的 --cpu-period(CPU 调度周期)和 --cpu-quota(CPU 调度限制)参数;使用该参数可以指定容器使用宿主(主机)中的可用 CPU 资源,假设宿主机中是有 4 个 CPU,启动容器时设置了 --cpus=1.5,则表示容器最多可以访问宿主机 1.5 个 CPU,并且可以是在 4 个 CPU 的每个核心上都使用一点,但总数不能超过 1.5 个。
        (2) --cpuset-cpus 参数:用于指定容器运行的CPU编号,也就是我们说的绑核。
        (3) --cpuset-mem 参数:用于设置使用哪个cpu的内存,这个仅对非统一内存访问(NUMA)的架构有效,这个参数用的少。
        (4) --cpu-shares 参数:用于设置 cfs 中调度的相对最大比例权重,cpu-share 的值越高的容器,将会分得更多的时间片(宿主机多核 CPU 的总数为 100%,假设容器 A 的 –cpu-shares 设定值为 1024,容器 B 的 –cpu-shares 设定值为 2048,则容器 B 能获得的宿主(主机)CPU 资源最多为容器 A 的 2 倍),默认的时间片是 1024,最大是 262144。

    2) 容器 CPU 限制的验证

        (1) 不限制容器的 CPU

            本文使用的虚拟机 cpu 核数是 2个,不对容器的 CPU 做限制,分配 2 个 CPU 在加上两个工作进程,启动容器后查看cpu.cfs_quota_us 文件。

            $ docker run -it -d --name test-c1 -m 128m lorel/docker-stress-ng --vm 2 --cpu 2

                8f54ce693f4d87e2192e7e77f67514573167a4b503fa1b23effa0a998b481c5a

            $ cat /sys/fs/cgroup/cpu,cpuacct/docker/8f54ce693f4d87e2192e7e77f67514573167a4b503fa1b23effa0a998b481c5a/cpu.cfs_quota_us

                -1

            注:-1 表示宿主(主机)CPU 资源使用不受限制。

        (2) 限制容器的 CPU

            使用 --cpus 参数限制容器的 CPU 的使用数量。

            $ docker run -it -d --name test-c2 -m 128m --cpus=1.5 lorel/docker-stress-ng --vm 2 --cpu 2

                f36c4370f7d81fefc796102a754a4593ed0f4c5aa4149db7321c42009aa0d3f8

            $ cat /sys/fs/cgroup/cpu,cpuacct/docker/f36c4370f7d81fefc796102a754a4593ed0f4c5aa4149db7321c42009aa0d3f8/cpu.cfs_quota_us

                150000
            

            注:150000 这个值是以百分比的形式来呈现的,每个核 CPU 是按照 1000 位单位转换成百分比来进行资源分配的,150000/1000=150%,以此类推。给容器分配 CPU 资源时,不能超过宿主(主机)的最大 CPU 核数。

        (3) 容器绑定指定 CPU

            要绑定使用 CPU 的某一个核,需要用到 --cpuset-cpus 参数,Linux 中是从 0 开始编号的,1 号 CPU 核就是编号 0,绑定多个 CPU 核用逗号隔开,连续的可以使用短横线。

                $ docker run -it -d --name test-c3 -m 128m --cpus=1 --cpuset-cpus 1 lorel/docker-stress-ng --vm 2 --cpu 2

                    e8bc040a36184c81f0fec46ac03269b99da5ae667da272b0f568a6ce51881b07

                $ cat /sys/fs/cgroup/cpuset/docker/cpuset.cpus

                    0-1
                
                $ cat /sys/fs/cgroup/cpuset/docker/e8bc040a36184c81f0fec46ac03269b99da5ae667da272b0f568a6ce51881b07/cpuset.cpus

                    1


        (4) 基于 --cpu-share 来切分 CPU

            --cpu-shares 参数是根据不同容器所占的权重来划分宿主(主机)CPU 资源,如果设置的权重越高,容器就越容易获得更多的宿主(主机)CPU 资源。这里启动两个容器来做测试了一个容器的 --cpu-shares 值设置为 1000,另一个就设置 500,查看 CPU 利用率。

                $ docker run -it -d --name test-c4 --cpu-shares 1000 -m 512m lorel/docker-stress-ng --vm 2 --cpu 2

                    5996f645551e3295e3cb98b4a71f3cd0360ef4dbcb3e1b8935bfb24965a940e7

                $ docker run -it -d --name test-c5 --cpu-shares 500 -m 512m lorel/docker-stress-ng --vm 2 --cpu 2

                    0f8ddf733455b01012980b4726f33c544e03b8438bc49d022cc69c193a093981

                $ docker stats

                    CONTAINER ID   NAME     CPU %    MEM USAGE / LIMIT   MEM %    NET I/O       BLOCK I/O    PIDS
                    0f8ddf733455   test-c5  62.04%   297.6MiB / 512MiB   58.12%   2.66kB / 0B   316MB / 0B   7
                    5996f645551e   test-c4  133.65%  511.9MiB / 512MiB   99.99%   3.1kB / 0B    5.47GB / 0B  7


        (5) 动态修改 cpu-share 值(修改权重)

            这里我们直接动态修改 test-c5 容器的 --cpu-shares 值,修改完是立即生效的,这个值是可以动态调大或调小的,因为我这里的宿主(主机)的 CPU 核是 2 个,CPU 的百分率变成了 200%。

            $ cat /sys/fs/cgroup/cpu,cpuacct/docker/0f8ddf733455b01012980b4726f33c544e03b8438bc49d022cc69c193a093981/cpu.shares

                500
            
            $ echo 2000 > /sys/fs/cgroup/cpu,cpuacct/docker/0f8ddf733455b01012980b4726f33c544e03b8438bc49d022cc69c193a093981/cpu.shares

            $ cat /sys/fs/cgroup/cpu,cpuacct/docker/0f8ddf733455b01012980b4726f33c544e03b8438bc49d022cc69c193a093981/cpu.shares

                2000

            $ docker stats

                CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT    MEM %     NET I/O      BLOCK I/O     PIDS
                0f8ddf733455   test-c5   146.79%   511.9MiB / 512MiB    99.98%    5.79kB / 0B  55.2GB / 0B   7
                5996f645551e   test-c4   43.35%    511.9MiB / 512MiB    99.98%    6.05kB / 0B  101GB / 0B    7


4. Docker 监控

    1) Dcker stats 命令

        使用 Docker 自带的 docker stats 命令可以很方便地看到主机上所有容器的 CPU、内存、网络 IO、磁盘 IO、PID 资源的使用情况。

        这里启动一个资源限制 CPU 为 1 核,内存为 512m 的 nginx 容器,然后用 docker stats 命令来查看。

            $ docker images

                REPOSITORY               TAG         IMAGE ID       CREATED         SIZE
                nginx                    latest      605c77e624dd   13 months ago   141MB
                lorel/docker-stress-ng   latest      1ae56ccafe55   6 years ago     8.1MB

            $ docker run --name nginx-c1-512m --cpus 1 -m 512m -d nginx

                a449f6eea9e6edd992d4ec6509789690a7bb8e6aabbcb44b0a27d7eb4e14ce1d

            $ docker ps

                CONTAINER ID   IMAGE    COMMAND                 ...   PORTS     NAMES
                84433adb9dd7   nginx   "/docker-entrypoint.…"         80/tcp    nginx-c1-512m

            $ docker stats nginx-c1-512m

                CONTAINER ID   NAME            CPU %     MEM USAGE / LIMIT   MEM %     NET I/O       BLOCK I/O     PIDS
                84433adb9dd7   nginx-c1-512m   0.00%     2.617MiB / 512MiB   0.51%     3.28kB / 0B   0B / 8.19kB   3


        从容器的运行状态可以看出,docker stats 命令可以获取并显示 Docker 容器运行状态。但是它的缺点也很明显,因为它只能获取本机数据,无法查看历史监控数据,没有可视化展示面板。因此,生产环境中我们通常使用另一种容器监控解决方案 cAdvisor。

    2) cAdvisor 监控

        cAdvisor 是 Google 开源的一款通用的容器监控解决方案。cAdvisor 不仅可以采集机器上所有运行的容器信息,还提供了基础的查询界面和 HTTP 接口,更方便 Prometheus 等监控系统进行数据的获取。所以,cAdvisor很快成了容器指标监控最常用组件,并且 Kubernetes 也集成了 cAdvisor 作为容器监控指标的默认工具。

        cAdvisor Github: https://github.com/google/cadvisor

        (1) 安装运行 cAdvisor

            $ docker pull google/cadvisor

            $ docker run \
                --volume=/:/rootfs:ro \
                --volume=/var/run:/var/run:rw \
                --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=true \
                google/cadvisor

                注:该命令在容器中挂载了几个目录,ro 代表只读,rw 代表可读写。指定/var/run 目录,用于 Docker 套接字的挂载;
                
                    --publish=8080:8080:cadvisor 的 Web 服务端口;
                    --detach:将以守护进程的方式运行;
                    --name:对生成的容器进行命名;
                    --privileged=true:在 Ret Hat、CentOS、Fedora 等发行版上需要传递该参数。

            $ docker ps | grep cadvisor

                be73f761cb2a  google/cadvisor  "/usr/bin/cadvisor -…"  ...  0.0.0.0:8080->8080/tcp,...  cadvisor

            浏览器访问 http://$ip:8080 (或 http://localhost:8080) ,可看到 cAdvisor 的 Web 界面。

        (2) 容器指标

            以下是比较常用到的一些容器指标。

            CPU 指标:

                container_cpu_load_average_10s       # 最近10秒容器的CPU平均负载情况
                container_cpu_usage_seconds_total    # 容器的CPU累积占用时间

            内存指标:

                container_memory_max_usage_bytes     # 容器的最大内存使用量(单位:字节)
                container_memory_usage_bytes        # 容器的当前内存使用量(单位:字节)
                container_spec_memory_limit_bytes    # 容器的可使用最大内存数量(单位:字节)

            网络指标:

                container_network_receive_bytes_total   # 容器网络累积接收字节数据总量(单位:字节)
                container_network_transmit_bytes_total  # 容器网络累积传输数据总量(单位:字节)

            存储指标:

                container_fs_usage_bytes    # 容器中的文件系统存储使用量(单位:字节)
                container_fs_limit_bytes    # 容器中的文件系统存储总量(单位:字节)

    3) Prometheus 集成

        Prometheus 是一套开源的系统监控报警框架。它以给定的时间间隔从已配置的目标收集指标,评估规则表达式,显示结果,并在发现某些情况为真时触发警报。作为新一代的监控框架,Prometheus 包含了许多组件,其中许多组件都是可选的。

        cAdvisor 简单易用,它除了有详细的监控指标,也提供了可供查看的 Web 图表界面。但 cAdvisor 本身的数据保存时间只有 2 分钟,而且在多主机的情况下,要单独去登录每台机器查看 docker 数据也是一件麻烦的事情。

        对此,更好的方法是与 Prometheus 集成,实现 Docker 容器数据的收集与保存。cAdvisor 提供了支持 Prometheus 的 metrics 格式接口(http://$ip:8080/metrics),Prometheus 只需要按照获取 Exporter 指标的方式,创建相关的 Job 即可。

        Prometheus: https://prometheus.io/

        (1) Ubuntu 20.04 下安装 Prometheus

            下载 https://github.com/prometheus/prometheus/releases/download/v2.37.5/prometheus-2.37.5.linux-amd64.tar.gz (LTS 版) 并保持到 ~/docker 目录下。

                $ cd ~/docker
                $ tar -vxzf prometheus-2.37.5.linux-amd64.tar.gz
                $ mv prometheus-2.37.5.linux-amd64 prometheus-2.37.5

        (2)配置运行 Prometheus

            $ cd prometheus-2.37.5
            $ vim prometheus.yml ...

                - job_name: 'docker_cadvisor'
                    static_configs:
                        - targets:
                        - 'localhost:8080'   

            注:在 prometheus.yml 文件新增一个 'docker_cadvisor'  用于访问 cAdvisor。
            
                本文 Prometheus 安装在上文所安装的 cAdvisor 的宿主(主机)上,所以使用 localhost,如果不是本地主机要使用 IP 地址。

            $ ./prometheus --config.file=prometheus.yml

            Prometheus 开始运行,浏览器访问 http://$ip:9090 (或 http://localhost:9090),可看到 Prometheus 的 Web 界面。

        (3)使用 Prometheus
           
            查看 Prometheus 收集的有关自身的一些数据,Prometheus 的 Web 界面顶部的输入框内,输入如下信息:

                promhttp_metric_handler_requests_total

            点击 "Execute" 按钮,返回如下信息:

                promhttp_metric_handler_requests_total{code="200", instance="localhost:9090", job="prometheus"}     31
                promhttp_metric_handler_requests_total{code="500", instance="localhost:9090", job="prometheus"}     0
                promhttp_metric_handler_requests_total{code="503", instance="localhost:9090", job="prometheus"}     0

            查看 cAdvisor 的数据,输入如下信息:

                container_network_receive_bytes_total

            点击 "Execute" 按钮,返回如下信息:
   container_network_receive_bytes_total{container_label_com_docker_compose_config_hash="06c49a9f05e4b82db3a3546671e0d050e91cced3a503d572984535a922581f18", container_label_com_docker_compose_container_number="1", container_label_com_docker_compose_depends_on="nginx:service_started,mariadb:service_started", container_label_com_docker_compose_image="sha256:4686d50df7e6fedf1ff406402dcb80f15310d2fa02bc7bdf8b2be637db99710d", container_label_com_docker_compose_oneoff="False", container_label_com_docker_compose_project="build", container_label_com_docker_compose_project_config_files="/home/docker/gunicorn/build/docker-compose.yml", container_label_com_docker_compose_project_working_dir="/home/docker/gunicorn/build", container_label_com_docker_compose_service="python-django", container_label_com_docker_compose_version="2.6.1", id="/docker/1336b0e3f2cf2e568ae4d10894073769a4a57cf67b5ab0a1491480058944d05c", image="python:3.8-gunicorn", instance="localhost:8080", interface="eth0", job="docker_cadvisor", name="python-3.8-gunicorn-django"}

                ...  


    4) 监控原理

        无论何种监控方案的实现,底层数据都来源于 cgroups。

        cgroups 的工作目录为/sys/fs/cgroup,/sys/fs/cgroup目录下包含了 cgroups 的所有内容。cgroups包含很多子系统,可以用来对不同的资源进行限制。例如对 CPU、内存、PID、磁盘IO 等资源进行限制和监控。

            ls /sys/fs/cgroup/
            blkio  cpuacct      cpuset   freezer  memory   net_cls,net_prio  perf_event  rdma     unified
            cpu    cpu,cpuacct  devices  hugetlb  net_cls  net_prio          pids        systemd

        这些目录代表了 cgroups 的子系统,Docker 会在每一个 cgroups 子系统目录下创建 docker 文件夹。
        
        示例:

            # 获取容器的内存限制
            $ cat /sys/fs/cgroup/memory/docker/a449f6eea9e6edd992d4ec6509789690a7bb8e6aabbcb44b0a27d7eb4e14ce1d/memory.limit_in_bytes

                536870912

            $ echo "536870912/1024/1024" | bc

                512
            
            注:memory.limit_in_bytes 的值为 512 MB,符合上文创建的 nginx-c1-512m 容器的内存限制 512m。


            # 获取容器的内存使用状态
            $ cat  /sys/fs/cgroup/memory/docker/a449f6eea9e6edd992d4ec6509789690a7bb8e6aabbcb44b0a27d7eb4e14ce1d/memory.usage_in_bytes

                2785280

            $ echo "2785280/1024/1024" | bc

                2

            注: 当前内存的使用大小约为 2 MB。


            # 获取容器的网络使用状态
            # 网络的监控数据来源是从 /proc/{PID}/net/dev 目录下读取的,其中 PID 为容器在主机上的进程 ID。
            # 使用 docker inspect 命令查看一下上文启动的 nginx 容器的 PID
            $ docker inspect -f {{.State.Pid}} nginx-c1-512m

                82219

            $ cat /proc/82219/net/dev
            
                Inter-|   Receive                   |  Transmit
                face  |bytes  packets errs drop ... |bytes    packets errs drop ...
                    lo:       0       0    0                  0       0    0
                  eth0:       3548    31   0                  0       0    0

            注:/proc/82219/net/dev 文件记录了该容器里每一个网卡的流量接收和发送情况,以及错误数、丢包数等信息。


标签:25,容器,--,CPU,基础知识,内存,memory,Docker,docker
From: https://www.cnblogs.com/tkuang/p/17093785.html

相关文章

  • Docker安装
    我们很容易就可以在你的环境中安装docker,只要你选择好你的安装方式即可。Docker实际上分为DockerDesktop和Dockerengine。DockerDesktop是一个桌面应用程序,可以在各种l......
  • Docker安装
    我们很容易就可以在你的环境中安装docker,只要你选择好你的安装方式即可。Docker实际上分为DockerDesktop和Dockerengine。DockerDesktop是一个桌面应用程序,可以在各种......
  • docker基础
    一.Docker概述1.1Docker是什么Docker是一种开源的应用容器引擎,基于go语言开发并遵循了apache2.0协议开源,可以轻松的为任何应用创建一个轻量级、可移植的、自给自足的容......
  • Docker基础
    一、Docker概述1.1、Docker是什么?是一个开源的应用容器引擎,基于go语言开发并遵循了apache2.0协议开源是在Linux容器里运行应用的开源工具是一种轻量级的“虚拟机"Doc......
  • Docker网络
    一、Docker网络实现原理Docker使用Linux桥接,在宿王机虚拟一个Docker容器网桥(dockero),pocker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为container-IP,......
  • Docker-compose 容器集群的快速编排
    一、Docker-compose简介Docker-Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。Docker-Compose将所管理的容器分为三层,分别是 工程(projec......
  • Docker 镜像创建之dockerfile
    引言创建镜像有三种方法,分别为基于已有键像创建、基于本地模板创建以及基于Dockerfile创建。一、基于现有镜像创建#首先启动一个镜像,在容器里操作yuminstall-yepel-......
  • Docker cgroups 资源控制
    一、CPU资源控制cgroups,是一个非常强大的1inux内核工具,他不仅可以限制被namespace隔离起来的资源,还可以为资源设置权、计算使用量、操控进程启停等等。所以cgroups(Contro......
  • Docker--consul 注册中心
    前言服务注册与发现是微服务架构中不可或缺的重要功能。起初服务都是单节点的,不保障高可用性,也不考虑服务的压力承载,服务之间调用单纯的通过接口访问。直到后来出现了多个......
  • Docker-harbor私有仓库的部署与管理
    一、Harbor简介1.1、什么是HarborHarbor是VMware公司开源的企业级DockerRegistry项目,其目标是帮助用户迅速搭建一个企业级的DockerRegistry(私有仓库)服务。......