简体   繁体   English

docker 不断重启,直到在挂载的卷中创建文件

[英]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_onlong-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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM