Skip to content

Container Images

CobaltCore builds its own OCI-compliant container images for all OpenStack services. These images are lightweight, reproducible, and support fast patching without repository forks.

Design Goals

GoalImplementation
Build specific versionsBranch, tag, or commit SHA as build input (see Versioning)
Lightweight imagesMulti-stage builds, only runtime dependencies in the final image
Fast buildsuv instead of pip, layer caching, bind mounts (see Build Pipeline)
Fast patchingpatches/<service>/<release>/ directory with git apply, no fork required (see Patching)
Multi-release supportA single C5C3 branch manages multiple OpenStack releases simultaneously
Library patchingConstraint overrides and patches at the dependency level (see Patching — Library Patches)
Supply chain transparencySigned SBOM (CycloneDX) attested to each image via Sigstore (see SBOM)

Image Hierarchy

text
┌─────────────────────────────────────────────────────────────────┐
│                       Image Hierarchy                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ubuntu:noble (24.04 LTS)                                       │
│       │                                                         │
│       ├──▶ c5c3/python-base:3.12-noble                          │
│       │    ├── Python 3.12, runtime libraries                   │
│       │    ├── PATH=/var/lib/openstack/bin:$PATH                │
│       │    └── Service user (UID 42424)                         │
│       │         │                                               │
│       │         └──▶ c5c3/<service>  (final runtime image)      │
│       │              ├── COPY --from=build /var/lib/openstack   │
│       │              └── Service-specific system packages       │
│       │                                                         │
│       └──▶ c5c3/venv-builder:3.12-noble                         │
│            ├── Build dependencies (gcc, python3-dev, libssl-dev)│
│            ├── uv (Python package manager)                      │
│            └── upper-constraints.txt                            │
│                 │                                               │
│                 └──▶ Build stage (discarded)                    │
│                      └── Compiles venv into                     │
│                         /var/lib/openstack                      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Key principle: The venv builder contains all build dependencies (compilers, header files) but is never included in the final image. Only the compiled virtual environment (/var/lib/openstack) is copied via COPY --from=build into the lightweight runtime image.

Comparison of Existing Approaches

The C5C3 strategy is based on an analysis of OpenStack LOCI and Vexxhost Atmosphere:

AspectLOCIAtmosphereC5C3
Dockerfile structureSingle generic Dockerfile for all servicesPer-service repos with own DockerfilePer-service Dockerfile in monorepo
Python installerpip + pre-built wheelsuv (Rust-based)uv (Rust-based)
Dependency strategySeparate requirements image with wheelsupper-constraints.txt + uv directlyupper-constraints.txt + uv directly
Base imageUbuntu JammyMulti-distro (Ubuntu, Debian, Rocky)Ubuntu Noble (24.04 LTS)
Source code in buildgit clone inside DockerfileBuild context (bind mount from CI)Build context (bind mount from CI)
PatchingNo built-in mechanismpatches/ directory with git applypatches/ + library patches + constraint overrides
Library patchingNot supportedNot explicitConstraint overrides + library patches
Multi-archExperimentalNative (amd64 + arm64)Native (amd64 + arm64)
CI/CDZuul (OpenDev)GitHub Actions + Depot.devGitHub Actions
VersioningBuild args (PROJECT_REF)Branch-per-release + commit SHA pinsOwn version scheme + per-release refs (branch, tag, or SHA)
Automated updatesNoneRenovate BotRenovate Bot

Why Not LOCI?

  • No patching mechanism: Patches require repository forks or child images
  • Slow builds: pip + pre-built wheels instead of uv
  • Monolithic approach: A single generic Dockerfile for all services prevents service-specific optimizations
  • No library patching: Dependencies cannot be patched individually

What We Adopt from Atmosphere

  • uv as package manager: Dramatically faster builds
  • Build context pattern: Source code is checked out via CI and passed as a build context, not cloned inside the Dockerfile
  • Structured patching: patches/ directory with git format-patch / git apply
  • Source reference pinning: Reproducible builds through branch, tag, or commit SHA references

What C5C3 Does Differently

  • Multi-release per branch: A single C5C3 branch manages images for multiple OpenStack releases (e.g., 2025.2 and 2025.1), unlike Atmosphere which uses one branch per release
  • Release-scoped patches: Patches are organized as patches/<service>/<release>/, allowing different patches per OpenStack release within the same C5C3 branch
  • Library patching: Explicit support for patches at the dependency level (e.g., oslo.messaging, python-novaclient)
  • Constraint overrides: Targeted version pin changes for individual libraries, scoped per release
  • Monorepo structure: Dockerfiles live in the c5c3/forge monorepo, not in separate repos per service
  • Focus on Ubuntu Noble: A single base image instead of multi-distro to reduce complexity

Container Registry

text
ghcr.io/c5c3/<service>:<tag>

Tag schema:

Tag formatExampleUsage
<upstream-version>28.0.0Release tag (default)
<upstream-version>-p<N>28.0.0-p1Release with patch revision
<branch>stable-2025.2Branch tracking (mutable)
<short-sha>a1b2c3dCommit-based (immutable)

Currently integrated services:

ComponentUpstream VersionImage
Keystone28.0.0ghcr.io/c5c3/keystone:28.0.0
Nova32.1.0ghcr.io/c5c3/nova:32.1.0
Neutron27.0.1ghcr.io/c5c3/neutron:27.0.1
Glance31.0.0ghcr.io/c5c3/glance:31.0.0
Cinder27.0.0ghcr.io/c5c3/cinder:27.0.0
Placement14.0.0ghcr.io/c5c3/placement:14.0.0
OVN24.03.4ghcr.io/c5c3/ovn:24.03.4
OVS3.4.1ghcr.io/c5c3/ovs:3.4.1
Tempest41.0.0ghcr.io/c5c3/tempest:41.0.0
Cortex0.5.0ghcr.io/c5c3/cortex:0.5.0

Note: OVN and OVS are built from C source and follow a separate build pipeline. Tempest and Cortex use their own build pipelines. The Python-based pipeline described here applies to the core OpenStack services (Keystone, Nova, Neutron, Glance, Cinder, Placement).

Note: Infrastructure services (Memcached, MariaDB, RabbitMQ, Valkey) use upstream container images directly and are not built by C5C3. They are managed by their respective operators (see Infrastructure Service Operators).

Further Reading

  • Build Pipeline — Multi-stage builds, Dockerfile structure, GitHub Actions
  • Versioning — Branch strategy, tag schema, automated updates
  • Patching — Service patches, library patches, constraint overrides
  • SBOM — Software Bill of Materials, signing, attestation, regulatory compliance