CLOVER🍀

That was when it all began.

cAdvisorで稼働中のコンテナのメトリクスを取得する(+Prometheus)

cAdvisor?

cAdvisor(Container Advisor)は、稼働中のコンテナのリソース使用量や、パフォーマンス特性を提供してくれるものです。

GitHub - google/cadvisor: Analyzes resource usage and performance characteristics of running containers.

【Docker】cAdvisorによるDockerコンテナの監視について - Qiita

あるホストで稼働する以下の情報をコンテナごとに取得し、エクスポートしてくれます。

  • リソースごとのパラメーター
  • リソース使用量のヒストグラム
  • ネットワーク統計情報

ちなみに、KubernetesではkubeletにcAdvisorが統合、導入されているようです。

cAdvisor

マシン内のすべてのコンテナを検出し、CPU、メモリ、ファイルシステム、ネットワーク使用量の統計を収集してくれますと。
さらにはマシン全体も、と。

Kubernetesに、Kustomizeを使ってDaemonSetとしてデプロイする例もあります。

https://github.com/google/cadvisor/tree/v0.33.0/deploy/kubernetes

使ってみる

とまあ、なんとなくcAdvisorの役割を見たところで、動かしてみましょう。

Quick Startの通り、Dockerコンテナを使って動かすようです。

Quick Start: Running cAdvisor in a Docker Container

google/cAdvisor

実行するOS(CentOS、Fedora、RHEL、Debian)によっては注意事項があったりするようなので、必要に応じてこちらを参照しましょう。

https://github.com/google/cadvisor/blob/v0.33.0/docs/running.md

設定項目はこちら。今回は、特に指定せずにいきます。

https://github.com/google/cadvisor/blob/v0.33.0/docs/runtime_options.md

環境は、こちらを使います。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.2 LTS
Release:    18.04
Codename:   bionic


$ docker version
Client:
 Version:           18.09.4
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        d14af54266
 Built:             Wed Mar 27 18:35:44 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.4
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       d14af54
  Built:            Wed Mar 27 18:01:48 2019
  OS/Arch:          linux/amd64
  Experimental:     false

Quick Startに起動例が書かれていますが、ホスト側へのポートバインドやlatestタグの使用はやめて、こんな感じで利用。

$ docker run -it --rm \
  --volume=/:/rootfs:ro \
  --volume=/var/run:/var/run:ro \
  --volume=/sys:/sys:ro \
  --volume=/var/lib/docker/:/var/lib/docker:ro \
  --volume=/dev/disk/:/dev/disk:ro \
  --name=cadvisor \
  google/cadvisor:v0.33.0

バージョンは、v0.33.0とします。

google/cadvisor

「http://[cAdvisorのIPアドレス]:8080」にアクセスすると、cAdvisorのWeb UIを見ることができます。

f:id:Kazuhira:20190401221740p:plain

参考)
なお、REST APIもある模様。

https://github.com/google/cadvisor/blob/v0.33.0/docs/api_v2.md

この状態だと、ホスト側の情報を見ることができるようです。ページをスクロースさせて下の方に行くと、プロセスの一覧や
CPU、メモリ、ネットワーク、ファイルシステムの状態を見ることができます。

では、他のコンテナを立ててみましょう。

せっかくなので、少しわかりやすいように簡単なサーバーと負荷をかけるツールを動かすコンテナを作ってみます。

次の2つのコンテナを作成します。

  • 簡単なSpring Bootアプリケーションを動かすコンテナ(172.17.0.3)
  • Locustで負荷をかけるコンテナ(172.17.0.4)

最初に、サーバー側。

$ sdk install springboot 2.1.3.RELEASE

こんな感じの簡単なRestControllerを用意。なんとなく、パラメーターを受け取るようにしています。
server.groovy

@RestController
public class SimpleController {
    @GetMapping('/')
    public index(@RequestParam('id') id) {
        id
    }
}

