Docker Compose 在启动 Y 之前等待容器 X
Docker Compose wait for container X before starting Y
我正在使用 rabbitmq 和来自 here 的简单 python 示例
连同 docker-compose。我的问题是我需要等待 rabbitmq 完全启动。从我到目前为止的搜索来看,我不知道如何等待容器 x(在我的案例中是 worker)直到 y (rabbitmq) 启动。
我发现这个 blog post 他在其中检查其他主机是否在线。
我还发现了这个 docker command:
wait
Usage: docker wait CONTAINER [CONTAINER...]
Block until a container stops, then print its exit code.
等待容器停止可能不是我想要的,但如果
是的,是否可以在 docker-compose.yml 中使用该命令?
到目前为止,我的解决方案是等待几秒钟并检查端口,但这是实现此目的的方法吗?如果我不等待,我会得到一个错误。
docker-compose.yml
worker:
build: myapp/.
volumes:
- myapp/.:/usr/src/app:ro
links:
- rabbitmq
rabbitmq:
image: rabbitmq:3-management
python 你好示例 (rabbit.py):
import pika
import time
import socket
pingcounter = 0
isreachable = False
while isreachable is False and pingcounter < 5:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect(('rabbitmq', 5672))
isreachable = True
except socket.error as e:
time.sleep(2)
pingcounter += 1
s.close()
if isreachable:
connection = pika.BlockingConnection(pika.ConnectionParameters(
host="rabbitmq"))
channel = connection.channel()
channel.queue_declare(queue='hello')
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print (" [x] Sent 'Hello World!'")
connection.close()
工人的 Dockerfile:
FROM python:2-onbuild
RUN ["pip", "install", "pika"]
CMD ["python","rabbit.py"]
2015 年 11 月更新:
shell 脚本或在您的程序中等待可能是一个可能的解决方案。但是在看到这个 Issue 之后,我正在寻找 docker/docker-compose 本身的命令或功能。
他们提到了实施健康检查的解决方案,这可能是最好的选择。打开的 TCP 连接并不意味着您的服务已准备就绪或可能保持就绪状态。除此之外,我还需要更改 docker 文件中的入口点。
所以我希望通过 docker-compose on board 命令得到一个答案,如果他们完成这个问题,希望情况会如此。
2016 年 3 月更新
有一个 proposal 用于提供确定容器是否“活动”的内置方法。所以 docker-compose 可能会在不久的将来使用它。
2016 年 6 月更新
在1.12.0
版本中,healthcheck似乎会integrated变成docker
2017 年 1 月更新
我找到了一个 docker-compose 解决方案,请参阅:
这在本地是不可能的。另见 feature request.
到目前为止,您需要在容器中执行此操作 CMD
以等待所有必需的服务都到位。
在 Dockerfile
s CMD
中,您可以参考自己的启动脚本,该脚本包装了启动容器服务的过程。在你开始之前,你等待一个依赖的人,比如:
Dockerfile
FROM python:2-onbuild
RUN ["pip", "install", "pika"]
ADD start.sh /start.sh
CMD ["/start.sh"]
start.sh
#!/bin/bash
while ! nc -z rabbitmq 5672; do sleep 3; done
python rabbit.py
可能您还需要在 Dockerfile
中安装 netcat。我不知道 python 图像上预装了什么。
有一些工具可以提供易于使用的等待逻辑,用于简单的 tcp 端口检查:
对于更复杂的等待:
有一个名为“docker-wait”的即用型实用程序,可用于等待。
使用restart: unless-stopped
或restart: always
可能会解决这个问题。
如果 worker container
在 rabbitMQ 未就绪时停止,它将重新启动直到准备好。
您也可以将它添加到命令选项中,例如
command: bash -c "sleep 5; start.sh"
https://github.com/docker/compose/issues/374#issuecomment-156546513
要在端口上等待,你也可以使用类似这样的东西
command: bash -c "while ! curl -s rabbitmq:5672 > /dev/null; do echo waiting for xxx; sleep 3; done; start.sh"
要增加等待时间,您可以再修改一下:
command: bash -c "for i in {1..100} ; do if ! curl -s rabbitmq:5672 > /dev/null ; then echo waiting on rabbitmq for $i seconds; sleep $i; fi; done; start.sh"
最近他们添加了 depends_on
feature。
编辑:
从 compose 版本 2.1+ 到版本 3,您可以将 depends_on
与 healthcheck
结合使用来实现此目的:
version: '2.1'
services:
web:
build: .
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
redis:
image: redis
db:
image: redis
healthcheck:
test: "exit 0"
2.1版本之前
您仍然可以使用 depends_on
,但它只会影响服务启动的 顺序 - 如果它们在相关服务启动之前就绪,则不会。
好像至少需要1.6.0版本。
用法看起来像这样:
version: '2'
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
来自文档:
Express dependency between services, which has two effects:
- docker-compose up will start services in dependency order. In the following example, db and redis will be started before web.
- docker-compose up SERVICE will automatically include SERVICE’s dependencies. In the following example, docker-compose up web will also create and start db and redis.
注意:据我了解,虽然这确实设置了容器加载的顺序。不保证容器里面的服务真的加载了。
例如,您的 postgres container 可能已启动。但是 postgres 服务本身可能仍在容器内初始化。
您还可以通过设置端点来解决此问题,该端点使用 netcat(使用 docker-wait 脚本)等待服务启动。我喜欢这种方法,因为您的 docker-compose.yml
中仍然有一个干净的 command
部分,您不需要向您的应用程序添加 docker 特定代码:
version: '2'
services:
db:
image: postgres
django:
build: .
command: python manage.py runserver 0.0.0.0:8000
entrypoint: ./docker-entrypoint.sh db 5432
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
那么你的docker-entrypoint.sh
:
#!/bin/sh
postgres_host=
postgres_port=
shift 2
cmd="$@"
# wait for the postgres docker to be running
while ! nc $postgres_host $postgres_port; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
>&2 echo "Postgres is up - executing command"
# run the command
exec $cmd
这在官方 docker documentation 中已有记录。
PS:如果不可用,您应该在 docker 实例中安装 netcat
。为此,请将此添加到您的 Docker
文件中:
RUN apt-get update && apt-get install netcat-openbsd -y
容器开始订购使用
depends_on:
等待上一个容器启动使用脚本
entrypoint: ./wait-for-it.sh db:5432
终于用docker-compose的方法找到了解决办法。由于 docker-compose 文件格式 2.1 您可以定义 healthchecks.
我在 example project
您至少需要安装 docker 1.12.0+。
我还需要 extend the rabbitmq-management Dockerfile,因为官方镜像上没有安装 curl。
现在测试rabbitmq-container的管理页面是否可用。如果 curl 以退出代码 0 结束,容器应用程序 (python pika) 将启动并向 hello 队列发布消息。它现在工作(输出)。
docker-compose(2.1 版):
version: '2.1'
services:
app:
build: app/.
depends_on:
rabbit:
condition: service_healthy
links:
- rabbit
rabbit:
build: rabbitmq/.
ports:
- "15672:15672"
- "5672:5672"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:15672"]
interval: 30s
timeout: 10s
retries: 5
输出:
rabbit_1 | =INFO REPORT==== 25-Jan-2017::14:44:21 ===
rabbit_1 | closing AMQP connection <0.718.0> (172.18.0.3:36590 -> 172.18.0.2:5672)
app_1 | [x] Sent 'Hello World!'
healthcheckcompose_app_1 exited with code 0
Dockerfile(rabbitmq + curl):
FROM rabbitmq:3-management
RUN apt-get update
RUN apt-get install -y curl
EXPOSE 4369 5671 5672 25672 15671 15672
版本3不再支持depends_on.的条件形式
所以我从 depends_on 移动到重新启动 on-failure。现在我的应用程序容器将重新启动 2-3 次,直到它正常工作,但它仍然是一个 docker-compose 功能,不会覆盖入口点。
docker-compose(版本 3):
version: "3"
services:
rabbitmq: # login guest:guest
image: rabbitmq:management
ports:
- "4369:4369"
- "5671:5671"
- "5672:5672"
- "25672:25672"
- "15671:15671"
- "15672:15672"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:15672"]
interval: 30s
timeout: 10s
retries: 5
app:
build: ./app/
environment:
- HOSTNAMERABBIT=rabbitmq
restart: on-failure
depends_on:
- rabbitmq
links:
- rabbitmq
基于此博客posthttps://8thlight.com/blog/dariusz-pasciak/2016/10/17/docker-compose-wait-for-dependencies.html
我的 docker-compose.yml
配置如下所示:
version: "3.1"
services:
rabbitmq:
image: rabbitmq:3.7.2-management-alpine
restart: always
environment:
RABBITMQ_HIPE_COMPILE: 1
RABBITMQ_MANAGEMENT: 1
RABBITMQ_VM_MEMORY_HIGH_WATERMARK: 0.2
RABBITMQ_DEFAULT_USER: "rabbitmq"
RABBITMQ_DEFAULT_PASS: "rabbitmq"
ports:
- "15672:15672"
- "5672:5672"
volumes:
- data:/var/lib/rabbitmq:rw
start_dependencies:
image: alpine:latest
links:
- rabbitmq
command: >
/bin/sh -c "
echo Waiting for rabbitmq service start...;
while ! nc -z rabbitmq 5672;
do
sleep 1;
done;
echo Connected!;
"
volumes:
data: {}
然后我为 运行 做 =>:
docker-compose up start_dependencies
rabbitmq
服务将以守护进程模式启动,start_dependencies
将完成工作。
restart: on-failure
对我有用……见下文
---
version: '2.1'
services:
consumer:
image: golang:alpine
volumes:
- ./:/go/src/srv-consumer
working_dir: /go/src/srv-consumer
environment:
AMQP_DSN: "amqp://guest:guest@rabbitmq:5672"
command: go run cmd/main.go
links:
- rabbitmq
restart: on-failure
rabbitmq:
image: rabbitmq:3.7-management-alpine
ports:
- "15672:15672"
- "5672:5672"
替代解决方案之一是使用像 Kubernetes 这样的容器编排解决方案。 Kubernetes 支持初始化容器 运行 在其他容器启动之前完成。您可以在此处找到 SQL Server 2017 Linux 容器的示例,其中 API 容器使用 init 容器来初始化数据库
https://www.handsonarchitect.com/2018/08/understand-kubernetes-object-init.html
这是 main
容器在开始响应 ping 时等待 worker
的示例:
version: '3'
services:
main:
image: bash
depends_on:
- worker
command: bash -c "sleep 2 && until ping -qc1 worker; do sleep 1; done &>/dev/null"
networks:
intra:
ipv4_address: 172.10.0.254
worker:
image: bash
hostname: test01
command: bash -c "ip route && sleep 10"
networks:
intra:
ipv4_address: 172.10.0.11
networks:
intra:
driver: bridge
ipam:
config:
- subnet: 172.10.0.0/24
然而,正确的方法是使用healthcheck
(>=2.1).
尝试了很多不同的方式,但喜欢这种简单的方式:https://github.com/ufoscout/docker-compose-wait
您可以在 docker 撰写文件中使用 ENV 变量来提交服务主机列表(带有端口)的想法,该列表应该是 "awaited",如下所示:WAIT_HOSTS: postgres:5432, mysql:3306, mongo:27017
。
假设您有以下 docker-compose.yml 文件(copy/past 来自 repo README):
version: "3"
services:
mongo:
image: mongo:3.4
hostname: mongo
ports:
- "27017:27017"
postgres:
image: "postgres:9.4"
hostname: postgres
ports:
- "5432:5432"
mysql:
image: "mysql:5.7"
hostname: mysql
ports:
- "3306:3306"
mySuperApp:
image: "mySuperApp:latest"
hostname: mySuperApp
environment:
WAIT_HOSTS: postgres:5432, mysql:3306, mongo:27017
接下来,为了让服务等待,您需要将以下两行添加到您的 Dockerfiles(到应该等待其他服务启动的服务的 Dockerfile 中):
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.5.0/wait /wait
RUN chmod +x /wait
此类示例 Dockerfile 的完整示例(再次来自项目 repo README):
FROM alpine
## Add your application to the docker image
ADD MySuperApp.sh /MySuperApp.sh
## Add the wait script to the image
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.5.0/wait /wait
RUN chmod +x /wait
## Launch the wait tool and then your application
CMD /wait && /MySuperApp.sh
有关可能用法的其他详细信息,请参阅 README
不推荐用于严肃的部署,但这里本质上是一个 "wait x seconds" 命令。
与docker-compose
版本3.4
一个start_period
instruction has been added to healthcheck
。这意味着我们可以执行以下操作:
docker-compose.yml
:
version: "3.4"
services:
# your server docker container
zmq_server:
build:
context: ./server_router_router
dockerfile: Dockerfile
# container that has to wait
zmq_client:
build:
context: ./client_dealer/
dockerfile: Dockerfile
depends_on:
- zmq_server
healthcheck:
test: "sh status.sh"
start_period: 5s
status.sh
:
#!/bin/sh
exit 0
这里发生的是 healthcheck
在 5 秒后被调用。这会调用 status.sh
脚本,它总是 returns "No problem"。
我们刚刚让 zmq_client
容器在启动前等待 5 秒!
注意:version: "3.4"
很重要。如果 .4
不存在,docker-compose 会抱怨。
在 Docker Compose 文件的版本 3 中,您可以使用 RESTART。
例如:
docker-compose.yml
worker:
build: myapp/.
volumes:
- myapp/.:/usr/src/app:ro
restart: on-failure
depends_on:
- rabbitmq
rabbitmq:
image: rabbitmq:3-management
请注意,我使用了 depends_on instead of links,因为后者在版本 3 中已弃用。
即使它有效,它也可能不是理想的解决方案,因为您在每次失败时重新启动 docker 容器。
也看看 RESTART_POLICY。它可以让您微调重启策略。
当您 use Compose in production 时,实际上最佳做法是使用重启策略:
Specifying a restart policy like restart: always to avoid downtime
我只有 2 个撰写文件,先开始一个,然后再开始第二个。我的脚本看起来像这样:
#!/bin/bash
#before i build my docker files
#when done i start my build docker-compose
docker-compose -f docker-compose.build.yaml up
#now i start other docker-compose which needs the image of the first
docker-compose -f docker-compose.prod.yml up
我目前还有这样的要求,即等待某些服务启动并 运行在其他服务启动之前等待。另请阅读此处和其他一些地方的建议。但是他们中的大多数都要求 docker-compose.yml
一些方法必须稍微改变一下。
所以我开始研究一个解决方案,我认为它是围绕 docker-compose 本身的编排层,我最终想出了一个 shell 脚本,我称之为 docker-compose-profile
。
它可以等待到某个容器的 tcp 连接,即使该服务没有向主机目录公开任何端口。我使用的技巧是在堆栈中启动另一个 docker 容器,然后我可以(通常)从那里连接到每个服务(只要没有应用其他网络配置)。
还有等待方法来监视某个日志消息。
服务可以组合在一起,在一个步骤中启动,然后另一个步骤将被触发启动。
您还可以排除一些服务而不列出所有其他服务以启动(例如可用服务的集合减去一些排除的服务)。
这种配置可以捆绑到配置文件中。
有一个名为 dcp.yml
的 yaml 配置文件(目前)必须放在 docker-compose.yml 文件旁边。
对于你的问题,这看起来像:
command:
aliases:
upd:
command: "up -d"
description: |
Create and start container. Detach afterword.
profiles:
default:
description: |
Wait for rabbitmq before starting worker.
command: upd
steps:
- label: only-rabbitmq
only: [ rabbitmq ]
wait:
- 5@tcp://rabbitmq:5432
- label: all-others
您现在可以通过调用
来开始您的堆栈
dcp -p default upd
甚至只是
dcp
因为只有 运行 up -d
的默认配置文件。
有一个小问题。我当前的版本(还)不支持像 ony 这样的特殊等待条件
你实际上需要。所以没有测试给rabbit发消息
我已经在考虑进一步等待 运行 主机上的某个命令或作为 docker 容器的方法。
我们可以通过
之类的方式扩展该工具
...
wait:
- service: rabbitmq
method: container
timeout: 5
image: python-test-rabbit
...
有一张名为 python-test-rabbit
的 docker 图片可以进行检查。
这样做的好处是,不再需要将等待的部分带给您的工人。
它将 隔离 并留在编排层内。
可能有人觉得这对使用有帮助。非常欢迎任何建议。
找到此工具
如果您只想启动服务,则另一个服务已成功完成(例如迁移、数据填充等),docker-compose
版本 1.29,附带 build in functionality for this - service_completed_successfully
。
depends_on:
<service-name>:
condition: service_completed_successfully
service_completed_successfully
- specifies that a dependency is expected to run to successful completion before starting a dependent service
我正在使用 rabbitmq 和来自 here 的简单 python 示例 连同 docker-compose。我的问题是我需要等待 rabbitmq 完全启动。从我到目前为止的搜索来看,我不知道如何等待容器 x(在我的案例中是 worker)直到 y (rabbitmq) 启动。
我发现这个 blog post 他在其中检查其他主机是否在线。 我还发现了这个 docker command:
wait
Usage: docker wait CONTAINER [CONTAINER...]
Block until a container stops, then print its exit code.
等待容器停止可能不是我想要的,但如果 是的,是否可以在 docker-compose.yml 中使用该命令? 到目前为止,我的解决方案是等待几秒钟并检查端口,但这是实现此目的的方法吗?如果我不等待,我会得到一个错误。
docker-compose.yml
worker:
build: myapp/.
volumes:
- myapp/.:/usr/src/app:ro
links:
- rabbitmq
rabbitmq:
image: rabbitmq:3-management
python 你好示例 (rabbit.py):
import pika
import time
import socket
pingcounter = 0
isreachable = False
while isreachable is False and pingcounter < 5:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect(('rabbitmq', 5672))
isreachable = True
except socket.error as e:
time.sleep(2)
pingcounter += 1
s.close()
if isreachable:
connection = pika.BlockingConnection(pika.ConnectionParameters(
host="rabbitmq"))
channel = connection.channel()
channel.queue_declare(queue='hello')
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print (" [x] Sent 'Hello World!'")
connection.close()
工人的 Dockerfile:
FROM python:2-onbuild
RUN ["pip", "install", "pika"]
CMD ["python","rabbit.py"]
2015 年 11 月更新:
shell 脚本或在您的程序中等待可能是一个可能的解决方案。但是在看到这个 Issue 之后,我正在寻找 docker/docker-compose 本身的命令或功能。
他们提到了实施健康检查的解决方案,这可能是最好的选择。打开的 TCP 连接并不意味着您的服务已准备就绪或可能保持就绪状态。除此之外,我还需要更改 docker 文件中的入口点。
所以我希望通过 docker-compose on board 命令得到一个答案,如果他们完成这个问题,希望情况会如此。
2016 年 3 月更新
有一个 proposal 用于提供确定容器是否“活动”的内置方法。所以 docker-compose 可能会在不久的将来使用它。
2016 年 6 月更新
在1.12.0
版本中,healthcheck似乎会integrated变成docker2017 年 1 月更新
我找到了一个 docker-compose 解决方案,请参阅:
这在本地是不可能的。另见 feature request.
到目前为止,您需要在容器中执行此操作 CMD
以等待所有必需的服务都到位。
在 Dockerfile
s CMD
中,您可以参考自己的启动脚本,该脚本包装了启动容器服务的过程。在你开始之前,你等待一个依赖的人,比如:
Dockerfile
FROM python:2-onbuild
RUN ["pip", "install", "pika"]
ADD start.sh /start.sh
CMD ["/start.sh"]
start.sh
#!/bin/bash
while ! nc -z rabbitmq 5672; do sleep 3; done
python rabbit.py
可能您还需要在 Dockerfile
中安装 netcat。我不知道 python 图像上预装了什么。
有一些工具可以提供易于使用的等待逻辑,用于简单的 tcp 端口检查:
对于更复杂的等待:
有一个名为“docker-wait”的即用型实用程序,可用于等待。
使用restart: unless-stopped
或restart: always
可能会解决这个问题。
如果 worker container
在 rabbitMQ 未就绪时停止,它将重新启动直到准备好。
您也可以将它添加到命令选项中,例如
command: bash -c "sleep 5; start.sh"
https://github.com/docker/compose/issues/374#issuecomment-156546513
要在端口上等待,你也可以使用类似这样的东西
command: bash -c "while ! curl -s rabbitmq:5672 > /dev/null; do echo waiting for xxx; sleep 3; done; start.sh"
要增加等待时间,您可以再修改一下:
command: bash -c "for i in {1..100} ; do if ! curl -s rabbitmq:5672 > /dev/null ; then echo waiting on rabbitmq for $i seconds; sleep $i; fi; done; start.sh"
最近他们添加了 depends_on
feature。
编辑:
从 compose 版本 2.1+ 到版本 3,您可以将 depends_on
与 healthcheck
结合使用来实现此目的:
version: '2.1'
services:
web:
build: .
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
redis:
image: redis
db:
image: redis
healthcheck:
test: "exit 0"
2.1版本之前
您仍然可以使用 depends_on
,但它只会影响服务启动的 顺序 - 如果它们在相关服务启动之前就绪,则不会。
好像至少需要1.6.0版本。
用法看起来像这样:
version: '2'
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
来自文档:
Express dependency between services, which has two effects:
- docker-compose up will start services in dependency order. In the following example, db and redis will be started before web.
- docker-compose up SERVICE will automatically include SERVICE’s dependencies. In the following example, docker-compose up web will also create and start db and redis.
注意:据我了解,虽然这确实设置了容器加载的顺序。不保证容器里面的服务真的加载了。
例如,您的 postgres container 可能已启动。但是 postgres 服务本身可能仍在容器内初始化。
您还可以通过设置端点来解决此问题,该端点使用 netcat(使用 docker-wait 脚本)等待服务启动。我喜欢这种方法,因为您的 docker-compose.yml
中仍然有一个干净的 command
部分,您不需要向您的应用程序添加 docker 特定代码:
version: '2'
services:
db:
image: postgres
django:
build: .
command: python manage.py runserver 0.0.0.0:8000
entrypoint: ./docker-entrypoint.sh db 5432
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
那么你的docker-entrypoint.sh
:
#!/bin/sh
postgres_host=
postgres_port=
shift 2
cmd="$@"
# wait for the postgres docker to be running
while ! nc $postgres_host $postgres_port; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
>&2 echo "Postgres is up - executing command"
# run the command
exec $cmd
这在官方 docker documentation 中已有记录。
PS:如果不可用,您应该在 docker 实例中安装 netcat
。为此,请将此添加到您的 Docker
文件中:
RUN apt-get update && apt-get install netcat-openbsd -y
容器开始订购使用
depends_on:
等待上一个容器启动使用脚本
entrypoint: ./wait-for-it.sh db:5432
终于用docker-compose的方法找到了解决办法。由于 docker-compose 文件格式 2.1 您可以定义 healthchecks.
我在 example project 您至少需要安装 docker 1.12.0+。 我还需要 extend the rabbitmq-management Dockerfile,因为官方镜像上没有安装 curl。
现在测试rabbitmq-container的管理页面是否可用。如果 curl 以退出代码 0 结束,容器应用程序 (python pika) 将启动并向 hello 队列发布消息。它现在工作(输出)。
docker-compose(2.1 版):
version: '2.1'
services:
app:
build: app/.
depends_on:
rabbit:
condition: service_healthy
links:
- rabbit
rabbit:
build: rabbitmq/.
ports:
- "15672:15672"
- "5672:5672"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:15672"]
interval: 30s
timeout: 10s
retries: 5
输出:
rabbit_1 | =INFO REPORT==== 25-Jan-2017::14:44:21 ===
rabbit_1 | closing AMQP connection <0.718.0> (172.18.0.3:36590 -> 172.18.0.2:5672)
app_1 | [x] Sent 'Hello World!'
healthcheckcompose_app_1 exited with code 0
Dockerfile(rabbitmq + curl):
FROM rabbitmq:3-management
RUN apt-get update
RUN apt-get install -y curl
EXPOSE 4369 5671 5672 25672 15671 15672
版本3不再支持depends_on.的条件形式 所以我从 depends_on 移动到重新启动 on-failure。现在我的应用程序容器将重新启动 2-3 次,直到它正常工作,但它仍然是一个 docker-compose 功能,不会覆盖入口点。
docker-compose(版本 3):
version: "3"
services:
rabbitmq: # login guest:guest
image: rabbitmq:management
ports:
- "4369:4369"
- "5671:5671"
- "5672:5672"
- "25672:25672"
- "15671:15671"
- "15672:15672"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:15672"]
interval: 30s
timeout: 10s
retries: 5
app:
build: ./app/
environment:
- HOSTNAMERABBIT=rabbitmq
restart: on-failure
depends_on:
- rabbitmq
links:
- rabbitmq
基于此博客posthttps://8thlight.com/blog/dariusz-pasciak/2016/10/17/docker-compose-wait-for-dependencies.html
我的 docker-compose.yml
配置如下所示:
version: "3.1"
services:
rabbitmq:
image: rabbitmq:3.7.2-management-alpine
restart: always
environment:
RABBITMQ_HIPE_COMPILE: 1
RABBITMQ_MANAGEMENT: 1
RABBITMQ_VM_MEMORY_HIGH_WATERMARK: 0.2
RABBITMQ_DEFAULT_USER: "rabbitmq"
RABBITMQ_DEFAULT_PASS: "rabbitmq"
ports:
- "15672:15672"
- "5672:5672"
volumes:
- data:/var/lib/rabbitmq:rw
start_dependencies:
image: alpine:latest
links:
- rabbitmq
command: >
/bin/sh -c "
echo Waiting for rabbitmq service start...;
while ! nc -z rabbitmq 5672;
do
sleep 1;
done;
echo Connected!;
"
volumes:
data: {}
然后我为 运行 做 =>:
docker-compose up start_dependencies
rabbitmq
服务将以守护进程模式启动,start_dependencies
将完成工作。
restart: on-failure
对我有用……见下文
---
version: '2.1'
services:
consumer:
image: golang:alpine
volumes:
- ./:/go/src/srv-consumer
working_dir: /go/src/srv-consumer
environment:
AMQP_DSN: "amqp://guest:guest@rabbitmq:5672"
command: go run cmd/main.go
links:
- rabbitmq
restart: on-failure
rabbitmq:
image: rabbitmq:3.7-management-alpine
ports:
- "15672:15672"
- "5672:5672"
替代解决方案之一是使用像 Kubernetes 这样的容器编排解决方案。 Kubernetes 支持初始化容器 运行 在其他容器启动之前完成。您可以在此处找到 SQL Server 2017 Linux 容器的示例,其中 API 容器使用 init 容器来初始化数据库
https://www.handsonarchitect.com/2018/08/understand-kubernetes-object-init.html
这是 main
容器在开始响应 ping 时等待 worker
的示例:
version: '3'
services:
main:
image: bash
depends_on:
- worker
command: bash -c "sleep 2 && until ping -qc1 worker; do sleep 1; done &>/dev/null"
networks:
intra:
ipv4_address: 172.10.0.254
worker:
image: bash
hostname: test01
command: bash -c "ip route && sleep 10"
networks:
intra:
ipv4_address: 172.10.0.11
networks:
intra:
driver: bridge
ipam:
config:
- subnet: 172.10.0.0/24
然而,正确的方法是使用healthcheck
(>=2.1).
尝试了很多不同的方式,但喜欢这种简单的方式:https://github.com/ufoscout/docker-compose-wait
您可以在 docker 撰写文件中使用 ENV 变量来提交服务主机列表(带有端口)的想法,该列表应该是 "awaited",如下所示:WAIT_HOSTS: postgres:5432, mysql:3306, mongo:27017
。
假设您有以下 docker-compose.yml 文件(copy/past 来自 repo README):
version: "3"
services:
mongo:
image: mongo:3.4
hostname: mongo
ports:
- "27017:27017"
postgres:
image: "postgres:9.4"
hostname: postgres
ports:
- "5432:5432"
mysql:
image: "mysql:5.7"
hostname: mysql
ports:
- "3306:3306"
mySuperApp:
image: "mySuperApp:latest"
hostname: mySuperApp
environment:
WAIT_HOSTS: postgres:5432, mysql:3306, mongo:27017
接下来,为了让服务等待,您需要将以下两行添加到您的 Dockerfiles(到应该等待其他服务启动的服务的 Dockerfile 中):
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.5.0/wait /wait
RUN chmod +x /wait
此类示例 Dockerfile 的完整示例(再次来自项目 repo README):
FROM alpine
## Add your application to the docker image
ADD MySuperApp.sh /MySuperApp.sh
## Add the wait script to the image
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.5.0/wait /wait
RUN chmod +x /wait
## Launch the wait tool and then your application
CMD /wait && /MySuperApp.sh
有关可能用法的其他详细信息,请参阅 README
不推荐用于严肃的部署,但这里本质上是一个 "wait x seconds" 命令。
与docker-compose
版本3.4
一个start_period
instruction has been added to healthcheck
。这意味着我们可以执行以下操作:
docker-compose.yml
:
version: "3.4"
services:
# your server docker container
zmq_server:
build:
context: ./server_router_router
dockerfile: Dockerfile
# container that has to wait
zmq_client:
build:
context: ./client_dealer/
dockerfile: Dockerfile
depends_on:
- zmq_server
healthcheck:
test: "sh status.sh"
start_period: 5s
status.sh
:
#!/bin/sh
exit 0
这里发生的是 healthcheck
在 5 秒后被调用。这会调用 status.sh
脚本,它总是 returns "No problem"。
我们刚刚让 zmq_client
容器在启动前等待 5 秒!
注意:version: "3.4"
很重要。如果 .4
不存在,docker-compose 会抱怨。
在 Docker Compose 文件的版本 3 中,您可以使用 RESTART。
例如:
docker-compose.yml
worker:
build: myapp/.
volumes:
- myapp/.:/usr/src/app:ro
restart: on-failure
depends_on:
- rabbitmq
rabbitmq:
image: rabbitmq:3-management
请注意,我使用了 depends_on instead of links,因为后者在版本 3 中已弃用。
即使它有效,它也可能不是理想的解决方案,因为您在每次失败时重新启动 docker 容器。
也看看 RESTART_POLICY。它可以让您微调重启策略。
当您 use Compose in production 时,实际上最佳做法是使用重启策略:
Specifying a restart policy like restart: always to avoid downtime
我只有 2 个撰写文件,先开始一个,然后再开始第二个。我的脚本看起来像这样:
#!/bin/bash
#before i build my docker files
#when done i start my build docker-compose
docker-compose -f docker-compose.build.yaml up
#now i start other docker-compose which needs the image of the first
docker-compose -f docker-compose.prod.yml up
我目前还有这样的要求,即等待某些服务启动并 运行在其他服务启动之前等待。另请阅读此处和其他一些地方的建议。但是他们中的大多数都要求 docker-compose.yml
一些方法必须稍微改变一下。
所以我开始研究一个解决方案,我认为它是围绕 docker-compose 本身的编排层,我最终想出了一个 shell 脚本,我称之为 docker-compose-profile
。
它可以等待到某个容器的 tcp 连接,即使该服务没有向主机目录公开任何端口。我使用的技巧是在堆栈中启动另一个 docker 容器,然后我可以(通常)从那里连接到每个服务(只要没有应用其他网络配置)。
还有等待方法来监视某个日志消息。
服务可以组合在一起,在一个步骤中启动,然后另一个步骤将被触发启动。
您还可以排除一些服务而不列出所有其他服务以启动(例如可用服务的集合减去一些排除的服务)。
这种配置可以捆绑到配置文件中。
有一个名为 dcp.yml
的 yaml 配置文件(目前)必须放在 docker-compose.yml 文件旁边。
对于你的问题,这看起来像:
command:
aliases:
upd:
command: "up -d"
description: |
Create and start container. Detach afterword.
profiles:
default:
description: |
Wait for rabbitmq before starting worker.
command: upd
steps:
- label: only-rabbitmq
only: [ rabbitmq ]
wait:
- 5@tcp://rabbitmq:5432
- label: all-others
您现在可以通过调用
来开始您的堆栈dcp -p default upd
甚至只是
dcp
因为只有 运行 up -d
的默认配置文件。
有一个小问题。我当前的版本(还)不支持像 ony 这样的特殊等待条件 你实际上需要。所以没有测试给rabbit发消息
我已经在考虑进一步等待 运行 主机上的某个命令或作为 docker 容器的方法。 我们可以通过
之类的方式扩展该工具...
wait:
- service: rabbitmq
method: container
timeout: 5
image: python-test-rabbit
...
有一张名为 python-test-rabbit
的 docker 图片可以进行检查。
这样做的好处是,不再需要将等待的部分带给您的工人。 它将 隔离 并留在编排层内。
可能有人觉得这对使用有帮助。非常欢迎任何建议。
找到此工具如果您只想启动服务,则另一个服务已成功完成(例如迁移、数据填充等),docker-compose
版本 1.29,附带 build in functionality for this - service_completed_successfully
。
depends_on:
<service-name>:
condition: service_completed_successfully
service_completed_successfully
- specifies that a dependency is expected to run to successful completion before starting a dependent service