Recently I changed my home server from a couple of Raspberry Pi’s to a dedicated mini computer, and it seemed like the perfect opportunity to tidy up my deployment setup.
Previously I’d had a mixture of containerised applications and straight on the pi’s, so stage 1 to make sure everything was containerised, stage 2 was to get everything built/compiled to run on the new hardware, stage 3 was writing the new docker-compose files. During this process I encountered a handful of problems.
Multi-stage Dockerfiles
I’ve got a couple of Rust projects which require compilation before the container can be published.
Attempt 1 compile the code outside of docker process, and copy the result into the image. This caused issues though when trying to run the container, it would error when starting up, the simplest advice I found to fix the problem was to run the code in the same environment it was compiled.
Attempt 2 was the compile the code in the docker file when building the image but this resulted in images sizes of 2.5GB, which is quite big.
Attempt 3 Multi stage dockerfiles, the first stage compiles the code, the second stage gets the result copied in, both stages use the same base image and the result is only 0.5GB.
The BIG GOTCHA I got here was trying to copy the result between images.
# Name initial stage here, it'll be needed later
FROM rust:latest as build
WORKDIR /app
COPY . .
RUN cargo build --release --features vendored-openssl
FROM rust:latest
WORKDIR /app
RUN apt-get update
RUN apt-get install -y rtl-433
# HERE the --from=build is important to say where to copy the files from,
# without it will try to copy it from the host system
COPY --from=build /app/target/release/listener ./listener
ENTRYPOINT ["./listener"]
Networks
My new setup involved sharing a service container between multiple containers, for me it was a postgres, and a nginx container. I was having trouble setting this up in my docker compse I would include the networks at the bottom of the file, set them as external but the containers would not join, forgetting its also needed to include a networks section in each service.
version: '3'
services:
weather-station-api:
image: image
restart: unless-stopped
// Dont forget this
networks:
- nginx-proxy-manager
- postgres_network
# Remove this if using different networks
networks:
nginx-proxy-manager:
name: nginx-proxy-manager
external: true
postgres_network:
name: postgres_network
external: true