跳转至

Datakit Operator



概述和安装

Datakit Operator 是 Datakit 在 Kubernetes 编排的联动项目,旨在协助 Datakit 更方便的部署,以及其他诸如验证、注入的功能。

目前 Datakit-Operator 提供以下功能:

  • 注入 DDTrace SDK(Java/Python/Node.js)以及对应环境变量信息,参见文档
  • 注入 Sidecar logfwd 服务以采集容器内日志,参见文档
  • 支持 Datakit 采集器的任务选举,参见文档

先决条件:

  • 推荐 Kubernetes v1.24.1 及以上版本,且能够访问互联网(下载 yaml 文件并拉取对应镜像)
  • 确保启用 MutatingAdmissionWebhookValidatingAdmissionWebhook 控制器
  • 确保启用了 admissionregistration.k8s.io/v1 API

安装步骤

下载 datakit-operator.yaml,步骤如下:

$ kubectl create namespace datakit
$ wget https://static.guance.com/datakit-operator/datakit-operator.yaml
$ kubectl apply -f datakit-operator.yaml
$ kubectl get pod -n datakit

NAME                               READY   STATUS    RESTARTS   AGE
datakit-operator-f948897fb-5w5nm   1/1     Running   0          15s

前提条件

  • Kubernetes >= 1.14
  • Helm >= 3.0+
$ helm install datakit-operator datakit-operator \
     --repo  https://pubrepo.guance.com/chartrepo/datakit-operator \
     -n datakit --create-namespace

查看部署状态:

$ helm -n datakit list

可以通过如下命令来升级:

$ helm -n datakit get values datakit-operator -a -o yaml > values.yaml
$ helm upgrade datakit-operator datakit-operator \
    --repo https://pubrepo.guance.com/chartrepo/datakit-operator \
    -n datakit \
    -f values.yaml

可以通过如下命令来卸载:

$ helm uninstall datakit-operator -n datakit
Attention
  • Datakit-Operator 有严格的程序和 yaml 对应关系,如果使用一份过旧的 yaml 可能无法安装新版 Datakit-Operator,请重新下载最新版 yaml。
  • 如果出现 InvalidImageName 报错,可以手动 pull 镜像。

配置说明

Version-1.4.2

Datakit Operator 配置是 JSON 格式,在 Kubernetes 中单独以 ConfigMap 存放,以环境变量方式加载到容器中。

默认配置如下:

{
    "server_listen": "0.0.0.0:9543",
    "log_level":     "info",
    "admission_inject": {
        "ddtrace": {
            "enabled_namespaces":     [],
            "enabled_labelselectors": [],
            "images": {
                "java_agent_image":   "pubrepo.guance.com/datakit-operator/dd-lib-java-init:v1.30.1-guance"
            },
            "envs": {
                "DD_AGENT_HOST":           "datakit-service.datakit.svc",
                "DD_TRACE_AGENT_PORT":     "9529",
                "DD_JMXFETCH_STATSD_HOST": "datakit-service.datakit.svc",
                "DD_JMXFETCH_STATSD_PORT": "8125",
                "DD_SERVICE":              "{fieldRef:metadata.labels['service']}",
                "POD_NAME":                "{fieldRef:metadata.name}",
                "POD_NAMESPACE":           "{fieldRef:metadata.namespace}",
                "NODE_NAME":               "{fieldRef:spec.nodeName}",
                "DD_TAGS":                 "pod_name:$(POD_NAME),pod_namespace:$(POD_NAMESPACE),host:$(NODE_NAME)"
            }
        },
        "logfwd": {
            "options": {
                "reuse_exist_volume": "false"
            },
            "images": {
                "logfwd_image": "pubrepo.guance.com/datakit/logfwd:1.28.1"
            }
        },
        "profiler": {
            "images": {
                "java_profiler_image":   "pubrepo.guance.com/datakit-operator/async-profiler:0.1.0",
                "python_profiler_image": "pubrepo.guance.com/datakit-operator/py-spy:0.1.0",
                "golang_profiler_image": "pubrepo.guance.com/datakit-operator/go-pprof:0.1.0"
            },
            "envs": {
                "DK_AGENT_HOST":  "datakit-service.datakit.svc",
                "DK_AGENT_PORT":  "9529",
                "DK_PROFILE_VERSION": "1.2.333",
                "DK_PROFILE_ENV": "prod",
                "DK_PROFILE_DURATION": "240",
                "DK_PROFILE_SCHEDULE": "0 * * * *"
            }
        }
    }
}

