コンテンツにスキップ

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 にアクセスしてアカウントを登録し、登録済みのアカウントとパスワードでログインします。

image


DaemonSet 方式による DataKit のデプロイ

OpenWay アドレスのトークンを取得する

「管理」→「基本設定」をクリックし、下図のトークンをコピーします。

image

「統合」→「DataKit」→「Kubernetes」をクリックし、最新の datakit.yaml ファイルを取得します。

image

インストールの実行

  • 前の手順で取得した datakit.yaml ファイルを使用し、上図で取得したトークンをファイル内の your-token と置き換えます。
  • container 収集、logfwd 収集、ddtrace 収集を有効にします。つまり、DataKit コンテナに container.conflogfwdserver.confddtrace.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 クラスターのメトリクス収集のベストプラクティス> を参照してください。

コマンドを実行します。

$ cd /usr/local/k8s/
$ kubectl apply -f  datakit.yaml
$ kubectl get pod -n datakit

image

DataKit のインストールが完了すると、Linux ホストの標準プラグインがデフォルトで有効になります。これは、「Guance」→「シナリオ」→「インフラストラクチャ Linux ホスト監視ビュー」で確認できます。

収集名 説明
cpu ホストの CPU 使用状況を収集します
disk ディスク使用状況を収集します
diskio ホストのディスク IO 状況を収集します
mem ホストのメモリ使用状況を収集します
swap Swap メモリ使用状況を収集します
system ホストの OS 負荷を収集します
net ホストのネットワークトラフィック状況を収集します
host_process ホスト上の常駐プロセスリスト(10 分以上生存)を収集します
hostobject ホストの基本情報(OS 情報、ハードウェア情報など)を収集します
kubernetes Kubernetes クラスターのメトリクスを収集します
container ホスト上のコンテナオブジェクトとコンテナログを収集します

「インフラストラクチャ」モジュールをクリックすると、インストールされているすべての DataKit ホストのリストが表示されます。

image

「ホスト名」をクリックすると、ホストの詳細なシステム情報と、統合の実行状況(そのホストにインストールされているすべてのプラグイン)を確認できます。

image

image

アプリケーションサンプルのデプロイ

サンプルの説明

Web 層はゲートウェイを介してバックエンドの Auth サービスと System サービスにアクセスします。Web は Vue で、バックエンドは Java で開発されています。
このサンプルでは、Statsd を有効にして JVM を収集します。サンプルで使用するイメージレジストリは 172.16.0.215:5000 です。サンプルでは ddtrace を使用して Java アプリケーションの JVM メトリクスを収集します。サンプルで使用する Nacos、Redis、MySQL の内部 IP は 172.16.0.230 です。

image

Web デプロイファイルの作成

Web アプリケーションの内容を /usr/local/k8s/dist ディレクトリにコピーします。

image

/usr/local/k8s/DockerfileWeb ファイルを新規作成します。

$ vim /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では、このイメージを提供しています。

pubrepo.guance.com/datakit-operator/dd-lib-java-init

本サンプルでは 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 を新規作成します。

$ vim /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 を新規作成します。

$ vim  /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 を新規作成します。

$ vim /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:v1pubrepo.guance.com/datakit/logfwd:1.2.7pubrepo.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」と入力します。

image

フロントエンド 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.conflisten="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 を起動するコマンドは次の通りです。

exec java ${JAVA_OPTS}   -jar ${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 を参照してください。

- name: DD_AGENT_HOST
  valueFrom:
    fieldRef:
      apiVersion: v1
      fieldPath: status.hostIP

クロスオリジンリクエストのホワイトリスト設定

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 をログに出力するように設定します。これにより、リンクとの関連付けが可能になります。

image

ログ収集の有効化

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")

image

アプリケーションのデプロイ

イメージの作成と 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

image

リンク分析

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、ログの連携が実現されます。

image

「ユーザーアクセス監視(RUM)」→「ruoyi-k8s-web」→「エクスプローラー」→「view」をクリックします。前述の操作はユーザー管理リストのクエリであるため、リスト内の /system/user をクリックします。

image

「Fetch/XHR」をクリックします。

image

上図の prod-api/system/user/list をクリックします。prod-api は nginx によって追加された転送リクエストであり、/system/user/list はバックエンドの API インターフェースです。クリックすると、具体的なリクエストとその所要時間を確認できます。

image

image

image

ログ分析

「ログ」モジュールをクリックし、「すべてのソース」を選択します。デフォルトでは最近 15 分間のログがクエリされます。フロントエンドで生成された trace_id 2772508174716324531 を「検索バー」に入力し、Enter キーを押して検索します。

image

「アプリケーションパフォーマンスモニタリング(APM)」→「リンクフィルターボックス」をクリックし、trace_id:704229736283371775 と入力して Enter キーを押すと、リンクの呼び出し状況が表示されます。

image

「SysUserController.list」をクリックして詳細情報を表示します。

image

フィードバック

このページは役に立ちましたか?