如何在Docker Compose中使一个容器等待另一个容器?

3
我正在按照这个教程尝试使用Docker Compose启动基础设施,而不是调用docker客户端的shell脚本。一切正常,除了gitlab容器在gitlab-postgreql和gitlab-redis之前启动,因此失败,因为它期望这些服务已经在运行。
我尝试使用depends_on属性,但它没有解决问题。据我所知,如果其他容器启动得更快,它也没有帮助。经过研究,我发现Docker Compose没有提供开箱即用的解决方案来控制容器创建顺序。
这怎么可能呢?我不能相信这样一个基本功能被未实现。似乎Docker在自己的聪明才智上绊倒了,并忘记了基础知识。那么,如何在没有一些疯狂的支持脚本(这将使整个配置比仅使用脚本/ docker客户端更混乱)的情况下控制容器创建顺序?
这是docker-compose.yml的内容:
version: '2'
services:

  gitlab-postgresql:
    image: sameersbn/postgresql:9.4-3
    volumes:
      - /srv/docker/gitlab/postgresql:/var/lib/postgresql
    environment:
      - DB_NAME=gitlabhq_production
      - DB_USER=gitlab
      - DB_PASS=password

  gitlab-redis:
    image: sameersbn/redis:latest
    volumes:
      - /srv/docker/gitlab/redis:/var/lib/redis
    depends_on:
      - "gitlab-postgresql"

  gitlab:
    image: sameersbn/gitlab:7.14.3
    volumes:
      - /srv/docker/gitlab/gitlab:/home/git/data
    ports:
      - "2222:22"
      - "8080:80"
    environment:
      - GITLAB_PORT=8080
      - GITLAB_SSH_PORT=2222
    depends_on:
      - gitlab-postgresql
      - gitlab-redis

  registry:
    image: registry:2
    volumes:
      - /srv/docker/registry/data:/var/lib/registry
    ports:
      - "5000:5000"
    depends_on:
      - "gitlab"

  jenkins:
    image: jenkins:1.609.3
    volumes:
      - /srv/docker/jenkins/home:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock
      - /usr/bin/docker:/bin/docker
      - /usr/lib/x86_64-linux-gnu/libapparmor.so.1.1.0:/lib/x86_64-linux-gnu/libapparmor.so.1
    ports:
      - "8081:8080"
      - "50000:50000"
    user: root
    depends_on:
      - "registry"
2个回答

9

gitlab容器在gitlab-postgresql和gitlab-redis之前启动,

您正在使用depends_on,它会等待docker容器状态不是“up”,但是容器内的每个服务或程序都可以是“未完成”的或处于类似“run”或“up”的状态。

请查看 Compose中控制启动顺序,我认为这正是您所需要的。

使用wait-for-it或dockerize等工具。这些都是可以包含在应用程序镜像中的小包装器脚本,并将轮询给定的主机和端口,直到它接受TCP连接。假设您的应用程序镜像在其Dockerfile中设置了CMD,则可以通过在docker-compose.yml中设置入口点来包装它:

因此,您将需要entrypoint,在postgres端口可用且postgres处于运行状态后等待。 在docker-compose中,您需要例如 entrypoint: ./wait-for-it.sh db:5432

并且在脚本中,您将每秒检查一次postgres是否正在运行- docker容器将被阻止,直到postgres不可用。

就像文档中所述:

until psql -h "$host" -U "postgres" -c '\l'; do
  >&2 echo "Postgres is unavailable - sleeping"
  sleep 1
done

这太荒谬了。嗯,最好等待Compose变得更加成熟,而不是浪费时间学习这些用于学习破损工具的技巧。无论如何,感谢您的回答,这是一个有趣的玩笑。 - Tuomas Toivonen
1
@TuomasToivonen 嗯,这个问题在分布式系统领域并不容易解决,正如他们建议的最好的方法是在应用层执行检查。但我同意它应该由Compose本身提供,但现在这个“解决方法”是docker文档的官方建议。无论如何,这个功能的PULL REQUEST - 374(自2014年以来开放)正在进行中。 - VladoDemcak
1
很好的答案,我不知道它是docker-compose文档的一部分。这个问题被问了很多次,只是变量不同而已。这个链接简化了回答这些问题的任务。 - Carlos Rafael Ramirez

2
您可以在使用Compose v2.1+时,与healthcheck一起使用depends_on(但不适用于3+,因为它删除了conditionhttps://github.com/peter-evans/docker-compose-healthcheck/issues/3)。 GitHub上的示例 例如,在数据库容器中:
healthcheck:
  test: ["CMD-SHELL", "pg_isready -U postgres"]
  interval: 30s
  timeout: 30s
  retries: 3

依赖于数据库的项目:

depends_on:
  kong-database:
    condition: service_healthy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接