使用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环境:
- 在builder阶段、
cargo build之前添加编译sqlx-cli的步骤:
RUN cargo install sqlx-cli --no-default-features --features postgres
- 在runtime阶段复制编译好的sqlx二进制文件:
# 复制my_app之后添加 COPY --from=builder /usr/local/cargo/bin/sqlx /usr/local/bin/sqlx
此方案仅增加单个二进制文件的体积,完全保留镜像轻量化优势。
方案2:在应用代码中内置迁移逻辑
修改Rust代码,让应用启动时自动执行迁移,彻底摆脱对sqlx-cli的依赖:
- 在
Cargo.toml中添加sqlx的migrate特性:
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio-native-tls", "migrate"] }
- 在应用启动入口添加迁移执行逻辑:
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),执行完成后自动退出:
- 修改
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 # 挂载本地迁移文件目录
- 启动流程:先执行
docker-compose run --rm migrate完成迁移,再启动应用服务。
此方案无需修改runtime镜像,迁移逻辑与应用容器完全分离。
内容的提问来源于stack exchange,提问作者BWStearns
相关产品推荐
相关产品推荐

