docker swarm service 的 container 如何获取自己 task 的信息
背景
Docker swarm 启动 service 的时候,如果设置了 --replicas 大于 1,那么一个 service 会有多个 container 实例,在每个 container 对应一个 task;现在的问题是,多个 container 如何标记谁是谁呢,例如有些工作只需要第一个 task 去做,其他 task 主要读取就行,那么 container 如何标识自己是不是第一个 task 呢。
举个例子来说:
创建一个 replicas=4 的 service:
$ docker service create --name my_service --replicas=4 my_image 查看 service 信息:
$ docker service ps my_service
ID NAME IMAGE ...
pf7l70cormgi my_service.1 my_image ...
wb4w57a3th5k my_service.2 my_image ...
p6olyrhij5mw my_service.3 my_image ...
q87wxtsx3lwg my_service.4 my_image ...
查看 container 信息:
$ docker ps | grep my_service
CONTAINER ID IMAGE ... NAMES
234ba9f6035a my_image:latest ... my_service.3.p6olyrhij5mw5pjhxjby4w29c
d8f85a31e5b3 my_image:latest ... my_service.4.q87wxtsx3lwgedui78ek66x5h
3bf23184df3e my_image:latest ... my_service.1.pf7l70cormgiltla2z237icgm
5a39c2172633 my_image:latest ... my_service.2.wb4w57a3th5kbveqqnq2tp8id
现在的问题是,如何在 container 内部得到自己对应的 service 标号呢,是 my_service.1,my_service.2,my_service.3,还是 my_service.4 呢?
遗憾的是目前 docker 并没有提供这样的机制简单获取这个值。
方法 1
使用 container 的环境变量 HOSTNAME,因为环境变量 HOSTNAME 是内置的,不同的 container 其值不一样,而这个值正好就是 container 的 id (如果用户没有显示的修改过 HOSTNAME 值)。
接着我们可以使用 docker inspect 得到这个 container 的详细信息,然后从 container 信息里面我们又能获取 task 的信息,具体内容看如下脚本:
#/bin/bash
...
TASKID=$(docker inspect --format '{{index .Config.Labels "com.docker.swarm.task.id"}}' ${HOSTNAME})
TASKSLOT=$(docker inspect --format '{{.Slot}}' ${TASKID})
echo "TASKSLOT=${TASKSLOT}"
...
这个段代码在 container 内部执行。
需要一个环境变量 HOSTNAME,就是内置的 container ID
先从 container inspect 信息里面得到 TASKID
再根据 taskid 得到 task inspect 信息,最后从 task inspect 信息里面提取 slot 值即可。
这个 TASKSLOT 就用来区分当前的 task,其值是:1,2,3,和 4。于是我们就区分了谁是谁的问题。
方法 2
这个方法是最近刚刚发现的。
就是在创建 service 的时候配置一个环境变量,然后在 container 里面就可以直接使用了,例如:
$ docker service create \
--name my_service \
--replicas=2 \
--env MY_TASK_SLOT={{.Task.Slot}} \
my_image
这样在 container 里面就可以直接访问 MY_TASK_SLOT 得到当前 task 的 slot 值,是不是很方便。
变量 {{...}} 中总共可以设置如下值:它的定义是在 https://github.com/docker/swarmkit/blob/master/template/context.go
{{.Service.Name}}
{{.Node.Hostname}}
{{.Service.Slot}}
...
type Context struct {
Service struct {
ID string
Name string
Labels map[string]string
}
Node struct {
ID string
Hostname string
Platform Platform
}
Task struct {
ID string
Name string
Slot string
}
}