[英]docker keep restarting until file is created in a mounted volume
I am trying to create a script that would restart itself, a micro service (in my case its node-red
).我正在尝试创建一个可以自行重启的脚本,一个微服务(在我的例子中是
node-red
)。
Here is my docker compose file:这是我的码头工人撰写文件:
docker-compose.yml
version: '2.1'
services:
wifi-connect:
build: ./wifi-connect
restart: always
network_mode: host
privileged: true
google-iot:
build: ./google-iot
volumes:
- 'app-data:/data'
restart: always
network_mode: host
depends_on:
- "wifi-connect"
ports:
- "8883:8883"
node-red:
build: ./node-red/node-red
volumes:
- 'app-data:/data'
restart: always
privileged: true
network_mode: host
depends_on:
- "google-iot"
volumes:
app-data:
I am using wait-for-it.sh in order to check if the previous container.我正在使用wait-for-it.sh来检查之前的容器。
Here is an extract from the Dockerfile of the node-red microservice.这是 node-red 微服务的 Dockerfile 的摘录。
RUN chmod +x ./wait-for-it/wait-for-it.sh
# server.js will run when container starts up on the device
CMD ["bash", "/usr/src/app/start.sh", "bash", "/usr/src/app/wait-for-it/wait-for-it.sh google-iot:8883 -- echo Google IoT Service is up and running"]
I have seen the inotify
.我见过
inotify
。
Basically all I want is to restart the container node-red
after a file has been created within the app-data
volume which is mounted to the node-red
container as well under /data
folder path, the file path for eg would be: /data/myfile.txt
.基本上,我想要的只是在安装到
node-red
容器以及/data
文件夹路径下的app-data
卷中创建文件后重新启动容器node-red
,例如,文件路径为: /data/myfile.txt
。
Please note that this file gets generated automatically to the google-iot
micro service but node-red
container needs that file and pretty often is the case that the node-red
container starts and /data/myfile.txt
file is not present.请注意,此文件会自动生成到
google-iot
微服务,但node-red
容器需要该文件,并且通常是node-red
容器启动且/data/myfile.txt
文件不存在的情况。
It sounds like you're trying to delay one container's startup until another has produced the file you're looking for, or exit if it's not available.听起来您正在尝试延迟一个容器的启动,直到另一个容器生成了您要查找的文件,或者如果它不可用则退出。
You can write that logic into a shell script fairly straightforwardly.您可以相当直接地将该逻辑写入 shell 脚本。 For example:
例如:
#!/bin/sh
# entrypoint.sh
# Wait for the server to be available
./wait-for-it/wait-for-it.sh google-iot:8883
if [ $? -ne 0 ]; then
echo 'google-iot container did not become available' >&2
exit 1
fi
# Wait for the file to be present
seconds=30
while [ $seconds -gt 0 ]; do
if [ -f /data/myfile.txt ]; then
break
fi
sleep 1
seconds=$(($seconds-1))
done
if [ $seconds -eq 0 ]; then
echo '/data/myfile.txt was not created' >&2
exit 1
fi
# Run the command passed to us as arguments
exec "$@"
In your Dockerfile, make this script be the ENTRYPOINT
.在您的 Dockerfile 中,将此脚本设为
ENTRYPOINT
。 You must use JSON-array syntax in the ENTRYPOINT
line.您必须在
ENTRYPOINT
行中使用 JSON 数组语法。 Your CMD
can use any valid syntax.您的
CMD
可以使用任何有效的语法。 Note that we're running the wait-for-it
script in the entrypoint wrapper, so you don't need to include that in the CMD
.请注意,我们在入口点包装器中运行
wait-for-it
脚本,因此您无需将其包含在CMD
中。 (And since the script is executable and begins with a "shebang" line #!/bin/sh
, we do not need to explicitly name an interpreter to run it.) (而且由于脚本是可执行的并且以“shebang”行
#!/bin/sh
开头,我们不需要显式地命名解释器来运行它。)
# Dockerfile
RUN chmod +x entrypoint.sh wait-for-it/wait-for-it.sh
ENTRYPOINT ["/usr/src/app/entrypoint.sh"]
CMD ["/usr/src/app/start.sh"]
The entrypoint wrapper has two checks, first that the google-iot
container eventually accepts TCP connections on port 8883 and a second that the file is created.入口点包装器有两个检查,首先是
google-iot
容器最终接受端口 8883 上的 TCP 连接,其次是创建文件。 If either of these cases fails the script exit 1
before it runs the CMD
.如果其中任何一种情况失败,则脚本在运行
CMD
之前exit 1
。 This will cause the container as a whole to exit with that status code (a restart: on-failure
will still restart it).这将导致整个容器以该状态码退出(
restart: on-failure
仍将重新启动它)。
I also might consider whether some other approach to get the file might work, like using curl
to make an HTTP request to the other container.我也可能会考虑其他获取文件的方法是否可行,例如使用
curl
向另一个容器发出 HTTP 请求。 There are several practical issues with sharing Docker volumes (particularly around ownership, but also if an old copy of the file is still around from a previous run) and sharing files works especially badly in a clustered environment like Kubernetes.共享 Docker 卷存在几个实际问题(特别是在所有权方面,但如果文件的旧副本仍然存在于之前的运行中),并且在 Kubernetes 等集群环境中共享文件的效果尤其糟糕。
You can fix the issue with the race condition by using the long-syntax
of depends_on
where you can specify a health check.您可以使用
depends_on
的long-syntax
来解决竞争条件问题,您可以在其中指定运行状况检查。 This will guarantee that your file is present when your node-red
service runs.这将保证您的文件在您的
node-red
服务运行时存在。
node-red:
build: ./node-red/node-red
volumes:
- 'app-data:/data'
restart: always
privileged: true
network_mode: host
depends_on:
google-iot:
condition: service_healthy
Then you can define a health-check
(see docs here ) to see if your file is present in the volume.然后您可以定义
health-check
(请参阅此处的文档)以查看您的文件是否存在于卷中。 You can add the following to the service description for google-iot
service:您可以在
google-iot
服务的服务描述中添加以下内容:
healthcheck:
test: ["CMD", "cat", "/data/myfile.txt"]
interval: 1m30s
timeout: 10s
retries: 3
start_period: 40s
Feel free to tune the duration values as needed.根据需要随意调整持续时间值。
Does this fix your problem?这能解决您的问题吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.