You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker Compose中如何等待数据库就绪后再构建容器

问题:构建镜像前等待MariaDB容器完全就绪

执行docker-compose up -d my_service_dev时,需要等待mariadb_test容器完全就绪后,再开始构建my_service_dev镜像。现有docker-compose配置如下:

version: '3.8'

services:
  mariadb_test:
    image: mariadb/server:10.5
    ports:
      - 3306:3306
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_USER=root
      - MYSQL_ROOT_HOST=10.5.0.1
    healthcheck:
      test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
      interval: 1m30s
      timeout: 10s
      retries: 3
    networks:
      my_network:
        ipv4_address: 10.5.0.5

  my_service_dev:
    build:
      context: .
      dockerfile: Dockerfile_my_service
    depends_on:
      mariadb_test:
        condition: service_completed_successfully   
    environment:
      - DB_HOST=10.5.0.5
      - DB_USER=root
      - DB_PASSWORD=password
    tty: true
    networks:
      my_network:
        ipv4_address: 10.5.0.6

networks:
  my_network:
    driver: bridge
    ipam:
      config:
        - subnet: 10.5.0.0/16
          gateway: 10.5.0.1

对应的Dockerfile:

FROM debian:11.6

ENV DEBIAN_FRONTEND=noninteractive

ARG DB_HOST
ARG DB_USER
ARG DB_PASSWORD
ENV DB_HOST=${DB_HOST}
ENV DB_USER=${DB_USER}
ENV DB_PASSWORD=${DB_PASSWORD}

RUN apt-get update && apt-get install -y --no-install-recommends apt-utils
RUN apt-get install -y \
    libmariadb3 \
    wget

WORKDIR /usr/local/bin

RUN wget https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh
RUN chmod +x wait-for-it.sh

RUN ./wait-for-it.sh 10.5.0.5:3306 --timeout=40 -- echo "MariaDB is up"

RUN mariadb --host=${DB_HOST} --port=3306 --user=${DB_USER} --password=${DB_PASSWORD} -e "CREATE USER 'test_user'@'' IDENTIFIED BY '12345';"

尝试过以下三种方案均无效:

尝试过的无效方案

方案1

在my_service_dev中配置:

depends_on:
  mariadb_test:
    condition: service_completed_successfully

问题:service_completed_successfully要求目标容器运行后退出,但MariaDB是长期运行服务,永远不会满足该条件,导致my_service_dev无法启动。

方案2

添加wait-for-db组件:

wait-for-db:
    image: atkrad/wait4x
    depends_on:
      - mariadb_test
    command: tcp mariadb_test:3306 -t 30s -i 250ms

同时修改my_service_dev的depends_on:

depends_on:
  wait-for-db:
    condition: service_completed_successfully 

问题:Docker Compose在启动容器前会优先构建所有需要构建的镜像,wait-for-db容器还没启动,my_service_dev的镜像已经开始构建,无法达到等待效果。

方案3

在Dockerfile中执行wait-for-it.sh:

RUN ./wait-for-it.sh 10.5.0.5:3306 --timeout=40 -- echo "MariaDB is up"

问题:镜像构建阶段无法访问容器网络,此时mariadb_test容器尚未启动,导致等待超时。

可行解决方案

核心思路

Docker Compose的depends_on只能控制容器启动顺序,无法控制镜像构建顺序。镜像构建是独立于容器网络的离线过程,不应依赖外部运行中的服务。正确的做法是将数据库初始化逻辑移到容器启动阶段,同时分步骤控制容器启动与镜像构建的顺序。

步骤1:调整Dockerfile,将初始化逻辑移到容器启动阶段

修改后的Dockerfile:

FROM debian:11.6

ENV DEBIAN_FRONTEND=noninteractive

ARG DB_HOST
ARG DB_USER
ARG DB_PASSWORD
ENV DB_HOST=${DB_HOST}
ENV DB_USER=${DB_USER}
ENV DB_PASSWORD=${DB_PASSWORD}

RUN apt-get update && apt-get install -y --no-install-recommends apt-utils
RUN apt-get install -y \
    libmariadb3 \
    wget \
    mariadb-client  # 安装mariadb客户端工具

WORKDIR /usr/local/bin

RUN wget https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh
RUN chmod +x wait-for-it.sh

# 复制初始化脚本到容器
COPY init-db.sh /usr/local/bin/
RUN chmod +x init-db.sh

# 容器启动时执行初始化脚本
ENTRYPOINT ["/usr/local/bin/init-db.sh"]

创建init-db.sh脚本(与Dockerfile同目录):

#!/bin/bash

# 等待MariaDB服务就绪
./wait-for-it.sh ${DB_HOST}:3306 --timeout=40 -- echo "MariaDB is up"

# 执行数据库初始化(添加IF NOT EXISTS避免重复执行报错)
mariadb --host=${DB_HOST} --port=3306 --user=${DB_USER} --password=${DB_PASSWORD} -e "CREATE USER IF NOT EXISTS 'test_user'@'%' IDENTIFIED BY '12345';"

# 保持容器运行(根据实际业务调整,若有其他进程可替换)
exec tail -f /dev/null

步骤2:调整docker-compose.yml,依赖健康状态

修改mariadb_test的健康检查配置(缩短间隔,更快检测就绪),并调整my_service_dev的depends_on为依赖健康状态:

version: '3.8'

services:
  mariadb_test:
    image: mariadb/server:10.5
    ports:
      - 3306:3306
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_ROOT_HOST=10.5.0.1
    healthcheck:
      test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost", "-u", "root", "-ppassword" ]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      my_network:
        ipv4_address: 10.5.0.5

  my_service_dev:
    build:
      context: .
      dockerfile: Dockerfile_my_service
      args:
        - DB_HOST=10.5.0.5
        - DB_USER=root
        - DB_PASSWORD=password
    depends_on:
      mariadb_test:
        condition: service_healthy  # 等待MariaDB容器进入健康状态
    environment:
      - DB_HOST=10.5.0.5
      - DB_USER=root
      - DB_PASSWORD=password
    tty: true
    networks:
      my_network:
        ipv4_address: 10.5.0.6

networks:
  my_network:
    driver: bridge
    ipam:
      config:
        - subnet: 10.5.0.0/16
          gateway: 10.5.0.1

步骤3:分批次执行命令(可选,严格先启动数据库再构建)

如果必须先启动mariadb_test再构建my_service_dev镜像,可通过以下脚本自动化:

#!/bin/bash

# 启动MariaDB容器
docker-compose up -d mariadb_test

# 等待MariaDB进入健康状态(需Docker Compose 1.29+)
docker-compose wait mariadb_test

# 构建并启动my_service_dev
docker-compose up -d my_service_dev

执行该脚本即可实现先启动数据库并等待就绪,再构建镜像并启动容器的效果。


内容的提问来源于stack exchange,提问作者Mircea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 07:22:55