Docker 容器日志分为两类:引擎日志和容器日志。Docker引擎日志是 Docker本身运行的日志, 「容器日志是各个容器内产生的日志。

查看引擎日志

CentOS 系统下的 docker 引擎日志一般由 systemd 管理,可通过 journalctl -u docker.service 命令

[root@docker ~]# journalctl -u docker.service
-- Logs begin at 五 2023-12-08 14:31:42 CST, end at 五 2023-12-08 18:01:01 CST. --
12月 08 14:32:30 docker systemd[1]: Starting Docker Application Container Engine...
12月 08 14:32:32 docker dockerd[1613]: time="2023-12-08T14:32:32.488867039+08:00" level=info msg="Starting up"
12月 08 14:32:36 docker dockerd[1613]: time="2023-12-08T14:32:36.469622664+08:00" level=info msg="[graphdriver] using prior storage driver: overlay2"
12月 08 14:32:37 docker dockerd[1613]: time="2023-12-08T14:32:37.832745699+08:00" level=info msg="Loading containers: start."
12月 08 14:32:38 docker dockerd[1613]: time="2023-12-08T14:32:38.505509615+08:00" level=info msg="Firewalld: docker zone already exists, returning"
12月 08 14:32:39 docker dockerd[1613]: time="2023-12-08T14:32:39.378392400+08:00" level=info msg="Firewalld: interface docker0 already part of docker zone, returning"
12月 08 14:32:39 docker dockerd[1613]: time="2023-12-08T14:32:39.834554819+08:00" level=info msg="Removing stale sandbox c556776518828de2c76a5dfa6ad9b4c85d05cf1a4db4fef4693d46218a5e609f (94bdab7fccd4c6138825d128143e144b0932f02d6d73046026156cdb651afd93)"
12月 08 14:32:39 docker dockerd[1613]: time="2023-12-08T14:32:39.930431986+08:00" level=warning msg="Error (Unable to complete atomic operation, key modified) deleting object [endpoint b70b5e0d8b0ef67ea219f8125de513cfc17566e721ac192e76b049bf5a957fb6 a3e35b9e5ed87b8dd6ae96a18ffee459a26107f6c532a4b11d7146f95987f972], retrying...."
12月 08 14:32:40 docker dockerd[1613]: time="2023-12-08T14:32:40.095854667+08:00" level=info msg="Default bridge (docker0) is assigned with an IP address 172.17.0.0/16. Daemon option --bip can be used to set a preferred IP address"
12月 08 14:32:40 docker dockerd[1613]: time="2023-12-08T14:32:40.208657317+08:00" level=info msg="Firewalld: interface docker0 already part of docker zone, returning"
12月 08 14:32:42 docker dockerd[1613]: time="2023-12-08T14:32:42.783924317+08:00" level=info msg="Loading containers: done."
12月 08 14:32:43 docker dockerd[1613]: time="2023-12-08T14:32:43.146322478+08:00" level=info msg="Docker daemon" commit=311b9ff graphdriver=overlay2 version=24.0.7
12月 08 14:32:43 docker dockerd[1613]: time="2023-12-08T14:32:43.146485575+08:00" level=info msg="Daemon has completed initialization"
12月 08 14:32:49 docker dockerd[1613]: time="2023-12-08T14:32:49.217343665+08:00" level=info msg="API listen on /run/docker.sock"
12月 08 14:32:49 docker systemd[1]: Started Docker Application Container Engine.
12月 08 15:23:46 docker dockerd[1613]: time="2023-12-08T15:23:46.513482123+08:00" level=info msg="Container failed to exit within 10s of signal 15 - using the force" container=94bdab7fccd4c6138825d128143e144b0932f02d6d73046026156cdb651afd93
12月 08 15:23:46 docker dockerd[1613]: time="2023-12-08T15:23:46.615199323+08:00" level=info msg="ignoring event" container=94bdab7fccd4c6138825d128143e144b0932f02d6d73046026156cdb651afd93 module=libcontainerd namespace=moby topic=/tasks/delete type="*events.TaskDelete"
12月 08 15:23:46 docker dockerd[1613]: time="2023-12-08T15:23:46.651098851+08:00" level=warning msg="ShouldRestart failed, container will not be restarted" container=94bdab7fccd4c6138825d128143e144b0932f02d6d73046026156cdb651afd93 daemonShuttingDown=false error="restart canceled" execDuration=51m3.868806588s exitStatus="{137 2023-
12月 08 15:23:46 docker dockerd[1613]: time="2023-12-08T15:23:46.652223124+08:00" level=warning msg="failed to close stdin: task 94bdab7fccd4c6138825d128143e144b0932f02d6d73046026156cdb651afd93 not found: not found"
12月 08 15:37:04 docker dockerd[1613]: time="2023-12-08T15:37:04.223369618+08:00" level=info msg="Container failed to exit within 10s of signal 15 - using the force" container=aacb5bb995f445c8af7fdb2080bb07e8adc6631cce6e912b01147bb35cee36bf
12月 08 15:37:04 docker dockerd[1613]: time="2023-12-08T15:37:04.268250290+08:00" level=info msg="ignoring event" container=aacb5bb995f445c8af7fdb2080bb07e8adc6631cce6e912b01147bb35cee36bf module=libcontainerd namespace=moby topic=/tasks/delete type="*events.TaskDelete"
12月 08 15:37:04 docker dockerd[1613]: time="2023-12-08T15:37:04.286252145+08:00" level=warning msg="failed to close stdin: task aacb5bb995f445c8af7fdb2080bb07e8adc6631cce6e912b01147bb35cee36bf not found: not found"
12月 08 15:50:06 docker dockerd[1613]: time="2023-12-08T15:50:06.948356892+08:00" level=info msg="ignoring event" container=04a2094843d3dc1c8b2593ebb037958eb7b503de9dcab81d4c445457d7b8c3aa module=libcontainerd namespace=moby topic=/tasks/delete type="*events.TaskDelete"
12月 08 15:50:06 docker dockerd[1613]: time="2023-12-08T15:50:06.961873949+08:00" level=warning msg="failed to close stdin: task 04a2094843d3dc1c8b2593ebb037958eb7b503de9dcab81d4c445457d7b8c3aa not found: not found"
12月 08 16:00:33 docker dockerd[1613]: time="2023-12-08T16:00:33.790717267+08:00" level=info msg="ignoring event" container=48965c452ca1e94d7dfa8466b762b2cb914b77301ed6a66dd78b63f17bb6c3d4 module=libcontainerd namespace=moby topic=/tasks/delete type="*events.TaskDelete"
12月 08 16:00:33 docker dockerd[1613]: time="2023-12-08T16:00:33.803760333+08:00" level=warning msg="failed to close stdin: task 48965c452ca1e94d7dfa8466b762b2cb914b77301ed6a66dd78b63f17bb6c3d4 not found: not found"
12月 08 16:01:04 docker dockerd[1613]: time="2023-12-08T16:01:04.307850681+08:00" level=info msg="Firewalld: interface br-fadc61adc807 already part of docker zone, returning"
12月 08 16:04:59 docker dockerd[1613]: time="2023-12-08T16:04:59.048337328+08:00" level=info msg="Firewalld: interface br-77a453e66636 already part of docker zone, returning"
12月 08 16:13:51 docker dockerd[1613]: time="2023-12-08T16:13:51.065772600+08:00" level=info msg="ignoring event" container=6b62a768d0371d2c80c884b8140db3f001915b1ed215d394993cabe1e7c01836 module=libcontainerd namespace=moby topic=/tasks/delete type="*events.TaskDelete"
12月 08 16:13:51 docker dockerd[1613]: time="2023-12-08T16:13:51.080526973+08:00" level=warning msg="failed to close stdin: task 6b62a768d0371d2c80c884b8140db3f001915b1ed215d394993cabe1e7c01836 not found: not found"
12月 08 16:25:59 docker dockerd[1613]: time="2023-12-08T16:25:59.307416662+08:00" level=info msg="ignoring event" container=03895d7695377f480ef2df607f91d91554ce25c10b889b9a672cba356b2504f4 module=libcontainerd namespace=moby topic=/tasks/delete type="*events.TaskDelete"
12月 08 16:25:59 docker dockerd[1613]: time="2023-12-08T16:25:59.323151718+08:00" level=warning msg="failed to close stdin: task 03895d7695377f480ef2df607f91d91554ce25c10b889b9a672cba356b2504f4 not found: not found"
12月 08 16:36:18 docker dockerd[1613]: time="2023-12-08T16:36:18.232611440+08:00" level=info msg="ignoring event" container=fadd2aa8e0794040e9f8e513b225978cb41e241587e866af34c4cd859796a91d module=libcontainerd namespace=moby topic=/tasks/delete type="*events.TaskDelete"
12月 08 16:36:18 docker dockerd[1613]: time="2023-12-08T16:36:18.261760448+08:00" level=warning msg="failed to close stdin: task fadd2aa8e0794040e9f8e513b225978cb41e241587e866af34c4cd859796a91d not found: not found"
12月 08 16:38:22 docker dockerd[1613]: time="2023-12-08T16:38:22.763764859+08:00" level=info msg="Firewalld: interface br-438b3f575ef1 already part of docker zone, returning"
12月 08 16:45:11 docker dockerd[1613]: time="2023-12-08T16:45:11.875388247+08:00" level=error msg="Not continuing with pull after error: context canceled"
12月 08 16:55:56 docker dockerd[1613]: time="2023-12-08T16:55:56.899939948+08:00" level=info msg="Container failed to exit within 10s of signal 15 - using the force" container=7b0d2c995abb7d77603cbd85f10b5e0cb661c2f10f3020f9c8e01d1e22cd72c7
12月 08 16:55:56 docker dockerd[1613]: time="2023-12-08T16:55:56.959024527+08:00" level=info msg="ignoring event" container=7b0d2c995abb7d77603cbd85f10b5e0cb661c2f10f3020f9c8e01d1e22cd72c7 module=libcontainerd namespace=moby topic=/tasks/delete type="*events.TaskDelete"
12月 08 16:55:56 docker dockerd[1613]: time="2023-12-08T16:55:56.986586495+08:00" level=warning msg="failed to close stdin: task 7b0d2c995abb7d77603cbd85f10b5e0cb661c2f10f3020f9c8e01d1e22cd72c7 not found: not found"
12月 08 17:01:58 docker dockerd[1613]: time="2023-12-08T17:01:58.248339774+08:00" level=info msg="Firewalld: interface br-8de5141d76ac already part of docker zone, returning"
12月 08 17:05:30 docker dockerd[1613]: time="2023-12-08T17:05:30.148720212+08:00" level=info msg="Firewalld: interface br-2b29b0dd322b already part of docker zone, returning"
12月 08 17:05:48 docker dockerd[1613]: time="2023-12-08T17:05:48.136838304+08:00" level=error msg="Handler for POST /v1.43/containers/3d9de04e05f2bb555289fa17e787e822634b6152e8d25b88d0f49916bd3ba690/start returned error: Invalid address 172.18.0.6: It does not belong to any of this network's subnets"
12月 08 17:20:07 docker dockerd[1613]: time="2023-12-08T17:20:07.864689212+08:00" level=info msg="ignoring event" container=76346a72fe318ac14d921188281203b05659b365792fb2f1be7419b3cf19d63a module=libcontainerd namespace=moby topic=/tasks/delete type="*events.TaskDelete"
12月 08 17:20:07 docker dockerd[1613]: time="2023-12-08T17:20:07.878362951+08:00" level=warning msg="failed to close stdin: task 76346a72fe318ac14d921188281203b05659b365792fb2f1be7419b3cf19d63a not found: not found"
[root@docker ~]# 

