容器日志¶
Datakit 支持采集 Kubernetes 和主机容器日志,从数据来源上,可以分为以下两种:
-
控制台输出:即容器应用的 stdout/stderr 输出,也是最常见的方式,可以使用类似
docker logs
或kubectl logs
查看 -
容器内部文件:如果日志不输出到 stdout/stderr,那应该就是落盘存储到文件,采集这种日志的稍微麻烦一些需要做 mount 挂载
本文会详细介绍这两种采集方式。
控制台 stdout/stderr 日志采集¶
控制台输出(即 stdout/stderr)通过容器 runtime 落盘到文件,Datakit 会自动获取到该容器的 LogPath 进行采集。
如果要自定义采集的配置,可以通过添加容器环境变量或 Kubernetes Pod Annotation 的方式。
- 自定义配置的 Key 有以下几种情况:
- 容器环境变量的 Key 固定为
DATAKIT_LOGS_CONFIG
- Pod Annotation 的 Key 有两种写法:
datakit/<container_name>.logs
,其中<container_name>
需要替换为当前 Pod 的容器名,这在多容器环境下会用到datakit/logs
会对该 Pod 的所有容器都适用
- 容器环境变量的 Key 固定为
Info
如果一个容器存在环境变量 DATAKIT_LOGS_CONFIG
,同时又能找到它所属 Pod 的 Annotation datakit/logs
,按照就近原则,以容器环境变量的配置为准。
- 自定义配置的 Value 如下:
[
{
"disable" : false,
"source" : "<your-source>",
"service" : "<your-service>",
"pipeline": "<your-pipeline.p>",
"tags" : {
"<some-key>" : "<some_other_value>"
}
}
]
字段说明:
字段名 | 取值 | 说明 |
---|---|---|
disable |
true/false | 是否禁用该容器的日志采集,默认是 false |
type |
file /不填 |
选择采集类型。如果是采集容器内文件,必须写成 file 。默认为空是采集 stdout/stderr |
path |
字符串 | 配置文件路径。如果是采集容器内文件,必须填写 volume 的 path,注意不是容器内的文件路径,是容器外能访问到的路径。默认采集 stdout/stderr 不用填 |
source |
字符串 | 日志来源,参见容器日志采集的 source 设置 |
service |
字符串 | 日志隶属的服务,默认值为日志来源(source) |
pipeline |
字符串 | 适用该日志的 Pipeline 脚本,默认值为与日志来源匹配的脚本名(<source>.p ) |
multiline_match |
正则表达式字符串 | 用于多行日志匹配时的首行识别,例如 "multiline_match":"^\\d{4}" 表示行首是 4 个数字,在正则表达式规则中 \d 是数字,前面的 \ 是用来转义 |
character_encoding |
字符串 | 选择编码,如果编码有误会导致数据无法查看,支持 utf-8 , utf-16le , utf-16le , gbk , gb18030 or ""。默认为空即可 |
tags |
key/value 键值对 | 添加额外的 tags,如果已经存在同名的 key 将以此为准( Version-1.4.6 ) |
完整示例如下:
$ cat Dockerfile
FROM pubrepo.guance.com/base/ubuntu:18.04 AS base
Run mkdir -p /opt
Run echo 'i=0; \n\
while true; \n\
do \n\
echo "$(date +"%Y-%m-%d %H:%M:%S") [$i] Bash For Loop Examples. Hello, world! Testing output."; \n\
i=$((i+1)); \n\
sleep 1; \n\
done \n'\
>> /opt/s.sh
CMD ["/bin/bash", "/opt/s.sh"]
## 构建镜像
$ docker build -t testing/log-output:v1 .
## 启动容器,添加环境变量 DATAKIT_LOGS_CONFIG
$ docker run --name log-output -env DATAKIT_LOGS_CONFIG='[{"disable":false,"source":"testing-source","service":"testing-service"}]' -d testing/log-output:v1
apiVersion: v1
kind: Pod
metadata:
name: log-output
annotations:
## 添加配置,且指定容器为 log-output
datakit/log-output.logs: |
[{
"disable": false,
"source": "testing-source-02",
"service": "testing-service",
"tags" : {
"some_tag": "some_value"
}
}]"
spec:
containers:
- name: log-output
image: pubrepo.guance.com/base/ubuntu:18.04
args:
- /bin/sh
- -c
- >
i=0;
while true;
do
echo "$(date +'%F %H:%M:%S') [$i] Bash For Loop Examples. Hello, world! Testing output.";
i=$((i+1));
sleep 1;
done
执行 Kubernetes 命令,应用该配置:
Attention
- 如无必要,不要轻易在环境变量和 Pod Annotation 中配置 Pipeline,一般情况下,通过
source
字段自动推导即可。 - 如果是在配置文件或终端命令行添加 Env/Annotations,两边是英文状态双引号,需要添加转义字符。
multiline_match
的值是双重转义,4 根斜杠才能表示实际的 1 根,例如 \"multiline_match\":\"^\\\\d{4}\"
等价 "multiline_match":"^\d{4}"
,示例:
容器内日志文件采集¶
对于容器内部的日志文件,和控制台输出日志的区别是需要指定文件路径,其他配置项大同小异。
Attention
配置的文件路径,不是容器内的文件路径,是通过 volume mount 能在外部访问到的路径。
同样是添加容器环境变量或 Kubernetes Pod Annotation 的方式,Key 和 Value 基本一致,详见前文。
完整示例如下:
$ cat Dockerfile
FROM pubrepo.guance.com/base/ubuntu:18.04 AS base
Run mkdir -p /opt
Run echo 'i=0; \n\
while true; \n\
do \n\
echo "$(date +"%Y-%m-%d %H:%M:%S") [$i] Bash For Loop Examples. Hello, world! Testing output." >> /tmp/opt/log; \n\
i=$((i+1)); \n\
sleep 1; \n\
done \n'\
>> /opt/s.sh
CMD ["/bin/bash", "/opt/s.sh"]
## 构建镜像
$ docker build -t testing/log-to-file:v1 .
## 启动容器,添加环境变量 DATAKIT_LOGS_CONFIG,注意字符转义
## 指定非 stdout 路径,"type" 和 "path" 是必填字段,且需要创建采集路径的 volume
## 例如采集 `/tmp/opt/log` 文件,需要添加 `/tmp/opt` 的匿名 volume
$ docker run --env DATAKIT_LOGS_CONFIG="[{\"disable\":false,\"type\":\"file\",\"path\":\"/tmp/opt/log\",\"source\":\"testing-source\",\"service\":\"testing-service\"}]" -v /tmp/opt -d testing/log-to-file:v1
apiVersion: v1
kind: Pod
metadata:
name: logging
annotations:
## 添加配置,且指定容器为 logging
## 同时配置了 file 和 stdout 两种采集。注意要采集 "/tmp/opt/log" 文件,需要先给 "/tmp/opt" 添加 emptyDir volume
datakit/logging.logs: |
[
{
"disable": false,
"type": "file",
"path":"/tmp/opt/log",
"source": "logging-file",
"tags" : {
"some_tag": "some_value"
}
},
{
"disable": false,
"source": "logging-output"
}
]"
spec:
containers:
- name: logging
image: pubrepo.guance.com/base/ubuntu:18.04
args:
- /bin/sh
- -c
- >
i=0;
while true;
do
echo "$(date +'%F %H:%M:%S') [$i] Bash For Loop Examples. Hello, world! Testing output.";
echo "$(date +'%F %H:%M:%S') [$i] Bash For Loop Examples. Hello, world! Testing output." >> /tmp/opt/log;
i=$((i+1));
sleep 1;
done
volumeMounts:
- mountPath: /tmp/opt
name: datakit-vol-opt
volumes:
- name: datakit-vol-opt
emptyDir: {}
执行 Kubernetes 命令,应用该配置:
对于容器内部的日志文件,在 Kubernetes 环境中还可以通过添加 sidecar 实现采集,参见这里。
根据容器 image 来调整日志采集¶
默认情况下,DataKit 会收集所在机器/Node 上所有容器的 stdout/stderr 日志,这可能不是大家的预期行为。某些时候,我们希望只采集(或不采集)部分容器的日志,这里可以通过镜像名称来间接指代目标容器。
## 当容器的 image 能够匹配 `hello*` 时,会采集此容器的日志
container_include_logging = ["image:hello*"]
## 忽略所有容器
container_exclude_logging = ["image:*"]
container_include
和 container_exclude
必须以 image
开头,格式为一种类正则的 Glob 通配:"image:<glob 规则>"
可通过如下环境变量
- ENV_INPUT_CONTAINER_CONTAINER_INCLUDE_LOG
- ENV_INPUT_CONTAINER_CONTAINER_EXCLUDE_LOG
来配置容器的日志采集。假设有 3 个 Pod,其 image 分别是:
- A:
hello/hello-http:latest
- B:
world/world-http:latest
- C:
registry.jiagouyun.com/datakit/datakit:1.2.0
如果只希望采集 Pod A 的日志,那么配置 ENV_INPUT_CONTAINER_CONTAINER_INCLUDE_LOG 即可:
如何查看镜像
Docker:
Kubernetes Pod:
Attention
通过全局配置的 container_exclude_logging 优先级低于容器的自定义配置 disable
。例如,配置了 container_exclude_logging = ["image:*"]
不采集所有日志,如果有 Pod Annotation 如下:
[
{
"disable": false,
"type": "file",
"path":"/tmp/opt/log",
"source": "logging-file",
"tags" : {
"some_tag": "some_value"
}
},
{
"disable": true,
"source": "logging-output"
}
]"
这份配置距离容器更近,优先级更高。配置的 disable=fasle
表明要采集日志文件,把上面的全局配置覆盖了。
所以这个容器日志文件最终还是会采集,但是控制台输出 stdout/stderr 不采集,因为 disable=true
。
FAQ¶
容器日志采集的 source 设置¶
在容器环境下,日志来源(source
)设置是一个很重要的配置项,它直接影响在页面上的展示效果。但如果挨个给每个容器的日志配置一个 source 未免残暴。如果不手动配置容器日志来源,DataKit 有如下规则(优先级递减)用于自动推断容器日志的来源:
所谓不手动指定容器日志来源,就是指在 Pod Annotation 中不指定,在 container.conf 中也不指定(目前 container.conf 中无指定容器日志来源的配置项)
- Kubernetes 指定的容器名:从容器的
io.kubernetes.container.name
这个 label 上取值 - 容器本身的名称:通过
docker ps
或crictl ps
能看到的容器名 default
: 默认的source