Search code examples
dockerrustdocker-composerust-sqlx

Running rust sqlx migrations locally with docker-compose


I'm working through Zero to Prod in Rust and I've gone off script a bit. I'm working on dockerizing the whole setup locally including the database. On ENTRYPOINT the container calls a startup script that attempts to call sqlx migrate run, leading to the error ./scripts/init_db.sh: line 10: sqlx: command not found.

I think I've worked it out that because I'm using bullseye-slim as the runtime it doesn't keep the installed rust packages around for the final image, which helps with the build time and image size.

Is there a way to run sqlx migrations without having rust, cargo etc installed? Or is there a better way altogether to accomplish this? I'd like to avoid just reinstalling everything in the bullseye-slim image and losing some of the docker optimization there.

# 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 looks like below

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


Solution

  • You can install sqlx-cli with cargo install in your build stage

    cargo install sqlx-cli
    

    then copy it over to the deployment stage with

    COPY --from=builder $HOME/.cargo/bin/sqlx-cli sqlx-cli
    

    Or you can run the migrations when your application starts with the migrate! macro

    sqlx::migrate!("db/migrations")
        .run(&pool)
        .await?;