Uber JARにします。

$ spring jar server.jar server.groovy

OpenJDK 8のイメージを使って、アプリケーションを起動。CPUは絞っておきます。

$ docker container run -it --rm --name server -v `pwd`:/host --cpuset-cpus=0,1 openjdk:8-jdk-slim bash
# java -jar /host/server.jar

続いて、Locust。

まず、シナリオを用意。 locustfile.py

from locust import HttpLocust, TaskSet, task
import uuid

class WebAccess(TaskSet):
    @task
    def index(self):
        id = uuid.uuid4()

        with self.client.get("/?id=" + str(id), catch_response = True) as response:
            if response.status_code != 200:
                response.failure("request failed!!")

class WebAccessUser(HttpLocust):
    task_set = WebAccess
    min_wait = 300
    max_wait = 500

Python 3.7のイメージを使って、環境を用意。

$ $ docker container run -it --rm --name locust -v `pwd`/locustfile.py:/tmp/locustfile.py --cpuset-cpus=2,3 python:3.7 bash
# pip3 install locustio

ここで、cAdvisorのWeb UIの「Docker Containers」リンクを押すと、現在のコンテナの一覧を見ることができます。

f:id:Kazuhira:20190401225602p:plain

コンテナ名をクリックすると、コンテナ単位に情報(CPUやメモリなども)を見ることができます。

f:id:Kazuhira:20190401225645p:plain

では、負荷をかけてみましょう。

# locust -f /tmp/locustfile.py --host=http://172.17.0.3:8080 --no-web -c 200 -r 20 -t 180

各コンテナのページを見ると、リソースの使用状況が変化していく様子を確認することができます。

f:id:Kazuhira:20190401225813p:plain

なんとなく、確認できた気がします。

Prometheusにメトリクスをエクスポートする

cAdvisorは、Storage Driver Pluginとして情報をエクスポートする仕組みがあるようです。

https://github.com/google/cadvisor/blob/v0.33.0/docs/storage/README.md

Prometheus向けのものがあるようですので、こちらを使ってみましょう。

https://github.com/google/cadvisor/blob/v0.33.0/docs/storage/prometheus.md

設定ファイルは、こんな感じで用意。 prometheus.yml

global:
  scrape_interval:     3s
  evaluation_interval: 3s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
    - targets: ['localhost:9090']
  - job_name: "cadvisor"
    static_configs:
    - targets: ["172.17.0.2:8080"]

この設定ファイルを使って、Prometheusのコンテナを起動します。

$ docker container run -it --rm --name prometheus -v `pwd`/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus:v2.8.1

ちなみに、cAdvisorのPrometheus向けのエンドポイントは、「/metrics」のようですよ。設定で変更することもできるようです。

CPUに関する情報を見てみます。

