Datadog Log Management と Kubernetes を連携する

Datadog Log Management 便利ですね。

https://docs.datadoghq.com/logs/

私も愛用していますが、日本語のブログ記事等では Hello World 的な記述が多い気がするので、比較的実践的な Kubernetes との連携について、備忘録的に記述をしておきます。


目的

Kubernetes 上で動作している何かしらのアプリケーションのコンテナログを、Kubernetes 上で動作する dd-agent 経由で収集し、 Datadog Log Management で扱えるようにする。


手順


Version 6 用の dd-agent docker image の準備

Kubernetes 環境下で Datadog を使用する際は、Datadog Agent の Docker Image を Daemonset として動作させます。

Version 6 からはそれ以前に比べて Agent の構成が大幅に変更になったこともあってか、docker image が別の名前で提供されるようになっています。

Log Management 機能は、 Datadog の Agent が Version が 6 以上である必要があるため、Version 6 以上用の Docker Image を Daemonset として起動します。


datadog 用の RBAC の設定

Kubernetes 環境で dd-agent を動作させる際は、以下の公式ドキュメントのように RBAC を用いて権限設定をすることが推奨されています。これにより必要以上に dd-agent にファイルアクセスなどの権限を付与させることなく動作させることができます。

https://docs.datadoghq.com/integrations/faq/using-rbac-permission-with-your-kubernetes-integration/

---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: dd-agent
rules:
- apiGroups:
- ""
resources:
- services
- events
- endpoints
- pods
- nodes
- componentstatuses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- configmaps
resourceNames:
- datadogtoken # Kubernetes event collection state
- datadog-leader-election # Leader election token
verbs:
- get
- update
- apiGroups: # To create the leader election token
- ""
resources:
- configmaps
verbs:
- create
- nonResourceURLs:
- "/version"
- "/healthz"
verbs:
- get
- apiGroups: # Kubelet connectivity
- ""
resources:
- nodes/metrics
- nodes/spec
- nodes/proxy
verbs:
- get

---
kind: ServiceAccount
apiVersion: v1
metadata:
name: dd-agent
namespace: dd-agent

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: dd-agent
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: dd-agent
subjects:
- kind: ServiceAccount
name: dd-agent
namespace: dd-agent

ここで設定した ServiceAccount の名前を、Daemonset の設定時も使用します。


dd-agent の Daemonset 設定

以下のような YAML ファイルを用意し、Kubernetes に Apply することで、Datadog の Daemonset が動作します。

---

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: dd-agent
namespace: dd-agent
spec:
template:
metadata:
labels:
app: dd-agent
name: dd-agent
spec:
serviceAccountName: dd-agent
containers:
- image: datadog/agent:latest
imagePullPolicy: Always
name: dd-agent
ports:
- containerPort: 8125
name: dogstatsdport
protocol: UDP
- containerPort: 8126
name: traceport
protocol: TCP
env:
- name: DD_API_KEY
valueFrom:
secretKeyRef:
name: dd-agent-secret
key: DATADOG_API_KEY
- name: DD_LOGS_ENABLED
value: "true"
- name: DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL
value: "true"
- name: DD_TAGS
value: "env:sada"
volumeMounts:
- name: dockersocket
mountPath: /var/run/docker.sock
- name: procdir
mountPath: /host/proc
readOnly: true
- name: cgroups
mountPath: /host/sys/fs/cgroup
readOnly: true
- name: pointerdir
mountPath: /opt/datadog-agent/run
volumes:
- hostPath:
path: /var/run/docker.sock
name: dockersocket
- hostPath:
path: /proc
name: procdir
- hostPath:
path: /sys/fs/cgroup
name: cgroups
- hostPath:
path: /opt/datadog-agent/run
name: pointerdir

いままでの Version 5 との設定の相違点は以下です。


Log Management 系の環境変数の追加



  • DD_LOGS_ENABLED : Log Management 向けのログ収集を有効にするかどうか。


  • DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL : コンテナに出力されたすべてのログを収集するかどうか。


Mount 先のディスクの追加



  • /opt/datadog-agent/run をマウント先に追加。


ServiceAccountName の設定

※こちらは厳密には Datadog Agent Version 5 / 6 による差異ではないです。

今回は RBAC 経由で権限を付与しているため、RBAC で設定をした ServiceAccount の名前を ServiceAccoutName に設定します。


pod の設定

Datadog としての設定は上記までで完了ですが、実際は Pod (Deployment) 上で動作させている Web Application などのログを Datadog Agent 経由で収集することが目的になります。

ということで Pod の設定になりますが、基本的には以下の戦略に則るのが管理上楽ではないかなと思います。


  • Datadog Log Management に収集するログは、コンテナログとする。

  • コンテナログは、JSON フォーマットで出力する。

ここでは、Nginx のアクセスログを出力する例を記載します。


Nginx のアクセスログを JSON 化する

Datadog Log Management に取り込んだログが JSON フォーマットの場合、Datadog 側で自動的にフィールドをパースしてくれます。

そのため、JSON フォーマットで出力をしたほうが Live Tail Dashboard や後続の Pipeline などでの処理が楽になりますので、基本的には JSON でログを扱うのが望ましいです。

Nginx の出力ログを JSON 化する方法については Qiita 上に参考になる記事が存在しますので詳細は割愛します。

https://qiita.com/progrhyme/items/c85d28eb18359f3f50d9

log_format json escape=json '{"time": "$time_iso8601",'

'"host": "$remote_addr",'
'"vhost": "$host",'
'"user": "$remote_user",'
'"status": "$status",'
'"protocol": "$server_protocol",'
'"method": "$request_method",'
'"path": "$request_uri",'
'"req": "$request",'
'"size": "$body_bytes_sent",'
'"reqtime": "$request_time",'
'"apptime": "$upstream_response_time",'
'"user_agent": "$http_user_agent",'
'"forwarded_for": "$http_x_forwarded_for",'
'"forwarded_by": "$http_x_forwarded_by",'
'"forwarded_host": "$http_x_forwarded_host",'
'"forwarded_proto": "$http_x_forwarded_proto",'
'"referrer": "$http_referer"}';


Pod の Annotation で Log Management 向けの設定を行う

https://docs.datadoghq.com/logs/log_collection/docker/

上記の公式ドキュメント内 「Activate Log Collection」 に記載されているうちの、 OPTION 2: AUTODISCOVERY の方法となります。

Annotation 内に Datadog の AutoDiscovery 機能向けの設定を行い、収集対象となるコンテナログの設定を行います。

ad.datadoghq.com/(container name).logs: '[{"source": "nginx", "service": "webapp"}]'

以上で、設定は完了です。

動作イメージとして実稼働している画面を貼ろうと思ったのですが、ログの画面はセンシティブな内容が多くモザイクだらけになって意味がなさそうなので、割愛します。イメージが付き辛くすみません。