towerops/k8s/Dockerfile.base
Graham McIntire 31cbd18128 ci: cache slow runtime apt deps in a prebuilt base image
Splits the runtime apt installs (gdal-bin, snmp, libsnmp40, locales,
BEAM runtime libs) into k8s/Dockerfile.base, hosted at
codeberg.org/gmcintire/towerops-base:latest. The app Dockerfile now
does FROM that base instead of re-installing gdal (~500 MB) on every
push.

The new build-base workflow rebuilds the base image only when
k8s/Dockerfile.base or the workflow itself changes, weekly via cron
(Sundays 06:00 UTC, with CACHE_BUST=<ISO week> to force apt-get update
on a week boundary), or via workflow_dispatch.

Production workflow now uses buildx + does docker login before the
build so it can pull the private base image.
2026-05-05 11:19:49 -05:00

62 lines
2.7 KiB
Text

# syntax=docker/dockerfile:1.6
#
# Pre-built runtime base image for the Towerops Phoenix app. Contains:
# * Debian trixie-slim with locale set to en_US.UTF-8
# * Runtime apt deps for the BEAM + Erlang ssl + snmp
# * `gdal-bin` (~500 MB dep tree, the slowest install) for the LIDAR
# elevation reader
#
# Built by `.forgejo/workflows/build-base.yaml` only when this file or
# the workflow changes. The app `Dockerfile` does
# `FROM codeberg.org/gmcintire/towerops-base:latest` so everyday code
# pushes skip the gdal + snmp apt install entirely.
#
# Bumping the Debian release: change the ARG below and push — the base
# workflow rebuilds and re-tags `:latest`. The app Dockerfile follows
# `:latest`, so the next app push picks it up automatically.
ARG DEBIAN_VERSION=trixie-20260316-slim
ARG RUNNER_IMAGE="docker.io/debian:${DEBIAN_VERSION}"
FROM ${RUNNER_IMAGE} AS base
# Weekly cron passes CACHE_BUST=<iso year+week> so the apt layers below
# re-execute and pick up Debian security patches. Source-controlled
# pushes leave the value at its `none` default, so day-to-day base
# rebuilds (Dockerfile.base edits) don't pay the apt-update cost
# unless the week has rolled over.
#
# Note: the registry occasionally GCs base-image blobs that the
# manifest still references. When that happens, push any change to
# this file (or run the workflow via workflow_dispatch) to re-trigger
# the build-base workflow and re-upload the layers.
ARG CACHE_BUST=none
# Runtime apt deps for the BEAM + ICU/locale + ping + SNMP + GDAL.
# gdal-bin is split into a second RUN so a transient gdal install
# failure doesn't invalidate the smaller base layer above. Referencing
# `${CACHE_BUST}` in the RUN line changes the layer hash week-to-week
# without altering the install set.
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
echo "cache-bust=${CACHE_BUST}" \
&& rm -f /etc/apt/apt.conf.d/docker-clean \
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get upgrade -y \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
libstdc++6 openssl libncurses6 locales ca-certificates iputils-ping \
snmp libsnmp40
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
echo "cache-bust=${CACHE_BUST}" \
&& rm -f /etc/apt/apt.conf.d/docker-clean \
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends gdal-bin
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen \
&& locale-gen
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8