问题描述
我有一个名为 node
的码头集装箱,我想扩展到n个集装箱。
一个给定的 node
容器需要知道它在n个按比例缩放的 node
容器的集合中的哪个容器。
总数可能在一个环境变量中,但当前值更令人不安。
I have a docker container called node
that I want to scale to n containers.A given node
container needs to know which container it is in the set of n scaled node
containers.The total could be in an environment variable, but the current is more troubling.
$ docker-compose scale node=100
Starting projectdir_node_1 ... done
Creating and starting projectdir_node_2 ... done
Creating and starting projectdir_node_3 ... done
Creating and starting projectdir_node_4 ... done
Creating and starting projectdir_node_5 ... done
Creating and starting projectdir_node_6 ... done
Creating and starting projectdir_node_7 ... done
Creating and starting projectdir_node_8 ... done
Creating and starting projectdir_node_9 ... done
...
Creating and starting projectdir_node_99 ... done
Creating and starting projectdir_node_100 ... done
projectdir_node_100
如何知道它是节点 100
?
我看到 $ HOSTNAME
是容器ID(例如 2c73136347cd
),但是没有发现ENV变量
How can projectdir_node_100
know it is node 100
?I saw that $HOSTNAME
is the container id (e.g. 2c73136347cd
), but found no ENV variable for the hostname with number I need.
作为参考,我的 docker-compose.yml
:
version: '2'
services:
node:
build: ./node/
volumes:
- ./node/code/:/code:ro
entrypoint: ["/bin/bash"]
我发现了尚未解决的,但是我仍然不知道我是哪个容器。
I found the unsolved How to reach additional containers by the hostname after docker-compose scale?, but I still don't know which container I am.
推荐答案
这可以通过使用Docker api来解决。
This can be solved by using the Docker api.
虽然此答案中的代码是Python,而我链接的示例是Java,但这与您的语言无关。只需将Docker API与您选择的库一起使用,或直接向Docker API套接字发出请求。
While the code in this answer is Python, and my linked example is Java, this is pretty independent of your language. Just use the Docker API with a library of your choice, or make requests directly to the Docker API socket.
我使用了软件包即可访问。
I used the docker-py package to access it.
该api公开了标签
每个容器的字典,以及键 com.docker.compose.container-number
, com.docker.compose.project
和 com.docker.compose.service
完成了构建主机名所需的工作。
The api exposes a labels
dictionary for each container, and the keys com.docker.compose.container-number
, com.docker.compose.project
and com.docker.compose.service
did what was needed to build the hostname.
下面的代码是我现在正在使用的代码的简化。
您可以在Github上的以及试图在Java中执行相同的操作,但可能更难阅读,并且没有缓存。
The code below is a simplified for code I am now using.You can find my advanced code with caching and fancy stuff that at Github at luckydonald/pbft/dockerus.ServiceInfos (python) as well as a similar java version at luckydonald/pbft-java/de.luckydonald.utils.dockerus.Dockerus (java) which tries to do the same thing in java, but is probably harder to read, and has no caching.
某些事情
让我们分步解决此问题:
Lets tackle this in steps:
0。
我们需要使套接字文件可用于该卷,因此在 docker-的volume部分中, compose.yml
文件添加 /var/run/docker.sock:/var/run/docker.sock
:
We need to make the socket file available to the volume, so in the volume section of your docker-compose.yml
file add /var/run/docker.sock:/var/run/docker.sock
:
version: '2'
services:
node:
build: .
volumes:
- /var/run/docker.sock:/var/run/docker.sock
这会将套接字文件映射到docker容器中。
因为我们不暴露任何套接字端口,所以我们不必担心外部防火墙。
This maps the socket file into the docker container.Because we don't expose any socket ports, we don't have to worry about firewalls for the outside world.
1。连接到API
现在我们可以连接到它了。当我使用python时,我为此使用。
Now we can connect to it. As I am using python, I use docker-py for that.
from docker import Client # pip install docker-py
cli = Client(base_url='unix://var/run/docker.sock')
2。通过按我们自己的项目名称和服务名称过滤容器,将所有容器归入同一比例组。
要知道我们是哪个容器,我们将 $ HOSTNAME
环境变量与容器 Id
进行比较。
To know which container we are, we compare the $HOSTNAME
environment variable with the container Id
.
import os
HOSTNAME = os.environ.get("HOSTNAME")
all_containers = cli.containers()
# filter out ourself by HOSTNAME
our_container = [c for c in all_containers if c['Id'][:12] == HOSTNAME[:12]][0]
主机名应为 Id
的12个字符,因此在进行比较时我们会切掉ID以确保它将等于。
our_container
现在是我们自己的api表示。是的。
The hostname should be 12 characters of the Id
, so we cut the id when comparing to be sure it will be equal.our_container
now is the api representation of ourself. Yay.
我们将搜索具有相同项目和服务名称的容器。
这样我们就知道它们是我们自己的实例。
We will search for containers which have the same project and service names.That way we know they are instances of ourself.
service_name = our_container.Labels['com.docker.compose.service']
project_name = our_container.Labels['com.docker.compose.project']
filters = [
'com.docker.compose.project={}'.format(project_name),
'com.docker.compose.service={}'.format(service_name)
]
# The python wrapper has a filter function to do that work for us.
containers = cli.containers(filters={'label': filters})
我们只希望每个容器其中 com.docker.compose.project
和 com.docker.compose.service
标签与我们自己的标签相同
We only want each container where the com.docker.compose.project
and com.docker.compose.service
label is the same as our own container's.
hostname_list = list()
for container in containers:
project = container.Labels["com.docker.compose.project"]
service = container.Labels["com.docker.compose.service"]
number = container.Labels["com.docker.compose.container-number"]
hostname = "{project}_{service}_{i}".format(project=project, service=service, i=number)
hostname_list.append(hostname)
# end for
因此,我们得到了 hostname_list
。
我也将其用作一个类,将值缓存一分钟:
(备份)
I am also using that as a class, with caching the values for a minute:dockerus.ServiceInfos (backup at gist.github.com)
这篇关于容器如何识别一组扩展的docker-compose服务中的哪个容器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!