主要配置项是 ddtracelogfwdprofiler,指定注入的镜像和环境变量。此外,ddtrace 还支持根据 enabled_namespacesenabled_selectors 批量注入,详见后文的“注入方式”。

指定镜像地址

Datakit Operator 主要作用就是注入镜像和环境变量,使用 images 配置镜像地址。images 是多个 Key/Value,Key 是固定的,修改 Value 值指定镜像地址。

正常情况下,镜像统一存放在 pubrepo.guance.com/datakit-operator,对于一些特殊环境不方便访问此镜像库,可以使用以下方法(以 dd-lib-java-init 镜像为例):

  1. 在可以访问 pubrepo.guance.com 的环境中,pull 镜像 pubrepo.guance.com/datakit-operator/dd-lib-java-init:v1.30.1-guance,并将其转存到自己的镜像库,例如 inside.image.hub/datakit-operator/dd-lib-java-init:v1.30.1-guance
  2. 修改 JSON 配置,将 admission_inject->ddtrace->images->java_agent_image 修改为 inside.image.hub/datakit-operator/dd-lib-java-init:v1.30.1-guance,应用此 yaml
  3. 此后 Datakit Operator 会使用的新的 Java Agent 镜像路径

Datakit Operator 不检查镜像,如果该镜像路径错误,Kubernetes 创建 Pod 会报错。

添加环境变量

所有需要注入的环境变量,都必须在配置文件指定,Datakit Operator 不默认添加任何环境变量。

环境变量配置项是 envs,由多个 Key/Value 组成:Key 是固定值;Value 可以是固定值,也可以是占位符,根据实际情况取值。

例如在 envs 中添加一个 testing-env

{
    "admission_inject": {
        "ddtrace": {
            "envs": {
                "DD_AGENT_HOST":       "datakit-service.datakit.svc",
                "DD_TRACE_AGENT_PORT": "9529",
                "testing-env":         "ok"
            }
        }
    }
}

所有注入 ddtrace agent 的容器,都会添加 envs 的 3 个环境变量。

在 Datakit Operator v1.4.2 及以后版本,envs 支持 Kubernetes Downward API 的 环境变量取值字段。现支持以下几种:

  • metadata.name:Pod 的名称
  • metadata.namespace: Pod 的命名空间
  • metadata.uid: Pod 的唯一 ID
  • metadata.annotations['<KEY>']: Pod 的注解 <KEY> 的值(例如:metadata.annotations['myannotation'])
  • metadata.labels['<KEY>']: Pod 的标签 <KEY> 的值(例如:metadata.labels['mylabel'])
  • spec.serviceAccountName: Pod 的服务账号名称
  • spec.nodeName: Pod 运行时所处的节点名称
  • status.hostIP: Pod 所在节点的主 IP 地址
  • status.hostIPs: 这组 IP 地址是 status.hostIP 的双协议栈版本,第一个 IP 始终与 status.hostIP 相同。 该字段在启用了 PodHostIPs 特性门控后可用。
  • status.podIP: Pod 的主 IP 地址(通常是其 IPv4 地址)
  • status.podIPs: 这组 IP 地址是 status.podIP 的双协议栈版本,第一个 IP 始终与 status.podIP 相同。

举个例子,现有一个 Pod 名称是 nginx-123,namespace 是 middleware,要给它注入环境变量 POD_NAMEPOD_NAMESPACE,参考以下:

{
    "admission_inject": {
        "ddtrace": {
            "envs": {
                "POD_NAME":      "{fieldRef:metadata.name}",
                "POD_NAMESPACE": "{fieldRef:metadata.namespace}"
            }
        }
    }
}

