Docker: Task: How to Get Container Metrics

 7th March 2021 at 8:25pm

在容器宿主机上获取容器 CPU 及内存使用率。

方案一:使用 docker 命令行

示例代码:

docker stats --no-stream $(docker ps --format={{.Names}} | grep ${CONTAINER_NAME}) \
  --format "{{.CPUPerc}}:{{.MemPerc}}:{{.MemUsage}}" | head -n 1 | \
  while IFS=: read cpu_percent mem_percent mem_usage;
  do
    echo $mem_usage | while IFS=' / ' read mem_used mem_total
    do
      # mem_used / mem_total 可能有这几种单位:
      # https://github.com/docker/go-units/blob/1364ead0d8e38649c7d8d8920d1eafeaf5064071/size.go#L22
      # 但是他们会带一个 B 表示字节,如 7.527MiB 。${mem_used::-1} 去掉最后的 B,使其可以被 numfmt 理解。
      mem_used_kb=$(echo ${mem_used::-1} | numfmt --from iec-i --to-unit Ki)
      mem_total_kb=$(echo ${mem_total::-1} | numfmt --from iec-i --to-unit Ki)
    done
  done

方案优点:

  • 利用 docker stats 来获取计算好的 CPU / Mem 内存占用,相对方便

方案缺点:

  • docker stats 输出的数据不够可编程(比如 MemUsage 字段输出 7.42 MiB / 512 MiB,仍然需要自己去做解析)
  • Bash 脚本操纵数据能力差,不得不引入 numfmt, jo 等工具用来解析单位、生成 JSON 等
  • Bash 脚本难写,一个 split string 就写得很别扭,编码、调试时间增加

方案二:使用 Docker Engine API

这个方案使用 Docker Engine API 来获取 docker stats 所展现的数据。

CONTAINER_ID=$(curl -s --unix-socket ${DOCKER_SOCK_PATH} -H "Content-Type: application/json" "http:/v1.24/containers/json?filters=\{\"name\":\[\"${CONTAINER_NAME}\"\]\}" | jq -r ".[0].Names[0][1:]")
STATS_JSON_DATA=$(curl --unix-socket ${DOCKER_SOCK_PATH} -H "Content-Type: application/json" http:/v1.24/containers/${CONTAINER_ID}/stats?stream=false)

STATS_JSON_DATA 便存储了 Docker API 返回的资源占用 JSON 数据(参考)。然后你需要模仿 Docker 命令行的做法(参考),把这些数据计算成我们实际需要的资源占用数据。

方案优点:

  • 比直接用 Docker 命令行轻量及快速

方案缺点:

  • 难以仅用 Bash 完成所有任务,需要额外写一个 Go 程序来做 JSON 处理和计算
  • 未来 docker stats 的计算方法如果改变,可能需要随之变化
  • 需要考虑 API 兼容性(参考),比如 Docker 1.12.6 版本对应 Docker API 1.24 版本。你需要收集 TSF 的所有容器运行环境的 Docker 版本,来判断用哪个 API 版本