This repo does deterministic builds of Fedora Linux with latest updates applied. Starting from Fedora 37, builds should be bit-for-bit reproducible. Versions below 37 - not completely, but very close.
DNF cache is retained in the image, and commands like dnf install
will
install the cached package versions (if they're still available in the mirror)
instead of the latest ones (unless the cache is rebuilt).
Beware, that the Fedora mirror selected during the build will end up in the cache and dnf commands executed in the future will pull use it.
As old package versions are removed from Fedora mirrors, some older image tags may become non-rebuildable. This can be solved by hosting your own mirror with old packages retained.
New images are built in CI when there are new security updates available.
- Proof of concept for bit-for-bit reproducible container image builds.
- Source for point-in-time snapshots of DNF metadata cache. Useful for deterministic updates of native (non-containerised) Fedora machines (see below).
The following example assumes x86_64
architecture.
make clean dnf-cache \
FEDORA_IMAGE=docker.io/alikov/fedora-base-x86_64:37-1677955848 \
CACHE_OP=extract
This will save a tarball with DNF cache in dnf-cache/fedora-37-x86_64.tar.gz
On the destination machine:
-
Extract
fedora-37-x86_64.tar.gz
(orfedora-37-aarch64.tar.gz
) to/var/cache/dnf
. -
Set
metadata_expire=-1
andcheck_config_file_age=False
in/etc/dnf/dnf.conf
: -
Comment out the
metadata_expire
setting in/etc/yum.repos.d/*.repo
files. -
Run
dnf update
.
That's it. Later on you can check if there are any updates available locally
by starting a container using docker.io/alikov/fedora-base-x86_64:37-1677955848
,
installing same packages as on the native machine, then executing
dnf makecache && dnf check-update
in that container.
This is only going to work with Fedora 37 or later.
The following example will reproduce
docker.io/alikov/fedora-base-x86_64:37-1677955848
locally. The existing image
will be used as DNF the cache source.
# Check out the same Git commit as the image was built from.
GIT_SHA=$(skopeo inspect docker://docker.io/alikov/fedora-base-x86_64:37-1677955848 \
| jq -er '.Labels."com.alikov.image.ref"')
git checkout "$GIT_SHA"
# Fetch the DNF cache and some metadata (timestamp, base image, version) from the
# existing image.
make clean dnf-cache \
FEDORA_IMAGE=docker.io/alikov/fedora-base-x86_64:37-1677955848 \
CACHE_OP=extract
# Remove all images, otherwise some existing layers might get reused and affect
# the build purity.
podman image prune --all --force
# Build.
make build
# Get image ID, which is a hash of local image configuration.
IID=$(podman image inspect --format '{{ .Id }}' docker.io/alikov/fedora-base-x86_64:37-1677955848)
# Check if the ID is the same as the original one.
if [ "$IID" = '9183e087a4d843c566a910ab89a39ef0edf8c2a2ab12f5378daafa6f0e68943e' ]; then
echo 'Great success! :)'
fi