十二、Docker日志管理

Docker日志管理

Docker的日志大致有两种,一是Docker 引擎日志,也就是 dockerd服务自身运行时的日志;二是容器内的服务产生的日志。后一种有一定使用经验的童鞋应该发现有时候我们能通过docker logs查看容器日志,有时候又不能,这是为什么呢?希望本文能对你有一定的帮助。

一 、Docker 引擎日志

Docker 引擎日志一般是交给了 Upstart(Ubuntu 14.04) 或者 systemd (CentOS 7, Ubuntu 16.04)。前者一般位于 /var/log/upstart/docker.log 下,后者我们一般 通过 journalctl -u docker 来进行查看。

二、容器日志

1、常用查看日志命令-docker logs

docker logs CONTAINER显示当前运行的容器的日志信息, UNIX 和 Linux 的命令有三种 输入输出,分别是 STDIN(标准输入)、STDOUT(标准输出)、STDERR(标准错误输出),docker logs 显示的内容包含 STOUT 和 STDERR。在生产环境,如果我们的应用输出到我们的日志文件里,所以我们在使用 docker logs 一般收集不到太多重要的日志信息。

如nginx 官方镜像,使用了一种方式,让日志输出到 STDOUT,也就是创建一个软链接/var/log/nginx/access.log 到 /dev/stdout,默认就能通过docker logs看到nginx的access日志。(删除 rm -rf /var/log/nginx/access.log ,需要重启才能看到效果,就不能看到日志了,可以手动再创建软链接后重启容器恢复查看ln -sf /dev/stdout /var/log/nginx/access.log)。
而httpd 使用的是让其输出到指定文件 ,正常日志输出到 /proc/self/fd/1 (STDOUT) ,错误日志输出到 /proc/self/fd/2 (STDERR)。

[root@k8s-m1 ~]# docker run -id -p 80:80 httpd
root@fdfe62f0dafb:/usr/local/apache2# cat conf/httpd.conf |grep -i log|grep proc
ErrorLog /proc/self/fd/2
CustomLog /proc/self/fd/1 common

当日志量比较大的时候,我们使用 docker logs 来查看日志,会对 docker daemon 造成比较大的压力,容器导致容器创建慢等一系列问题。**只有使用了 `local 、json-file、journald` 的日志驱动的容器才可以使用 docker logs 捕获日志,使用其他日志驱动无法使用 `docker logs`**Docker支持的LogDriver具体来说有以下几种,详情请参考docker官网。(https://docs.docker.com/config/containers/logging/configure/)

2、查看日志驱动
#查看某个容器目前使用的日志驱动
[root@k8s-m1 ~]# docker inspect fd -f {{.HostConfig.LogConfig.Type}}
json-file
#查看系统当前docker设置的日志驱动
[root@k8s-m1 ~]# docker info |grep -i driver
Storage Driver: overlay2
Logging Driver: json-file
Cgroup Driver: systemd

3、Docker日志驱动

Docker 提供了两种模式用于将消息从容器到日志驱动。

(默认)拒绝,阻塞从容器到容器驱动
非阻塞传递,日志将储存在容器的缓冲区。当缓冲区满,旧的日志将被丢弃。

在 mode 日志选项控制使用 blocking(默认) 或者 non-blocking, 当设置为 non-blocking需要设置 max-buffer-size 参数(默认为 1MB)。

支持的驱动
使用 Docker-CE 版本,docker logs命令 仅仅适用于以下驱动程序(前面 docker logs 详解也提及到了)

local、json-file、journald

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sx0Aq0rO-1686053731838)(image/5d95e469661f1fb59522a580a2f2d2c1.png)]
修改日志驱动,在配置文件 /etc/docker/daemon.json(注意该文件内容是 JSON 格式的)进行配置即可。

示例:
{“log-driver”: “syslog”}以上更改是针对所有的容器的日志驱动的。我们也可以单独为单一容器设置日志驱动。

