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

使用Docker Compose本地运行Rust sqlx迁移的问题

问题

我正在学习《Zero to Prod in Rust》,但偏离了教程内容,尝试将包含数据库在内的整套本地环境进行Docker容器化。容器的ENTRYPOINT调用启动脚本执行sqlx migrate run时,出现错误:./scripts/init_db.sh: line 10: sqlx: command not found。

我推测这是因为使用bullseye-slim作为运行时镜像,该镜像未保留已安装的Rust相关包(这有助于优化构建时间和镜像体积)。

请问是否可以在不安装Rust、Cargo等工具的情况下运行sqlx迁移?或者有没有更好的实现方案?我希望避免在bullseye-slim镜像中重新安装所有依赖,以保留Docker的优化效果。

相关配置文件

Dockerfile

# .... chef segment omitted
FROM chef as builder
COPY --from=planner /app/recipe.json recipe.json
# Build our project dependencies, not our application!
RUN cargo chef cook --release --recipe-path recipe.json
# Up to this point, if our dependency tree stays the same,
# all layers should be cached.
COPY . .

ENV SQLX_OFFLINE true
# Build our project
RUN cargo build --release --bin my_app
FROM debian:bullseye-slim AS runtime
WORKDIR /app
RUN apt-get update -y \
&& apt-get install -y --no-install-recommends openssl ca-certificates \
&& apt-get install -y --no-install-recommends postgresql-client \
# Clean up
&& apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/my_app my_app
COPY configuration configuration
COPY scripts scripts
RUN chmod -R +x scripts
ENTRYPOINT ["./scripts/docker_startup.sh"]

docker-compose.yml

version: '3'
services:
  db:
    image: postgres:latest
    environment:
      - POSTGRES_DB=my_app
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
    ports:
      - "5432:5432"
    volumes:
      - dbdata:/var/lib/postgresql/data

  app:
    image: my_app
    environment:
      - DATABASE_URL=postgres://postgres:password@postgres:5432/my_app
    depends_on:
      - db
    ports:
      - "8080:8080"

volumes:
  dbdata:
    driver: local
解决方案

方案1:构建独立的sqlx-cli二进制文件(推荐)

在builder阶段编译sqlx-cli的二进制文件,复制到runtime镜像中,无需安装完整Rust环境:

  1. 在builder阶段、cargo build之前添加编译sqlx-cli的步骤:
RUN cargo install sqlx-cli --no-default-features --features postgres
  1. 在runtime阶段复制编译好的sqlx二进制文件:
# 复制my_app之后添加
COPY --from=builder /usr/local/cargo/bin/sqlx /usr/local/bin/sqlx

此方案仅增加单个二进制文件的体积,完全保留镜像轻量化优势。

方案2:在应用代码中内置迁移逻辑

修改Rust代码,让应用启动时自动执行迁移,彻底摆脱对sqlx-cli的依赖:

  1. 在Cargo.toml中添加sqlx的migrate特性:
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio-native-tls", "migrate"] }
  1. 在应用启动入口添加迁移执行逻辑:
use sqlx::postgres::PgPoolOptions;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    // 加载配置并获取数据库URL(替换为你的实际配置逻辑)
    let config = your_config_loader();
    let pool = PgPoolOptions::new()
        .max_connections(5)
        .connect(&config.database_url)
        .await?;

    // 执行迁移
    sqlx::migrate!("./migrations")
        .run(&pool)
        .await?;

    // 启动应用服务
    // ...
    Ok(())
}

该方案将迁移与应用生命周期绑定,适合生产环境,且镜像体积不受影响。

方案3:使用独立迁移容器

创建临时容器专门执行迁移,基于builder镜像(内置sqlx-cli),执行完成后自动退出:

  1. 修改docker-compose.yml,新增migrate服务:
services:
  # ... 保留原有db和app服务
  migrate:
    image: my_app_builder # 需提前构建builder阶段的镜像
    environment:
      - DATABASE_URL=postgres://postgres:password@db:5432/my_app
    depends_on:
      - db
    command: ["sqlx", "migrate", "run"]
    volumes:
      - ./migrations:/app/migrations # 挂载本地迁移文件目录
  1. 启动流程:先执行docker-compose run --rm migrate完成迁移,再启动应用服务。
    此方案无需修改runtime镜像,迁移逻辑与应用容器完全分离。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 20:40:29