Develop and Deploy Rust Rocket App Using Docker Compose (Traefik/Docker Hub)

This article will talk about how to use Docker for quick Rocket web app deployment. This architecture can be scaled with more complicated CI/CD framework and Kubernetes clusters for large scale application and zero downtime deployment.

Prerequisite

  • Linux server
  • Local dev machine with Rust installed
  • Docker with Docker Compose
  • Follow this guide for setting up Traefik.
  • Domain name

Getting started

Update rust

Install rustup by following the instructions on its website. Once rustup is installed, ensure the latest toolchain is installed by running the command:

rustup default stable

Initiate Rocket sample app

cargo new hello-rocket --bin
cd hello-rocket

Now, add Rocket as a dependency in your Cargo.toml:

[dependencies]
rocket = "0.5.1"

Modify src/main.rs so that it contains the code for the Rocket Hello, world! program, reproduced below:

#[macro_use] extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    "Hello, world!"
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![index])
}

Finally, we can run below command to test our first app:

cargo run

Build docker image and upload

Add Dockerfile

There are many tutorials out there but it is always a good practice to follow official documents: https://rocket.rs/guide/v0.5/deploying/#containerization

Note that, in order to test Docker image in local, EXPOSE is needed:

FROM docker.io/rust:1-slim-bookworm AS build

## cargo package name: customize here or provide via --build-arg
ARG pkg=hello-rocket

WORKDIR /build

COPY . .

RUN --mount=type=cache,target=/build/target \
    --mount=type=cache,target=/usr/local/cargo/registry \
    --mount=type=cache,target=/usr/local/cargo/git \
    set -eux; \
    cargo build --release; \
    objcopy --compress-debug-sections target/release/$pkg ./main

################################################################################

FROM docker.io/debian:bookworm-slim

WORKDIR /app

## copy the main binary
COPY --from=build /build/main ./

## copy runtime assets which may or may not exist
COPY --from=build /build/Rocket.tom[l] ./static
COPY --from=build /build/stati[c] ./static
COPY --from=build /build/template[s] ./templates

## ensure the container listens globally on port 8000
ENV ROCKET_ADDRESS=0.0.0.0
ENV ROCKET_PORT=8000

## uncomment below to test in local
## EXPOSE 8000

CMD ./main

Make sure the pkg set to same value as package name in Cargo.toml

Build Docker image

docker build -t your_username/my-rocket-image .

Upload Docker image to Docker Hub

First make sure you have Docker Hub account and then login to Docker:

Docker login

Then upload Docker image to Docker Hub:

docker push your_username/my-rocket-image

Deploy docker image to cloud instance with Docker Compose and Traefik

Assume you already followed this guide and Traefik reverse proxy is up running in your server.

Run uploaded Rocket app Docker image

First let’s add a folder:

mkdir ~/rocket-docker && cd ~/rocket-docker

Then add docker-compose.yml:

vi docker-compose.yml
networks:
  traefik:
    external: true
 
services:
  app:
    image: your_username/my-rocket-image:latest
    networks:
      - traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.rocket-docker.rule=Host(`your-domain.com`)"
      - "traefik.http.routers.rocket-docker.service=rocket-docker"
      - "traefik.http.routers.rocket-docker.entrypoints=websecure"
      - "traefik.http.services.rocket-docker.loadbalancer.server.port=8000"
      - "traefik.http.services.rocket-docker.loadbalancer.passhostheader=true"
      - "traefik.http.routers.rocket-docker.tls=true"
      - "traefik.http.routers.rocket-docker.tls.certresolver=letsencrypt"
      - "traefik.http.routers.rocket-docker.middlewares=compresstraefik"
      - "traefik.http.middlewares.compresstraefik.compress=true"
      - "traefik.docker.network=traefik"
    restart: unless-stopped

Make sure to update your-domain.com

Run below to start service:

docker compose up -d

Verify by visiting www.your-domain.com see if everything works properly.

Develop and update service with latest change

Try change something in your local Next.js app, and run upload script again:

docker build -t your_username/my-rocket-image . && docker push your_username/my-rocket-image

Then go to your cloud instance and run below:

docker pull your_username/my-rocket-image:latest && docker compose -f ~/rocket-docker/docker-compose.yml up -d

Lastly, verify the change by visiting www.your-domain.com.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *