Back

Rust for NodeJS developers (III) - Docker development environment

Captain's log, stardate d209.y41/AB

Rust Docker Node.js Web development Guides
Carlos López
Full-stack developer
Rust for NodeJS developers (III) - Docker development environment

This article is the third in our "Rust for NodeJS developers" series. If you missed the previous article, you can read it here: Rust for NodeJS developers (II) - Rocket.

Docker can be beneficial not just for deploying applications but also for local development. By creating a Docker environment for our Rust API, we can ensure a consistent and isolated development experience across different machines and team members. Additionally, Docker allows us to run services like databases on different versions without any conflicts.

Pre-requisites

Make sure you have Docker and Docker Compose installed on your system.
You can follow the official instructions for your operating system.

Docker ignore

To avoid polluting our Docker image with unnecessary files or including development secrets without noticing, we'll create a .dockerignore file.

.dockerignore

/target
.git
.gitignore

Remember that the target folder holds the build artifacts created based on your system and will be overwritten by the Docker image using its own.

A good starting rule is to include everything from your .gitignore file in the .dockerignore.

Dockerfile

To keep the development configuration separate from the potential production configuration and avoid confusion, we'll create the necessary files inside a new .dockerdev folder.

.dockerdev/Dockerfile

# Use the official Rust image
FROM rust:1.77.0

# Create a new working directory
WORKDIR /app

# Copy the source code and Cargo.toml file
COPY . .

# Install required tools
RUN cargo install cargo-watch

# Expose the port on which the application will run
EXPOSE 8000

# Run the application
CMD ["cargo", "watch", "-x", "run"]

Docker Compose

Now, we'll create a compose.yml file inside the .dockerdev folder to orchestrate the necessary containers:

.dockerdev/compose.yml

name: rust-for-nodejs-developers

services:
  backend-app:
    command: ["cargo", "watch", "-x", "run"]
    restart: unless-stopped
    # Assign a terminal to the container to view the output of 'cargo watch'
    tty: true
    # Configure the ROCKET_ADDRESS env var to make the app accessible
    # from outside the container
    environment:
      ROCKET_ADDRESS: 0.0.0.0
    # Required since our code is one directory up
    build:
      context: ../
      dockerfile: ./.dockerdev/Dockerfile
    volumes:
      # Mount the host directory to /app inside the container
      - ../.:/app
      # Mount a named volume to hold build artifacts
      - backend-target:/app/target
      # Mount a named volume to hold cargo packages and build artifacts
      - backend-cargo:/usr/local/cargo
    # Map the container's port 8000 to the host's port 8000
    ports:
      - 8000:8000

volumes:
  backend-target:
  backend-cargo:

Mounting /app/target and /usr/local/cargo in separate volumes provides several benefits regarding compilation performance, build efficiency, and consistency in the development environment.

Up command

Now, within your project directory, run the following command to build and run the containers:

docker compose -f .dockerdev/compose.yml up

Once the containers run, you can access your API at http://localhost:8000 as usual.
While it might not seem very different now, the advantages will become clear once a database is required, as everything will run inside a Docker container.

Cargo Make

Typing that long command every time can be annoying, which is why cargo-make is so helpful.
Think of it as a powerful alternative to package.json scripts.

First, install it in your system with cargo install cargo-make.
Then, create a Makefile.toml file in your project root like this:

Makefile.toml

[tasks.develop]
script = "docker compose -f .dockerdev/compose.yml up"

Now, you can start your Docker environment with cargo make develop.

Result

You can check the result in this branch.

Upcoming

We'll add a Postgres database and SQLx to our stack in the next installment.

Share this post

Related Articles

How I use Docker for Rails development: running services

How I use Docker for Rails development: running services

Project setup can be a very cumbersome process for developers. In this blog post, our developer Dani explains how he uses Docker to develop in Rails

Read full article
Rust for NodeJS developers (I) - Why and how?

Rust for NodeJS developers (I) - Why and how?

We are always open to exploring new technologies. Recently, Rust has caught our attention due to its high performance, memory safety and reliability. In this series of articles, we will share the experience of learning Rust as a Node.js developer by building a GraphQL API in Rust.

Read full article
Rust for NodeJS developers (II) - Rocket

Rust for NodeJS developers (II) - Rocket

Rocket is a robust web framework for Rust, offering developers a streamlined approach to building high-performance web applications. In this article, we'll dive into how to get started with Rocket.

Read full article