最终在该 Pod 可以看到:

$ env | grep POD
POD_NAME=nginx-123
POD_NAMESPACE=middleware
Attention

如果该 Value 占位符无法识别,会以纯字符串添加到环境变量。例如 "POD_NAME": "{fieldRef:metadata.PODNAME}",这是错误的写法,在环境变量是 POD_NAME={fieldRef:metadata.PODNAME}

注入方式

Datakit-Operator 支持两种资源输入方式,分别是“全局配置 namespaces 和 selectors”,以及在目标 Pod 添加指定 Annotation。它们的区别如下:

  • 全局配置 namespace 和 selector:通过修改 Datakit-Operator config,指定目标 Pod 的 Namespace 和 Selector,如果发现 Pod 符合条件,就执行注入资源。

    • 优点:不需要在目标 Pod 添加 Annotation(但是需要重启目标 Pod)
    • 缺点:范围不够精确,可能存在无效注入
  • 在目标 Pod 添加 Annotation:在目标 Pod 添加 Annotation,Datakit-Operator 会检查 Pod Annotation,如果符合条件就执行注入。

    • 优点:范围足够精确,不存在无效注入
    • 缺点:必须在目标 Pod 添加 Annotation,且需要重启目标 Pod
Attention

截止到 Datakit-Operator v1.5.8,全局配置 namespaces 和 selectors 方式只在注入 DDtrace 生效,对于 logfwd 和 profiler 无效,后者仍需添加 annotation 注入。

全局配置 namespaces 和 selectors 配置

enabled_namespacesenabled_labelselectorsddtrace 专属,它们是对象数组,需要指定 namespacelanguage。数组之间是“或”的关系,写法如下(详见后文的配置说明):

{
    "server_listen": "0.0.0.0:9543",
    "log_level":     "info",
    "admission_inject": {
        "ddtrace": {
            "enabled_namespaces": [
                {
                    "namespace": "testns",  # 指定 namespace
                    "language": "java"      # 指定需要注入的 agent 语言
                }
            ],
            "enabled_labelselectors": [
                {
                    "labelselector": "app=log-output",  # 指定 labelselector
                    "language": "java"                  # 指定需要注入的 agent 语言
                }
            ]
            # other..
        }
    }
}

如果一个 Pod 即满足 enabled_namespaces 规则,又满足 enabled_labelselectors,以 enabled_labelselectors 配置为准(通常在 language 取值用到)。

关于 labelselector 的编写规范,可参考此官方文档

Note
  • 在 Kubernetes 1.16.9 或更早版本,Admission 不记录 Pod Namespace,所以无法使用 enabled_namespaces 功能。

添加 Annotation 配置注入

在 Deployment 添加指定 Annotation,表示需要注入 ddtrace 文件。注意 Annotation 要添加在 template 中。

其格式为:

  • key 是 admission.datakit/%s-lib.version%s 需要替换成指定的语言,目前支持 java
  • value 是指定版本号。默认是 Datakit-Operator 配置 java_agent_image 指定的版本

例如添加 Annotation 如下:

      annotations:
        admission.datakit/java-lib.version: "v1.36.2-guance"

表示这个 Pod 需要注入的镜像版本是 v1.36.2-guance,镜像地址取自配置 admission_inject->ddtrace->images->java_agent_image,替换镜像版本为"v1.36.2-guance",即 pubrepo.guance.com/datakit-operator/dd-lib-java-init:v1.36.2-guance

Datakit Operator 注入

在大型 Kubernetes 集群中,批量修改配置是比较麻烦的事情。Datakit-Operator 会根据 Annotation 配置,决定是否对其修改或注入。

目前支持的功能有:

  • 注入 ddtrace agent 和 environment 的功能
  • 挂载 logfwd sidecar 并开启日志采集的功能
  • 注入 async-profiler 采集 JVM 程序的 profile 数据 Experimental
  • 注入 py-spy 采集 Python 应用的 profile 数据 Experimental
Info