$ curl -s 172.17.0.2:8080/metrics | grep cpu | grep -E 'server|locust'
container_cpu_load_average_10s{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 0 1554127322988
container_cpu_load_average_10s{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 0 1554127321610
container_cpu_system_seconds_total{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 10.18 1554127322988
container_cpu_system_seconds_total{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 5.06 1554127321610
container_cpu_usage_seconds_total{container_label_maintainer="",cpu="cpu00",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 21.025954446 1554127321610
container_cpu_usage_seconds_total{container_label_maintainer="",cpu="cpu01",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 18.710983788 1554127321610
container_cpu_usage_seconds_total{container_label_maintainer="",cpu="cpu02",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 66.183811872 1554127322988
container_cpu_usage_seconds_total{container_label_maintainer="",cpu="cpu02",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 0.256701358 1554127321610
container_cpu_usage_seconds_total{container_label_maintainer="",cpu="cpu03",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 165.403016329 1554127322988
container_cpu_usage_seconds_total{container_label_maintainer="",cpu="cpu03",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 0.610232295 1554127321610
container_cpu_usage_seconds_total{container_label_maintainer="",cpu="cpu05",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 0.000928385 1554127321610
container_cpu_user_seconds_total{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 221.28 1554127322988
container_cpu_user_seconds_total{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 34.14 1554127321610
container_spec_cpu_period{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 100000
container_spec_cpu_period{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 100000
container_spec_cpu_shares{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 1024
container_spec_cpu_shares{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 1024

PrometheusのWeb UIでも見てみましょう。

f:id:Kazuhira:20190401230259p:plain

「CPU使用率」、みたいな感じでは得られないみたいですね。計算する必要があるようです。

Average CPU % usage per container · Issue #2026 · google/cadvisor · GitHub

とすると、cAdvisorのWeb UIではコンテナ内のプロセスに対してCPU使用率が表示されていたのでは?と思うのですが、
こちらは自前で計算しているみたいですね。

https://github.com/google/cadvisor/blob/v0.33.0/pages/assets/js/containers.js#L369-L370

なるほど…。

メモリもちらっと。

$ curl -s 172.17.0.2:8080/metrics | grep memory | grep -E 'server|locust'
container_memory_cache{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 6.2480384e+07 1554128366591
container_memory_cache{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 32768 1554128366572
container_memory_failcnt{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 0 1554128366591
container_memory_failcnt{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 0 1554128366572
container_memory_failures_total{container_label_maintainer="",failure_type="pgfault",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust",scope="container"} 185466 1554128366591
container_memory_failures_total{container_label_maintainer="",failure_type="pgfault",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust",scope="hierarchy"} 185466 1554128366591
container_memory_failures_total{container_label_maintainer="",failure_type="pgfault",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server",scope="container"} 213939 1554128366572
container_memory_failures_total{container_label_maintainer="",failure_type="pgfault",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server",scope="hierarchy"} 213939 1554128366572
container_memory_failures_total{container_label_maintainer="",failure_type="pgmajfault",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust",scope="container"} 0 1554128366591
container_memory_failures_total{container_label_maintainer="",failure_type="pgmajfault",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust",scope="hierarchy"} 0 1554128366591
container_memory_failures_total{container_label_maintainer="",failure_type="pgmajfault",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server",scope="container"} 0 1554128366572
container_memory_failures_total{container_label_maintainer="",failure_type="pgmajfault",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server",scope="hierarchy"} 0 1554128366572
container_memory_mapped_file{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 2.781184e+06 1554128366591
container_memory_mapped_file{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 32768 1554128366572
container_memory_max_usage_bytes{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 1.9380224e+08 1554128366591
container_memory_max_usage_bytes{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 8.28792832e+08 1554128366572
container_memory_rss{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 6.3279104e+07 1554128366591
container_memory_rss{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 8.22767616e+08 1554128366572
container_memory_swap{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 0 1554128366591
container_memory_swap{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 0 1554128366572
container_memory_usage_bytes{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 1.36892416e+08 1554128366591
container_memory_usage_bytes{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 8.27752448e+08 1554128366572
container_memory_working_set_bytes{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 8.820736e+07 1554128366591
container_memory_working_set_bytes{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 8.2771968e+08 1554128366572
container_spec_memory_limit_bytes{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 0
container_spec_memory_limit_bytes{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 0
container_spec_memory_reservation_limit_bytes{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 0
container_spec_memory_reservation_limit_bytes{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 0
container_spec_memory_swap_limit_bytes{container_label_maintainer="",id="/docker/c6ad0ec76ccf0b4bc8aa3363c21215605269f88d224bf55e2fc8e1568dba7b3a",image="python:3.7",name="locust"} 0
container_spec_memory_swap_limit_bytes{container_label_maintainer="",id="/docker/d8239a9c87003f352da6da885a2687eb93ed7c67428dacbfaec0aba9a5158dda",image="openjdk:8-jdk-slim",name="server"} 0

Web UIでも。

f:id:Kazuhira:20190401232002p:plain