Docker之日志设置

引言

系统运行一段时间之后难免容器会出现问题,出现问题并不可怕,可怕的是不知道问题出现在哪里,这个时候查看当前容器运行的日志就能够排查出一些问题

正文

日志存储位置

在Linux系统中 Docker 启动后,日志默认会以 json-file 的格式存储于 /var/lib/docker/containers/容器ID/容器ID-json.log

1
2
3
4
5
6
7
8
9
-rw-r----- 1 root root 10325 Nov 16 14:09 12f7f218aa3ba42cf58e3a77ab7ff615c3b06cb04c8d2f22561592c2ea2d3126-json.log
drwx------ 2 root root 4096 Nov 16 14:07 checkpoints
-rw------- 1 root root 3664 Nov 16 14:07 config.v2.json
-rw-r--r-- 1 root root 1514 Nov 16 14:07 hostconfig.json
-rw-r--r-- 1 root root 13 Nov 16 14:07 hostname
-rw-r--r-- 1 root root 174 Nov 16 14:07 hosts
drwx------ 2 root root 4096 Nov 16 14:07 mounts
-rw-r--r-- 1 root root 108 Nov 16 14:07 resolv.conf
-rw-r--r-- 1 root root 71 Nov 16 14:07 resolv.conf.hash

不建议去这里直接读取内容,而是使用 docker logs -f 来实时查看,如果使用 docker Compose,则可以通过 docker-compose logs 容器ID/名称 来查看

日志驱动

Docker 的默认是 json-file 会将容器的日志保存在 json 文件中,Docker 负责格式化其内容并输出到 STDOUT 和 STDERR

支持的驱动

驱动 描述
none 运行的容器没有日志,docker logs 也不返回任何输出
local 日志以自定义格式存储
json-file 日志格式为JSON,默认
syslog 将日志消息写入syslog
journald 将日志消息写入journald
gelf 将日志消息写入 Graylog 扩展日志格式(GELF)端点,例如 Graylog 或 Logstash
fluentd 将日志消息写入 fluentd(转发输入)
awslogs 将日志消息写入Amazon CloudWatch Logs
splunk 使用HTTP事件收集器将日志消息写入splunk
etwlogs 将日志消息写为Windows事件跟踪(ETW)事件,仅适用于Windows平台
gcplogs 将日志消息写入Google Cloud Platform(GCP)Logging
logentries 将日志消息写入Rapid7 Logentries

local

local驱动,记录从容器的 STOUT/STDERR 的输出,并写到宿主机的磁盘,默认为每个容器保留100MB日志,存储位置在

1
/var/lib/docker/containers/容器id/local-logs/容器id.log

可配置项

选项 注释
max-size 每个日志文件最大的大小(k,m,g)
max-file 最大日志文件数量
compress 是否压缩

配置路径

1
2
3
4
5
6
7
$ vim /etc/docker/daemon.json
{
"log-driver": "local",
"log-opts": {
"max-size": "10m"
}
}

json-file

记录从容器的 STOUT/STDERR 的输出 ,用 JSON 的格式写到文件中,日志中包含输出日志、时间戳和输出格式

日志保存在

1
/var/lib/docker/containers/容器ID/容器ID-json.log

可配置项

选项 注释
max-size 每个日志文件最大的大小(k,m,g)
max-file 最大日志文件数量
labels 与日志记录相关的标签列表
env 与日志记录相关的环境变量列表
env-regex 与日志记录相关的环境变量正则
compress 是否压缩

配置方式

1
2
3
4
5
6
$ vim /etc/docker/daemon.json
{
"registry-mirrors": ["http://f1361db2.m.daocloud.io"],
"log-driver":"json-file",
"log-opts": {"max-size":"50m", "max-file":"1"}
}

syslog

将日志路由到 syslog 服务器,可接收如下字段

  • level:日志级别
  • timestamp:时间戳
  • hostname:日志主机
  • facillty:系统模块
  • 进程名和进程ID

Journald

将容器的日志发送到 systemd journal,可以使用 journal API 或者使用 docker logs 来查日志

查看容器驱动

可以通过如下命令查看系统当前设置的驱动

1
docker info|grep "Logging Driver" | docker info --format '{{.LoggingDriver}}'

也可以通过如下命令查看某个容器的驱动

1
docker inspect -f '{{.HostConfig.LogConfig.Type}}' 容器id

设置容器驱动

可以在 /etc/docker/daemon.json 配置默认系统容器驱动

1
2
3
{
"log-driver": "syslog"
}

也可以在启动容器时设置 --log-driver参数

1
docker run -itd --log-driver json-file 镜像名

限制容器日志大小

从上面可以知道 Docker 容器日志存储在文件中,容器销毁后日志也被一并删除

如果容器一直运行并且一直产生日志,容器日志会导致磁盘空间爆满,如何解决这个问题?

查看下日志大小情况

1
find /var/lib/docker/containers/  -name '*.log' -exec ls -lh {} \;

限制日志文件的大小方式有挺多种

设置容器日志大小

新建 /etc/docker/daemon.json,有就编辑,添加 log-dirverlog-opts 参数

1
2
3
4
5
{
"registry-mirrors": ["http://f613ce8f.m.daocloud.io"],
"log-driver":"json-file",
"log-opts": {"max-size":"500m", "max-file":"3"}
}
  • max-size=500m:表示一个容器日志大小上限是500M
  • max-file=3 表示一个容器最多有三个日志,分别是 容器id-json.log、容器id-json.log.1、容器id-json.log.2

这两个参数设置之后说明,一个容器最多保存 1500M(3 * 500) 日志,超过范围的日志不会被保存,文件中保存的是最新的日志,文件会自动滚动更新

设置完成之后,需要重新 docker

