An Interest In:
Web News this Week
- April 2, 2024
- April 1, 2024
- March 31, 2024
- March 30, 2024
- March 29, 2024
- March 28, 2024
- March 27, 2024
Building with Docker
Intro
Client engineers, embedded systems engineers, and other engineers who never worked with the backend can still benefit significantly from using containers. In this piece, I would like to share how I structure nearly all of my side projects so that they can be built on any machine that has make
and docker
installed.
Motivation
Environment guarantee. Multiple employees and the continuous integration server (CI) can be confident they are building in exactly the same environment.
Environment versioning. Every team member does not have to build the builder images locally. Docker Registry can be used to store and version the images.
Easy workstation/build agent setup. As mentioned above, the only tools required to build such a project are make
and docker
.
Make
is not used here as the project build system but rather as a convenient tool to wrap lengthy docker
commands. For the scope of the article, we will assume a Rust project located at $(ROOT_DIR)/main
using cargo
build system.
Linux target
Let us start simple. Docker is always Linux, so the easiest way target platform to build for is Linux. This also works perfect for unit testing if you are writing a Linux or platform-independent application.
Makefile
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))SOURCE_DIR := $(ROOT_DIR)/mainIMAGE_BUILDER_LINUX := rust:1.61.0build_linux: builder_linux @docker run \ --rm \ -v $(SOURCE_DIR):/src \ $(IMAGE_BUILDER_LINUX) \ sh -c 'cd /src && cargo build'test_linux: builder_linux @docker run \ --rm \ -v $(SOURCE_DIR):/src \ $(IMAGE_TESTER_LINUX) \ sh -c 'cd /src && cargo test'builder_linux: @docker pull $(IMAGE_BUILDER_LINUX)
Now a simple make build_linux
and make test_linux
should
- Make sure the builder Docker image is pulled
- Run build/test using the image
Custom builders
It is most likely that, eventually, you will need to customize the builder image. That would imply creating a Dockerfile
and building an image using it instead of pulling the image as we did above.
Assuming the Dockerfile
is located at $(ROOT_DIR)/image/x
:
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))SOURCE_DIR := $(ROOT_DIR)/mainPROJECT_NAME := $(shell basename $(ROOT_DIR))IMAGE_BUILDER_X := $(PROJECT_NAME)-builder-xbuilder_x: @docker build -t $(IMAGE_BUILDER_X) $(ROOT_DIR)/image/x
WebAssembly
Let me use this opportunity to share some scripts to build Rust code into WebAssembly and run the unit tests.
Makefile
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))SOURCE_DIR := $(ROOT_DIR)/mainPROJECT_NAME := $(shell basename $(ROOT_DIR))RUST_TARGET_WEB := wasm32-unknown-unknownIMAGE_BUILDER_WEB := $(PROJECT_NAME)-builder-webbuild_web: builder_web @docker run \ --rm \ -v $(SOURCE_DIR):/src \ $(IMAGE_BUILDER_WEB) \ sh -c 'cd /src && cargo build --target $(RUST_TARGET_WEB)'test_web: builder_web @docker run \ --rm \ -v $(SOURCE_DIR):/src \ $(IMAGE_BUILDER_WEB) \ sh -c 'cd /src && CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER=wasmtime_test_runner.sh cargo test --target $(RUST_TARGET_WEB)'builder_web: @docker build -t $(IMAGE_BUILDER_WEB) $(ROOT_DIR)/image/web
image/web/Dockerfile
FROM rust:1.61.0RUN \rustup toolchain install '1.61.0-x86_64-unknown-linux-gnu' \--target 'wasm32-unknown-unknown' \--component 'rust-std'RUN curl https://wasmtime.dev/install.sh -sSf | bashCOPY wasmtime_test_runner.sh /usr/binVOLUME ["/usr/local/cargo/registry"]
image/web/wasmtime_test_runner.sh
#!/bin/sh/root/.wasmtime/bin/wasmtime "$@" --invoke main 0 0
It is relatively easy with Rust because rustup
has a wasm32
toolchain ready to download, but with a more complicated cross-compiler setup, being able to make a Dockerfile
describing the setup sequence is a lifesaver.
Thoughts
The more complicated the required build setup is, the more I recommend looking at the Docker-based building. Setting up a workstation to build a project requiring multiple cross compilers, especially when using certain toolchains that might require some user-fixing, can take up to a few hundred bash commands. That could theoretically be done without containers by a bash script, but that how numerous caveats, including:
- State zero would have to be identical before running the script
- Updating the build setup while keeping it identical between workstations
- No environment guarantee
- No switching between build setup versions
Original Link: https://dev.to/nikitakatchik/building-with-docker-2a9h
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To