只支持 v1 版本的 deployments/daemonsets/cronjobs/jobs/statefulsets 这五类 Kind,且因为 Datakit-Operator 实际对 PodTemplate 操作,所以不支持 Pod。 在本文中,以 Deployment 代替描述这五类 Kind。

DDtrace Agent

使用说明

  1. 在目标 Kubernetes 集群,下载和安装 Datakit-Operator
  2. 在 deployment 添加指定 Annotation admission.datakit/java-lib.version: "",表示需要注入默认版本的 DDtrace Java Agent。

用例

下面是一个 Deployment 示例,给 Deployment 创建的所有 Pod 注入 dd-java-lib

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
      annotations:
        admission.datakit/java-lib.version: ""
    spec:
      containers:
      - name: nginx
        image: nginx:1.22
        ports:
        - containerPort: 80

使用 yaml 文件创建资源:

$ kubectl apply -f nginx.yaml
...

验证如下:

$ kubectl get pod

NAME                                   READY   STATUS    RESTARTS      AGE
nginx-deployment-7bd8dd85f-fzmt2       1/1     Running   0             4s

$ kubectl get pod nginx-deployment-7bd8dd85f-fzmt2 -o=jsonpath={.spec.initContainers\[\*\].name}

datakit-lib-init

logfwd

前置条件

logfwd 是 Datakit 的专属日志采集应用,需要先在同一个 Kubernetes 集群中部署 Datakit,且达成以下两点:

  1. Datakit 开启 logfwdserver 采集器,例如监听端口是 9533
  2. Datakit service 需要开放 9533 端口,使得其他 Pod 能访问 datakit-service.datakit.svc:9533

使用说明

  1. 在目标 Kubernetes 集群,下载和安装 Datakit-Operator
  2. 在 deployment 添加指定 Annotation,表示需要挂载 logfwd sidecar。注意 Annotation 要添加在 template 中
    • key 统一是 admission.datakit/logfwd.instances
    • value 是一个 JSON 字符串,是具体的 logfwd 配置,示例如下:
[
    {
        "datakit_addr": "datakit-service.datakit.svc:9533",
        "loggings": [
            {
                "logfiles": ["<your-logfile-path>"],
                "ignore": [],
                "source": "<your-source>",
                "service": "<your-service>",
                "pipeline": "<your-pipeline.p>",
                "character_encoding": "",
                "multiline_match": "<your-match>",
                "tags": {}
            },
            {
                "logfiles": ["<your-logfile-path-2>"],
                "source": "<your-source-2>"
            }
        ]
    }
]

参数说明,可参考 logfwd 配置

  • datakit_addr 是 Datakit logfwdserver 地址
  • loggings 为主要配置,是一个数组,可参考 Datakit logging 采集器
    • logfiles 日志文件列表,可以指定绝对路径,支持使用 glob 规则进行批量指定,推荐使用绝对路径
    • ignore 文件路径过滤,使用 glob 规则,符合任意一条过滤条件将不会对该文件进行采集
    • source 数据来源,如果为空,则默认使用 'default'
    • service 新增标记 tag,如果为空,则默认使用 $source
    • pipeline Pipeline 脚本路径,如果为空将使用 $source.p,如果 $source.p 不存在将不使用 Pipeline(此脚本文件存在于 DataKit 端)
    • character_encoding 选择编码,如果编码有误会导致数据无法查看,默认为空即可。支持 utf-8/utf-16le/utf-16le/gbk/gb18030
    • multiline_match 多行匹配,详见 Datakit 日志多行配置,注意因为是 JSON 格式所以不支持 3 个单引号的“不转义写法”,正则 ^\d{4} 需要添加转义写成 ^\\d{4}
    • tags 添加额外 tag,书写格式是 JSON map,例如 { "key1":"value1", "key2":"value2" }

注入 logfwd 时,允许复用相同路径的 volume,避免因为存在同样路径的 volume 而注入报错,将配置项 admission_inject->logfwd->options->reuse_exist_volume 改为 true 即可。

例如,目标 Pod 有一个 Volume 路径是 /var/log,刚好 /var/log 就是需要采集的目录路径:

spec:
  container:
    # other...
    volumeMounts:
    - name: volume-log
      mountPath: /var/log
  volumes:
  - name: volume-log
    emptyDir: {}

如果开启了 reuse_exist_volume,就不再新增 volume 和 volumeMount,而且复用当前的 volume-log

Attention

路径末尾有斜线和无斜线的意义不同,/var/log/var/log/ 是不同路径,不能复用。

用例

下面是一个 Deployment 示例,使用 shell 持续向文件写入数据,且配置该文件的采集:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: logging-deployment
  labels:
    app: logging
spec:
  replicas: 1
  selector:
    matchLabels:
      app: logging
  template:
    metadata:
      labels:
        app: logging
      annotations:
        admission.datakit/logfwd.instances: '[{"datakit_addr":"datakit-service.datakit.svc:9533","loggings":[{"logfiles":["/var/log/log-test/*.log"],"source":"deployment-logging","tags":{"key01":"value01"}}]}]'
    spec:
      containers:
      - name: log-container
        image: busybox
        args: [/bin/sh, -c, 'mkdir -p /var/log/log-test; i=0; while true; do printf "$(date "+%F %H:%M:%S") [%-8d] Bash For Loop Examples.\\n" $i >> /var/log/log-test/1.log; i=$((i+1)); sleep 1; done']

使用 yaml 文件创建资源:

$ kubectl apply -f logging.yaml
...

验证如下:

$ kubectl get pod

NAME                                   READY   STATUS    RESTARTS      AGE
logging-deployment-5d48bf9995-vt6bb       1/1     Running   0             4s

$ kubectl get pod logging-deployment-5d48bf9995-vt6bb -o=jsonpath={.spec.containers\[\*\].name}
log-container datakit-logfwd

最终可以在观测云日志平台查看日志是否采集。

async-profiler

前置条件

Note

async-profiler 使用 perf_events 工具来抓取 Linux 的内核调用堆栈,非特权进程依赖内核的相应设置,可以使用以下命令来修改内核参数:

$ sudo sysctl kernel.perf_event_paranoid=1
$ sudo sysctl kernel.kptr_restrict=0
# 或者
$ sudo sh -c 'echo 1 >/proc/sys/kernel/perf_event_paranoid'
$ sudo sh -c 'echo 0 >/proc/sys/kernel/kptr_restrict'

在你的 Pod 控制器 资源配置文件中的 .spec.template.metadata.annotations 节点下添加 annotation:admission.datakit/java-profiler.version: "latest",然后应用该资源配置文件, Datakit-Operator 会自动在相应的 Pod 中创建一个名为 datakit-profiler 的容器来辅助进行 profiling。

接下来以一个名为 movies-javaDeployment 资源配置文件为例进行说明。

kind: Deployment
metadata:
  name: movies-java
  labels:
    app: movies-java
spec:
  replicas: 1
  selector:
    matchLabels:
      app: movies-java
  template:
    metadata:
      name: movies-java
      labels:
        app: movies-java
      annotations:
        admission.datakit/java-profiler.version: "0.4.4"
    spec:
      containers:
        - name: movies-java
          image: zhangyicloud/movies-java:latest
          imagePullPolicy: IfNotPresent
          securityContext:
            seccompProfile:
              type: Unconfined
          env:
            - name: JAVA_OPTS
              value: ""

      restartPolicy: Always

应用配置文件并检查是否生效:

$ kubectl apply -f deployment-movies-java.yaml

$ kubectl get pods | grep movies-java
movies-java-784f4bb8c7-59g6s   2/2     Running   0          47s

$ kubectl describe pod movies-java-784f4bb8c7-59g6s | grep datakit-profiler
      /app/datakit-profiler from datakit-profiler-volume (rw)
  datakit-profiler:
      /app/datakit-profiler from datakit-profiler-volume (rw)
  datakit-profiler-volume:
  Normal  Created    12m   kubelet            Created container datakit-profiler
  Normal  Started    12m   kubelet            Started container datakit-profiler