1
systemctl restart docker

注意:设置的日志大小,只对 新建的容器有效


我们可以看到 hostconfig.json 文件的变化如下

设置之前

1
2
3
4
5
...
"LogConfig": {
"Type": "json-file",
"Config": {}
}

设置之后

1
2
3
4
5
6
7
8
...
"LogConfig": {
"Type": "json-file",
"Config": {
"max-file": "3",
"max-size": "500m"
}
}

k8s中的容器日志

k8s 集群中 Docker 容器日志/var/lib/docker/containers/容器ID/目录 的文件如下

1
2
3
4
5
-rw-r----- 1 root root  27K Oct 30 19:45 830b17595b2c5cac86e9294b00e90d90e867d7d67489b4e4ee47f847d4726efb-json.log
drwx------ 2 root root 4.0K Oct 30 19:44 checkpoints
-rw------- 1 root root 24K Oct 30 19:44 config.v2.json
-rw-r--r-- 1 root root 2.1K Oct 30 19:44 hostconfig.json
drwx------ 2 root root 4.0K Oct 30 19:44 mounts

与 docker 容器目录相比少了一些文件:hostname、hosts、resolv.conf、resolv.conf.hash

k8s通过 sandbox(pause容器)关联了这些文件,查看 config.v2.json 配置文件

1
2
3
4
"HostnamePath": "/var/lib/docker/containers/27c9b0c0d1d7c8c7db515f96d5ae8c50ef7aeea02ecddcaa6546ea233dc5445c/hostname",
"HostsPath": "/var/lib/kubelet/pods/88f3a665-fdd1-4ad5-b0e0-0b613f762b4c/etc-hosts",
"ShmPath": "/var/lib/docker/containers/27c9b0c0d1d7c8c7db515f96d5ae8c50ef7aeea02ecddcaa6546ea233dc5445c/mounts/shm",
"ResolvConfPath": "/var/lib/docker/containers/27c9b0c0d1d7c8c7db515f96d5ae8c50ef7aeea02ecddcaa6546ea233dc5445c/resolv.conf",

查看 /var/lib/docker/containers/<容器id>/hostconfig.json 发现有如下设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"Binds": [
"/var/lib/kubelet/pods/e268cba1-95c6-4c16-904c-6be0b70344ea/volumes/kubernetes.io~secret/default-token-7vpxg:/var/run/secrets/kubernetes.io/serviceaccount:ro",
"/var/lib/kubelet/pods/e268cba1-95c6-4c16-904c-6be0b70344ea/etc-hosts:/etc/hosts",
"/var/lib/kubelet/pods/e268cba1-95c6-4c16-904c-6be0b70344ea/containers/demo/eee5300c:/dev/termination-log"
],
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {
"max-file": "10",
"max-size": "100m"
}
},
"NetworkMode": cd "container:ab24db5934f3a0153d9deb3c2de054c87148c3919f1bc2b1d2c11c4c8a2c8c57",
"PortBindings": null,
//其他参数没有列出来
......
......
}

说明一个容器中日志文件的大小最大为100m,最多10个文件,一个容器的日志最多保存1000m日志数据

查看 /etc/docker/daemon.json 发现有如下配置

1
2
3
4
5
6
7
8
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "10"
}
}

下面列出了一个容器的日志文件达到设置值的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
total 927M
drwx------ 2 root root 4.0K Sep 9 14:51 checkpoints
-rw------- 1 root root 24K Sep 9 14:51 config.v2.json
-rw-r----- 1 root root 69M Nov 16 14:21 f627a603df6e162645d6e29ad27b379b1b92607ea3a95667bcfcd851d9695f38-json.log
-rw-r----- 1 root root 96M Nov 16 07:24 f627a603df6e162645d6e29ad27b379b1b92607ea3a95667bcfcd851d9695f38-json.log.1
-rw-r----- 1 root root 96M Nov 15 21:49 f627a603df6e162645d6e29ad27b379b1b92607ea3a95667bcfcd851d9695f38-json.log.2
-rw-r----- 1 root root 96M Nov 15 12:04 f627a603df6e162645d6e29ad27b379b1b92607ea3a95667bcfcd851d9695f38-json.log.3
-rw-r----- 1 root root 96M Nov 15 02:21 f627a603df6e162645d6e29ad27b379b1b92607ea3a95667bcfcd851d9695f38-json.log.4
-rw-r----- 1 root root 96M Nov 14 16:47 f627a603df6e162645d6e29ad27b379b1b92607ea3a95667bcfcd851d9695f38-json.log.5
-rw-r----- 1 root root 96M Nov 14 07:11 f627a603df6e162645d6e29ad27b379b1b92607ea3a95667bcfcd851d9695f38-json.log.6
-rw-r----- 1 root root 96M Nov 13 21:35 f627a603df6e162645d6e29ad27b379b1b92607ea3a95667bcfcd851d9695f38-json.log.7
-rw-r----- 1 root root 96M Nov 13 11:57 f627a603df6e162645d6e29ad27b379b1b92607ea3a95667bcfcd851d9695f38-json.log.8
-rw-r----- 1 root root 96M Nov 13 02:21 f627a603df6e162645d6e29ad27b379b1b92607ea3a95667bcfcd851d9695f38-json.log.9
-rw-r--r-- 1 root root 2.2K Sep 9 14:51 hostconfig.json
drwx------ 2 root root 4.0K Sep 9 14:51 mounts

其他

清空日志脚本

1
2
3
4
5
6
7
8
9
#!/bin/sh
echo "======== start clean docker containers logs ========"
logs=$(find /var/lib/docker/containers/ -name *-json.log)
for log in $logs
do
echo "clean logs : $log"
cat /dev/null > $log
done
echo "======== end clean docker containers logs ========