Small experiments in writing Rust programs that work in a "Cloud Native" way, mainly containers, Kubernetes, Docker, and serverless (AWS Lambda).
- Basic Container
- Basic Container Alpine
- Basic Container Scratch
- Workspace Multiple Containers
- Workspace Cargo Make
- Workspace Cargo Chef
- Cargo Chef Scratch
Simple multi-stage build to create a small (79Mb!) container with a "Hello, World" application. Uses Debian Bookworm slim for both building and running.
To build:
cd basic-container
docker build --rm -t keithsharp/basic-container .To run:
docker run -ti --rm keithsharp/basic-container Simple multi-stage build to create a smaller (12Mb) container with a "Hello, World" application. Uses Alpine 3.18 for both building and running.
To build:
cd basic-container-alpine
docker build --rm -t keithsharp/basic-container-alpine .To run:
docker run -ti --rm keithsharp/basic-container-alpine Simple multi-stage build to create a tiny (4.5Mb) container with a "Hello, World" application. Uses Alpine 3.18 for building and Scratch for running.
To build:
cd basic-container-scratch
docker build --rm -t keithsharp/basic-container-scratch .To run:
docker run -ti --rm keithsharp/basic-container-scratchA cargo workspace containing two binary crates (one and two). The Dockerfile builds both crates as static binaries with each binary being copied into a separate from Scratch container. The code is based on this Stack Overflow answer.
To build:
cd workspace-multiple-containers
docker build --rm --target one .
docker build --rm --target two .If you do a docker image ls you'll see that you have two new containers that are untagged. What we now need to do is tag the containers by filtering on the labels we assigned in the Dockerfile:
docker tag $(docker image ls -q --filter=dangling=true --filter=label=service=one) keithsharp/workspace-one
docker tag $(docker image ls -q --filter=dangling=true --filter=label=service=two) keithsharp/workspace-twoYou can then run each container separately:
docker run -ti --rm keithsharp/workspace-one
docker run -ti --rm keithsharp/workspace-twoBuilds on the Workspace Multiple Containers example to use Cargo Make to automate the building and tagging of the containers.
To install Cargo Make:
cargo install --force cargo-makeTo build and tag a single container:
cargo make build-oneBecause I've configured [tasks.default] alias, you can build and tag both containers:
cargo make Or, more explicitly relying on the [tasks.build] alias:
cargo make buildRun the containers as previously (or you could add another task):
docker run -ti --rm keithsharp/workspace-one
docker run -ti --rm keithsharp/workspace-twoNote Each of the tasks has
workspace = falseset so that the tasks only run at the workspace level and not for each member. This is necessary because you might be defining things like dependencies in the workspaceCargo.tomlwhich are referenced from the memberCargo.toml, so build at the member level without the workspace will fail. See the documentation for more details.
Builds on the Workspace Cargo Make example to use Cargo Chef to create a cached layer of the compiled version of all of the projects dependencies, speeding up repeated builds.
The magic is in the invocations of cargo chef planner ... and cargo chef cook ... in the Dockerfile.
Building is exactly the same:
cargo make buildTo run the containers:
docker run -ti --rm keithsharp/chef-one
docker run -ti --rm keithsharp/chef-twoNote I've switched back to using
rust:slim-bookwormto build anddebian:bookworm-slimto run, this is to avoid having to complicate theDockerfilewith building and linking a static versions of OpenSSL which is a requirement of reqwest.
This workspace is an update to Workspace Cargo Chef where the final containers are based on Scratch and are only 11.3Mb and 7.7Mb in size. To make this work I changed the Cargo.toml file for crate two so that Reqwest now uses rustls rather than native TLS (usually OpenSSL).
I then needed to add a couple of lines to the top of the Dockerfile to get cross-compilation from Debian to MUSL/Alpine working:
RUN apt-get update && apt-get install -y musl-tools
RUN rustup target add x86_64-unknown-linux-muslWith these lines in place I could add --target=x86_64-unknown-linux-musl to cargo chef cook ... and cargo build .... I think that you could also use rust:alpine3.18 as the base build container, but you would need to use RUN apk add musl-dev to install the MUSL tools.
Building and running remains the same as before:
cargo make buildTo run the containers:
docker run -ti --rm keithsharp/chef-one
docker run -ti --rm keithsharp/chef-twoCopyright 2023, Keith Sharp, kms@passback.co.uk.
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/.