查看容器日志

通常,容器日志指容器的标准输出,在容器启动失败或者其他场景,可以通过控制台查看 日志,用于定位容器相关问题。
通过 docker logs 命令可以查看容器的日志。命令格式如下:

docker 1ogs OPTIONS]CONTAINER

选项说明:
● --details 显示更多的信息
● -f,–follow 跟踪事实日志
● --since 显示某个timestamp之后的日志,或相对时间,如36m(即36分钟)
● --tail string 从日志末尾显示多少行日志,默认是all
● -t,–timestam 显示时间戳
● --until string 显示自摸个timestamp之前的日志,或者相对时间,如36m(即36分钟)

查看实时日志示例如下:

docker logs -f -t --since="2017-05-31" --tail=10 vm2

● --since 此参数指定了输出日志开始日期,即只输出指定日期之后的日志。
● -f 查看实时日志。
● -t 查看日志产生的日期。
● -tail=10 查看最后的10条日志。
●vm2 容器名称。

查看指定时间后的日志,只显示最后100行:

docker logs -f -t --since="2018-02-08" --tail=100 CONTAINER_ID

查看最近30分钟的日志:

docker logs --since=30m CONTAINER_ID

查看某时间之后的日志:

docker logs -t --since="2018-02-08T13:23:37" CONTAINER_ID

