Captain's log, stardate d209.y41/AB
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.
Make sure you have Docker and Docker Compose installed on your system.
You can follow the official instructions for your operating system.
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
.
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"]
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.
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.
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
.
You can check the result in this branch.
We'll add a Postgres database and SQLx to our stack in the next installment.
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 articleWe 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 articleRocket 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