控制docker-compose中服务的启动顺序

官方文档:https://docs.docker.com/compose/startup-order/

可以通过depends_on来编排服务之间的依赖关系,但是有一个问题,比如一个web项目,依赖一个数据库或者依赖一个redis服务,那么要等到数据库完全准备好之后,才能让web服务开始启动并连接数据库,docker默认的依赖方式是只要依赖数据库服务容器启动就会启动web容器,而不 检查数据库是否已经准备好。

解决方法一个方面是在连接层面使用自动重连策略,比如mysql jdbc可以有auto reconnect自动重连参数。或者使用下面建议的用一个脚本(wait-for-it.sh)来探测依赖服务已经完全准备好,或者自己编写一个health check脚本来检测依赖服务的健康状况来判断依赖服务是否启动完成。

You can control the order of service startup with the depends_on option. Compose always starts containers in dependency order, where dependencies are determined by depends_onlinksvolumes_from, and network_mode: "service:...".

However, Compose will not wait until a container is “ready” (whatever that means for your particular application) - only until it’s running. There’s a good reason for this.

The problem of waiting for a database (for example) to be ready is really just a subset of a much larger problem of distributed systems. In production, your database could become unavailable or move hosts at any time. Your application needs to be resilient to these types of failures.

To handle this, your application should attempt to re-establish a connection to the database after a failure. If the application retries the connection, it should eventually be able to connect to the database.

The best solution is to perform this check in your application code, both at startup and whenever a connection is lost for any reason. However, if you don’t need this level of resilience, you can work around the problem with a wrapper script:

  • Use a tool such as wait-for-it, dockerize, or sh-compatible wait-for. These are small wrapper scripts which you can include in your application’s image and will poll a given host and port until it’s accepting TCP connections.

    For example, to use wait-for-it.sh or wait-for to wrap your service’s command:

    version: "2"
    services:
      web:
        build: .
        ports:
          - "80:8000"
        depends_on:
          - "db"
        command: ["./wait-for-it.sh", "db:5432", "--", "python", "app.py"]
      db:
        image: postgres
    

    Tip: There are limitations to this first solution; e.g., it doesn’t verify when a specific service is really ready. If you add more arguments to the command, you’ll need to use the bash shift command with a loop, as shown in the next example.

  • Alternatively, write your own wrapper script to perform a more application-specific health check. For example, you might want to wait until Postgres is definitely ready to accept commands:

    #!/bin/bash
    # wait-for-postgres.sh
    
    set -e
    
    host="$1"
    shift
    cmd="$@"
    
    until psql -h "$host" -U "postgres" -c '\q'; do
      >&2 echo "Postgres is unavailable - sleeping"
      sleep 1
    done
    
    >&2 echo "Postgres is up - executing command"
    exec $cmd
    

    You can use this as a wrapper script as in the previous example, by setting:

    command: ["./wait-for-postgres.sh", "db", "python", "app.py"]

注意如果你使用wait-for-it.sh脚本,如果你的基础镜像不包含bash命令(比如alpine镜像)需要安装bash,不然没法执行wait-for-it.sh脚本导致容器启动失败。

如果Dockerfile的基础镜像用的是alpine相关的基础镜像的话,记得添加如下指令安装bash:

RUN apk update
RUN apk upgrade
RUN apk add --no-cache bash


你可能感兴趣的:(docker)