查看某时间段日志:

docker logs -t --since="2018-02-08T13:23:37" --until="2018-02-09T12:23:37" CONTAINER_ID

跟踪查看容器vm2的日志输出

[root@docker ~]# docker logs -f vm2
[root@280a32d6a877 /]# ip addr
bash: ip: command not found
[root@280a32d6a877 /]# docker run -it --name vm3 --network=my_net2 --ip=172.22.18.10 centos:7 
bash: docker: command not found
[root@280a32d6a877 /]# docker run -it --name vm3 --network=my_net2 --ip=172.22.18.10 centos:7 
bash: docker: command not found

查看容器 vm2在2016年7月1日之后的最新10条日志:

[root@docker ~]# docker logs --since="2016-07-01" --tail=10 vm2
[root@280a32d6a877 /]# ip addr
bash: ip: command not found
[root@280a32d6a877 /]# docker run -it --name vm3 --network=my_net2 --ip=172.22.18.10 centos:7 
bash: docker: command not found
[root@280a32d6a877 /]# docker run -it --name vm3 --network=my_net2 --ip=172.22.18.10 centos:7 
bash: docker: command not found
[root@docker ~]# 

Docker 日志是跟随容器而产生的,如果删除了某个容器,那么相应的日志文件也会随着被删除。
当输入 docker logs 命令的时候会转换为 Docker Client 向 Docker Daemon 发起请求,Docker
Daemon 在运行容器时会去创建一个协程(goroutine), 绑定了整个容器内所有进程的标准输出文 件描述符。因此,容器内所有的应用只要是标准输出日志,都会被 goroutine 接收,Docker Daemon
会根据容器 ID 和日志类型读取日志内容,最终会输出到用户终端上并且通过 JSON 格式存放在 var/lib/docker/containers目录下。

