mirror of
https://gitlab.com/fedora/bootc/base-images.git
synced 2026-09-02 22:40:45 +00:00
Merge branch 'bivl' into 'main'
BIPVL: New design doc See merge request fedora/bootc/base-images!317
This commit is contained in:
commit
6f36d2d74c
1 changed files with 146 additions and 0 deletions
146
docs/todo/base-image-version-locking.md
Normal file
146
docs/todo/base-image-version-locking.md
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
# Base Image Package Version Locking
|
||||
|
||||
## Overview
|
||||
|
||||
This design proposes a mechanism for base container images and disk/cloud images to version-lock all installed packages, providing reproducible and secure package management for derived images and systems.
|
||||
|
||||
## Related Work
|
||||
|
||||
See [dnf5#833](https://github.com/rpm-software-management/dnf5/issues/833) which discusses a complementary approach using dependency lockfiles. This proposal takes a different approach focused on image-level version pinning through repository metadata.
|
||||
|
||||
See also [bootc-tracker#59](https://gitlab.com/fedora/bootc/tracker/-/issues/59) which tracks the overall implementation of base image version locking.
|
||||
|
||||
## Core Design
|
||||
|
||||
### IMAGE_VERSION in os-release
|
||||
|
||||
Today Fedora derivative images don't usually set the (relatively new) `IMAGE_VERSION` variable in [os-release](https://man7.org/linux/man-pages/man5/os-release.5.html)
|
||||
in this proposal they will:
|
||||
|
||||
```
|
||||
NAME="Fedora Linux"
|
||||
VERSION="42"
|
||||
ID=fedora
|
||||
VERSION_ID=42
|
||||
# Version scheme the same as a "compose" today
|
||||
IMAGE_VERSION=20251015.0
|
||||
...
|
||||
```
|
||||
|
||||
The `IMAGE_VERSION` represents a specific snapshot of the base image + repository state that corresponds to the exact package versions installed in the base image, plus additional packages for all default-enabled rpm-md repositories.
|
||||
|
||||
### BASE_IMAGE_VERSION for Derived Images
|
||||
|
||||
Some image-based systems (like Fedora CoreOS) may want to set their own `IMAGE_VERSION` while still benefiting from version locking of the base packages. For these cases, DNF will also recognize `BASE_IMAGE_VERSION` which takes precedence over `IMAGE_VERSION` for repository version locking.
|
||||
|
||||
This allows a derived image to:
|
||||
- Set `IMAGE_VERSION` to its own version scheme
|
||||
- Set `BASE_IMAGE_VERSION` to inherit the base image's package snapshot
|
||||
- Maintain independent versioning while preserving reproducible package installations
|
||||
|
||||
Derived images can also override the base image version by writing to `/etc/dnf/vars/imageversion`, which DNF will use in preference to values from os-release.
|
||||
|
||||
### DNF Integration
|
||||
|
||||
Any client can request a specific version-locked snapshot by appending $imageversion.
|
||||
|
||||
**Current URL:**
|
||||
```
|
||||
metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch
|
||||
```
|
||||
|
||||
**URL with version locking:**
|
||||
```
|
||||
metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever-$imageversion&arch=$basearch
|
||||
```
|
||||
|
||||
The metalink service will redirect to a pinned, immutable rpm-md repository snapshot that corresponds to the exact state of packages at the time the base image was built.
|
||||
|
||||
## Benefits
|
||||
|
||||
### Reproducibility
|
||||
|
||||
Derived images and systems will install the exact same package versions as the base image, regardless of when the build occurs. This eliminates the common problem where a cached container layer contains outdated packages.
|
||||
|
||||
### Security and Updates
|
||||
|
||||
When a new base image is released with updated `IMAGE_VERSION`, derived images automatically rebuild and pick up all security updates in a controlled manner. This provides:
|
||||
- Clear update points tied to base image releases
|
||||
- Ability to validate and test base image updates before adoption
|
||||
- Audit trail of which package versions are in use
|
||||
|
||||
### Supply Chain Security
|
||||
|
||||
The image version provides a single identifier that pins all package versions, making it easy to:
|
||||
- Track exactly which packages are in a given deployment
|
||||
- Coordinate security updates across fleet of systems
|
||||
- Verify package integrity against known-good snapshots
|
||||
|
||||
### Compatibility with Existing Workflows
|
||||
|
||||
Unlike lockfile approaches, this design:
|
||||
- Requires no changes to Containerfiles/Dockerfiles
|
||||
- Works transparently with existing package management commands
|
||||
- Applies automatically to all derivative images
|
||||
|
||||
## Implementation Considerations
|
||||
|
||||
### Repository Infrastructure
|
||||
|
||||
We propose that these snapshots are NOT stored in the donated "mirror network" but are managed by dedicated cloud-native storage backed by Fedora project sponsors.
|
||||
|
||||
In general an important thing to preserve here is that if a container image (or disk image) is published, the corresponding packages must be available as well. Hence,
|
||||
what will likely be the best implementation path is to publish the rpm-md snapshots before publishing images, but not mark it as the "latest".
|
||||
|
||||
But the system will work most reliably if the two are co-located; e.g. container images hosted in quay.io could have content served from the same infrastructure.
|
||||
|
||||
One possible implementation approach is to extend [archive-repo-manager](https://pagure.io/releng/archive-repo-manager), which already handles repository archival and versioning. Each time repodata updates, it could also be copied to a versioned name that remains immutable. However, this is just one potential implementation path - other approaches such as storing RPMs as OCI artifacts in a registry are also viable.
|
||||
|
||||
### DNF Changes
|
||||
|
||||
DNF needs to:
|
||||
1. Check for `imageversion` in the following priority order:
|
||||
- `/etc/dnf/vars/imageversion` (highest priority, allows derived images to override)
|
||||
- `BASE_IMAGE_VERSION` from `/usr/lib/os-release`
|
||||
- `IMAGE_VERSION` from `/usr/lib/os-release`
|
||||
2. Substitute `$imageversion` in metalink URLs when a version is found
|
||||
3. Provide clear messaging about which version is being used
|
||||
|
||||
### Override Mechanism
|
||||
|
||||
There are several ways to override or disable version locking:
|
||||
|
||||
1. **One-time override**: Use `dnf --setvar imageversion=latest` to bypass version locking for a single command
|
||||
2. **Persistent override**: Write a different version to `/etc/dnf/vars/imageversion`
|
||||
3. **Complete removal**: Remove `$imageversion` from the metalink URL in repository configuration files
|
||||
|
||||
The metalink service may also support the alias `latest` as a value for `$imageversion`, allowing users to override the variable without editing URLs.
|
||||
|
||||
### Mixed Repository Sources
|
||||
|
||||
Third-party and local repositories will not include `$imageversion` in their URLs by default, as they are not part of the versioned snapshot infrastructure. This is expected behavior - only official Fedora repositories that participate in the snapshot system will use `$imageversion`.
|
||||
|
||||
When DNF processes repository configurations:
|
||||
- Repositories with `$imageversion` in their metalink/baseurl use the locked snapshot
|
||||
- Repositories without `$imageversion` use their default behavior (typically latest packages)
|
||||
|
||||
This allows mixing locked base packages with latest versions from third-party sources.
|
||||
|
||||
### Error Handling
|
||||
|
||||
If a repository snapshot becomes unavailable (404 or similar error), DNF will fail hard rather than falling back to the latest packages. This is intentional - silently falling back would break the reproducibility guarantee and could introduce unexpected package versions.
|
||||
|
||||
Users must explicitly modify repository configurations to disable version locking if a snapshot is unavailable.
|
||||
|
||||
### Snapshot Lifecycle
|
||||
|
||||
Package snapshots are lifecycle-bound to the base images that reference them. A snapshot must be retained at least as long as any base image using that `IMAGE_VERSION` remains supported or available.
|
||||
|
||||
For example:
|
||||
- Base image `fedora-bootc:42` with `IMAGE_VERSION=20251015.0` is published
|
||||
- The corresponding snapshot `fedora-42-20251015.0` must remain available
|
||||
- When the base image reaches end-of-life or is removed from registries, the snapshot may be retired
|
||||
- In practice, snapshots should be retained longer than images to support derived images and cached layers
|
||||
|
||||
This binding ensures that any published image can always install its matching package versions, maintaining the reproducibility guarantee throughout the image's lifecycle.
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue