AKS の監視機能 Azure Monitor for Containers の裏側を垣間見る

Azure のマネージド Kubernetes サービスである AKS には、Azure Monitor for Containers という監視機能があります。 ノードのパフォーマンス情報や Pod の標準出力ログ等を統合的に確認できるので非常に便利です。

今回はこの AKS と Azure Monitor for Containers がどのように連携しているかを見ていきます。
# ちなみに、ConfigMaps で一部設定をチューニングできますが今回の前提は既定値としています。

この記事に書いてあること

  • Azure Monitor for Containers を有効にすると、DaemonSet と Deployment が展開される
  • Pod のインベントリやノード情報等クラスタ全体の情報は Deployment が情報を取得
  • Pod ごとの情報は DaemonSet が情報を取得
  • Pod の標準出力は、DaemonSet がノードのログディレクトリをマウントして td-agent-bit で取得

f:id:mitsuki0820:20200613202059p:plain

そもそも Azure Monitor for Containers って?

Azure には、Azure Monitor というブランドでさまざまなリソースの監視が出来るような統合的な監視サービスが提供されています。

AKS に関してもこれで監視をすることになるのですが、特に AKS(コンテナ) 向けのものと位置づけられているのが、Azure Monitor for Containers です。

その開発コンセプトについては、US の開発チームの原田さんの記事が非常にわかりやすいのでぜひご参照ください。
qiita.com

こちらにも引用しておきます。

• Azureと言う広範囲な場所にAKSなどのサービス群を発見し、簡単に監視できること。
• 監視されていないAKSはあるのか?
クラウドサービスの傍らに監視がないといけない。監視ツールを探す手間が面倒。
• 簡単に問題が発見でき、監視ツールを覚える必要のないユーザー体験(UX)が必要。
• 監視ツールの管理や監視をしなくても良く、手間いらずで、自動的にメンテナンスやアップグレードをしてくれる。つまり、監視ツールにでなく、自社のビジネス向上だけに人件費をかけることが出来る。

原田さんの記事にもありますが、 Azure Monitor for Containers を使うと、次のような情報が取得できます。

  • API サーバーの正常性
  • ノードごとの CPU 使用率、メモリ使用状況
  • ノード数、Pod 数
  • Deployment の Ready や Up to date、Available の情報
  • コンテナの標準出力

さて、この監視機能の中身ですが、Log Analytics という Azure のエージェント型の SaaS 監視ソリューションが使われています。

Log Analytics と AKS の連携

この Log Analytics ですがどのようにコンテナの情報を集め、Azure Monitor for Containers にデータを送信しているのか、を調べてみます。

ノードに展開されているリソース

おもむろに kube-system に展開されているリソースを見てみると、こんなリソースがありました。

以下抜粋です。

$ k get all
NAME                                                     READY   STATUS    RESTARTS   AGE
pod/omsagent-62kxc                                       1/1     Running   1          2d3h
pod/omsagent-rs-66964c9f75-wn5hg                         1/1     Running   1          2d3h

NAME                         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                 AGE
daemonset.apps/omsagent      5         5         5       5            5           beta.kubernetes.io/os=linux   4d18h

NAME                                                 READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/omsagent-rs                          1/1     1            1           2d3h

NAME                                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/omsagent-rs-66964c9f75                         1         1         1       2d3h

以前から Azure を使っていると、この oms というキーワードにピンときます。OMS というのは、Azure Monitor の前身の様なものです。

というところで、恐らくこの Deployment と DaemonSet が何かしてるんだろうというあたりがつきます。

omsagent-rs の役割

まず、Deployment の omsagent-rs のシェルでプロセスを見てみましょう。

# ps auxwwww
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.0  18508  3008 ?        Ss   02:49   0:00 /bin/bash /opt/main.sh
root         29  0.0  0.0   6704   120 ?        S    02:49   0:00 inotifywait /etc/config/settings --daemon --recursive --outfile /opt/inotifyoutput.txt --event create,delete --format %e : %T --timefmt +%s
syslog      225  0.0  0.0 129672  2776 ?        Ssl  02:49   0:00 /usr/sbin/rsyslogd
omsagent    266  0.8  0.8 396948 63648 ?        Sl   02:49   2:02 /opt/microsoft/omsagent/ruby/bin/ruby /opt/microsoft/omsagent/bin/omsagent-6408bb34-6b60-4a40-b218-3ad8d671bd15 -d /var/opt/microsoft/omsagent/6408bb34-6b60-4a40-b218-3ad8d671bd15/run/omsagent.pid --no-supervisor -o /var/opt/microsoft/omsagent/6408bb34-6b60-4a40-b218-3ad8d671bd15/log/omsagent.log -c /etc/opt/microsoft/omsagent/6408bb34-6b60-4a40-b218-3ad8d671bd15/conf/omsagent.conf
root        314  0.0  0.0  28356  2636 ?        Ss   02:49   0:00 /usr/sbin/cron
root        340  0.0  0.5 148080 42300 ?        Sl   02:50   0:01 /opt/td-agent-bit/bin/td-agent-bit -c /etc/opt/microsoft/docker-cimprov/td-agent-bit-rs.conf -e /opt/td-agent-bit/bin/out_oms.so
root        346  0.0  0.5 215480 39520 ?        Sl   02:50   0:05 /opt/telegraf --config /etc/opt/microsoft/docker-cimprov/telegraf-rs.conf
root        440  0.0  0.0   4536   764 ?        S    02:50   0:00 sleep inf
root      11637  0.0  0.0  18624  3548 pts/0    Ss   06:15   0:00 bash

そうすると、2つの td-agent が立ち上がっています。

/opt/microsoft/omsagent/ruby/bin/ruby /opt/microsoft/omsagent/bin/omsagent-6408bb34-6b60-4a40-b218-3ad8d671bd15
/opt/td-agent-bit/bin/td-agent-bit

※1 つ目のプロセスって td-agent なの?と思われるかもしれませんが、実は、Azure の Log Analytics のエージェントの実態は、td-agent だったりします。そしてプロセス名の後ろの GUID は、omsagent を識別するための ID になっています。

ちなみに、td-agent-bit では、CPU 使用率を stdout に吐いているだけの様なので割愛します。

td-agent の1つ目: omsagent-**

では、omsagent-** の設定を見てみます。設定は、/etc/opt/microsoft/omsagent//conf/omsagent.conf なのですが、ファイルをインクルードしており、特に AKS に関わりがありそうな設定は /etc/opt/microsoft/omsagent/conf/omsagent.d/container.conf の様です。

とりあえず、source の type だけ見てみるとこんな感じでした。(これも Linux AKS に関係ありそうなものに絞ってます)

kubepodinventory
kubeevents
kubenodeinventory
kubehealth

このキーワードどこかで見たことないでしょうか?



実はこちら、Log Analytics のログから確認できる、テーブルの名前と同じものがあります。
f:id:mitsuki0820:20200613191200p:plain

※上記4つのtype以外に存在するテーブルとして、KubeServices、ContainerNodeInventory、KubeMonAgentEvents がありますが、KubeServices に関しては、kubepodinventory と同じスクリプト、ContainerNodeInventoryに関しては kubenodeinventory で取得されています。KubeMonAgentEvents は出所が分かりませんでしたが、恐らく omsagent-rs から送信されているものと思われます。

さらに、これらのソースとなるものがどのように定義されているのかを見てみます。おもむろに、 /opt/microsoft/omsagent/plugin/* を grep してみます。

# egrep -Ir "kubepodinventory|kubeevents|kubenodeinventory|kubehealth" /opt/microsoft/omsagent/plugin/*  | grep Plugin.reg
/opt/microsoft/omsagent/plugin/in_kube_events.rb:    Plugin.register_input("kubeevents", self)
/opt/microsoft/omsagent/plugin/in_kube_health.rb:    Plugin.register_input("kubehealth", self)
/opt/microsoft/omsagent/plugin/in_kube_nodes.rb:    Plugin.register_input("kubenodeinventory", self)
/opt/microsoft/omsagent/plugin/in_kube_podinventory.rb:    Plugin.register_input("kubepodinventory", self)

この中の一つ、in_kube_podinventory.rb を見てみましょう。

# Initializing continuation token to nil
continuationToken = nil
$log.info("in_kube_podinventory::enumerate : Getting pods from Kube API @ #{Time.now.utc.iso8601}")
continuationToken, podInventory = KubernetesApiClient.getResourcesAndContinuationToken("pods?limit=#{@PODS_CHUNK_SIZE}")
$log.info("in_kube_podinventory::enumerate : Done getting pods from Kube API @ #{Time.now.utc.iso8601}")

雰囲気ですがなんとなくこの in_kube_podinventory.rb の中で Pod 周りの情報を取得している、ということが分かりました。

最後に、もう一度設定ファイルに戻って、これらのログをどこに送っているか見てみましょう。

<match oms.containerinsights.KubeNodeInventory**>
 type out_oms
 log_level debug
 num_threads 5
 buffer_chunk_limit 4m
 buffer_type file
 buffer_path /var/opt/microsoft/omsagent/6408bb34-6b60-4a40-b218-3ad8d671bd15/state/state/out_oms_kubenodes*.buffer
 buffer_queue_limit 20
 buffer_queue_full_action drop_oldest_chunk
 flush_interval 20s
 retry_limit 10
 retry_wait 5s
 max_retry_wait 5m
</match>

大体想像がつきますが、out_oms プラグインを使って Log Analytics にデータを送り付けていそうですね。
プラグインの実態はこちら。

/opt/microsoft/omsagent/plugin/out_oms.rb

プラグインから参照している設定ファイルはこちら。なんかそれっぽい設定がありますね。

root@omsagent-rs-66964c9f75-wn5hg:/etc/opt/microsoft/omsagent/conf/omsagent.d# cat /etc/opt/microsoft/omsagent/conf/omsadmin.conf
WORKSPACE_ID=6408bb34-6b60-4a40-b218-3ad8d671bd15
AGENT_GUID=e5fe9077-2ee1-4483-87ca-be35a694bd2e
LOG_FACILITY=local0
CERTIFICATE_UPDATE_ENDPOINT=https://6408bb34-6b60-4a40-b218-3ad8d671bd15.oms.opinsights.azure.com/ConfigurationService.Svc/RenewCertificate
URL_TLD=opinsights.azure.com
DSC_ENDPOINT=https://6408bb34-6b60-4a40-b218-3ad8d671bd15.agentsvc.azure-automation.net/Accounts/6408bb34-6b60-4a40-b218-3ad8d671bd15/Nodes\(AgentId='e5fe9077-2ee1-4483-87ca-be35a694bd2e'\)
OMS_ENDPOINT=https://6408bb34-6b60-4a40-b218-3ad8d671bd15.ods.opinsights.azure.com/OperationalData.svc/PostJsonDataItems
AZURE_RESOURCE_ID=
OMSCLOUD_ID=7783-7084-3265-9085-8269-3286-77
UUID=0255E095-271E-9F4A-A4A1-D1C3EDC4B0AF
root@omsagent-rs-66964c9f75-wn5hg:/etc/opt/microsoft/omsagent/conf/omsagent.d# fg
view /opt/microsoft/omsagent/plugin/out_oms.rb

ひとまずここまで omsagent-rs が何をやっているか、ということをまとめると、Pod や ノードのインベントリー、イベント、正常性を取得して、Log Analytics へ送信していることが分かりました。

omsagent の役割

では続いて同じようなステップで DaemonSet である omsagent を見てみましょう。同じように ps してみます。

# ps auxwwww
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.0  18504  3140 ?        Ss   02:49   0:00 /bin/bash /opt/main.sh
root         29  0.0  0.0   6704   124 ?        S    02:49   0:00 inotifywait /etc/config/settings --daemon --recursive --outfile /opt/inotifyoutput.txt --event create,delete --format %e : %T --timefmt +%s
syslog      227  0.0  0.0 129672  3124 ?        Ssl  02:50   0:00 /usr/sbin/rsyslogd
omsagent    268  0.4  0.6 317832 46796 ?        Sl   02:50   1:43 /opt/microsoft/omsagent/ruby/bin/ruby /opt/microsoft/omsagent/bin/omsagent-6408bb34-6b60-4a40-b218-3ad8d671bd15 -d /var/opt/microsoft/omsagent/6408bb34-6b60-4a40-b218-3ad8d671bd15/run/omsagent.pid --no-supervisor -o /var/opt/microsoft/omsagent/6408bb34-6b60-4a40-b218-3ad8d671bd15/log/omsagent.log -c /etc/opt/microsoft/omsagent/6408bb34-6b60-4a40-b218-3ad8d671bd15/conf/omsagent.conf
root        297  0.0  0.0  28356  2632 ?        Ss   02:50   0:00 /usr/sbin/cron
root        339  0.0  0.6 160440 49044 ?        Sl   02:50   0:03 /opt/td-agent-bit/bin/td-agent-bit -c /etc/opt/microsoft/docker-cimprov/td-agent-bit.conf -e /opt/td-agent-bit/bin/out_oms.so
root        361  0.0  0.6 203316 48108 ?        Sl   02:50   0:12 /opt/telegraf --config /etc/opt/microsoft/docker-cimprov/telegraf.conf
root        409  0.0  0.0   4536   784 ?        S    02:50   0:00 sleep inf
root      15617  0.0  0.0  18624  3448 pts/0    Ss   04:54   0:00 bash
root      46957  0.0  0.0  34408  2800 pts/0    R+   09:05   0:00 ps auxwwww

こちらでも、2つの td-agent が動いてますね。

/opt/microsoft/omsagent/ruby/bin/ruby /opt/microsoft/omsagent/bin/omsagent-6408bb34-6b60-4a40-b218-3ad8d671bd15
/opt/td-agent-bit/bin/td-agent-bit
td-agent の1つ目: omsagent-**

設定ファイルのパスは同じなので、source の type から見ていきます。

containerinventory
cadvisorperf

Deployment の omsagent-rs と違ってますね。
これも名前から大体想像がつきますが、コンテナのインベントリと、cAdvisor によるパフォーマンスを取得しているようです。

先ほどと同じように、Log Analytics のテーブルと照らし合わせてみます。
f:id:mitsuki0820:20200613192543p:plain

まず、containerinventory はそのまま、td-agent の source です。

次に、cadvisorperf がどこに行ってしまったかというと、LogManagement の Perf テーブルに送信されているようです。これは、プラグインの in_cadvisor_perf.rb を見てみると、以下の様なコードがありました。

record["DataType"] = "LINUX_PERF_BLOB"
record["IPName"] = "LogManagement"
eventStream.add(time, record) if record

恐らくですが、LINUX_PERF_BLOB というのはコンテナに関係なく、Linux のパフォーマンス情報を格納するための LogManagement 配下の Perf のことを指していると思われます。このテーブルは、Windows / Linux 共通で、Log Analytics から取得されてきたパフォーマンス情報を格納するテーブルになるので、同じ仕組みを AKS のコンテナに対しても使っているようです。

そして実はこの Perf テーブルですが、omsagent-rs から、ノードレベルの情報を取得しているようです。そういう意味で、色を紫にしています
また、InsightsMetrics も同様にコンテナ個々の情報、ノード情報をそれぞれ omsaget、omsagent-rs から情報を取得しているようです。

次に、ContainerImageInventory は、filter_container.rb というフィルタープラグインの中で識別されていました。

dataType = case r["ClassName"]
        when "Container_ImageInventory" then "CONTAINER_IMAGE_INVENTORY_BLOB"
        when "Container_ContainerInventory" then "CONTAINER_INVENTORY_BLOB"
        when "Container_DaemonEvent" then "CONTAINER_SERVICE_LOG_BLOB"
        when "Container_ContainerLog" then "CONTAINER_LOG_BLOB"
end

一旦ここまででまとめると、DaemonSet で展開されている omsagent は、ノード上にあるコンテナ特有の情報を取得して、Log Analytics へ送信していることが分かりました。

コンテナの標準出力は?

さて、ここで、Azure Monitor for Containers では、コンテナの標準出力も収集されると最初に書きました。
それはどのように収集されてるのでしょうか?

答えは、この DaemonSet の omsagent の td-agent-bit です。設定ファイルを見てみましょう。

# cat /etc/opt/microsoft/docker-cimprov/td-agent-bit.conf
[INPUT]
    Name tail
    Tag oms.container.log.la.*
    Path ${AZMON_LOG_TAIL_PATH}
# env | grep AZMON_LOG_TAIL_PATH
AZMON_LOG_TAIL_PATH=/var/log/containers/*.log

td-agent-bit の INPUT を見ると、AZMON_LOG_TAIL_PATH にあるファイルを tail しているようです。そして、/var/log は、ノードのディレクトリをマウントしていることで、各ノードのコンテナの標準出力をキャッチできる、というわけです。

volumeMounts:
    - mountPath: /var/log
      name: host-log
volumes:
  - hostPath:
      path: /var/log
      type: ""
    name: host-log

まとめ

今回は Log Analytics に関する Pod がどのような動きをしているのかをざっと調べてみました。

今回かいていない内容として、それぞれのプラグインの処理の詳細、omsagent の ConfigMaps によるカスタマイズの方法、telegraf によるメトリクスの取得など、Deep Dive するとどこまでも行けそうなので引き続き Azure Monitor for Container ネタを書いていきたいと思います。