三、Docker 单一容器日志驱动配置
在 运行容器的时候指定 日志驱动 --log-driver。

1、日志类型为none

[root@k8s-m1 ~]#docker run -itd --log-driver none nginx  # 这里指定的日志驱动为 none 

[root@k8s-m1 ~]#docker inspect 30 -f {{.HostConfig.LogConfig.Type}}

[root@k8s-m1 ~]#docker inspect 30 -f {{.NetworkSettings.IPAddress}}

[root@k8s-m1 ~]#curl `docker inspect 30 -f {{.NetworkSettings.IPAddress}}`

[root@k8s-m1 ~]#docker logs 30
Error response from daemon: configured logging driver does not support reading

2、日志驱动 local

local 驱动支持的选项

全局日志驱动设置为—local

在配置文件 /etc/docker/daemon.json(注意该文件内容是 JSON 格式的)进行配置即可。

{“log-driver”: “local”,“log-opts”: {“max-size”: “10m” }}
需要重启 docker 即可生效,并只对后面创建的容器生效。

单个容器日志驱动设置为—local

运行容器并设定为 local 驱动。

local 日志驱动 记录从容器的 STOUT/STDERR 的输出,并写到宿主机的磁盘。

[root@k8s-m1 ~]#docker run -itd --log-driver local  nginx

[root@k8s-m1 ~]# docker exec -it 23  /bin/bash

root@230b90b9ab90:/# ls -la /var/log/nginx/access.log  

lrwxrwxrwx 1 root root 11 Sep 10  2020 /var/log/nginx/access.log -> /dev/stdout

默认情况下,local 日志驱动为每个容器保留 100MB 的日志信息,并启用自动压缩来保存。(经过测试,保留100MB 的日志是指没有经过压缩的日志)

local 日志驱动的储存位置 /var/lib/docker/containers/容器id/local-logs/ 以container.log 命名。

注意事项:经过测试,当我们产生了100 MB 大小的日志时 会有 四个压缩文件和一个container.log:[root@localhost local-logs]# ls -ltotal 32544-rw-r-----. 1 root root 18339944 May 16 09:41 container.log-rw-r-----. 1 root root 3698660 May 16 09:41 container.log.1.gz-rw-r-----. 1 root root 3726315 May 16 09:41 container.log.2.gz-rw-r-----. 1 root root 3805668 May 16 09:41 container.log.3.gz-rw-r-----. 1 root root 3744104 May 16 09:41 container.log.4.gz那么当超过了 100MB 的日志文件,日志文件会继续写入到 container.log,但是会将 container.log 日志中老的日志删除,追加新的,也就是 当写满 100MB 日志后 ,再产生一条新日志,会删除 container.log 中的一条老日志,保存 100MB 的大小。**这个 对我们是会有一些影响的,**当我运行系统时 第一天由于bug产生了 100MB 日志,那么之前的日志就已经有 80MB 日志变成的压缩包,所以我在后续的运行中,只能获取最近的 20MB日志。

3、 默认的日志驱动-JSON

所有容器默认的日志驱动 json-file

json-file 日志驱动 记录从容器的 STOUT/STDERR 的输出 ,用 JSON 的格式写到文件中,日志中不仅包含着 输出日志,还有时间戳和 输出格式。
在这里插入图片描述

json-file 日志的路径位于 /var/lib/docker/containers/container_id/container_id-json.log。相比直接用docker logs查看多了时间戳。

json-file 的 日志驱动支持以下选项:

json-file 的日志驱动示例

# 设置 日志驱动为 json-file ,我们也可以不设置,因为默认就是 json-file

[root@k8s-m1 ~]# docker run \-itd \-\-name test\-log\-json \-\-log\-driver json\-file alpine ping  www.baidu.com
b8ac15abf30aeacfea8e6ecd8b9b5df967e5996ed3b7af49946ef1da08489720

查看日志,通过docker logs或者存放在宿主机的文件

[root@k8s-m1 ~]# docker logs b8
[root@k8s-m1 ~]# tail -f /var/lib/docker/containers/b8ac15abf30aeacfea8e6ecd8b9b5df967e5996ed3b7af49946ef1da08489720/b8ac15abf30aeacfea8e6ecd8b9b5df967e5996ed3b7af49946ef1da08489720-json.log 
{"log":"64 bytes from 14.119.104.254: seq=202 ttl=53 time=33.848 ms\r\n","stream":"stdout","time":"2023-06-07T01:02:33.112767747Z"}
{"log":"64 bytes from 14.119.104.254: seq=203 ttl=53 time=33.855 ms\r\n","stream":"stdout","time":"2023-06-07T01:02:34.112985708Z"}
{"log":"64 bytes from 14.119.104.254: seq=204 ttl=53 time=33.819 ms\r\n","stream":"stdout","time":"2023-06-07T01:02:35.113281475Z"}
{"log":"64 bytes from 14.119.104.254: seq=205 ttl=53 time=33.080 ms\r\n","stream":"stdout","time":"2023-06-07T01:02:36.112737837Z"}
{"log":"64 bytes from 14.119.104.254: seq=206 ttl=53 time=33.279 ms\r\n","stream":"stdout","time":"2023-06-07T01:02:37.113129431Z"}
{"log":"64 bytes from 14.119.104.254: seq=207 ttl=53 time=33.650 ms\r\n","stream":"stdout","time":"2023-06-07T01:02:38.113798225Z"}
{"log":"64 bytes from 14.119.104.254: seq=208 ttl=53 time=33.337 ms\r\n","stream":"stdout","time":"2023-06-07T01:02:39.113779104Z"}
{"log":"64 bytes from 14.119.104.254: seq=209 ttl=53 time=33.455 

4、syslog类型

syslog 日志驱动将日志路由到 syslog 服务器,syslog 以原始的字符串作为 日志消息元数据,接收方可以提取以下的消息:

level 日志等级 ,如debug,warning,error,info。timestamp 时间戳hostname 事件发生的主机facillty 系统模块进程名称和进程 ID

syslog 日志驱动全局配置

编辑 /etc/docker/daemon.json 文件

{“log-driver”: “syslog”,“log-opts”: {“syslog-address”: “[udp://1.2.3.4:514])” }}重启 docker 即可生效,注意调整格式。

单个容器日志驱动设置为—syslog

Linux 系统中 我们用的系统日志模块是rsyslog ,它是基于syslog 的标准实现。我们要使用 syslog 驱动需要使用 系统自带的 rsyslog 服务。

# 查看当前 rsyslog 版本和基本信息

[root@k8s-m2 ~]# rsyslogd \-v
rsyslogd 8.24.0-34.el7, compiled with:
        PLATFORM:                               x86_64-redhat-linux-gnu
        PLATFORM (lsb_release -d):
        FEATURE_REGEXP:                         Yes
        GSSAPI Kerberos 5 support:              Yes
        FEATURE_DEBUG (debug build, slow code): No
        32bit Atomic operations supported:      Yes
        64bit Atomic operations supported:      Yes
        memory allocator:                       system default
        Runtime Instrumentation (slow code):    No
        uuid support:                           Yes
        Number of Bits in RainerScript integers: 64

See http://www.rsyslog.com for more information.

我测试了将一台服务器上容器的日志传到另一台服务器。如下:
在k8s-m2配置 syslog , 在配置文件 /etc/rsyslog.conf 大约14-20行,我们可以看到两个配置,一个udp,一个tcp ,都是监听 514 端口,提供 syslog 的接收。选择 tcp 就将 tcp 的两个配置的前面 # 号注释即可。

# Provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514

# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514

然后重启 rsyslog,我们可以看到514端口在监听。

systemctl restart rsyslog
[root@k8s-m2 ~]# netstat -anp|grep 514
tcp        0      0 0.0.0.0:514             0.0.0.0:*               LISTEN      21072/rsyslogd      
tcp        0      0 192.168.2.141:51492     192.168.2.140:6443      ESTABLISHED 1928/kube-scheduler 
tcp        0      0 192.168.2.141:2379      192.168.2.142:37514     ESTABLISHED 17909/etcd          
tcp6       0      0 :::514                  :::*                    LISTEN      21072/rsyslogd      
udp        0      0 0.0.0.0:514             0.0.0.0:*                           21072/rsyslogd      
udp6       0      0 :::514                  :::*                                21072/rsyslogd   

在k8s-m1上创建将日志传到k8s-m2的容器:

[root@k8s-m1 ~]# docker run \-d \-it \-p 8080:80 \-\-log\-driver syslog \-\-log\-opt syslog\-address=udp://192.168.2.141:514  nginxcb28bb13dee1fe646a46a254005c886740b88e4f007f6ec94e25afd70b369979

# 在k8s-m1服务器访问nginx
curl 127.0.0.1:8080

# 在k8s-m2服务器查看访问日志tail -f /var/log/messages,当然该文件还包括其他日志。

Jun  7 09:33:44 k8s-m1 cb28bb13dee1[1581]: 172.16.0.1 - - [07/Jun/2023:01:33:44 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"#015
Jun  7 09:33:45 k8s-m1 cb28bb13dee1[1581]: 172.16.0.1 - - [07/Jun/2023:01:33:45 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"#015
Jun  7 09:33:45 k8s-m1 cb28bb13dee1[1581]: 172.16.0.1 - - [07/Jun/2023:01:33:45 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0" "-"#015

5、Journald类型

journald 日志驱动程序将容器的日志发送到 systemd journal, 可以使用 journal API 或者使用 docker logs 来查日志。

除了日志本身以外, journald 日志驱动还会在日志加上下面的数据与消息一起储存。

选项

journald 日志驱动全局配置

编辑 /etc/docker/daemon.json 文件·

{“log-driver”: “journald”}**单个容器日志驱动设置为—**journald

[root@k8s-m1 ~]# docker run \-d \-it \-\-log\-driver=journald \-\-log\-opt labels=location \-\-log\-opt env=test \-\-env "TEST=true" \-\-label location=china \-\-name nginx\-journald \-p 80:80  nginx
[root@k8s-m1 ~]# curl 127.0.0.1:80

查看日志 journalctl

# 只查询指定容器的相关消息 journalctl CONTAINER_NAME=nginx-journald

# -b 指定从上次启动以来的所有消息 journalctl -b CONTAINER_NAME=webserver

# -o 指定日志消息格式,-o json 表示以json 格式返回日志消息 journalctl -o json CONTAINER_NAME=webserver

# -f 一直捕获日志输出 journalctl -f CONTAINER_NAME=webserver

# --all 显示完整的日志

如果我们的容器在启动的时候加了 -t 参数,启用了 TTY 的话,那么我查看日志是会像下面一样May

Jun 07 09:42:09 k8s-m1 10016be35a75[1581]: [74B blob data]
Jun 07 09:42:09 k8s-m1 10016be35a75[1581]: [86B blob data]
Jun 07 09:42:09 k8s-m1 10016be35a75[1581]: [94B blob data]
Jun 07 09:42:09 k8s-m1 10016be35a75[1581]: [96B blob data]

显示[96B blob data] 而不是完整日志原因是因为有 \r 的存在,如果我们要完整显示,需要加上参数 --all 。

四、 生产环境中该如何储存容器中的日志

上面我们了解到了 Docker 官方提供了 很多种日志驱动,但是上面的这些驱动都是针对的标准输出的日志驱动。

容器日志分类

容器的日志实际是有两大类的:

1、标准输出的,也就是 STDOUT 、STDERR
这类日志我们可以通过 Docker 官方的日志驱动进行收集。示例:Nginx 日志,Nginx 日志有 access.log 和 error.log ,通过在 Docker Hub 上可以看到 Nginx 的 dockerfile 对于这两个日志的处理是:RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log都软连接到 /dev/stdout 和 /dev/stderr ,也就是标准输出,所以这类 容器是可以使用 Docker 官方的日志驱动。

2、文本日志
存在在于容器内部,并没有重定向到 容器的标准输出的日志。如我们很多的java后端业务服务,日志并没有做重定向,这类容器我们下面有专门的方案来应对。

方案一:当是完全是标准输出的类型的容器

我们可以选择 json-file 、syslog、local 等 Docker 支持的日志驱动。

方案二:当有文件文本日志的类型容器

挂载目录 bind
创建一个目录,将目录挂载到 容器中产生日志的目录。

--mount type=bind,src=/opt/logs/,dst=/var/log/*.log
示例:

# 创建挂载目录/opt/logs
[root@k8s-m1 ~]# mkdir /opt/logs

# 创建容器tomcat并将 /opt/logs 挂载至 /usr/local/tomcat/logs/

[root@k8s-m1 ~]# docker run -d --name tomcat-bind -p 8080:8080  --mount  type=bind,src=/opt/logs/,dst=/usr/local/tomcat/logs/ tomcat 
6558292625ecc908028714fb798d079db671e71df58c60d872af62a6b433bae3
[root@k8s-m1 ~]# ll /opt/logs/
total 8
-rw-r----- 1 root root 4962 Jun  7 10:34 catalina.2023-06-07.log
-rw-r----- 1 root root    0 Jun  7 10:34 localhost_access_log.2023-06-07.txt

方案三 使用数据卷 volume

创建数据卷,创建容器时绑定数据卷,

--mount type=volume src=volume_name dst=/usr/local/tomcat/logs/ 示例:

# 创建tomcat应用数据卷名称为 tomcat

[root@k8s-m1 ~]# docker volume create tomcat
[root@k8s-m1 ~]# docker volume inspect  tomcat 
[
    {
        "CreatedAt": "2023-06-07T11:29:40+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/tomcat/_data",
        "Name": "tomcat",
        "Options": {},
        "Scope": "local"
    }
]

# 创建容器tomcat-volume 并指定数据卷为 tomcat,绑定至 /usr/local/tomcat/logs/
[root@k8s-m1 ~]# docker run -d --name tomcat-volume -p 8080:8080  --mount type=volume,src=tomcat,dst=/usr/local/tomcat/logs/ tomcat 
#查看数据卷里面的内容
[root@k8s-m1 ~]# ll /var/lib/docker/volumes/tomcat/_data
total 8
-rw-r----- 1 root root 4962 Jun  7 11:29 catalina.2023-06-07.log
-rw-r----- 1 root root    0 Jun  7 11:29 localhost_access_log.2023-06-07.txt
[root@k8s-m1 ~]# 

方案四 计算容器 rootfs 挂载点

上面使用挂载宿主机目录的方式采集日志对应用会有一定的侵入性,因为它要求容器启动的时候包含挂载命令。如果采集过程能对用户透明那就完美了。事实上,可以通过计算容器 rootfs 挂载点来达到这种目的,类似上面的volume,只是这种情况下,挂载目录是自动生成的。

和容器 rootfs 挂载点密不可分的一个概念是 storage driver。实际使用过程中,用户往往会根据 linux 版本、文件系统类型、容器读写情况等因素选择合适的 storage driver。不同 storage driver 下,容器的 rootfs 挂载点遵循一定规律,因此我们可以根据 storage driver 的类型推断出容器的 rootfs 挂载点,进而采集容器内部日志。下表展示了部分 storage dirver 的 rootfs 挂载点及其计算方法。

Storage driverrootfs 挂载点计算方法
aufs/var/lib/docker/aufs/mnt/id 可以从如下文件读到,/var/lib/docker/image/aufs/layerdb/mounts//mount_id
overlay/var/lib/docker/overlay//merged完整路径可以通过如下命令得到。docker inspect -f ‘{{.GraphDriver.Data.MergedDir}}’
overlay2/var/lib/docker/overlay2//merged完整路径可以通过如下命令得到。docker inspect -f ‘{{.GraphDriver.Data.MergedDir}}’
devicemapper/var/lib/docker/devicemapper/mnt//rootfsid 可以通过如下命令得到。docker inspect -f ‘{{.GraphDriver.Data.DeviceName}}’

示例:

# 创建容器 tomcat-test
[root@k8s-m1 ~]# docker run -d --name tomcat-test -p 8080:8080 tomcat
f71a364e77ae6e6e3ad62ea49f8aa24ca066724987b7d74f1eb28f4822cffc1c
# 查看tomcat-test 容器的 挂载点位置
[root@k8s-m1 ~]# docker inspect -f '{{.GraphDriver.Data.MergedDir}}' f7
/var/lib/docker/overlay2/ffd66194a1758ab960a2e743fc7fd1999148174b88de310398f81aa7235d6f55/merged
# 查看挂载点的目录结构
[root@k8s-m1 ~]# ll /var/lib/docker/overlay2/ffd66194a1758ab960a2e743fc7fd1999148174b88de310398f81aa7235d6f55/merged
total 0
drwxr-xr-x 1 root root 179 Dec 22  2021 bin
drwxr-xr-x 2 root root   6 Dec 12  2021 boot
drwxr-xr-x 1 root root  43 Jun  7 13:47 dev
drwxr-xr-x 1 root root  66 Jun  7 13:47 etc
drwxr-xr-x 2 root root   6 Dec 12  2021 home
drwxr-xr-x 1 root root   6 Dec 23  2021 lib
drwxr-xr-x 2 root root  34 Dec 20  2021 lib64
drwxr-xr-x 2 root root   6 Dec 20  2021 media
drwxr-xr-x 2 root root   6 Dec 20  2021 mnt
drwxr-xr-x 2 root root   6 Dec 20  2021 opt
drwxr-xr-x 2 root root   6 Dec 12  2021 proc
drwx------ 1 root root  24 Dec 22  2021 root
drwxr-xr-x 3 root root  30 Dec 20  2021 run
drwxr-xr-x 1 root root  20 Dec 21  2021 sbin
drwxr-xr-x 2 root root   6 Dec 20  2021 srv
drwxr-xr-x 2 root root   6 Dec 12  2021 sys
drwxrwxrwt 1 root root  29 Dec 23  2021 tmp
drwxr-xr-x 1 root root  19 Dec 20  2021 usr
drwxr-xr-x 1 root root  41 Dec 20  2021 var
# 查看日志
[root@k8s-m1 ~]# ll /var/lib/docker/overlay2/ffd66194a1758ab960a2e743fc7fd1999148174b88de310398f81aa7235d6f55/merged/usr/local/tomcat/logs/
total 8
-rw-r----- 1 root root 4962 Jun  7 13:47 catalina.2023-06-07.log
-rw-r----- 1 root root    0 Jun  7 13:47 localhost_access_log.2023-06-07.txt

方案五 在代码层中实现直接将日志写入redis或者通过日志收集工具进行收集

docker ->redis ->Logstash ->Elasticsearch,通过代码层面,直接将日志写入redis,最后写入 Elasticsearch。
或者
docker(k8s) ->filebeat ->elasticsearch->kibana
docker(k8s) ->filebeat ->redis->logstash->elasticsearch->kibana,通过日志收集工具收集处理后存写入elasticsearch中,最后通过kibana进行展示查看。
以上就是对 Docker 日志的所有的概念解释和方提供,具体采用什么方案,根据公司的具体的业务来选择。合适的才是最好的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

margu_168

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值