Docker Engine自带有很多种日志类型,其中journald
类型和systemd
结合紧密。但是journald查看日志非常不方便,除了可以通过
journalctl -u docker
过滤一下日志来源为Docker这种systemd的服务外,其他的过滤选项大多数是通过变量的完全匹配来实现的。通常情况下包含下面这些容器相关的变量:
CONTAINER_ID
:默认是容器ID的前12位。CONTAINER_TAG
:默认情况下和CONTAINER_ID
相同。CONTAINER_ID_FULL
:默认是完整的容器ID。CONTAINER_NAME
:默认是容器名。
在单机环境使用下,问题不大。因为我们往往可以通过容器名来过滤。但是在Swarm集群环境中使用就非常不便了。因为在集群中使用时,我们通常过滤某个特定的服务的日志。而服务通常分布在一个或者多个,名字为服务名.序号.随机ID
的容器中。由于容器名具有很大的随机性,所以就无法简单的通过容器名作为过滤器过滤了。
这种情况下,Docker的journald日志驱动器提供了两类高级的自定义方式,可以便于我们处理。
- 采用journald专有的
labels
、env
、env-regexp
三个日志选项。他们分别将容器的标签、环境变量转换成journald日志的变量。例如设置选项labels为com.docker.swarm.service.name
、com.docker.swarm.task.id
,那么,就会在jounald日志记录里,生成COM_DOCKER_SWARM_SERVICE_NAME
、COM_DOCKER_SWARM_TASK_ID
这两个变量,值分别就是容器对应标签的值。 - 采用大多数日志驱动器都支持的
tag日
志选项,通过一些模板替换和操作,获取具体的值。
这里我们倾向于选择第二类方式。因为我们的需求是获取指定服务的日志。如果采用第一种方式,要么通过com.docker.swarm.service.name
这种label获取,但是生成的journald变量名太长了。要么通过env,需要手动添加一个变量,也比较有侵入性。而第二种方式的话,一方面不需要对容器的配置作任何修改,另一方面生成的journald变量名为CONTAINER_TAG
,也比较短小。
那么怎样通过tag选项获取服务名呢?
通过Docker的文档我们知道,Docker的tags参数,默认可以通过{{.xxx}}
这种方式,获取到容器的ID、完整名称、镜像等信息。但是不能简单的通过这种方式获取到容器的服务名。但是同时文档中也提到了,可以从日志的运行时loginfo中环境中获取。
翻看Docker日志的运行时环境,Info结构成员很丰富。其中就有一个map[string]string
类型的ContainerLabels
的成员。顾名思义,肯定就是容器的标签列表了。而所有的Swarm服务都会打上com.docker.swarm.service.name
这个标签,值就是容器的服务名。所以,只需要把tag设置为下面的模板即可:
{{index .ContainerLabels “com.docker.swarm.service.name”}}
如果你是通过/etc/docker/daemon.json
来配置的Docker Engine,可以在文件中这样配置:
{
"log-driver": "journald",
"log-opts": {"tag": "{{index .ContainerLabels \"com.docker.swarm.service.name\"}}"}
}
注意为了同时符合JSON语法以及模板的Go语言语法,模板的双引号应该转义。 如果你是通过命令行参数的方式配置的Docker Engine,可以添加如下命令行参数:
--log-driver=journald --log-opt tag='{{index .ContainerLabels "com.docker.swarm.service.name"}}'
参考资料: