Datakit Operator User Guide¶
Overview and Installation¶
Datakit Operator is a collaborative project between Datakit and Kubernetes orchestration. It aims to assist the deployment of Datakit as well as other functions such as verification and injection.
Currently, Datakit Operator provides the following functions:
- Injection DDTrace SDK(Java/Python/Node.js) and related environments. See documentation.
- Injection Sidecar logfwd to collect Pod logging. See documentation.
- Support task distribution for Datakit plugins. See documentation.
Prerequisites:
- Recommended Kubernetes version 1.24.1 or above and internet access (to download yaml file and pull images).
- Ensure
MutatingAdmissionWebhook
andValidatingAdmissionWebhook
controllers are enabled. - Ensure
admissionregistration.k8s.io/v1
API is enabled.
Installation Steps¶
Download datakit-operator.yaml, and follow these steps:
Precondition:
- Kubernetes >= 1.14
- Helm >= 3.0+
$ helm install datakit-operator datakit-operator \
--repo https://pubrepo.guance.com/chartrepo/datakit-operator \
-n datakit --create-namespace
View deployment status:
Upgrade with the following command:
$ 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
Uninstall with the following command:
Attention
- There is a strict correspondence between Datakit-Operator's program and yaml files. If an outdated yaml file is used, it may not be possible to install the new version of Datakit-Operator. Please download the latest yaml file.
- If you encounter
InvalidImageName
error, you can manually pull the image.
Configuration Explanation¶
The Datakit Operator configuration is in JSON format and is stored in Kubernetes as a separate ConfigMap. It is loaded into the container as environment variables.
The default configuration is as follows:
{
"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 * * * *"
}
}
}
}
The main configuration items are ddtrace
, logfwd
, and profiler
, which specify the injected images and environment variables. In addition, ddtrace
also supports batch injection based on enabled_namespaces
and enabled_selectors
, as detailed in the section below.
Configuration of Images¶
The primary function of the Datakit Operator is to inject images and environment variables, using the images
configuration to specify the image addresses. The images
configuration consists of multiple Key/Value pairs, where the Key is fixed, and the Value is modified to specify the image address.
Under normal circumstances, images are stored in pubrepo.guance.com/datakit-operator
. However, for some special environments where accessing this image repository is not convenient, you can use the following method (taking the dd-lib-java-init
image as an example):
- In an environment where
pubrepo.guance.com
is accessible, pull the imagepubrepo.guance.com/datakit-operator/dd-lib-java-init:v1.30.1-guance
, and then re-store it in your own image repository, for example,inside.image.hub/datakit-operator/dd-lib-java-init:v1.30.1-guance
. - Modify the JSON configuration, changing
admission_inject
->ddtrace
->images
->java_agent_image
toinside.image.hub/datakit-operator/dd-lib-java-init:v1.30.1-guance
, and apply this YAML file. - After this, the Datakit Operator will use the new Java Agent image path.
Attention
The Datakit Operator does not validate the image. If the image path is incorrect, Kubernetes will throw an error when creating the Pod.**
Adding Environment Variables¶
All environment variables that need to be injected must be specified in the configuration file, as the Datakit Operator does not add any environment variables by default.
The environment variable configuration is called envs
, envs
consists of multiple Key/Value pairs: the Key is a fixed value, and the Value can either be a fixed value or a placeholder, depending on the actual situation.
For example, to add an environment variable testing-env
in envs
:
"admission_inject": {
"ddtrace": {
# other..
"envs": {
"DD_AGENT_HOST": "datakit-service.datakit.svc",
"DD_TRACE_AGENT_PORT": "9529",
"FAKE_ENV": "ok"
}
}
}
All containers that have ddtrace
agent injected into them will have five environment variables added to their envs
.
In Datakit Operator v1.4.2 and later versions, envs
envs
support for the Kubernetes Downward API environment variable fetch field. The following are now supported:
metadata.name
: The pod's name.metadata.namespace
: The pod's namespace.metadata.uid
: The pod's unique ID.metadata.annotations['<KEY>']
: The value of the pod's annotation named<KEY>
(for example, metadata.annotations['myannotation']).metadata.labels['<KEY>']
: The text value of the pod's label named<KEY>
(for example, metadata.labels['mylabel']).spec.serviceAccountName
: The name of the pod's service account.spec.nodeName
: The name of the node where the Pod is executing.status.hostIP
: The primary IP address of the node to which the Pod is assigned.status.hostIPs
: The IP addresses is a dual-stack version of status.hostIP, the first is always the same as status.hostIP. The field is available if you enable the PodHostIPs feature gate.status.podIP
: The pod's primary IP address (usually, its IPv4 address).status.podIPs
: The IP addresses is a dual-stack version of status.podIP, the first is always the same as status.podIP.
For example, if there is a Pod with the name nginx-123
and the namespace middleware
, and you want to inject the environment variables POD_NAME
and POD_NAMESPACE
, refer to the following configuration:
{
"admission_inject": {
"ddtrace": {
"envs": {
"POD_NAME": "{fieldRef:metadata.name}",
"POD_NAMESPACE": "{fieldRef:metadata.namespace}"
}
}
}
}
Eventually, the environment variables can be seen in the Pod:
Attention
If the placeholder in the Value is unrecognized, it will be added to the environment variable as a plain string. For example, "POD_NAME": "{fieldRef:metadata.PODNAME}"
is incorrect, and the environment variable will be set as POD_NAME={fieldRef:metadata.PODNAME}
.
Injection Methods¶
Datakit-Operator supports two methods for resource injection global configuration namespaces and selectors
, and adding specific annotations to target Pods. The differences between them are as follows:
-
Global Configuration: Namespace and Selector: By modifying the Datakit-Operator configuration, you specify the target Pod's Namespace and Selector. If a Pod matches the criteria, the resource injection will occur.
- Advantages: No need to add annotations to the target Pod (but the target Pod must be restarted).
- Disadvantages: The scope is not precise enough, which may lead to unnecessary injections.
-
Adding Annotations to Target Pods: Add annotations to the target Pod, and Datakit-Operator will check the Pod's annotations to decide whether to perform the injection based on the conditions.
- Advantages: Precise scope, preventing unnecessary injections.
- Disadvantages: You must manually add annotations to the target Pod, and the Pod needs to be restarted.
Attention
As of Datakit-Operator v1.5.8, the global configuration namespaces and selectors
method only applies to DDtrace injection
. It does not apply to logfwd
and profiler
, for which annotations are still required.
Global Configuration: Namespaces and Selectors¶
The enabled_namespaces
and enabled_labelselectors
fields are specific to ddtrace
. They are object arrays that require the specification of namespace
and language
. The relationships between the arrays are "OR" (i.e., any match in the array will trigger injection). The configuration is written as follows (refer to the configuration details later):
{
"server_listen": "0.0.0.0:9543",
"log_level": "info",
"admission_inject": {
"ddtrace": {
"enabled_namespaces": [
{
"namespace": "testns", # Specify the namespace
"language": "java" # Specify the language for the agent to inject
}
],
"enabled_labelselectors": [
{
"labelselector": "app=log-output", # Specify the label selector
"language": "java" # Specify the language for the agent to inject
}
]
# other..
}
}
}
If a Pod satisfies both the enabled_namespaces
rule and the enabled_labelselectors
rule, the configuration in enabled_labelselectors
will take precedence (usually applied when the language
value is used).
For guidelines on how to write labelselector
, please refer to the official documentation.
Note
- In Kubernetes versions 1.16.9 or earlier, Admission does not record the Pod Namespace, so the
enabled_namespaces
feature cannot be used.
Adding Annotation Configuration for Injection¶
To inject the ddtrace
file into a Pod, add the specified annotation to the Deployment. Make sure to add the annotation to the template
section.
The annotation format is as follows:
- The key is
admission.datakit/%s-lib.version
, where%s
should be replaced with the desired language. Currently, it supportsjava
. - The value is the specified version number. By default, it uses the version specified by the Datakit-Operator configuration in the
java_agent_image
setting. For more details, see the configuration explanation below.
For example, to add an annotation:
This indicates that the image version to be injected for this Pod is v1.36.2-guance
. The image address is taken from the configuration admission_inject
-> ddtrace
-> images
-> java_agent_image
, where the image version is replaced with "v1.36.2-guance"
, similar to pubrepo.guance.com/datakit-operator/dd-lib-java-init:v1.36.2-guance
.
Using Datakit-Operator to Inject Files and Programs¶
In large Kubernetes clusters, it can be quite difficult to make bulk configuration changes. Datakit-Operator will determine whether or not to modify or inject data based on Annotation configuration.
The following functions are currently supported:
- Injection of
ddtrace
agent and environment - Mounting of
logfwd
sidecar and enabling log collection - Inject
async-profiler
for JVM profiling Experimental - Inject
py-spy
for Python profiling Experimental
Info
Only version v1 of deployments/daemonsets/cronjobs/jobs/statefulsets
Kind is supported, and because Datakit-Operator actually operates on the PodTemplate, Pod is not supported. In this article, we will use Deployment
to describe these five kinds of Kind.
DDTrace Agent¶
Usage¶
- On the target Kubernetes cluster, download and install Datakit-Operator.
- Add a Annotation
admission.datakit/java-lib.version: ""
in deployment.
Example¶
The following is an example of Deployment that injects dd-java-lib
into all Pods created by Deployment:
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
Create a resource using yaml file:
Verify as follows:
$ 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¶
Prerequisites¶
logfwd is a proprietary log collection application for Datakit. To use it, you need to first deploy Datakit in the same Kubernetes cluster and satisfy the following two conditions:
- The Datakit
logfwdserver
collector is enabled, for example, listening on port9533
. - The Datakit service needs to open port
9533
to allow other Pods to accessdatakit-service.datakit.svc:9533
.
Instructions¶
- On the target Kubernetes cluster, download and install Datakit-Operator.
- In the deployment, add the specified Annotation to indicate that a logfwd sidecar needs to be mounted. Note that the Annotation should be added in the template.
- The key is uniformly
admission.datakit/logfwd.instances
. - The value is a JSON string of specific logfwd configuration, as shown below:
- The key is uniformly
[
{
"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>"
}
]
}
]
Parameter explanation can refer to logfwd configuration:
datakit_addr
is the Datakit logfwdserver address.loggings
is the main configuration and is an array that can refer to Datakit logging collector.logfiles
is a list of log files, which can specify absolute paths and support batch specification using glob rules. Absolute paths are recommended.ignore
filters file paths using glob rules. If it meets any filtering condition, the file will not be collected.source
is the data source. If it is empty,'default'
will be used by default.service
adds a new tag. If it is empty,$source
will be used by default.pipeline
is the Pipeline script path. If it is empty,$source.p
will be used. If$source.p
does not exist, the Pipeline will not be used. (This script file exists on the DataKit side.)character_encoding
selects an encoding. If the encoding is incorrect, the data cannot be viewed. It is recommended to leave it blank. Supported encodings includeutf-8
,utf-16le
,utf-16le
,gbk
,gb18030
, or "".multiline_match
is for multiline matching, as described in Datakit Log Multiline Configuration. Note that since it is in the JSON format, it does not support the "unescaped writing method" of three single quotes. The regex^\d{4}
needs to be written as^\\d{4}
with an escape character.tags
adds additional tags in JSON map format, such as{ "key1":"value1", "key2":"value2" }
.
When injecting logfwd
, it is allowed to reuse a volume with the same path to avoid injection errors caused by an existing volume at the same path. To enable this, set the configuration admission_inject
->logfwd
->options
->reuse_exist_volume
to true
.
For example, if the target Pod has a volume mounted at the path /var/log
, and /var/log
is the directory to be collected:
spec:
container:
# other...
volumeMounts:
- name: volume-log
mountPath: /var/log
volumes:
- name: volume-log
emptyDir: {}
When reuse_exist_volume
is enabled, no new volume or volumeMount will be added, and the existing volume-log
will be reused.
Attention
That there is a difference between paths with and without a trailing slash. /var/log
and /var/log/
are considered different paths and cannot be reused.
Example¶
Here is an example Deployment that continuously writes data to a file using shell and configures the collection of that file:
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']
Creating Resources Using yaml File:
Verify as follows:
$ 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
Finally, you can check whether the logs have been collected on the Guance Cloud Log Platform.
FAQ¶
-
How to specify that a certain Pod should not be injected? Add the annotation
"admission.datakit/enabled": "false"
to the Pod. This will prevent any actions from being performed on it, with the highest priority. -
Datakit-Operator utilizes Kubernetes Admission Controller functionality for resource injection. For detailed mechanisms, please refer to the official documentation