tanger
发布于 2024-05-27 / 1 阅读 / 0 评论 / 0 点赞

docker swarm service 的 container 如何获取自己 task 的信息

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 内部执行。

  1. 需要一个环境变量 HOSTNAME,就是内置的 container ID

  2. 先从 container inspect 信息里面得到 TASKID

  3. 再根据 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
    }
}


评论