稍等几分钟后即可在观测云控制台 应用性能检监测-Profiling 页面查看应用性能数据。

Note

默认使用命令 jps -q -J-XX:+PerfDisableSharedMem | head -n 20 来查找容器中的 JVM 进程,出于性能的考虑,最多只会采集 20 个进程的数据。

Note

可以通过修改 datakit-operator.yaml 配置文件中的 datakit-operator-config 下的环境变量来配置 profiling 的行为。

环境变量 说明 默认值
DK_PROFILE_SCHEDULE profiling 的运行计划,使用与 Linux Crontab 相同的语法,如 */10 * * * * 0 * * * *(每小时调度一次)
DK_PROFILE_DURATION 每次 profiling 持续的时间,单位秒 240(4 分钟)
Note

若无法看到数据,可以进入 datakit-profiler 容器查看相应日志进行排查:

$ kubectl exec -it movies-java-784f4bb8c7-59g6s -c datakit-profiler -- bash
$ tail -n 2000 log/main.log

py-spy

前置条件

  • 当前只支持 Python 官方解释器(CPython

在你的 Pod 控制器 资源配置文件中的 .spec.template.metadata.annotations 节点下添加 annotation:admission.datakit/python-profiler.version: "latest",然后应用该资源配置文件, Datakit-Operator 会自动在相应的 Pod 中创建一个名为 datakit-profiler 的容器来辅助进行 profiling。

接下来将以一个名为 "movies-python" 的 Deployment 资源配置文件为例进行说明。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: movies-python
  labels:
    app: movies-python
spec:
  replicas: 1
  selector:
    matchLabels:
      app: movies-python
  template:
    metadata:
      name: movies-python
      labels:
        app: movies-python
      annotations:
        admission.datakit/python-profiler.version: "latest"
    spec:
      containers:
        - name: movies-python
          image: zhangyicloud/movies-python:latest
          imagePullPolicy: Always
          command:
            - "gunicorn"
            - "-w"
            - "4"
            - "--bind"
            - "0.0.0.0:8080"
            - "app:app"

应用资源配置并验证是否生效:

$ kubectl apply -f deployment-movies-python.yaml

$ kubectl get pods | grep movies-python
movies-python-78b6cf55f-ptzxf   2/2     Running   0          64s

$ kubectl describe pod movies-python-78b6cf55f-ptzxf | grep datakit-profiler
      /app/datakit-profiler from datakit-profiler-volume (rw)
  datakit-profiler:
      /app/datakit-profiler from datakit-profiler-volume (rw)
  datakit-profiler-volume:
  Normal  Created    98s   kubelet            Created container datakit-profiler
  Normal  Started    97s   kubelet            Started container datakit-profiler

稍等几分钟后即可在观测云控制台 应用性能检监测-Profiling 页面查看应用性能数据。

Note

默认使用命令 ps -e -o pid,cmd --no-headers | grep -v grep | grep "python" | head -n 20 来查找容器中的 Python 进程,出于性能考虑,最多只会采集 20 个进程的数据。

Note

可以通过修改 datakit-operator.yaml 配置文件中的 ConfigMap datakit-operator-config 下的环境变量来配置 profiling 的行为。

环境变量 说明 默认值
DK_PROFILE_SCHEDULE profiling 的运行计划,使用与 Linux Crontab 相同的语法,如 */10 * * * * 0 * * * *(每小时调度一次)
DK_PROFILE_DURATION 每次 profiling 持续的时间,单位秒 240(4 分钟)
Note

若无法看到数据,可以进入 datakit-profiler 容器查看相应日志进行排查:

$ kubectl exec -it movies-python-78b6cf55f-ptzxf -c datakit-profiler -- bash
$ tail -n 2000 log/main.log

FAQ

  • 怎样指定某个 Pod 不注入?给该 Pod 添加 Annotation "admission.datakit/enabled": "false",将不再为它执行任何操作,此优先级最高。

  • Datakit-Operator 使用 Kubernetes Admission Controller 功能进行资源注入,详细机制请查看官方文档

文档评价

文档内容是否对您有帮助? ×