docker 的 python sdk 如何计算docker 容器的 res 内存使用量?

起了一个 mysql 的 docker 容器

version: "3"

services:
  mysql8:
    container_name: mysql8
    image: mysql:8
    restart: always
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=123456
    volumes:
      - ./volumes/:/var/lib/mysql
      - ./my-custom.cnf:/etc/mysql/conf.d/my-custom.cnf

然后使用 htop 看到 mysql8 容器占用的 res 内存是 556MB

图片.png

使用 docker stats 看到的内存使用量是 739.5MB,和 htop 不一致

图片.png

使用 docker 的 python sdk 读取 mysql8 容器的信息

代码如下

from typing import List, Dict, Optional
from concurrent.futures.thread import ThreadPoolExecutor
import click
import docker
from rich.console import Console
from docker.models.containers import Container
import json

def get_container_info(container: Container):
    short_id: str = container.short_id
    status: str = container.attrs['State']['Status']
    name: str = container.attrs['Name']

    from docker.models.images import Image

    image: Image = container.image

    image_name = image.tags[0] if image.tags else image.short_id

    container_stats: Dict = container.stats(decode=True).__next__()

    print(json.dumps(container_stats,indent=4))

client = docker.from_env()


container = client.containers.get('c50ca07d3d41')

get_container_info(container)

输出内容:

{
    "read": "2023-10-03T03:27:20.913142192Z",
    "preread": "0001-01-01T00:00:00Z",
    "pids_stats": {
        "current": 47,
        "limit": 33438
    },
    "blkio_stats": {
        "io_service_bytes_recursive": [
            {
                "major": 259,
                "minor": 0,
                "op": "read",
                "value": 301391872
            },
            {
                "major": 259,
                "minor": 0,
                "op": "write",
                "value": 1556733952
            }
        ],
        "io_serviced_recursive": null,
        "io_queue_recursive": null,
        "io_service_time_recursive": null,
        "io_wait_time_recursive": null,
        "io_merged_recursive": null,
        "io_time_recursive": null,
        "sectors_recursive": null
    },
    "num_procs": 0,
    "storage_stats": {},
    "cpu_stats": {
        "cpu_usage": {
            "total_usage": 114408426000,
            "usage_in_kernelmode": 37930579000,
            "usage_in_usermode": 76477847000
        },
        "system_cpu_usage": 105739260000000,
        "online_cpus": 16,
        "throttling_data": {
            "periods": 0,
            "throttled_periods": 0,
            "throttled_time": 0
        }
    },
    "precpu_stats": {
        "cpu_usage": {
            "total_usage": 0,
            "usage_in_kernelmode": 0,
            "usage_in_usermode": 0
        },
        "throttling_data": {
            "periods": 0,
            "throttled_periods": 0,
            "throttled_time": 0
        }
    },
    "memory_stats": {
        "usage": 1346535424,
        "stats": {
            "active_anon": 4096,
            "active_file": 208646144,
            "anon": 546168832,
            "anon_thp": 0,
            "file": 779718656,
            "file_dirty": 0,
            "file_mapped": 36380672,
            "file_writeback": 0,
            "inactive_anon": 546164736,
            "inactive_file": 571072512,
            "kernel_stack": 770048,
            "pgactivate": 50248,
            "pgdeactivate": 0,
            "pgfault": 213604,
            "pglazyfree": 0,
            "pglazyfreed": 0,
            "pgmajfault": 453,
            "pgrefill": 0,
            "pgscan": 0,
            "pgsteal": 0,
            "shmem": 0,
            "slab": 17898776,
            "slab_reclaimable": 17314312,
            "slab_unreclaimable": 584464,
            "sock": 0,
            "thp_collapse_alloc": 0,
            "thp_fault_alloc": 0,
            "unevictable": 0,
            "workingset_activate": 0,
            "workingset_nodereclaim": 0,
            "workingset_refault": 0
        },
        "limit": 29296934912
    },
    "name": "/mysql8",
    "id": "c50ca07d3d41b26b9fca21bb90b942919066352c0f1866750afb7f2ab611d5ea",
    "networks": {
        "eth0": {
            "rx_bytes": 169903746,
            "rx_packets": 423759,
            "rx_errors": 0,
            "rx_dropped": 0,
            "tx_bytes": 18029112,
            "tx_packets": 228139,
            "tx_errors": 0,
            "tx_dropped": 0
        }
    }
}

可以看到 memory_stats 的 usage 是 1346535424,换算一下就是 1346535424/1024/1024/1024=1.25GB,这个结果和 htop 和 docker stats 都不一样

所以有两个问题:
问题一:看来需要组合计算 memory_stats 下面的 stats 中的某些参数才能获取和 htop 和 docker stats 一致的结果,但是我不知道该用哪些参数
问题二:为什么 htop 和 docker stats 的结果不一样

阅读 697
1 个回答

docker stats 是怎么算出来的,我倒是知道了,参考:docker stats Description

On Linux, the Docker CLI reports memory usage by subtracting cache usage from the total memory usage. The API does not perform such a calculation but rather provides the total memory usage and the amount from the cache so that clients can use the data as needed. The cache usage is defined as the value of total_inactive_file field in the memory.stat file on cgroup v1 hosts.
在 Linux 上,Docker CLI 通过从总内存使用量中减去缓存使用量来报告内存使用量。 API 不执行此类计算,而是提供总内存使用量和缓存量,以便客户端可以根据需要使用数据。缓存使用情况定义为 cgroup v1 主机上 memory.stat 文件中 total_inactive_file 字段的值。

On Docker 19.03 and older, the cache usage was defined as the value of cache field. On cgroup v2 hosts, the cache usage is defined as the value of inactive_file field.
在 Docker 19.03 及更早版本中,缓存使用情况定义为 cache 字段的值。在 cgroup v2 主机上,缓存使用情况定义为 inactive_file 字段的值。

因为我的主机是 cgroupv2 的,所以要想和 docker stats 一样,那就要 usage 减去 inactive_file

float(container_stats['memory_stats']['usage'])-float(container_stats['memory_stats']['stats']['inactive_file'])

至于第二个问题「问题二:为什么 htop 和 docker stats 的结果不一样」,我还得研究研究

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题