Kubernetes アプリケーションにおける RUM-APM-LOG の連携分析¶
ユースケースの概要¶
企業にとって最も重要な収益源はビジネスであり、現在、ほとんどの企業のビジネスは対応する IT システムによって支えられています。では、企業のビジネスを安定して運用するにはどうすればよいのでしょうか。それは、企業内部の IT システムをいかに安定して運用するかに帰着します。業務システムに異常や障害が発生した場合、多くの場合、ビジネス、アプリケーション開発、運用などの複数の部門の担当者が連携して問題の調査にあたることになります。そこにはプラットフォーム間、部門間、専門分野間をまたがるさまざまな問題が存在し、調査は時間と手間がかかるものになります。
この問題を解決するために、現在業界ではすでに成熟した方法が確立されています。それは、RUM + APM + LOG を活用して、業務システム全体のフロントエンド/バックエンド、およびログを統合的に監視し、さらに 3 つのデータをキーフィールドで連携させて連携分析を実現することで、担当者の作業効率を向上させ、システムの安定稼働を確保するというものです。
- APM:アプリケーションパフォーマンスモニタリング(APM)
- RUM:リアルユーザーモニタリング(RUM)
- LOG:ログ
本稿では、これら 3 つの監視をどのように導入するか、そしてGuanceを活用して連携分析を行う方法について説明します。デモには、RuoYi 権限管理システムを使用しています。詳細については、<ゼロからGuanceで Spring Cloud サービスの可観測性を構築する> を参照してください。
ログについては、本稿では DataKit の Logfwd 収集を使用してビジネス Pod のログを収集します。DataKit で Logfwd 収集を有効にし、Pod に Logfwd の Sidecar を追加して、ビジネスコンテナのログを収集し、DataKit にプッシュします。ビジネスは Sidecar を認識できるため、ログファイルをホストに保存する必要はありません。詳細な使用方法については、以下の System のデプロイ モジュールを参照してください。DataKit はログを受信後、設定された Pipeline を使用してログファイルを分割します。
前提条件¶
アカウント登録¶
Guance にアクセスしてアカウントを登録し、登録済みのアカウントとパスワードでログインします。
DaemonSet 方式による DataKit のデプロイ¶
OpenWay アドレスのトークンを取得する¶
「管理」→「基本設定」をクリックし、下図のトークンをコピーします。
「統合」→「DataKit」→「Kubernetes」をクリックし、最新の datakit.yaml ファイルを取得します。
インストールの実行¶
- 前の手順で取得した
datakit.yamlファイルを使用し、上図で取得したトークンをファイル内のyour-tokenと置き換えます。 - container 収集、logfwd 収集、ddtrace 収集を有効にします。つまり、DataKit コンテナに
container.conf、logfwdserver.conf、ddtrace.confファイルをマウントします。
注意: DataKit のバージョンによって設定が異なる場合があります。最新バージョンを参照してください。この yaml は、本デプロイの完全な設定であり、後述の DataKit に対する操作手順も含まれています。
yaml の完全な内容
apiVersion: v1
kind: Namespace
metadata:
name: datakit
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: datakit
rules:
- apiGroups:
- rbac.authorization.k8s.io
resources:
- clusterroles
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- nodes
- nodes/proxy
- namespaces
- pods
- pods/log
- events
- services
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- apps
resources:
- deployments
- daemonsets
- statefulsets
- replicasets
verbs:
- get
- list
- watch
- apiGroups:
- batch
resources:
- jobs
- cronjobs
verbs:
- get
- list
- watch
- apiGroups:
- guance.com
resources:
- datakits
verbs:
- get
- list
- apiGroups:
- metrics.k8s.io
resources:
- pods
- nodes
verbs:
- get
- list
- nonResourceURLs: ["/metrics"]
verbs: ["get"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: datakit
namespace: datakit
---
apiVersion: v1
kind: Service
metadata:
name: datakit-service
namespace: datakit
spec:
selector:
app: daemonset-datakit
ports:
- protocol: TCP
port: 9529
targetPort: 9529
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: datakit
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: datakit
subjects:
- kind: ServiceAccount
name: datakit
namespace: datakit
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
app: daemonset-datakit
name: datakit
namespace: datakit
spec:
revisionHistoryLimit: 10
selector:
matchLabels:
app: daemonset-datakit
template:
metadata:
labels:
app: daemonset-datakit
spec:
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
containers:
- env:
- name: HOST_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP
- name: ENV_K8S_NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
- name: ENV_DATAWAY
value: https://openway.guance.com?token=XXXXXX
- name: ENV_GLOBAL_HOST_TAGS # 非選出タグ
value: host=__datakit_hostname,host_ip=__datakit_ip,cluster_name_k8s=k8s-prod
- name: ENV_DEFAULT_ENABLED_INPUTS
value: cpu,disk,diskio,mem,swap,system,hostobject,net,host_processes,container,statsd,ebpf,rum
- name: ENV_ENABLE_ELECTION
value: enable
- name: ENV_GLOBAL_ENV_TAGS # 選出タグにのみ有効
value: cluster_name_k8s=k8s-prod
- name: ENV_HTTP_LISTEN
value: 0.0.0.0:9529
- name: ENV_NAMESPACE # 選出用
value: guance-k8s-demo
#- name: ENV_LOG_LEVEL
# value: debug
#- name: ENV_K8S_CLUSTER_NAME
# value: k8s-prod
image: pubrepo.guance.com/datakit/datakit:1.4.10
imagePullPolicy: Always
name: datakit
ports:
- containerPort: 9529
hostPort: 9529
name: port
protocol: TCP
securityContext:
privileged: true
volumeMounts:
- mountPath: /var/run
name: run
- mountPath: /var/lib
name: lib
- mountPath: /var/log
name: log
#- mountPath: /var/run/containerd/containerd.sock
# name: containerd-socket
# readOnly: true
- mountPath: /usr/local/datakit/conf.d/container/container.conf
name: datakit-conf
subPath: container.conf
- mountPath: /usr/local/datakit/conf.d/log/logfwdserver.conf
name: datakit-conf
subPath: logfwdserver.conf
- mountPath: /usr/local/datakit/conf.d/ddtrace/ddtrace.conf
name: datakit-conf
subPath: ddtrace.conf
- mountPath: /host/proc
name: proc
readOnly: true
- mountPath: /host/dev
name: dev
readOnly: true
- mountPath: /host/sys
name: sys
readOnly: true
- mountPath: /rootfs
name: rootfs
- mountPath: /sys/kernel/debug
name: debugfs
workingDir: /usr/local/datakit
hostIPC: true
hostPID: true
restartPolicy: Always
serviceAccount: datakit
serviceAccountName: datakit
tolerations:
- operator: Exists
volumes:
- configMap:
name: datakit-conf
name: datakit-conf
- hostPath:
path: /var/run
name: run
- hostPath:
path: /var/lib
name: lib
- hostPath:
path: /var/log
name: log
- hostPath:
path: /proc
type: ""
name: proc
- hostPath:
path: /dev
type: ""
name: dev
- hostPath:
path: /sys
type: ""
name: sys
- hostPath:
path: /
type: ""
name: rootfs
- hostPath:
path: /sys/kernel/debug
type: ""
name: debugfs
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
---
apiVersion: v1
kind: ConfigMap
metadata:
name: datakit-conf
namespace: datakit
data:
#### container
container.conf: |-
[inputs.container]
docker_endpoint = "unix:///var/run/docker.sock"
containerd_address = "/var/run/containerd/containerd.sock"
enable_container_metric = true
enable_k8s_metric = true
enable_pod_metric = true
## Containers logs to include and exclude, default collect all containers. Globs accepted.
container_include_log = []
container_exclude_log = ["image:*"]
#container_exclude_log = ["image:pubrepo.guance.com/datakit/logfwd*", "image:pubrepo.guance.com/datakit/datakit*"]
exclude_pause_container = true
## Removes ANSI escape codes from text strings
logging_remove_ansi_escape_codes = false
kubernetes_url = "https://kubernetes.default:443"
## Authorization level:
## bearer_token -> bearer_token_string -> TLS
## Use bearer token for authorization. ('bearer_token' takes priority)
## linux at: /run/secrets/kubernetes.io/serviceaccount/token
## windows at: C:\var\run\secrets\kubernetes.io\serviceaccount\token
bearer_token = "/run/secrets/kubernetes.io/serviceaccount/token"
# bearer_token_string = "<your-token-string>"
[inputs.container.tags]
# some_tag = "some_value"
# more_tag = "some_other_value"
#### ddtrace
ddtrace.conf: |-
[[inputs.ddtrace]]
endpoints = ["/v0.3/traces", "/v0.4/traces", "/v0.5/traces"]
# ignore_resources = []
customer_tags = ["node_ip"]
[inputs.ddtrace.close_resource]
"*" = ["PUT /nacos/*","GET /nacos/*","POST /nacos/*"]
## tags is ddtrace configed key value pairs
# [inputs.ddtrace.tags]
# some_tag = "some_value"
# more_tag = "some_other_value"
#### logfwdserver
logfwdserver.conf: |-
[inputs.logfwdserver]
## logfwd 受信側のリスニングアドレスとポート
address = "0.0.0.0:9531"
[inputs.logfwdserver.tags]
# some_tag = "some_value"
# more_tag = "some_other_value"
Kubernetes クラスターによっては、クラスター内の DaemonSet としてデプロイされた DataKit の選出を区別するために、ENV_NAMESPACE 環境変数を追加する必要があります。同じトークン内で値が重複しないようにしてください。
同じトークン内で異なる Kubernetes クラスターを区別するには、グローバルタグを追加する必要があります。値は cluster_name_k8s=k8s-prod です。
詳細については、<複数 Kubernetes クラスターのメトリクス収集のベストプラクティス> を参照してください。
コマンドを実行します。
DataKit のインストールが完了すると、Linux ホストの標準プラグインがデフォルトで有効になります。これは、「Guance」→「シナリオ」→「インフラストラクチャ Linux ホスト監視ビュー」で確認できます。
| 収集名 | 説明 |
|---|---|
| cpu | ホストの CPU 使用状況を収集します |
| disk | ディスク使用状況を収集します |
| diskio | ホストのディスク IO 状況を収集します |
| mem | ホストのメモリ使用状況を収集します |
| swap | Swap メモリ使用状況を収集します |
| system | ホストの OS 負荷を収集します |
| net | ホストのネットワークトラフィック状況を収集します |
| host_process | ホスト上の常駐プロセスリスト(10 分以上生存)を収集します |
| hostobject | ホストの基本情報(OS 情報、ハードウェア情報など)を収集します |
| kubernetes | Kubernetes クラスターのメトリクスを収集します |
| container | ホスト上のコンテナオブジェクトとコンテナログを収集します |
「インフラストラクチャ」モジュールをクリックすると、インストールされているすべての DataKit ホストのリストが表示されます。
「ホスト名」をクリックすると、ホストの詳細なシステム情報と、統合の実行状況(そのホストにインストールされているすべてのプラグイン)を確認できます。
アプリケーションサンプルのデプロイ¶
サンプルの説明¶
Web 層はゲートウェイを介してバックエンドの Auth サービスと System サービスにアクセスします。Web は Vue で、バックエンドは Java で開発されています。
このサンプルでは、Statsd を有効にして JVM を収集します。サンプルで使用するイメージレジストリは 172.16.0.215:5000 です。サンプルでは ddtrace を使用して Java アプリケーションの JVM メトリクスを収集します。サンプルで使用する Nacos、Redis、MySQL の内部 IP は 172.16.0.230 です。
Web デプロイファイルの作成¶
Web アプリケーションの内容を /usr/local/k8s/dist ディレクトリにコピーします。
/usr/local/k8s/DockerfileWeb ファイルを新規作成します。
内容は以下の通りです。
FROM nginx:1.21.0
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
COPY nginx.conf /etc/nginx/nginx.conf
RUN mkdir -p /data/nginx/web/dist/
COPY ./dist/ /data/nginx/web/dist/
WORKDIR /etc/nginx
CMD ["nginx","-g","daemon off;"]
EXPOSE 80
EXPOSE 443
/usr/local/k8s/nginx.conf を新規作成します。内容は以下の通りです。
/usr/local/k8s/nginx.conf
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#tcp_nopush on;
client_max_body_size 50m;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
location / {
root /data/nginx/web/dist;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /prod-api/{
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://172.16.0.229:30001/;
}
location /nginx_status{
stub_status;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
/usr/local/k8s/web-deployment.yaml を新規作成します。ファイルの内容は以下の通りです。
/usr/local/k8s/web-deployment.yaml
apiVersion: v1
kind: Service
metadata:
name: web-service
labels:
app: web-service
spec:
selector:
app: web-service
ports:
- protocol: TCP
port: 80
nodePort: 30000
targetPort: 80
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-service
labels:
app: web-service
spec:
replicas: 1
selector:
matchLabels:
app: web-service
template:
metadata:
labels:
app: web-service
spec:
containers:
- env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
name: web-service
image: 47.96.6.150:5000/df-demo/demo-web:v1
#command: ["sh","-c"]
ports:
- containerPort: 80
protocol: TCP
dd-java-agent イメージ¶
java -jar 方式でユーザーの jar を起動するには、-javaagent:/usr/local/datakit/data/dd-java-agent.jar を使用する必要があります。ユーザーのイメージにこの jar が存在するとは限らないため、顧客の業務イメージに影響を与えないように、dd-java-agent.jar を含むイメージを作成し、Init コンテナとして業務コンテナより先に起動し、共有ストレージとして dd-java-agent.jar を提供します。
Guanceでは、このイメージを提供しています。
本サンプルでは Sidecar 方式を使用しています。jar を直接イメージに組み込みたい場合は、dd-java-agent をダウンロードし、Dockerfile 内で以下のスクリプトを参考にして jar をイメージに組み込み、デプロイ用 yaml の -javaagent で使用する jar を組み込んだものに変更してください。
FROM openjdk:8u292
ENV workdir /data/app/
RUN mkdir -p ${workdir}
COPY dd-java-agent.jar ${workdir} # ここで dd-java-agent をイメージに組み込みます
Gateway デプロイファイルの作成¶
/usr/local/k8s/DockerfileGateway を新規作成します。
ファイルの内容は以下の通りです。
FROM openjdk:8u292
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
ENV jar demo-gateway.jar
ENV workdir /data/app/
RUN mkdir -p ${workdir}
COPY ${jar} ${workdir}
WORKDIR ${workdir}
ENTRYPOINT ["sh", "-ec", "exec java ${JAVA_OPTS} -jar ${jar} ${PARAMS} 2>&1 > /dev/null"]
/usr/local/k8s/gateway-deployment.yaml を新規作成します。ファイルの内容は以下の通りです。
/usr/local/k8s/gateway-deployment.yaml
apiVersion: v1
kind: Service
metadata:
name: gateway-service
labels:
app: gateway-service
spec:
selector:
app: gateway-service
ports:
- protocol: TCP
port: 9299
nodePort: 30001
targetPort: 9299
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gateway-service
labels:
app: gateway-service
spec:
replicas: 2
selector:
matchLabels:
app: gateway-service
template:
metadata:
labels:
app: gateway-service
spec:
containers:
- env:
- name: DD_AGENT_HOST
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NACOS_IP
value: "172.16.0.230"
- name: JAVA_OPTS
value: |-
-javaagent:/usr/dd-java-agent/agent/dd-java-agent.jar -Ddd.service.name=demo-k8s-gateway -Ddd.tags=container_host:$(POD_NAME),node_ip:$(DD_AGENT_HOST) -Ddd.service.mapping=redis:redisk8s -Ddd.env=dev -Ddd.agent.port=9529
- name: PARAMS
value: "--spring.redis.host=$(NACOS_IP) --spring.nacos.ip=$(NACOS_IP)"
name: gateway-service
image: 47.96.6.150:5000/df-demo/demo-gateway:v1
#command: ["sh","-c"]
ports:
- containerPort: 9299
protocol: TCP
volumeMounts:
- mountPath: /usr/dd-java-agent/agent
name: ddagent
initContainers:
- command:
- sh
- -c
- set -ex;mkdir -p /ddtrace/agent;cp -r /datadog-init/* /ddtrace/agent;
image: pubrepo.guance.com/datakit-operator/dd-lib-java-init
imagePullPolicy: Always
name: ddtrace-agent-sidecar
volumeMounts:
- mountPath: /ddtrace/agent
name: ddagent
restartPolicy: Always
volumes:
- emptyDir: {}
name: ddagent
Auth デプロイファイルの作成¶
/usr/local/k8s/DockerfileAuth を新規作成します。
ファイルの内容は以下の通りです。
FROM openjdk:8u292
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
ENV jar demo-auth.jar
ENV workdir /data/app/
RUN mkdir -p ${workdir}
COPY ${jar} ${workdir}
WORKDIR ${workdir}
ENTRYPOINT ["sh", "-ec", "exec java ${JAVA_OPTS} -jar ${jar} ${PARAMS} 2>&1 > /dev/null"]
/usr/local/k8s/auth-deployment.yaml を新規作成します。ファイルの内容は以下の通りです。
/usr/local/k8s/auth-deployment.yaml
apiVersion: v1
kind: Service
metadata:
name: auth-service
labels:
app: auth-service
spec:
selector:
app: auth-service
ports:
- protocol: TCP
port: 9200
targetPort: 9200
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: auth-service
labels:
app: auth-service
spec:
replicas: 2
selector:
matchLabels:
app: auth-service
template:
metadata:
labels:
app: auth-service
spec:
containers:
- env:
- name: DD_AGENT_HOST
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NACOS_IP
value: "172.16.0.230"
- name: JAVA_OPTS
value: |-
-javaagent:/usr/dd-java-agent/agent/dd-java-agent.jar -Ddd.service.name=demo-k8s-auth -Ddd.tags=container_host:$(POD_NAME),node_ip:$(DD_AGENT_HOST) -Ddd.service.mapping=redis:redisk8s -Ddd.env=dev -Ddd.agent.port=9529
- name: PARAMS
value: "--spring.redis.host=$(NACOS_IP) --spring.nacos.ip=$(NACOS_IP)"
name: auth-service
image: 47.96.6.150:5000/df-demo/demo-auth:v1
#command: ["sh","-c"]
ports:
- containerPort: 9200
protocol: TCP
volumeMounts:
- mountPath: /usr/dd-java-agent/agent
name: ddagent
initContainers:
- command:
- sh
- -c
- set -ex;mkdir -p /ddtrace/agent;cp -r /datadog-init/* /ddtrace/agent;
image: pubrepo.guance.com/datakit-operator/dd-lib-java-init
imagePullPolicy: Always
name: ddtrace-agent-sidecar
volumeMounts:
- mountPath: /ddtrace/agent
name: ddagent
restartPolicy: Always
volumes:
- emptyDir: {}
name: ddagent
System デプロイファイルの作成¶
/usr/local/k8s/DockerfileSystem を新規作成します。
ファイルの内容は以下の通りです。
FROM openjdk:8u292
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
ENV jar demo-modules-system.jar
ENV workdir /data/app/
RUN mkdir -p ${workdir}
COPY ${jar} ${workdir}
WORKDIR ${workdir}
ENTRYPOINT ["sh", "-ec", "exec java ${JAVA_OPTS} -jar ${jar} ${PARAMS} 2>&1 > /dev/null"]
/usr/local/k8s/system-deployment.yaml を新規作成します。Pod では、172.16.0.238/df-ruoyi/demo-system:v1、pubrepo.guance.com/datakit/logfwd:1.2.7、pubrepo.guance.com/datakit-operator/dd-lib-java-init の 3 つのイメージを使用しています。
このうち、dd-lib-java-init は dd-java-agent.jar ファイルを system-container 業務コンテナに提供し、logfwd は業務コンテナのログファイルを収集します。logfwd の設定ファイルは ConfigMap を介してコンテナにマウントされ、設定ファイルでは収集するログファイルの場所、ソース名などを指定します。
system-deployment.yaml の完全な内容は以下の通りです。
system-deployment.yaml
apiVersion: v1
kind: Service
metadata:
name: system-service
spec:
selector:
app: system-pod
ports:
- protocol: TCP
port: 9201
#nodePort: 30001
targetPort: 9201
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: system-deployment
#labels:
# app: system-deployment
spec:
replicas: 1
selector:
matchLabels:
app: system-pod
template:
metadata:
labels:
app: system-pod
spec:
containers:
- name: system-container
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: DD_AGENT_HOST
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP
- name: NACOS_IP
value: "172.16.0.229"
- name: DB_IP
value: "172.16.0.230"
- name: JAVA_OPTS
value: |-
-javaagent:/usr/dd-java-agent/agent/dd-java-agent.jar -Ddd.service.name=demo-k8s-system -Ddd.tags=container_host:$(POD_NAME),node_ip:$(DD_AGENT_HOST) -Ddd.service.mapping=mysql:mysql-k8s,redis:redisk8s -Ddd.env=dev -Ddd.agent.port=9529
- name: PARAMS
value: "--spring.redis.host=$(DB_IP) --spring.nacos.ip=$(NACOS_IP) --spring.db.ip=$(DB_IP)"
image: 172.16.0.238/df-ruoyi/demo-system:v1
#command: ["sh","-c"]
ports:
- containerPort: 9201
protocol: TCP
volumeMounts:
- name: ddagent
mountPath: /usr/dd-java-agent/agent
- name: varlog
mountPath: /data/app/logs/ruoyi-system
resources:
limits:
memory: 512Mi
requests:
memory: 256Mi
- name: logfwd
image: pubrepo.guance.com/datakit/logfwd:1.2.7
env:
- name: LOGFWD_DATAKIT_HOST
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP
- name: LOGFWD_DATAKIT_PORT
value: "9531"
- name: LOGFWD_LOGFWD_ANNOTATION_DATAKIT_LOG_CONFIGS
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.annotations['datakit/log']
- name: LOGFWD_POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: LOGFWD_POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
volumeMounts:
- mountPath: /var/log
name: varlog
- mountPath: /opt/logfwd/config
name: logfwd-config
subPath: config
initContainers:
- name: ddtrace-agent-sidecar
command:
- sh
- -c
- set -ex;mkdir -p /ddtrace/agent;cp -r /datadog-init/* /ddtrace/agent;
image: pubrepo.guance.com/datakit-operator/dd-lib-java-init
imagePullPolicy: Always
volumeMounts:
- mountPath: /ddtrace/agent
name: ddagent
restartPolicy: Always
volumes:
- name: varlog
emptyDir: {}
- name: ddagent
emptyDir: {}
- configMap:
name: logfwd-conf
name: logfwd-config
---
apiVersion: v1
kind: ConfigMap
metadata:
name: logfwd-conf
data:
config: |
[
{
"loggings": [
{
"logfiles": ["/var/log/info.log","/var/log/error.log"],
"source": "k8s-log-system",
"multiline_match": "^\\d{4}-\\d{2}-\\d{2}"
}
]
}
]
また、system-deployment.yaml ファイルでは、環境変数を使用して DataKit と logfwd のポートを指定しています。
環境変数の説明:
- LOGFWD_DATAKIT_HOST:DataKit アドレス
- LOGFWD_DATAKIT_PORT:logfwd ポート
logfwd-conf パラメータの説明:
- logfiles:ログファイルのリスト。
- ignore:ファイルパスのフィルタリング。glob ルールを使用し、いずれかのフィルタ条件に一致すると、そのファイルは収集されません。
- source:データソース。
- service:追加するタグ。空の場合は、デフォルトで $source が使用されます。
- pipeline:pipeline を使用する場合、スクリプトのパスを定義します。
- character_encoding:エンコーディングを選択します。
- multiline_match:複数行のマッチング。
- remove_ansi_escape_codes:ANSI エスケープコード(標準出力のテキスト色など)を削除するかどうか。値は true または false です。
リンクデータへの node_ip タグの追加¶
datakit.yaml に ConfigMap を追加します。
ddtrace.conf: |-
[[inputs.ddtrace]]
endpoints = ["/v0.3/traces", "/v0.4/traces", "/v0.5/traces"]
# ignore_resources = []
customer_tags = ["node_ip"]
volumeMounts の下に以下を追加します。
- mountPath: /usr/local/datakit/conf.d/ddtrace/ddtrace.conf
name: datakit-conf
subPath: ddtrace.conf
リアルユーザーモニタリング(RUM)¶
アプリケーションの新規作成¶
「Guanceプラットフォーム」にログインし、「ユーザーアクセス監視(RUM)」→「アプリケーションを新規作成」→「Web タイプを選択」→「同期読み込み」を選択し、アプリケーション名に「web-k8s-demo」と入力します。
フロントエンド RUM 監視の有効化¶
DataKit で RUM 収集を有効にするには、ENV_DEFAULT_ENABLED_INPUTS 環境変数の値の最後に rum を追加します。
- name: ENV_DEFAULT_ENABLED_INPUTS
value: cpu,disk,diskio,mem,swap,system,hostobject,net,host_processes,container,statsd,ebpf,rum
ユーザーアクセス監視(RUM)で使用する DataKit アドレスは、顧客のネットワークからアクセス可能なアドレスである必要があります。そのため、DataKit の設定ファイル /usr/local/datakit/conf.d/datakit.conf の listen="0.0.0.0:9529" を変更する必要があります。
本サンプルでは、DaemonSet 方式で DataKit をデプロイしており、デフォルトの設定を変更済みです。実際の本番環境では、RUM で使用する DataKit は個別にデプロイすることを推奨します。
/usr/local/k8s/dist/index.html ファイルを修正し、head タグ内に以下の内容を追加します。
<script src="https://static.guance.com/browser-sdk/v2/dataflux-rum.js" type="text/javascript"></script>
<script>
window.DATAFLUX_RUM &&
window.DATAFLUX_RUM.init({
applicationId: 'appid_ddxxxxxxxxxxxxxxxxxx5',
datakitOrigin: 'http://172.16.0.230:9529',
env: 'production',
version: '1.0.0',
trackInteractions: true,
traceType: 'ddtrace',
allowedTracingOrigins: ["http://8.136.207.182:30000","http://8.136.193.105:30000","http://8.136.204.98:30000"]
})
</script>
-
applicationId:アプリケーション ID。
-
datakitOrigin:ユーザーがアクセス可能な DataKit のアドレスまたはドメイン名です。ここでの 172.16.0.230 は k8s の node1 の IP アドレスです。
-
env:必須。アプリケーションが所属する環境(test や product など)。
-
version:必須。アプリケーションのバージョン番号。
-
allowedTracingOrigins:RUM と APM を連携させるために、バックエンドサーバーのアドレスまたはドメイン名を設定します。本サンプルでは、フロントエンドとバックエンドのアクセスアドレスはどちらも http://8.136.193.105:30000/ であるため、設定時に 30000 ポートを追加する必要があります。
-
trackInteractions:ユーザーアクションの追跡(ボタンクリック、フォーム送信など)。
-
traceType:オプション。デフォルトは ddtrace です。現在、ddtrace、zipkin、skywalking_v3、jaeger、zipkin_single_header、w3c_traceparent の 6 種類をサポートしています。
ユーザーアクセス監視(RUM)の詳細については、<Web アプリケーション監視(RUM)のベストプラクティス> を参照してください。
アプリケーションパフォーマンスモニタリング(APM)¶
ddtrace の有効化¶
詳細については、<リンクデータへの node_ip タグの追加> を参照してください。
Java アプリケーションの ddtrace への接続¶
system イメージファイル DockerfileSystem では、jar を起動するコマンドは次の通りです。
環境変数 JAVA_OPTS は、デプロイファイル system-deployment.yaml で次のように定義されています。
- name: JAVA_OPTS
value: |-
-javaagent:/usr/dd-java-agent/agent/dd-java-agent.jar -Ddd.service.name=demo-k8s-system -Ddd.tags=container_host:$(POD_NAME) -Ddd.service.mapping=mysql:mysql-k8s,redis:redisk8s -Ddd.env=dev -Ddd.agent.port=9529
JAVA_OPTS の詳細な説明:
-Ddd.env:アプリケーションの環境タイプ。オプション
-Ddd.tags:カスタムタグ。複数ある場合は , で区切ります。オプション
-Ddd.service.name:JVM データソースのアプリケーション名。必須
-Ddd.agent.host=localhost DataKit アドレス。オプション
-Ddd.agent.port=9529 DataKit ポート。必須
-Ddd.version:バージョン。オプション
-Ddd.jmxfetch.check-period 収集頻度を指定します。単位はミリ秒、デフォルトは 1500。オプション
-Ddd.jmxfetch.statsd.host=127.0.0.1 statsd 収集の接続アドレス。DataKit アドレスと同じ。オプション
-Ddd.jmxfetch.statsd.port=8125 DataKit 上の statsd 収集の UDP 接続ポート。デフォルトは 8125。オプション
-Ddd.trace.health.metrics.statsd.host=127.0.0.1 自身のメトリクスデータ収集送信先アドレス。DataKit アドレスと同じ。オプション
-Ddd.trace.health.metrics.statsd.port=8125 自身のメトリクスデータ収集送信ポート。オプション
-Ddd.service.mapping:アプリケーションが呼び出す redis、mysql などのエイリアス。オプション
注意:
JAVA_OPTSではリンクデータの報告先 DataKit アドレスを指定していません。代わりに、yaml 内で環境変数DD_AGENT_HOSTを定義して、リンクデータの報告先 DataKit アドレスを指定しています。Kubernetes クラスターにおけるリンクデータ報告の原則は、Pod のリンクデータを同じホストにデプロイされた DataKit に報告することです。詳細な設定はsystem-deployment.yamlを参照してください。
クロスオリジンリクエストのホワイトリスト設定¶
response.headers.add('Access-Control-Allow-Headers','x-datadog-parent-id,x-datadog-sampled,x-datadog-sampling-priority,x-datadog-trace-id')
ログ¶
logback.xml の設定¶
logback.xml を修正し、traceId、spanId、service をログに出力するように設定します。これにより、リンクとの関連付けが可能になります。
ログ収集の有効化¶
Kubernetes のログ収集には、DataKit の logfwd 収集を使用することを推奨します。
logfwdserver.conf: |-
[inputs.logfwdserver]
## logfwd 受信側のリスニングアドレスとポート
address = "0.0.0.0:9531"
[inputs.logfwdserver.tags]
# some_tag = "some_value"
# more_tag = "some_other_value"
volumeMounts の下に以下を追加します。
- mountPath: /usr/local/datakit/conf.d/log/logfwdserver.conf
name: datakit-conf
subPath: logfwdserver.conf
ログ分割 Pipeline¶
Pipeline を使用して System システムが生成したログを分割し、traceID などの重要な情報をタグとして抽出します。これにより、リンクとの関連付けが可能になります。
「ログ」モジュールをクリックし、「Pipelines」に入り、新しい Pipeline を作成します。フィルターで System モジュールのログ収集時に設定した Source:k8s-log-system を選択し、以下の内容を入力して、テストが成功したら「保存」をクリックします。
#2022-08-09 13:39:57.392 [http-nio-9201-exec-4] INFO c.r.s.c.SysUserController - [list,70] - demo-k8s-system 1241118275256671447 9052729774571622516 - ユーザーリストのクエリを開始します
grok(_, "%{TIMESTAMP_ISO8601:time} %{NOTSPACE:thread_name} %{LOGLEVEL:status}%{SPACE}%{NOTSPACE:class_name} - \\[%{NOTSPACE:method_name},%{NUMBER:line}\\] - %{DATA:service_name} %{DATA:trace_id} %{DATA:span_id} - %{GREEDYDATA:msg}")
default_time(time,"Asia/Shanghai")
アプリケーションのデプロイ¶
イメージの作成と Harbor レジストリへのプッシュ¶
$ cd /usr/local/k8s/
$ docker build -t 172.16.0.215:5000/df-demo/demo-web:v1 -f DockerfileWeb .
$ docker push 172.16.0.215:5000/df-demo/demo-web:v1
$ docker build -t 172.16.0.215:5000/df-demo/demo-gateway:v1 -f DockerfileGateway .
$ docker push 172.16.0.215:5000/df-demo/demo-gateway:v1
$ docker build -t 172.16.0.215:5000/df-demo/demo-auth:v1 -f DockerfileAuth .
$ docker push 172.16.0.215:5000/df-demo/demo-auth:v1
$ docker build -t 172.16.0.215:5000/df-demo/demo-system:v1 -f DockerfileSystem .
$ docker push 172.16.0.215:5000/df-demo/demo-system:v1
デプロイ¶
$ cd /usr/local/k8s/
$ kubectl apply -f web-deployment.yaml
$ kubectl apply -f gateway-deployment.yaml
$ kubectl apply -f auth-deployment.yaml
$ kubectl apply -f system-deployment.yaml
リンク分析¶
RUM APM 連携¶
Web アプリケーションにアクセスし、「システム管理」→「ユーザー管理」をクリックします。これにより、ユーザーリストクエリリクエスト list がトリガーされます。dataflux-rum.js は trace-id を生成してヘッダーに格納します。list インターフェースに対応する trace-id は 2772508174716324531 であることがわかります。リクエストはバックエンドの list インターフェースを呼び出し、バックエンドの ddtrace は trace-id を読み取って自身のトレースデータに記録します。logback.xml に %X{dd.trace_id} が追加されているため、trace_id はログとともに出力され、RUM、APM、ログの連携が実現されます。
「ユーザーアクセス監視(RUM)」→「ruoyi-k8s-web」→「エクスプローラー」→「view」をクリックします。前述の操作はユーザー管理リストのクエリであるため、リスト内の /system/user をクリックします。
「Fetch/XHR」をクリックします。
上図の prod-api/system/user/list をクリックします。prod-api は nginx によって追加された転送リクエストであり、/system/user/list はバックエンドの API インターフェースです。クリックすると、具体的なリクエストとその所要時間を確認できます。
ログ分析¶
「ログ」モジュールをクリックし、「すべてのソース」を選択します。デフォルトでは最近 15 分間のログがクエリされます。フロントエンドで生成された trace_id 2772508174716324531 を「検索バー」に入力し、Enter キーを押して検索します。
「アプリケーションパフォーマンスモニタリング(APM)」→「リンクフィルターボックス」をクリックし、trace_id:704229736283371775 と入力して Enter キーを押すと、リンクの呼び出し状況が表示されます。
「SysUserController.list」をクリックして詳細情報を表示します。





