清理容器日志

如果 Docker容器正在运行,那么使用rm-rf方式删除日志文件后,通过 df -h 会发现磁盘空 间并没有释放。原因是在 Linux 或者 UNIX系统中,通过 rm -rf命令或者文件管理器删除文件,只 会从文件系统的目录结构上解除链接(unlink)。如果文件是被打开的(至少有一个进程正在使用), 那么进程将仍然可以读取该文件,磁盘空间也一直被占用。因此,正确的方式是使用命令:

cat /dev/null > *-json.log

当然也可以通过 rm -rf 删除后再重启 Docker。
日志清理脚本 clean_docker_log.sh 示例如下:

!/bin/sh
[echo  "=========  docker containers logs file size  ========="                                      
logs=$(find /var/lib/docker/containers/ -name *-ison.log)
for log in slogs
	do
		1s -1h slog
	done
chmod +x docker_log_size.sh
./docker_log_size.sh

但是,这样清理之后,随着时间的推移,容器日志会不断堆积。
为了解决日志清理的问题,需要限制容器服务的日志大小。这个通过配置容器 docker-compos
的 max-size 选项来实现:

centos:
 image:centos:7
 restart:always
 1ogging:
  driver:"json-file"
  options:
  max-size:"5g"

重启 vm2 容器之后,其日志文件的大小就被限制在5GB。
接下来看看全局设置日志大小的方法。新建/etc/docker/daemon json 文件,若已经存在该文件。
则无须新建。添加log-dirver 和log-opts 参数,示例如下:

vim /etc/docker/daemon.json

"registry-mirrors":["http://f613ce8f.m.daocloud.io"],
"log-driver";"json-file",
"log-opts":("max-size":"500m","max-file":"3")

设 置 了max-size=500m, 意味着一个容器日志大小的上限是500MB 。设 置 max-file=3, 意味着
一个容器有三个日志,分别是id+,json、id+1,json、id+2,json。

systemct1 daemon-reload
systemctl  restart  docker

需要注意的是,设置的日志大小只对新建的容器有效。

日志驱动程序

日志驱动程序概述

Docker日志驱动程序有:
none:运行的容器没有日志,dockerlogs 命令也不返回任何输出。

  • local:日志以自定义格式存储,旨在实现最小开销。
  • json-file:日志格式为JSON。Docker 的默认日志记录驱动程序。
  • syslog:将日志消息写入syslog。该 syslog守护程序必须在主机上运行。
  • joumald:将日志消息写入journald。该jounald 守护程序必须在主机上运行。
  • gelf:将日志消息写入Graylog扩展日志格式(GELF) 端点,例如 Graylog或 Logstash。
  • fuentd:将日志消息写入fluentd(转发输入)。该fluentd 守护程序必须在主机上运行。
  • awslogs: 将日志消息写入Amazon CloudWatch Logs.
  • splunk: 使 用HTTP 事件收集器将日志消息写入splunk。
  • etwlogs: 将日志消息写为Windows 事件跟踪(ETW) 事件。仅适用于Windows 平台。
  • gcplogs:将日志消息写入Google Cloud Platform(GCP)Logging。
  • logentries: 将日志消息写入Rapid7 Logentries。 Docker 常用日志驱动程序:
  • json-file:日志格式换为JSON, 这是 Docker 默认的日志驱动程序。
  • jourmald: 将日志消息写入journald,journald 守护程序必须在主机上运行。
  • syslog: 将日志消息写入syslog,syslog 守护程序必须在主机上运行。
  • gelf:将日志消息写入Graylog扩展日志格式(GELF)端点,例如Graylog或 Logstash。

Docker CE版本,docker logs 命令仅适用于如下图 所示的驱动程序。

查看 Docker 当前日志驱动程序:

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

查看单个容器设置的日志驱动命令格式为:docker inspect -f '{{.HostConfig.LogConfig.Typely 容器ID:

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

Docker日志驱动全局配置文件在/etc/docker/daemon.json 中,为 JSON 格式:

{
	"log-driver":"syslog" //修改日志驱动类型
}

除了对所有容器更改配置之外,还可以针对单一容器设置日志驱动,使用参数–log-driver 修改
指定容器的日志驱动:

docker run -itd --log-driver syslog 镜像ID

local日志驱动

local 日志驱动记录从容器的 STDOUT/STDERR 输出,并写到主机硬盘。在默认情况下,local
日志驱动为每个容器保留100MB 的日志信息,并启用压缩来保存。
local 日志驱动存储位置为/var/ib/docker/containers/容器 ID/local-logs/,以 container.log命名。支持的驱动选项有:

{
	"log-driver":"local",
	"log-opts":{
		"max-size":"10m"
	}
}

重启Docker服务后生效
单个容器日志驱动这只为-local,加–log-driver local

运行一个容器,设定日志驱动为local并运行命令 ping www.baidu.com

docker run -idt --log-driver local alpine ping www.baidu,com

查看运行的容器日志驱动是不是local

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

json-file 日志驱动

json-file日志驱动记录从容器的STDOUT/STDERR输出,并用JSON格式写到文件中。
json-file日志路径为/var/lib/docker/containers/容器ID/容器ID-json.log

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

  • max-size: 切割之前日志的最大大小。可取值单位为 k、m、g, 默认值为-1,表示无 限制。示例: --log-opt max-size=10m。
  • max-file:可以存在的最大日志文件数。如果切割日志会创建超过阈值的文件数,则会 删除最旧的文件。仅在max-size设置时有效。设置值为正整数,默认为1。示例: -log-opt
    max-file=5。
  • labels:适用于启动 Docker守护程序时。此守护程序接收以英文逗号分隔的与日志记 录相关的标签列表。示例:-log-opt labels-production status,geo。
  • env: 适用于启动 Docker 守护程序时。此守护程序接收以英文逗号分隔的与日志记录相关的环境变量列表。示例:–log-opt env=os,customer。
  • env-regex:类似兼容env. 用于匹配与日志记录相关的环境变量的正则表达式。示例:–log-opt env-regex=(os|customer)。
  • compress:切割的日志是否进行压缩。默认是 disabled。示例: --log-opt compress=true。

syslog 日志驱动

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

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

修改全局日志驱动为 syslog:

cat /etc/docker/daemon.json
{
	"log-driver":"syslog",
	"1og-opts":(
		"syslog-address":"udp:// 1.2.3.4:1111"
	}
}

日志驱动的选择

Docker 官方提供的日志驱动都是针对容器的 STDOUT/STDERR输出的日志驱动。 容器中的日志可分为两大类:

(1) 标准输出 STDOUT/STDERR 日志。也就是 STDOUT/STDERR, 这类日志可通过 Dockel 官方的日志驱动进行收集。比如,Nginx 日志有 access.log 和 error.log,在 Docker Hub 上可看到 Nginx 的 Dockerfile 对于这两个日志的处理:

RUN  1n  -sf /dev/stdout  /var/log/nginx/access.log
&& ln -sf /dev/stderr /var/log/nginx/error.log

都是软链接到/dev/stdout 和/dev/stderr,所以这类容器可以使用 Docker官方的日志驱动。

(2) 文本日志,都存储于容器内部,没有重定向到容器的 STDOUT/STDERR。比 如 :Tomcat 日志有 catalina 、localhost 、manager 、host-manager,我们可在 Docker Hub上看到:Tomcat的Dockerfile
中只有catalina 做了处理,其他日志都存储于容器内部,只有进入容器才可看到。

CMD ["catalina.sh","run"]

针对这类容器可以采用其他方法处理:

  • 完全是 STDOUT/STDERR输出类型的容器,可选择json-file、syslog、local 等 Docker
    支持的日志驱动。
  • 当有文本文件日志类型容器时,有如下处理方案:
    • 1.挂载目录
      创建一个目录,将目录挂载到容器中产生日志的目录:
      docker run -d --name tomcat-bind -P --mount type=bind,src=/opt/logs/,dst=/usr/local/tomcat/logs/ tomcat

    • 2.使用数据卷
      创建数据卷,创建容器时绑定数据卷:
      ~docker run -d --name tomcat-bind -P --mount type=volume,src=volume_name,dst=/usr/local/tomcat/logs/ tomcat~

    • 3.计算容器rootfs挂载点
      使用挂载宿主机目录方式采集日志对应用会有一定的侵入性,因为它要求容器启动时包含挂载 命令。如果采集过程中能对用户透明那就太棒了,事实上,可以通过计算容器 rootfs 挂载点来达到 这个目的。
      与容器 rootfs 挂载点密不可分的一个概念是 storage driver。在实际使用过程中,用户往往会根 据Linux 版本、文件系统类型、容器读写情况等因素选择合适的storage driver。不同 storage driver 下,容器 rootfs 挂载遵循一定的规律,因此我们可以根据 storage driver 的类型推断出容器的 rootfs 挂载点,进而采集容器内部log, 表11-1展示了部分storage driver 的 rootfs 挂载点及其计算方法。

查看 sms 微服务容器挂载点位置:

docker ps | grep sms
b0c936ecaBce  9ela0eOee678 "/.r/r/bin/sh -c ..." 18 months ago r-ms-test-sms-1-561a64f3
docker inspect -f '{{.GraphDriver.Data.MergedDir}}' b0c936eca8ce //查看SMS容器的挂载点位置
/mnt/docker/overlay/ee687989905069e3450318a0750a0d88909190191441cccbd47d83c c042f23ab/merged

ll /mnt/docker/overlay/ee687989905069e3450318a0750a0d88909190191441cccbd47d83cc042f23ab/merged #查看挂载点的目录结构
ll /mnt/docker/overlay/ee687989905069e3450318a0750a0d88909190191441cccbd47d83cc042 f23ab/merged/usr/local/
    • 4.在代码中实现直接将日志写到Redis
Docker=>Redis=>Logstash=>Elasticsearch
12-09 07:43