build: build all images + run tests using them (#1069)

TODO

 Add patches
 Figure out why cache misses for Git clone (or something else)
diff --git a/Dockerfile b/Dockerfile
index 9c8e06b..4b74bee 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,161 +1,27 @@
-FROM ubuntu:jammy-20240227 AS ubuntu
-LABEL org.opencontainers.image.source=https://github.com/vexxhost/atmosphere
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
 
-FROM ubuntu AS helm
-ARG TARGETOS
-ARG TARGETARCH
-ARG HELM_VERSION=3.14.0
-ADD https://get.helm.sh/helm-v${HELM_VERSION}-${TARGETOS}-${TARGETARCH}.tar.gz /helm.tar.gz
-RUN tar -xzf /helm.tar.gz
-RUN mv /${TARGETOS}-${TARGETARCH}/helm /usr/bin/helm
+FROM golang:1.21 AS go-builder
+COPY go.mod go.sum /src/
+WORKDIR /src
+RUN go mod download
 
-FROM ubuntu AS ubuntu-cloud-archive
-ADD --chmod=644 https://git.launchpad.net/ubuntu/+source/ubuntu-keyring/plain/keyrings/ubuntu-cloud-keyring.gpg /etc/apt/trusted.gpg.d/ubuntu-cloud-keyring.gpg
-ARG RELEASE
-RUN <<EOF bash -xe
-source /etc/os-release
-if [ "\${VERSION_CODENAME}" = "jammy" ]; then \
-    if [ "${RELEASE}" = "yoga" ]; then \
-        # NOTE: Yoga shipped with 22.04, so no need to add an extra repository.
-        echo "" > /etc/apt/sources.list.d/cloudarchive.list; \
-    elif [ "${RELEASE}" = "zed" ]; then \
-        echo "deb http://ubuntu-cloud.archive.canonical.com/ubuntu \${VERSION_CODENAME}-updates/${RELEASE} main" > /etc/apt/sources.list.d/cloudarchive.list; \
-    elif [ "${RELEASE}" = "2023.1" ]; then \
-        echo "deb http://ubuntu-cloud.archive.canonical.com/ubuntu \${VERSION_CODENAME}-updates/antelope main" > /etc/apt/sources.list.d/cloudarchive.list; \
-    elif [ "${RELEASE}" = "2023.2" ]; then \
-        echo "deb http://ubuntu-cloud.archive.canonical.com/ubuntu \${VERSION_CODENAME}-updates/bobcat main" > /etc/apt/sources.list.d/cloudarchive.list; \
-    elif [ "${RELEASE}" = "master" ]; then \
-        echo "deb http://ubuntu-cloud.archive.canonical.com/ubuntu \${VERSION_CODENAME}-updates/caracal main" > /etc/apt/sources.list.d/cloudarchive.list; \
-    else \
-        echo "${RELEASE} is not supported on \${VERSION_CODENAME}"; \
-        exit 1; \
-    fi; \
-else
-    echo "Unsupported release"; \
-    exit 1; \
-fi
-EOF
+FROM go-builder AS libvirt-tls-sidecar-builder
+COPY cmd/ /src/cmd/
+COPY internal/ /src/internal/
+RUN go build -o main ./cmd/libvirt-tls-sidecar/main.go
 
-FROM alpine/git AS requirements
-ARG BRANCH
-ADD https://opendev.org/openstack/requirements.git#${BRANCH} /src
-RUN <<EOF sh -xe
-sed -i 's/cryptography===36.0.2/cryptography===42.0.4/' /src/upper-constraints.txt
-sed -i 's/cryptography===40.0.2/cryptography===42.0.4/' /src/upper-constraints.txt
-sed -i 's/cryptography===41.0.7/cryptography===42.0.4/' /src/upper-constraints.txt
-sed -i 's/Django===3.2.18/Django===3.2.24/' /src/upper-constraints.txt
-sed -i 's/Flask===2.2.3/Flask===2.2.5/' /src/upper-constraints.txt
-sed -i 's/Jinja2===3.1.2/Jinja2===3.1.3/' /src/upper-constraints.txt
-sed -i 's/oauthlib===3.2.0/oauthlib===3.2.2/' /src/upper-constraints.txt
-sed -i 's/paramiko===2.11.0/paramiko===3.4.0/' /src/upper-constraints.txt
-sed -i 's/paramiko===3.1.0/paramiko===3.4.0/' /src/upper-constraints.txt
-sed -i 's/protobuf===4.21.5/protobuf===4.21.6/' /src/upper-constraints.txt
-sed -i 's/pyOpenSSL===22.0.0/pyOpenSSL===24.0.0/' /src/upper-constraints.txt
-sed -i 's/pyOpenSSL===23.1.1/pyOpenSSL===24.0.0/' /src/upper-constraints.txt
-sed -i 's/requests===2.28.1/requests===2.31.0/' /src/upper-constraints.txt
-sed -i 's/requests===2.28.2/requests===2.31.0/' /src/upper-constraints.txt
-sed -i 's/sqlparse===0.4.2/sqlparse===0.4.4/' /src/upper-constraints.txt
-sed -i 's/urllib3===1.26.12/urllib3===1.26.18/' /src/upper-constraints.txt
-sed -i 's/urllib3===1.26.15/urllib3===1.26.18/' /src/upper-constraints.txt
-sed -i 's/Werkzeug===2.2.2/Werkzeug===2.3.8/' /src/upper-constraints.txt
-sed -i 's/Werkzeug===2.2.3/Werkzeug===2.3.8/' /src/upper-constraints.txt
-sed -i 's/zstd===1.5.2.5/zstd===1.5.4.0/' /src/upper-constraints.txt
-sed -i '/glance-store/d' /src/upper-constraints.txt
-sed -i '/horizon/d' /src/upper-constraints.txt
-EOF
-
-FROM ubuntu-cloud-archive AS openstack-venv-builder
-RUN <<EOF bash -xe
-apt-get update -qq
-apt-get install -qq -y --no-install-recommends \
-    build-essential \
-    git \
-    libldap2-dev \
-    libpcre3-dev \
-    libsasl2-dev \
-    libssl-dev \
-    lsb-release \
-    openssh-client \
-    python3 \
-    python3-dev \
-    python3-pip \
-    python3-venv
-EOF
-RUN <<EOF bash -xe
-python3 -m venv --upgrade-deps --system-site-packages /var/lib/openstack
-EOF
-ENV PATH=/var/lib/openstack/bin:$PATH
-COPY --link --from=requirements /src/upper-constraints.txt /upper-constraints.txt
-RUN <<EOF bash -xe
-pip3 install \
-    --constraint /upper-constraints.txt \
-        cryptography \
-        pymysql \
-        python-binary-memcached \
-        python-memcached \
-        uwsgi
-EOF
-
-FROM ubuntu-cloud-archive AS openstack-runtime
-RUN <<EOF bash -xe
-apt-get update -qq
-apt-get install -qq -y --no-install-recommends \
-    ca-certificates \
-    libpython3.10 \
-    lsb-release \
-    python3-distutils \
-    sudo
-EOF
-ARG PROJECT
-ARG SHELL=/usr/sbin/nologin
-RUN \
-    groupadd -g 42424 ${PROJECT} && \
-    useradd -u 42424 -g 42424 -M -d /var/lib/${PROJECT} -s ${SHELL} -c "${PROJECT} User" ${PROJECT} && \
-    mkdir -p /etc/${PROJECT} /var/log/${PROJECT} /var/lib/${PROJECT} /var/cache/${PROJECT} && \
-    chown -Rv ${PROJECT}:${PROJECT} /etc/${PROJECT} /var/log/${PROJECT} /var/lib/${PROJECT} /var/cache/${PROJECT}
-ENV PATH=/var/lib/openstack/bin:$PATH
-
-FROM alpine/git AS barbican-src
-ARG BARBICAN_GIT_REF
-ADD --keep-git-dir=true https://opendev.org/openstack/barbican.git#${BARBICAN_GIT_REF} /src
-RUN git -C /src fetch --unshallow
-
-FROM openstack-venv-builder AS barbican-build
-COPY --from=barbican-src --link /src /src/barbican
-RUN <<EOF bash -xe
-pip3 install \
-    --constraint /upper-constraints.txt \
-        /src/barbican \
-        pykmip
-EOF
-
-FROM openstack-runtime AS barbican
-COPY --from=barbican-build --link /var/lib/openstack /var/lib/openstack
-
-FROM alpine/git AS magnum-src
-ARG MAGNUM_GIT_REF
-ADD --keep-git-dir=true https://opendev.org/openstack/magnum.git#${MAGNUM_GIT_REF} /src
-RUN git -C /src fetch --unshallow
-ARG RELEASE
-COPY patches/${RELEASE}/magnum /patches
-RUN if [ -n "$(ls -A /patches/*.patch)" ]; then git -C /src apply --verbose /patches/*; fi
-
-FROM openstack-venv-builder AS magnum-build
-COPY --from=magnum-src --link /src /src/magnum
-RUN <<EOF bash -xe
-pip3 install \
-    --constraint /upper-constraints.txt \
-        /src/magnum \
-        magnum-cluster-api==0.16.0
-EOF
-
-FROM openstack-runtime AS magnum
-RUN <<EOF bash -xe
-apt-get update -qq
-apt-get install -qq -y --no-install-recommends \
-    haproxy
-apt-get clean
-rm -rf /var/lib/apt/lists/*
-EOF
-COPY --from=helm --link /usr/bin/helm /usr/local/bin/helm
-COPY --from=magnum-build --link /var/lib/openstack /var/lib/openstack
+FROM registry.atmosphere.dev/library/ubuntu:zed AS libvirt-tls-sidecar
+COPY --from=libvirt-tls-sidecar-builder /src/main /usr/bin/libvirt-tls-sidecar
+ENTRYPOINT ["/usr/bin/libvirt-tls-sidecar"]
diff --git a/Earthfile b/Earthfile
index e418ea9..3de16b3 100644
--- a/Earthfile
+++ b/Earthfile
@@ -36,47 +36,23 @@
     SAVE ARTIFACT /src/junit-go.xml AS LOCAL junit-go.xml
   END
 
+builder:
+  FROM ubuntu:jammy
+  RUN apt-get update -qq
+  RUN \
+    apt-get install -qq -y --no-install-recommends \
+      build-essential git python3-dev python3-pip python3-venv
+  ARG POETRY_VERSION=1.4.2
+  RUN pip3 install --no-cache-dir poetry==${POETRY_VERSION}
+
 build.collection:
   FROM registry.gitlab.com/pipeline-components/ansible-lint:latest
   COPY . /src
   RUN ansible-galaxy collection build /src
   SAVE ARTIFACT /code/*.tar.gz AS LOCAL dist/
 
-go.build:
-  FROM golang:1.21
-  WORKDIR /src
-  ARG GOOS=linux
-  ARG GOARCH=amd64
-  ARG VARIANT
-  COPY --dir go.mod go.sum ./
-  RUN go mod download
-
-libvirt-tls-sidecar.build:
-  FROM +go.build
-  ARG GOOS=linux
-  ARG GOARCH=amd64
-  ARG VARIANT
-  COPY --dir cmd internal ./
-  RUN GOARM=${VARIANT#"v"} go build -o main cmd/libvirt-tls-sidecar/main.go
-  SAVE ARTIFACT ./main
-
-libvirt-tls-sidecar.platform-image:
-  ARG TARGETPLATFORM
-  ARG TARGETARCH
-  ARG TARGETVARIANT
-  FROM --platform=$TARGETPLATFORM ./images/base+image
-  COPY \
-    --platform=linux/amd64 \
-    (+libvirt-tls-sidecar.build/main --GOARCH=$TARGETARCH --VARIANT=$TARGETVARIANT) /usr/bin/libvirt-tls-sidecar
-  ENTRYPOINT ["/usr/bin/libvirt-tls-sidecar"]
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push ${REGISTRY}/libvirt-tls-sidecar:latest
-
-libvirt-tls-sidecar.image:
-    BUILD --platform=linux/amd64 --platform=linux/arm64 +libvirt-tls-sidecar.platform-image
-
 build.wheels:
-  FROM ./images/builder+image
+  FROM +builder
   COPY pyproject.toml poetry.lock ./
   ARG --required only
   RUN poetry export --only=${only} -f requirements.txt --without-hashes > requirements.txt
@@ -114,10 +90,14 @@
   SAVE IMAGE --cache-hint
 
 image:
-  ARG RELEASE=2023.1
-  FROM ./images/cloud-archive-base+image --RELEASE ${RELEASE}
+  FROM ubuntu:jammy
   ENV ANSIBLE_PIPELINING=True
-  DO ./images+APT_INSTALL --PACKAGES "rsync openssh-client"
+  RUN \
+    apt-get update -qq && \
+    apt-get install -qq -y --no-install-recommends \
+      rsync openssh-client && \
+    apt-get clean && \
+    rm -rf /var/lib/apt/lists/*
   COPY +build.venv.runtime/venv /venv
   ENV PATH=/venv/bin:$PATH
   COPY +build.collections/ /usr/share/ansible
@@ -125,60 +105,6 @@
   ARG REGISTRY=ghcr.io/vexxhost/atmosphere
   SAVE IMAGE --push ${REGISTRY}:${tag}
 
-images:
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  BUILD +libvirt-tls-sidecar.image --REGISTRY=${REGISTRY}
-  BUILD ./images/cinder+image --REGISTRY=${REGISTRY}
-  BUILD ./images/cluster-api-provider-openstack+image --REGISTRY=${REGISTRY}
-  BUILD ./images/designate+image --REGISTRY=${REGISTRY}
-  BUILD ./images/glance+image --REGISTRY=${REGISTRY}
-  BUILD ./images/heat+image --REGISTRY=${REGISTRY}
-  BUILD ./images/horizon+image --REGISTRY=${REGISTRY}
-  BUILD ./images/ironic+image --REGISTRY=${REGISTRY}
-  BUILD ./images/keystone+image --REGISTRY=${REGISTRY}
-  BUILD ./images/kubernetes-entrypoint+image --REGISTRY=${REGISTRY}
-  BUILD ./images/libvirtd+image --REGISTRY=${REGISTRY}
-  BUILD ./images/magnum+image --REGISTRY=${REGISTRY}
-  BUILD ./images/manila+image --REGISTRY=${REGISTRY}
-  BUILD ./images/netoffload+image --REGISTRY=${REGISTRY}
-  BUILD ./images/neutron+image --REGISTRY=${REGISTRY}
-  BUILD ./images/nova-ssh+image --REGISTRY=${REGISTRY}
-  BUILD ./images/nova+image --REGISTRY=${REGISTRY}
-  BUILD ./images/octavia+image --REGISTRY=${REGISTRY}
-  BUILD ./images/openvswitch+image --REGISTRY=${REGISTRY}
-  BUILD ./images/ovn+images --REGISTRY=${REGISTRY}
-  BUILD ./images/placement+image --REGISTRY=${REGISTRY}
-  BUILD ./images/senlin+image --REGISTRY=${REGISTRY}
-  BUILD ./images/staffeln+image --REGISTRY=${REGISTRY}
-  BUILD ./images/tempest+image --REGISTRY=${REGISTRY}
-
-SCAN_IMAGE:
-  FUNCTION
-  ARG --required IMAGE
-  # TODO(mnaser): Include secret scanning when it's more reliable.
-  RUN \
-    trivy image \
-      --skip-db-update \
-      --skip-java-db-update \
-      --scanners vuln \
-      --exit-code 1 \
-      --ignore-unfixed \
-      --timeout 10m \
-      ${IMAGE}
-
-scan-image:
-  FROM ./images/trivy+image
-  ARG --required IMAGE
-  DO +SCAN_IMAGE --IMAGE ${IMAGE}
-
-scan-images:
-  FROM ./images/trivy+image
-  COPY roles/defaults/vars/main.yml /defaults.yml
-  # TODO(mnaser): Scan all images eventually
-  FOR IMAGE IN $(cat /defaults.yml | egrep -E 'ghcr.io/vexxhost|registry.atmosphere.dev' | cut -d' ' -f4 | sort | uniq)
-    BUILD +scan-image --IMAGE ${IMAGE}
-  END
-
 pin-images:
   FROM +build.venv.dev
   COPY roles/defaults/vars/main.yml /defaults.yml
diff --git a/docker-bake.hcl b/docker-bake.hcl
deleted file mode 100644
index 7237361..0000000
--- a/docker-bake.hcl
+++ /dev/null
@@ -1,98 +0,0 @@
-variable "REGISTRY" {
-    default = "registry.atmosphere.dev/library"
-}
-
-variable "CACHE_REGISTRY" {
-    default = "registry.atmosphere.dev/cache"
-}
-
-variable "PUSH_TO_CACHE" {
-    default = false
-}
-
-function "cache_from" {
-    params = [image]
-    result = ["type=registry,ref=${CACHE_REGISTRY}/${image}"]
-}
-
-function "cache_to" {
-    params = [image]
-    result = PUSH_TO_CACHE ? [format("%s,%s", cache_from(image)[0], "mode=max,image-manifest=true,oci-mediatypes=true,compression=zstd")] : []
-}
-
-target "barbican" {
-    name = "barbican-${release.tgt}"
-
-    context = "."
-    target = "barbican"
-
-    cache-from = cache_from("barbican:${release.name}")
-    cache-to = cache_to("barbican:${release.name}")
-
-    tags = [
-        "${REGISTRY}/barbican:${release.name}",
-        "${REGISTRY}/barbican:${release.ref}"
-    ]
-
-    matrix = {
-        release = [
-            {
-                tgt = "bobcat",
-                name = "2023.2",
-                ref = "a00fcade4138ffc52cd9c84b5999297966f019b5"
-            }
-        ]
-    }
-
-    args = {
-        RELEASE = release.name
-        BRANCH = format("stable/%s", release.name)
-        PROJECT = "barbican"
-        BARBICAN_GIT_REF = release.ref
-    }
-}
-
-target "magnum" {
-    name = "magnum-${release.tgt}"
-
-    context = "."
-    target = "magnum"
-
-    cache-from = cache_from("magnum:${release.name}")
-    cache-to = cache_to("magnum:${release.name}")
-
-    tags = [
-        "${REGISTRY}/magnum:${release.name}",
-        "${REGISTRY}/magnum:${release.ref}"
-    ]
-
-    matrix = {
-        release = [
-            {
-                tgt = "zed",
-                name = "zed",
-                ref = "0ee979099a01ae2c8b1b5d6757897a8993e4e34c"
-            },
-            {
-                tgt = "bobcat",
-                name = "2023.2",
-                ref = "5f921a72d22d7e96fb3584c4906a39de9a085a41"
-            }
-        ]
-    }
-
-    args = {
-        RELEASE = release.name
-        BRANCH = format("stable/%s", release.name)
-        PROJECT = "magnum"
-        MAGNUM_GIT_REF = release.ref
-    }
-}
-
-
-group "default" {
-    targets = [
-        "barbican",
-        "magnum"
-    ]
-}
diff --git a/images/Earthfile b/images/Earthfile
deleted file mode 100644
index 32cab4a..0000000
--- a/images/Earthfile
+++ /dev/null
@@ -1,52 +0,0 @@
-VERSION 0.8
-
-APT_INSTALL:
-  FUNCTION
-  ARG PACKAGES
-  RUN \
-    apt-get update && \
-    DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y ${PACKAGES} && \
-    apt-get clean && \
-    rm -rf /var/lib/apt/lists/*
-
-DNF_INSTALL:
-  FUNCTION
-  ARG PACKAGES
-  RUN \
-    dnf -y install \
-      ${PACKAGES} \
-      --setopt=install_weak_deps=False \
-      --setopt=tsflags=nodocs && \
-    dnf -y clean all && \
-    rm -rf /var/cache/dnf
-
-CREATE_PROJECT_USER:
-  FUNCTION
-  ARG PROJECT
-  ARG SHELL=/usr/sbin/nologin
-  RUN \
-    groupadd -g 42424 ${PROJECT} && \
-    useradd -u 42424 -g 42424 -M -d /var/lib/${PROJECT} -s ${SHELL} -c "${PROJECT} User" ${PROJECT} && \
-    mkdir -p /etc/${PROJECT} /var/log/${PROJECT} /var/lib/${PROJECT} /var/cache/${PROJECT} && \
-    chown -Rv ${PROJECT}:${PROJECT} /etc/${PROJECT} /var/log/${PROJECT} /var/lib/${PROJECT} /var/cache/${PROJECT}
-
-fetch-gerrit-patch:
-  FROM ./base+image
-  DO +APT_INSTALL --PACKAGES "ca-certificates curl git jq"
-  ARG --required IMAGE
-  ARG PROJECT=${IMAGE}
-  ARG --required CHANGE
-  ARG PROJECT_REF=master
-  DO ./openstack-service+GIT_CHECKOUT \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF}
-  ARG REF=$(curl "https://review.opendev.org/changes/?q=${CHANGE}&o=CURRENT_REVISION" | tail -1 | jq -r '.[0].revisions[].ref')
-  COPY ${IMAGE}/patches/${PROJECT} /patches
-  RUN \
-    git fetch https://review.opendev.org/openstack/${PROJECT} ${REF} && \
-    git format-patch -1 --output-directory /gerrit FETCH_HEAD
-  ARG PATCH_ID=$(ls -1 /patches | wc -l | xargs printf "%04d")
-  RUN \
-    cp /gerrit/0001-* \
-    /patches/${PATCH_ID}-$(basename /gerrit/*.patch | sed 's/0001-//')
-  SAVE ARTIFACT /patches AS LOCAL ${IMAGE}/patches/${PROJECT}
diff --git a/images/barbican/Dockerfile b/images/barbican/Dockerfile
new file mode 100644
index 0000000..e121478
--- /dev/null
+++ b/images/barbican/Dockerfile
@@ -0,0 +1,27 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG BARBICAN_GIT_REF=7d6749fcb1ad16a3350de82cd8e523d5b55306f8
+ADD --keep-git-dir=true https://opendev.org/openstack/barbican.git#${BARBICAN_GIT_REF} /src/barbican
+RUN git -C /src/barbican fetch --unshallow
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/barbican \
+        pykmip
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/base/Earthfile b/images/base/Earthfile
deleted file mode 100644
index 8b7b2df..0000000
--- a/images/base/Earthfile
+++ /dev/null
@@ -1,7 +0,0 @@
-VERSION 0.7
-
-image:
-  FROM ubuntu:jammy-20240212
-  LABEL org.opencontainers.image.source=https://github.com/vexxhost/atmosphere
-  # CVE-2023-4641
-  DO ../+APT_INSTALL --PACKAGES "login=1:4.8.1-2ubuntu2.2 passwd=1:4.8.1-2ubuntu2.2"
diff --git a/images/build.sh b/images/build.sh
deleted file mode 100755
index d93f853..0000000
--- a/images/build.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/bash -xe
-
-TARGET=""
-PUSH=false
-
-while [[ $# -gt 0 ]]; do
-    key="$1"
-
-    case $key in
-        --push)
-        PUSH=true
-        shift
-        ;;
-        *)
-        if [ -z "$TARGET" ]; then
-            TARGET="$1"
-        else
-            echo "Invalid argument: $1"
-            exit 1
-        fi
-        shift
-        ;;
-    esac
-done
-
-if [ -z "$TARGET" ]; then
-    echo "Usage: $0 [--push] <target>"
-    exit 1
-fi
-
-docker buildx create --name=atmosphere --driver=docker-container || true
-
-if [ "$PUSH" = true ]; then
-    docker buildx bake --builder=atmosphere --provenance --sbom=true --push $TARGET
-
-    # Sign all images
-    export COSIGN_PASSWORD=""
-    for IMAGE in $(docker buildx bake --print ${TARGET} | jq -r '.target[].tags | select(. != null)[]'); do
-        cosign sign -y --recursive --key cosign.key ${IMAGE}
-    done
-else
-    docker buildx bake --builder=atmosphere --provenance --sbom=true $TARGET
-fi
diff --git a/images/builder/Earthfile b/images/builder/Earthfile
deleted file mode 100644
index f4e92d3..0000000
--- a/images/builder/Earthfile
+++ /dev/null
@@ -1,7 +0,0 @@
-VERSION 0.7
-
-image:
-  FROM ../base+image
-  DO ../+APT_INSTALL --PACKAGES "build-essential git python3-dev python3-pip python3-venv"
-  ARG POETRY_VERSION=1.4.2
-  RUN pip3 install --no-cache-dir poetry==${POETRY_VERSION}
diff --git a/images/cinder/Dockerfile b/images/cinder/Dockerfile
new file mode 100644
index 0000000..4c8f153
--- /dev/null
+++ b/images/cinder/Dockerfile
@@ -0,0 +1,35 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG CINDER_GIT_REF=f74e2729554bee01b0a3e631a8001bb39e540433
+ADD --keep-git-dir=true https://opendev.org/openstack/cinder.git#${CINDER_GIT_REF} /src/cinder
+RUN git -C /src/cinder fetch --unshallow
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/cinder \
+        purestorage
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    ceph-common lsscsi nvme-cli python3-rados python3-rbd qemu-utils sysfsutils udev util-linux
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+ADD --chmod=755 https://dl.k8s.io/release/v1.29.3/bin/linux/amd64/kubectl /usr/local/bin/kubectl
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/cinder/Earthfile b/images/cinder/Earthfile
deleted file mode 100644
index 79561e7..0000000
--- a/images/cinder/Earthfile
+++ /dev/null
@@ -1,23 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=cinder
-ARG --global RELEASE=2023.2
-ARG --global PROJECT_REF=6abf43c220029bd47ec446971e14e293c9be2f78
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF} \
-    --PIP_PACKAGES="purestorage"
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  COPY ../kubernetes+image/kubectl /usr/local/bin/kubectl
-  DO ../+APT_INSTALL \
-    --PACKAGES "ceph-common lsscsi nvme-cli python3-rados python3-rbd qemu-utils sysfsutils udev util-linux"
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/images/cloud-archive-base/Earthfile b/images/cloud-archive-base/Earthfile
deleted file mode 100644
index 473d5d8..0000000
--- a/images/cloud-archive-base/Earthfile
+++ /dev/null
@@ -1,23 +0,0 @@
-VERSION 0.7
-
-image:
-  FROM ../base+image
-  DO ../+APT_INSTALL --PACKAGES "ca-certificates libpython3.10 lsb-release python3-distutils sudo ubuntu-cloud-keyring"
-  ARG RELEASE
-  IF [ "$(lsb_release -sc)" = "jammy" ]
-    IF [ "${RELEASE}" = "yoga" ]
-      # NOTE: Yoga shipped with 22.04, so no need to add an extra repository.
-      RUN echo "" > /etc/apt/sources.list.d/cloudarchive.list
-    ELSE IF [ "${RELEASE}" = "zed" ]
-      RUN echo "deb http://ubuntu-cloud.archive.canonical.com/ubuntu $(lsb_release -sc)-updates/${RELEASE} main" > /etc/apt/sources.list.d/cloudarchive.list
-    ELSE IF [ "${RELEASE}" = "2023.1" ]
-      RUN echo "deb http://ubuntu-cloud.archive.canonical.com/ubuntu $(lsb_release -sc)-updates/antelope main" > /etc/apt/sources.list.d/cloudarchive.list
-    ELSE IF [ "${RELEASE}" = "2023.2" ]
-      RUN echo "deb http://ubuntu-cloud.archive.canonical.com/ubuntu $(lsb_release -sc)-updates/bobcat main" > /etc/apt/sources.list.d/cloudarchive.list
-    ELSE IF [ "${RELEASE}" = "master" ]
-      RUN echo "deb http://ubuntu-cloud.archive.canonical.com/ubuntu $(lsb_release -sc)-updates/caracal main" > /etc/apt/sources.list.d/cloudarchive.list
-    ELSE
-      RUN echo "${RELEASE} is not supported on $(lsb_release -sc)"
-      RUN exit 1
-    END
-  END
diff --git a/images/cluster-api-provider-openstack/Dockerfile b/images/cluster-api-provider-openstack/Dockerfile
new file mode 100644
index 0000000..aa05489
--- /dev/null
+++ b/images/cluster-api-provider-openstack/Dockerfile
@@ -0,0 +1,32 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM alpine/git:2.43.0 AS src
+ARG CAPO_VERSION=v0.9.0
+ADD https://github.com/kubernetes-sigs/cluster-api-provider-openstack.git#${CAPO_VERSION} /src
+WORKDIR /src
+COPY /patches /patches
+RUN git apply /patches/*.patch
+
+FROM golang:1.20 AS builder
+COPY --from=src --link /src /src
+WORKDIR /src
+ARG ARCH
+RUN CGO_ENABLED=0 GOOS=linux GOARCH=${ARCH} \
+    go build -ldflags "-extldflags '-static'" -o manager ${package}
+
+FROM gcr.io/distroless/static:nonroot
+COPY --from=builder /src/manager /manager
+USER 65532
+ENTRYPOINT ["/manager"]
diff --git a/images/cluster-api-provider-openstack/Earthfile b/images/cluster-api-provider-openstack/Earthfile
deleted file mode 100644
index 111f465..0000000
--- a/images/cluster-api-provider-openstack/Earthfile
+++ /dev/null
@@ -1,18 +0,0 @@
-VERSION 0.7
-
-ARG --global CAPO_VERSION=v0.8.0
-ARG --global EPOCH=2
-
-clone:
-  FROM ../builder+image
-  GIT CLONE --branch ${CAPO_VERSION} https://github.com/kubernetes-sigs/cluster-api-provider-openstack /workspace/src
-  WORKDIR /workspace/src
-  COPY patches /workspace/patches
-  RUN git apply --verbose /workspace/patches/*.patch
-  SAVE ARTIFACT /workspace/src
-
-image:
-  FROM DOCKERFILE -f +clone/src/Dockerfile +clone/src/*
-  LABEL org.opencontainers.image.source=https://github.com/vexxhost/atmosphere
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push ${REGISTRY}/capi-openstack-controller:${CAPO_VERSION}-${EPOCH}
diff --git a/images/cluster-api-provider-openstack/patches/0001-chore-bump-k8s-api-for-cve.patch b/images/cluster-api-provider-openstack/patches/0001-chore-bump-k8s-api-for-cve.patch
index 2812ac5..cd99927 100644
--- a/images/cluster-api-provider-openstack/patches/0001-chore-bump-k8s-api-for-cve.patch
+++ b/images/cluster-api-provider-openstack/patches/0001-chore-bump-k8s-api-for-cve.patch
@@ -1,158 +1,89 @@
-From 139a57e7b0d4c57033e281b061e459039a5e21d3 Mon Sep 17 00:00:00 2001
+From eed5b5cc2a6cf48c0c9e0245695d0ac143150186 Mon Sep 17 00:00:00 2001
 From: Mohammed Naser <mnaser@vexxhost.com>
-Date: Mon, 22 Jan 2024 16:22:52 -0500
-Subject: [PATCH 2/2] chore: bump k8s api for cve
+Date: Tue, 12 Mar 2024 18:18:25 -0400
+Subject: [PATCH] chore: bump k8s api for cve
 
 ---
- go.mod | 17 +++++++++--------
- go.sum | 36 +++++++++++++++++++-----------------
- 2 files changed, 28 insertions(+), 25 deletions(-)
+ go.mod |  8 ++++----
+ go.sum | 16 ++++++++--------
+ 2 files changed, 12 insertions(+), 12 deletions(-)
 
 diff --git a/go.mod b/go.mod
-index db4a954a..49d2f7cf 100644
+index 997f8354..d6c300cc 100644
 --- a/go.mod
 +++ b/go.mod
-@@ -15,8 +15,8 @@ require (
- 	github.com/onsi/gomega v1.27.8
- 	github.com/prometheus/client_golang v1.16.0
+@@ -15,7 +15,7 @@ require (
+ 	github.com/onsi/gomega v1.30.0
+ 	github.com/prometheus/client_golang v1.17.0
  	github.com/spf13/pflag v1.0.5
--	golang.org/x/crypto v0.11.0
--	golang.org/x/text v0.11.0
-+	golang.org/x/crypto v0.14.0
-+	golang.org/x/text v0.13.0
+-	golang.org/x/crypto v0.15.0
++	golang.org/x/crypto v0.17.0
+ 	golang.org/x/text v0.14.0
  	gopkg.in/ini.v1 v1.67.0
- 	k8s.io/api v0.27.2
- 	k8s.io/apiextensions-apiserver v0.27.2
+ 	k8s.io/api v0.28.4
 @@ -24,7 +24,7 @@ require (
- 	k8s.io/client-go v0.27.2
- 	k8s.io/component-base v0.27.2
- 	k8s.io/klog/v2 v2.90.1
--	k8s.io/kubernetes v1.27.2
-+	k8s.io/kubernetes v1.27.8
- 	k8s.io/utils v0.0.0-20230313181309-38a27ef9d749
- 	sigs.k8s.io/cluster-api v1.5.1
- 	sigs.k8s.io/cluster-api/test v1.5.1
-@@ -113,15 +113,16 @@ require (
- 	go.uber.org/multierr v1.11.0 // indirect
- 	go.uber.org/zap v1.24.0 // indirect
- 	golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
--	golang.org/x/net v0.13.0 // indirect
-+	golang.org/x/net v0.17.0 // indirect
- 	golang.org/x/oauth2 v0.10.0 // indirect
--	golang.org/x/sys v0.10.0 // indirect
--	golang.org/x/term v0.10.0 // indirect
-+	golang.org/x/sys v0.13.0 // indirect
-+	golang.org/x/term v0.13.0 // indirect
+ 	k8s.io/client-go v0.28.4
+ 	k8s.io/component-base v0.28.4
+ 	k8s.io/klog/v2 v2.100.1
+-	k8s.io/kubernetes v1.28.3
++	k8s.io/kubernetes v1.28.4
+ 	k8s.io/utils v0.0.0-20230406110748-d93618cff8a2
+ 	sigs.k8s.io/cluster-api v1.6.0
+ 	sigs.k8s.io/cluster-api/test v1.6.0
+@@ -139,8 +139,8 @@ require (
+ 	golang.org/x/net v0.18.0 // indirect
+ 	golang.org/x/oauth2 v0.14.0 // indirect
+ 	golang.org/x/sync v0.4.0 // indirect
+-	golang.org/x/sys v0.14.0 // indirect
+-	golang.org/x/term v0.14.0 // indirect
++	golang.org/x/sys v0.15.0 // indirect
++	golang.org/x/term v0.15.0 // indirect
  	golang.org/x/time v0.3.0 // indirect
--	golang.org/x/tools v0.9.3 // indirect
-+	golang.org/x/tools v0.12.0 // indirect
- 	gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
- 	google.golang.org/appengine v1.6.7 // indirect
--	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
-+	google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a // indirect
-+	google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
- 	google.golang.org/protobuf v1.31.0 // indirect
- 	gopkg.in/inf.v0 v0.9.1 // indirect
- 	gopkg.in/yaml.v2 v2.4.0 // indirect
+ 	golang.org/x/tools v0.14.0 // indirect
+ 	gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
 diff --git a/go.sum b/go.sum
-index 66bd8109..f18ece49 100644
+index e3d46fdc..f5767735 100644
 --- a/go.sum
 +++ b/go.sum
-@@ -516,8 +516,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
+@@ -460,8 +460,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
  golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
  golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
  golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
--golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
--golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
-+golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
-+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+-golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
+-golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
++golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
++golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
  golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
  golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
  golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
-@@ -555,7 +555,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
- golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
- golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
- golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
--golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
-+golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
- golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
- golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
- golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-@@ -596,8 +596,8 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx
- golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
- golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
- golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
--golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY=
--golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
-+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
-+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
- golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
- golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
- golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-@@ -673,13 +673,13 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
- golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+@@ -609,13 +609,13 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
  golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
  golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
--golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
--golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
-+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+-golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
+-golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
++golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
++golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
  golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
  golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
  golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
--golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
--golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
-+golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
-+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
+-golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
+-golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
++golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
++golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
  golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
  golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
  golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-@@ -690,8 +690,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
- golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
- golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
- golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
--golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
--golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-+golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
-+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
- golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
- golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
- golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-@@ -752,8 +752,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
- golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
- golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
- golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
--golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
--golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
-+golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
-+golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
- golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
- golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
- golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-@@ -825,8 +825,10 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D
- google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
- google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
- google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
--google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
--google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
-+google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a h1:HiYVD+FGJkTo+9zj1gqz0anapsa1JxjiSrN+BJKyUmE=
-+google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8=
-+google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
-+google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
- google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
- google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
- google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-@@ -914,8 +916,8 @@ k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
- k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
- k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
- k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
--k8s.io/kubernetes v1.27.2 h1:g4v9oY6u7vBUDEuq4FvC50Bbw2K7GZuvM00IIESWVf4=
--k8s.io/kubernetes v1.27.2/go.mod h1:U8ZXeKBAPxeb4J4/HOaxjw1A9K6WfSH+fY2SS7CR6IM=
-+k8s.io/kubernetes v1.27.8 h1:K848lTo/D0jvrxUlTvw4nNADixbhXLHgKNDP/KlFGy8=
-+k8s.io/kubernetes v1.27.8/go.mod h1:PUXXrx0IhAi+kI9BMDqNJHUnLndVv9W0DkriqyjuJOs=
- k8s.io/utils v0.0.0-20230313181309-38a27ef9d749 h1:xMMXJlJbsU8w3V5N2FLDQ8YgU8s1EoULdbQBcAeNJkY=
- k8s.io/utils v0.0.0-20230313181309-38a27ef9d749/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+@@ -841,8 +841,8 @@ k8s.io/kms v0.28.4 h1:PMgY/3CQTWP9eIKmNQiTgjLIZ0ns6O+voagzD2/4mSg=
+ k8s.io/kms v0.28.4/go.mod h1:HL4/lR/bhjAJPbqycKtfhWiKh1Sp21cpHOL8P4oo87w=
+ k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ=
+ k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM=
+-k8s.io/kubernetes v1.28.3 h1:XTci6gzk+JR51UZuZQCFJ4CsyUkfivSjLI4O1P9z6LY=
+-k8s.io/kubernetes v1.28.3/go.mod h1:NhAysZWvHtNcJFFHic87ofxQN7loylCQwg3ZvXVDbag=
++k8s.io/kubernetes v1.28.4 h1:aRNxs5jb8FVTtlnxeA4FSDBVKuFwA8Gw40/U2zReBYA=
++k8s.io/kubernetes v1.28.4/go.mod h1:BTzDCKYAlu6LL9ITbfjwgwIrJ30hlTgbv0eXDoA/WoA=
+ k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk=
+ k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
  rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 -- 
 2.43.0
-
diff --git a/images/curl/Earthfile b/images/curl/Earthfile
deleted file mode 100644
index 06d3d8e..0000000
--- a/images/curl/Earthfile
+++ /dev/null
@@ -1,5 +0,0 @@
-VERSION 0.7
-
-image:
-  FROM curlimages/curl:7.78.0
-  WORKDIR /tmp
diff --git a/images/designate/Dockerfile b/images/designate/Dockerfile
new file mode 100644
index 0000000..e1610c8
--- /dev/null
+++ b/images/designate/Dockerfile
@@ -0,0 +1,33 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG DESIGNATE_GIT_REF=d247267823034c5e656f74e91b50475aa54d3fa6
+ADD --keep-git-dir=true https://opendev.org/openstack/designate.git#${DESIGNATE_GIT_REF} /src/designate
+RUN git -C /src/designate fetch --unshallow
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/designate
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    bind9utils
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/designate/Earthfile b/images/designate/Earthfile
deleted file mode 100644
index 65e5af8..0000000
--- a/images/designate/Earthfile
+++ /dev/null
@@ -1,21 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=designate
-ARG --global RELEASE=2023.2
-ARG --global PROJECT_REF=2c817b3d7f01de44023f195c6e8de8853683a54a
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF}
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  DO ../+APT_INSTALL \
-    --PACKAGES "bind9utils"
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/images/glance/Dockerfile b/images/glance/Dockerfile
new file mode 100644
index 0000000..2965d44
--- /dev/null
+++ b/images/glance/Dockerfile
@@ -0,0 +1,39 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG GLANCE_GIT_REF=06a18202ab52c64803f044b8f848ed1c160905d2
+ADD --keep-git-dir=true https://opendev.org/openstack/glance.git#${GLANCE_GIT_REF} /src/glance
+RUN git -C /src/glance fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/glance_store.git#stable/zed /src/glance_store
+RUN git -C /src/glance_store fetch --unshallow
+COPY patches/glance_store /patches/glance_store
+RUN git -C /src/glance_store apply --verbose /patches/glance_store/*
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/glance \
+        /src/glance_store[cinder]
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    ceph-common lsscsi nvme-cli python3-rados python3-rbd qemu-utils sysfsutils udev util-linux
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+ADD --chmod=755 https://dl.k8s.io/release/v1.29.3/bin/linux/amd64/kubectl /usr/local/bin/kubectl
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/glance/Earthfile b/images/glance/Earthfile
deleted file mode 100644
index 2646670..0000000
--- a/images/glance/Earthfile
+++ /dev/null
@@ -1,32 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=glance
-ARG --global RELEASE=2023.2
-ARG --global PROJECT_REF=9a4a3067b5c7c7f8ee9363bd939a3d86b260d660
-
-build.plugin:
-  ARG PLUGIN
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+GIT_CHECKOUT \
-    --PROJECT=${PLUGIN} \
-    --PROJECT_REF=stable/${RELEASE}
-  SAVE ARTIFACT /src
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  COPY (+build.plugin/src --PLUGIN=glance_store) /glance_store
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF} \
-    --PIP_PACKAGES="/glance_store[cinder]"
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  COPY ../kubernetes+image/kubectl /usr/local/bin/kubectl
-  DO ../+APT_INSTALL \
-    --PACKAGES "ceph-common lsscsi nvme-cli python3-rados python3-rbd qemu-utils sysfsutils udev util-linux"
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/images/heat/Dockerfile b/images/heat/Dockerfile
new file mode 100644
index 0000000..1162298
--- /dev/null
+++ b/images/heat/Dockerfile
@@ -0,0 +1,33 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG HEAT_GIT_REF=d3948706a3ff28d0160157f76f1e18244a8dad5c
+ADD --keep-git-dir=true https://opendev.org/openstack/heat.git#${HEAT_GIT_REF} /src/heat
+RUN git -C /src/heat fetch --unshallow
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/heat
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    curl jq
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/heat/Earthfile b/images/heat/Earthfile
deleted file mode 100644
index 8c3ebcd..0000000
--- a/images/heat/Earthfile
+++ /dev/null
@@ -1,21 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=heat
-ARG --global RELEASE=2023.2
-ARG --global PROJECT_REF=d1363cc17646893054f9e8daf40de67699078e7c
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF}
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  DO ../+APT_INSTALL \
-    --PACKAGES "curl jq"
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/images/helm/Earthfile b/images/helm/Earthfile
deleted file mode 100644
index d0b5155..0000000
--- a/images/helm/Earthfile
+++ /dev/null
@@ -1,11 +0,0 @@
-VERSION 0.7
-
-binary:
-  FROM ../curl+image
-  ARG TARGETOS
-  ARG TARGETARCH
-  ARG VERSION=3.14.0
-  RUN curl -LO https://get.helm.sh/helm-v3.14.0-${TARGETOS}-${TARGETARCH}.tar.gz
-  RUN tar -zxvf /tmp/helm-v3.14.0-${TARGETOS}-${TARGETARCH}.tar.gz
-  RUN ${TARGETOS}-${TARGETARCH}/helm version
-  SAVE ARTIFACT ${TARGETOS}-${TARGETARCH}/helm
diff --git a/images/horizon/Dockerfile b/images/horizon/Dockerfile
new file mode 100644
index 0000000..58e8a65
--- /dev/null
+++ b/images/horizon/Dockerfile
@@ -0,0 +1,61 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG HORIZON_GIT_REF=5de40f9b222608d35c5a0919117259e966217a86
+ADD --keep-git-dir=true https://opendev.org/openstack/horizon.git#${HORIZON_GIT_REF} /src/horizon
+RUN git -C /src/horizon fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/designate-dashboard.git#stable/zed /src/designate-dashboard
+RUN git -C /src/designate-dashboard fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/heat-dashboard.git#stable/zed /src/heat-dashboard
+RUN git -C /src/heat-dashboard fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/ironic-ui.git#stable/zed /src/ironic-ui
+RUN git -C /src/ironic-ui fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/magnum-ui.git#stable/zed /src/magnum-ui
+RUN git -C /src/magnum-ui fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/manila-ui.git#stable/zed /src/manila-ui
+RUN git -C /src/manila-ui fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/neutron-vpnaas-dashboard.git#stable/zed /src/neutron-vpnaas-dashboard
+RUN git -C /src/neutron-vpnaas-dashboard fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/octavia-dashboard.git#stable/zed /src/octavia-dashboard
+RUN git -C /src/octavia-dashboard fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/senlin-dashboard.git#stable/zed /src/senlin-dashboard
+RUN git -C /src/senlin-dashboard fetch --unshallow
+COPY patches/horizon /patches/horizon
+RUN git -C /src/horizon apply --verbose /patches/horizon/*
+COPY patches/magnum-ui /patches/magnum-ui
+RUN git -C /src/magnum-ui apply --verbose /patches/magnum-ui/*
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/designate-dashboard \
+        /src/heat-dashboard \
+        /src/horizon \
+        /src/ironic-ui \
+        /src/magnum-ui \
+        /src/manila-ui \
+        /src/neutron-vpnaas-dashboard \
+        /src/octavia-dashboard \
+        /src/senlin-dashboard
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    apache2 gettext libapache2-mod-wsgi-py3
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/horizon/Earthfile b/images/horizon/Earthfile
deleted file mode 100644
index 4a895ce..0000000
--- a/images/horizon/Earthfile
+++ /dev/null
@@ -1,38 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=horizon
-ARG --global RELEASE=2023.2
-ARG --global PROJECT_REF=4de36bb649c514f50d2a958c9277097a08b23cec
-
-build.plugin:
-  ARG PLUGIN
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+GIT_CHECKOUT \
-    --PROJECT=${PLUGIN} \
-    --PROJECT_REF=stable/${RELEASE}
-  SAVE ARTIFACT /src
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  COPY (+build.plugin/src --PLUGIN=designate-dashboard) /designate-dashboard
-  COPY (+build.plugin/src --PLUGIN=heat-dashboard) /heat-dashboard
-  COPY (+build.plugin/src --PLUGIN=ironic-ui) /ironic-ui
-  COPY (+build.plugin/src --PLUGIN=magnum-ui) /magnum-ui
-  COPY (+build.plugin/src --PLUGIN=manila-ui) /manila-ui
-  COPY (+build.plugin/src --PLUGIN=neutron-vpnaas-dashboard) /neutron-vpnaas-dashboard
-  COPY (+build.plugin/src --PLUGIN=octavia-dashboard) /octavia-dashboard
-  COPY (+build.plugin/src --PLUGIN=senlin-dashboard) /senlin-dashboard
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF} \
-    --PIP_PACKAGES "/designate-dashboard /heat-dashboard /ironic-ui /magnum-ui /neutron-vpnaas-dashboard /octavia-dashboard /senlin-dashboard /manila-ui"
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  DO ../+APT_INSTALL \
-    --PACKAGES "apache2 gettext libapache2-mod-wsgi-py3"
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/images/ironic/Dockerfile b/images/ironic/Dockerfile
new file mode 100644
index 0000000..614985a
--- /dev/null
+++ b/images/ironic/Dockerfile
@@ -0,0 +1,35 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG IRONIC_GIT_REF=995fa6c048297211deceddb05b00bbd34ef27eb6
+ADD --keep-git-dir=true https://opendev.org/openstack/ironic.git#${IRONIC_GIT_REF} /src/ironic
+RUN git -C /src/ironic fetch --unshallow
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/ironic \
+        python-dracclient \
+        sushy
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    ethtool ipmitool iproute2 ipxe lshw qemu-utils tftpd-hpa
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/ironic/Earthfile b/images/ironic/Earthfile
deleted file mode 100644
index 0f775a4..0000000
--- a/images/ironic/Earthfile
+++ /dev/null
@@ -1,22 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=ironic
-ARG --global RELEASE=zed
-ARG --global PROJECT_REF=e38735cb95263b0c54f2fd719ff6b714efbddbb3
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF} \
-    --PIP_PACKAGES "python-dracclient sushy"
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  DO ../+APT_INSTALL \
-    --PACKAGES "ethtool ipmitool iproute2 ipxe lshw qemu-utils tftpd-hpa"
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/images/keystone/Dockerfile b/images/keystone/Dockerfile
new file mode 100644
index 0000000..cf9daaf
--- /dev/null
+++ b/images/keystone/Dockerfile
@@ -0,0 +1,49 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG KEYSTONE_GIT_REF=f63062d47712406a807ce07b4ff3ec6213b0e824
+ADD --keep-git-dir=true https://opendev.org/openstack/keystone.git#${KEYSTONE_GIT_REF} /src/keystone
+RUN git -C /src/keystone fetch --unshallow
+COPY patches/keystone /patches/keystone
+RUN git -C /src/keystone apply --verbose /patches/keystone/*
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/keystone[ldap] \
+        keystone-keycloak-backend==0.1.8
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    apache2 libapache2-mod-wsgi-py3
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+ARG MOD_AUTH_OPENIDC_VERSION=2.4.12.1
+ARG TARGETARCH
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    curl
+curl -LO https://github.com/OpenIDC/mod_auth_openidc/releases/download/v${MOD_AUTH_OPENIDC_VERSION}/libapache2-mod-auth-openidc_${MOD_AUTH_OPENIDC_VERSION}-1.$(lsb_release -sc)_${TARGETARCH}.deb
+apt-get install -y --no-install-recommends ./libapache2-mod-auth-openidc_${MOD_AUTH_OPENIDC_VERSION}-1.$(lsb_release -sc)_${TARGETARCH}.deb
+a2enmod auth_openidc
+apt-get purge -y --auto-remove curl
+apt-get clean
+rm -rfv /var/lib/apt/lists/* libapache2-mod-auth-openidc_${MOD_AUTH_OPENIDC_VERSION}-1.$(lsb_release -sc)_${TARGETARCH}.deb
+EOF
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/keystone/Earthfile b/images/keystone/Earthfile
deleted file mode 100644
index 014401a..0000000
--- a/images/keystone/Earthfile
+++ /dev/null
@@ -1,34 +0,0 @@
-VERSION 0.7
-
-ARG --global RELEASE=2023.2
-ARG --global PROJECT=keystone
-ARG --global PROJECT_REF=5a55e9de15c7f390e43addc5f3ff1a4809ec1a5b
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF} \
-    --EXTRAS "[ldap]" \
-    --PIP_PACKAGES "keystone-keycloak-backend==0.1.8"
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  DO ../+APT_INSTALL \
-    --PACKAGES "apache2 libapache2-mod-wsgi-py3"
-  ARG MOD_AUTH_OPENIDC_VERSION=2.4.12.1
-  ARG TARGETARCH
-  RUN \
-    apt-get update && \
-    apt-get install -y --no-install-recommends curl && \
-    curl -LO https://github.com/OpenIDC/mod_auth_openidc/releases/download/v${MOD_AUTH_OPENIDC_VERSION}/libapache2-mod-auth-openidc_${MOD_AUTH_OPENIDC_VERSION}-1.$(lsb_release -sc)_${TARGETARCH}.deb && \
-    apt-get install -y --no-install-recommends ./libapache2-mod-auth-openidc_${MOD_AUTH_OPENIDC_VERSION}-1.$(lsb_release -sc)_${TARGETARCH}.deb && \
-    a2enmod auth_openidc && \
-    apt-get purge -y --auto-remove curl && \
-    apt-get clean && \
-    rm -rfv /var/lib/apt/lists/* libapache2-mod-auth-openidc_${MOD_AUTH_OPENIDC_VERSION}-1.$(lsb_release -sc)_${TARGETARCH}.deb
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/zuul.d/playbooks/buildset-registry/pre.yml b/images/kubernetes-entrypoint/Dockerfile
similarity index 60%
copy from zuul.d/playbooks/buildset-registry/pre.yml
copy to images/kubernetes-entrypoint/Dockerfile
index 81304bb..e7d0bc5 100644
--- a/zuul.d/playbooks/buildset-registry/pre.yml
+++ b/images/kubernetes-entrypoint/Dockerfile
@@ -12,9 +12,13 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-- name: Prepare host for building images
-  hosts: all
-  roles:
-    - ensure-docker
-    - run-buildset-registry
-    - use-buildset-registry
+FROM golang:1.21 AS build
+ARG KUBERNETES_ENTRYPOINT_GIT_REF=4fbcf7ce324dc66e78480f73035e31434cfea1e8
+ADD https://opendev.org/airship/kubernetes-entrypoint.git#${KUBERNETES_ENTRYPOINT_GIT_REF} /src
+WORKDIR /src
+RUN CGO_ENABLED=0 GOOS=linux go build -o /main
+
+FROM scratch
+COPY --from=build /main /kubernetes-entrypoint
+USER 65534
+ENTRYPOINT ["/kubernetes-entrypoint"]
diff --git a/images/kubernetes-entrypoint/Earthfile b/images/kubernetes-entrypoint/Earthfile
deleted file mode 100644
index 03617f2..0000000
--- a/images/kubernetes-entrypoint/Earthfile
+++ /dev/null
@@ -1,35 +0,0 @@
-VERSION 0.7
-
-ARG --global COMMIT=e8c2b17e1261c6a1b0fed1fcd5e1c337fc014219
-
-build:
-  FROM golang:1.21.5-bookworm
-  DO ../+APT_INSTALL --PACKAGES "patch"
-  GIT CLONE --branch ${COMMIT} https://opendev.org/airship/kubernetes-entrypoint /src
-  WORKDIR /src
-  RUN \
-    curl https://review.opendev.org/changes/airship%2Fkubernetes-entrypoint~904537/revisions/1/patch?download | \
-    base64 --decode | \
-    patch -p1
-  ARG GOARCH
-  RUN \
-    --mount=type=cache,target=/root/.cache/go-build \
-    --mount=type=cache,target=/go/pkg/mod \
-    CGO_ENABLED=0 GOOS=linux go build -o /main
-  SAVE ARTIFACT /main
-
-platform-image:
-  FROM scratch
-  ARG TARGETARCH
-  COPY \
-    --platform=linux/amd64 \
-    (+build/main --GOARCH=$TARGETARCH) /kubernetes-entrypoint
-  USER 65534
-  ENTRYPOINT ["/kubernetes-entrypoint"]
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/kubernetes-entrypoint:${COMMIT} \
-    ${REGISTRY}/kubernetes-entrypoint:latest
-
-image:
-  BUILD --platform linux/amd64 --platform linux/arm64 +platform-image
diff --git a/images/kubernetes/Earthfile b/images/kubernetes/Earthfile
deleted file mode 100644
index d31c1e0..0000000
--- a/images/kubernetes/Earthfile
+++ /dev/null
@@ -1,9 +0,0 @@
-VERSION 0.7
-
-image:
-  FROM ../curl+image
-  ARG TARGETOS
-  ARG TARGETARCH
-  RUN curl -L "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/${TARGETOS}/${TARGETARCH}/kubectl" -o /tmp/kubectl
-  RUN chmod +x /tmp/kubectl && /tmp/kubectl version --client=true
-  SAVE ARTIFACT /tmp/kubectl kubectl
diff --git a/images/libvirtd/Dockerfile b/images/libvirtd/Dockerfile
new file mode 100644
index 0000000..51cad16
--- /dev/null
+++ b/images/libvirtd/Dockerfile
@@ -0,0 +1,26 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-runtime:zed
+ADD --chmod=644 https://download.ceph.com/keys/release.gpg /etc/apt/trusted.gpg.d/ceph.gpg
+COPY <<EOF /etc/apt/sources.list.d/ceph.list
+deb http://download.ceph.com/debian-reef/ jammy main
+EOF
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    ceph-common cgroup-tools dmidecode ebtables iproute2 ipxe-qemu kmod libvirt-clients libvirt-daemon-system openssh-client openvswitch-switch ovmf pm-utils qemu-block-extra qemu-efi qemu-kvm seabios
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
diff --git a/images/libvirtd/Earthfile b/images/libvirtd/Earthfile
deleted file mode 100644
index 13e6aeb..0000000
--- a/images/libvirtd/Earthfile
+++ /dev/null
@@ -1,21 +0,0 @@
-VERSION 0.7
-
-platform-image:
-  ARG RELEASE=zed
-  FROM ../cloud-archive-base+image --RELEASE=${RELEASE}
-  COPY keyrings/ceph.gpg /etc/apt/trusted.gpg.d/
-  IF [ "$(lsb_release -sc)" = "focal" ]
-    RUN echo "deb http://download.ceph.com/debian-quincy/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/ceph.list
-  ELSE IF [ "$(lsb_release -sc)" = "jammy" ]
-    RUN echo "deb http://download.ceph.com/debian-reef/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/ceph.list
-  ELSE
-    RUN echo "${RELEASE} is not supported on $(lsb_release -sc)"
-    RUN exit 1
-  END
-  DO ../+APT_INSTALL --PACKAGES="ceph-common cgroup-tools dmidecode ebtables iproute2 ipxe-qemu kmod libvirt-clients libvirt-daemon-system openssh-client openvswitch-switch ovmf pm-utils qemu-block-extra qemu-efi qemu-kvm seabios"
-  DO ../+CREATE_PROJECT_USER --PROJECT=nova
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push ${REGISTRY}/libvirtd:${RELEASE}
-
-image:
-  BUILD --platform linux/amd64 --platform linux/arm64 +platform-image
diff --git a/images/libvirtd/keyrings/ceph.gpg b/images/libvirtd/keyrings/ceph.gpg
deleted file mode 100644
index c5d8bd3..0000000
--- a/images/libvirtd/keyrings/ceph.gpg
+++ /dev/null
Binary files differ
diff --git a/images/magnum/Dockerfile b/images/magnum/Dockerfile
new file mode 100644
index 0000000..f945cf1
--- /dev/null
+++ b/images/magnum/Dockerfile
@@ -0,0 +1,45 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/ubuntu:zed AS helm
+ARG TARGETOS
+ARG TARGETARCH
+ARG HELM_VERSION=3.14.0
+ADD https://get.helm.sh/helm-v${HELM_VERSION}-${TARGETOS}-${TARGETARCH}.tar.gz /helm.tar.gz
+RUN tar -xzf /helm.tar.gz
+RUN mv /${TARGETOS}-${TARGETARCH}/helm /usr/bin/helm
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG MAGNUM_GIT_REF=0ee979099a01ae2c8b1b5d6757897a8993e4e34c
+ADD --keep-git-dir=true https://opendev.org/openstack/magnum.git#${MAGNUM_GIT_REF} /src/magnum
+RUN git -C /src/magnum fetch --unshallow
+COPY patches/magnum /patches/magnum
+RUN git -C /src/magnum apply --verbose /patches/magnum/*
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/magnum \
+        magnum-cluster-api==0.16.0
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    haproxy
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+COPY --from=helm --link /usr/bin/helm /usr/local/bin/helm
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/magnum/Earthfile b/images/magnum/Earthfile
deleted file mode 100644
index ba8ed33..0000000
--- a/images/magnum/Earthfile
+++ /dev/null
@@ -1,23 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=magnum
-ARG --global RELEASE=2023.2
-ARG --global PROJECT_REF=272fd686d8c8bf5954e9e7d3bc991ff27e46184d
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF} \
-    --PIP_PACKAGES="magnum-cluster-api==0.13.4"
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  DO ../+APT_INSTALL \
-    --PACKAGES "haproxy"
-  COPY ../helm+binary/helm /usr/local/bin/helm
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/images/magnum/patches/magnum/0000-update-chart-metadata-version-to-reflect-breaking-change-in-helm-v3-5-2.patch b/images/magnum/patches/magnum/0000-update-chart-metadata-version-to-reflect-breaking-change-in-helm-v3-5-2.patch
deleted file mode 100644
index 9bee808..0000000
--- a/images/magnum/patches/magnum/0000-update-chart-metadata-version-to-reflect-breaking-change-in-helm-v3-5-2.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 61592d46e7fc5644c4b5148c7ca6bf767131e504 Mon Sep 17 00:00:00 2001
-From: okozachenko1203 <okozachenko1203@gmail.com>
-Date: Fri, 31 Mar 2023 23:41:43 +1100
-Subject: [PATCH] Update chart.metadata.version to reflect breaking change in
- helm v3.5.2
-
-https: //github.com/helm/helm/issues/9342
-Change-Id: I1dbe7b0b85380e713ebb5dcdd7ecbfc6a438b852
-(cherry picked from commit ebee3263b6b3d3fa213ea8f837911b89785a4700)
----
- .../templates/kubernetes/fragments/install-helm-modules.sh    | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/magnum/drivers/common/templates/kubernetes/fragments/install-helm-modules.sh b/magnum/drivers/common/templates/kubernetes/fragments/install-helm-modules.sh
-index 475e8dbf6c..a0b3f4bc75 100644
---- a/magnum/drivers/common/templates/kubernetes/fragments/install-helm-modules.sh
-+++ b/magnum/drivers/common/templates/kubernetes/fragments/install-helm-modules.sh
-@@ -72,8 +72,8 @@ else
-         cat << EOF > Chart.yaml
- apiVersion: v1
- name: magnum
--version: metachart
--appVersion: metachart
-+version: 1.0.0
-+appVersion: v1.0.0
- description: Magnum Helm Charts
- EOF
-         sed -i '1i\dependencies:' requirements.yaml
diff --git a/patches/zed/magnum/0000-Fix-Trust-token-scope-for-drivers.patch b/images/magnum/patches/magnum/0001-Fix-Trust-token-scope-for-drivers.patch
similarity index 100%
rename from patches/zed/magnum/0000-Fix-Trust-token-scope-for-drivers.patch
rename to images/magnum/patches/magnum/0001-Fix-Trust-token-scope-for-drivers.patch
diff --git a/images/manila/Dockerfile b/images/manila/Dockerfile
new file mode 100644
index 0000000..4a222e0
--- /dev/null
+++ b/images/manila/Dockerfile
@@ -0,0 +1,35 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG MANILA_GIT_REF=c0fc23a39f87629b59fae7bbf46f70e3e1b459cd
+ADD --keep-git-dir=true https://opendev.org/openstack/manila.git#${MANILA_GIT_REF} /src/manila
+RUN git -C /src/manila fetch --unshallow
+COPY patches/manila /patches/manila
+RUN git -C /src/manila apply --verbose /patches/manila/*
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/manila
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    iproute2 openvswitch-switch
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/manila/Earthfile b/images/manila/Earthfile
deleted file mode 100644
index be2bccb..0000000
--- a/images/manila/Earthfile
+++ /dev/null
@@ -1,21 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=manila
-ARG --global RELEASE=2023.2
-ARG --global PROJECT_REF=a9cea65b45f0c0bf148b6ac9db0a8141c74fa2a6
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF}
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  DO ../+APT_INSTALL \
-    --PACKAGES "iproute2 openvswitch-switch"
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/images/netoffload/Dockerfile b/images/netoffload/Dockerfile
new file mode 100644
index 0000000..9ffd6a3
--- /dev/null
+++ b/images/netoffload/Dockerfile
@@ -0,0 +1,29 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM golang:1.20 AS build
+ARG NETOFFLOAD_GIT_REF=94b8c0fdb0b83bd1b7e14b9a58077a047c78a800
+ADD https://github.com/vexxhost/netoffload.git#${NETOFFLOAD_GIT_REF} /src
+WORKDIR /src
+RUN go build -v -o offloadctl ./cmd/offloadctl/main.go
+
+FROM registry.atmosphere.dev/library/ubuntu:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    jq mstflint
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+COPY --from=build --link /src/offloadctl /usr/local/bin/offloadctl
diff --git a/images/netoffload/Earthfile b/images/netoffload/Earthfile
deleted file mode 100644
index d3a04be..0000000
--- a/images/netoffload/Earthfile
+++ /dev/null
@@ -1,28 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=netoffload
-ARG --global RELEASE=main
-ARG --global PROJECT_REF=94b8c0fdb0b83bd1b7e14b9a58077a047c78a800
-
-build:
-  FROM golang:1.20
-  WORKDIR /src
-  GIT CLONE --branch ${PROJECT_REF} https://github.com/vexxhost/netoffload /src
-  RUN \
-    --mount=type=cache,target=/root/.cache/go-build \
-    --mount=type=cache,target=/go/pkg/mod \
-      go build -v -o offloadctl cmd/offloadctl/main.go
-  SAVE ARTIFACT offloadctl
-
-platform-image:
-  FROM ../base+image
-  DO ../+APT_INSTALL --PACKAGES="jq mstflint"
-  COPY +build/offloadctl /usr/local/bin/offloadctl
-  ENTRYPOINT ["/usr/local/bin/offloadctl"]
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
-
-image:
-  BUILD --platform linux/amd64 --platform linux/arm64 +platform-image
diff --git a/images/neutron/Dockerfile b/images/neutron/Dockerfile
new file mode 100644
index 0000000..5d0fa5c
--- /dev/null
+++ b/images/neutron/Dockerfile
@@ -0,0 +1,38 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG NEUTRON_GIT_REF=ca25eb96f16dbe5ff1ca4446534f9a1d12fa7035
+ADD --keep-git-dir=true https://opendev.org/openstack/neutron.git#${NEUTRON_GIT_REF} /src/neutron
+RUN git -C /src/neutron fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/neutron-vpnaas.git#stable/zed /src/neutron-vpnaas
+RUN git -C /src/neutron-vpnaas fetch --unshallow
+COPY patches/neutron /patches/neutron
+RUN git -C /src/neutron apply --verbose /patches/neutron/*
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/neutron \
+        /src/neutron-vpnaas
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    conntrack dnsmasq dnsmasq-utils ebtables ethtool haproxy iproute2 ipset iptables iputils-arping jq keepalived lshw openvswitch-switch strongswan uuid-runtime
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/neutron/Earthfile b/images/neutron/Earthfile
deleted file mode 100644
index bfff1e2..0000000
--- a/images/neutron/Earthfile
+++ /dev/null
@@ -1,25 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=neutron
-ARG --global RELEASE=zed
-ARG --global PROJECT_REF=b9e3818b6e8905f5717d9888014f7e42141aacf0
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF} \
-    --PIP_PACKAGES="git+https://github.com/openstack/neutron-vpnaas.git@256464aea691f8b4957ba668a117963353f34e4c"
-
-platform-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  DO ../+APT_INSTALL \
-    --PACKAGES "conntrack dnsmasq dnsmasq-utils ebtables ethtool haproxy iproute2 ipset iptables iputils-arping jq keepalived lshw openvswitch-switch strongswan uuid-runtime"
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
-
-image:
-  BUILD --platform linux/amd64 --platform linux/arm64 +platform-image
diff --git a/images/neutron/patches/neutron/0000-fix-netns-deletion-of-broken-namespaces.patch b/images/neutron/patches/neutron/0000-fix-netns-deletion-of-broken-namespaces.patch
deleted file mode 100644
index efa4798..0000000
--- a/images/neutron/patches/neutron/0000-fix-netns-deletion-of-broken-namespaces.patch
+++ /dev/null
@@ -1,144 +0,0 @@
-From 69c49c4ef24648f97d895bfaacd7336917634565 Mon Sep 17 00:00:00 2001
-From: Felix Huettner <felix.huettner@mail.schwarz>
-Date: Fri, 22 Sep 2023 16:25:10 +0200
-Subject: [PATCH] fix netns deletion of broken namespaces
-
-normal network namespaces are bind-mounted to files under
-/var/run/netns. If a process deleting a network namespace gets killed
-during that operation there is the chance that the bind mount to the
-netns has been removed, but the file under /var/run/netns still exists.
-
-When the neutron-ovn-metadata-agent tries to clean up such network
-namespaces it first tires to validate that the network namespace is
-empty. For the cases described above this fails, as this network
-namespace no longer really exists, but is just a stray file laying
-around.
-
-To fix this we treat network namespaces where we get an `OSError` with
-errno 22 (Invalid Argument) as empty. The calls to pyroute2 to delete
-the namespace will then clean up the file.
-
-Additionally we add a guard to teardown_datapath to continue even if
-this fails. failing to remove a datapath is not critical and leaves in
-the worst case a process and a network namespace running, however
-previously it would have also prevented the creation of new datapaths
-which is critical for VM startup.
-
-Closes-Bug: #2037102
-Change-Id: I7c43812fed5903f98a2e491076c24a8d926a59b4
-(cherry picked from commit 566fea3fed837b0130023303c770aade391d3d61)
----
- neutron/agent/linux/ip_lib.py                 | 17 ++++++++++++-
- neutron/agent/ovn/metadata/agent.py           |  5 +++-
- neutron/tests/unit/agent/linux/test_ip_lib.py | 15 +++++++++++
- .../unit/agent/ovn/metadata/test_agent.py     | 25 +++++++++++++++++++
- 4 files changed, 60 insertions(+), 2 deletions(-)
-
-diff --git a/neutron/agent/linux/ip_lib.py b/neutron/agent/linux/ip_lib.py
-index 10bd33d9e1..5d2593da47 100644
---- a/neutron/agent/linux/ip_lib.py
-+++ b/neutron/agent/linux/ip_lib.py
-@@ -259,7 +259,22 @@ class IPWrapper(SubProcessBase):
-         return ip
- 
-     def namespace_is_empty(self):
--        return not self.get_devices()
-+        try:
-+            return not self.get_devices()
-+        except OSError as e:
-+            # This can happen if we previously got terminated in the middle of
-+            # removing this namespace. In this case the bind mount of the
-+            # namespace under /var/run/netns will be removed, but the namespace
-+            # file is still there. As the bind mount is gone we can no longer
-+            # access the namespace to validate that it is empty. But since it
-+            # should have already been removed we are sure that the check has
-+            # passed the last time and since the namespace is unuseable that
-+            # can not have changed.
-+            # Future calls to pyroute2 to remove that namespace will clean up
-+            # the leftover file.
-+            if e.errno == errno.EINVAL:
-+                return True
-+            raise e
- 
-     def garbage_collect_namespace(self):
-         """Conditionally destroy the namespace if it is empty."""
-diff --git a/neutron/agent/ovn/metadata/agent.py b/neutron/agent/ovn/metadata/agent.py
-index 1745239701..861715d8e1 100644
---- a/neutron/agent/ovn/metadata/agent.py
-+++ b/neutron/agent/ovn/metadata/agent.py
-@@ -430,7 +430,10 @@ class MetadataAgent(object):
-                              ns.startswith(NS_PREFIX) and
-                              ns not in metadata_namespaces]
-         for ns in unused_namespaces:
--            self.teardown_datapath(self._get_datapath_name(ns))
-+            try:
-+                self.teardown_datapath(self._get_datapath_name(ns))
-+            except Exception:
-+                LOG.exception('Error unable to destroy namespace: %s', ns)
- 
-         # resync all network namespaces based on the associated datapaths,
-         # even those that are already running. This is to make sure
-diff --git a/neutron/tests/unit/agent/linux/test_ip_lib.py b/neutron/tests/unit/agent/linux/test_ip_lib.py
-index d1c74fb3f7..159cafdb8e 100644
---- a/neutron/tests/unit/agent/linux/test_ip_lib.py
-+++ b/neutron/tests/unit/agent/linux/test_ip_lib.py
-@@ -357,6 +357,21 @@ class TestIpWrapper(base.BaseTestCase):
-                 self.assertNotIn(mock.call().delete('ns'),
-                                  ip_ns_cmd_cls.mock_calls)
- 
-+    def test_garbage_collect_namespace_existing_broken(self):
-+        with mock.patch.object(ip_lib, 'IpNetnsCommand') as ip_ns_cmd_cls:
-+            ip_ns_cmd_cls.return_value.exists.return_value = True
-+
-+            ip = ip_lib.IPWrapper(namespace='ns')
-+
-+            with mock.patch.object(ip, 'get_devices',
-+                                   side_effect=OSError(errno.EINVAL, None)
-+                                   ) as mock_get_devices:
-+                self.assertTrue(ip.garbage_collect_namespace())
-+
-+                mock_get_devices.assert_called_once_with()
-+                expected = [mock.call().delete('ns')]
-+                ip_ns_cmd_cls.assert_has_calls(expected)
-+
-     @mock.patch.object(priv_lib, 'create_interface')
-     def test_add_vlan(self, create):
-         retval = ip_lib.IPWrapper().add_vlan('eth0.1', 'eth0', '1')
-diff --git a/neutron/tests/unit/agent/ovn/metadata/test_agent.py b/neutron/tests/unit/agent/ovn/metadata/test_agent.py
-index 6df7da702d..9bf9f0db52 100644
---- a/neutron/tests/unit/agent/ovn/metadata/test_agent.py
-+++ b/neutron/tests/unit/agent/ovn/metadata/test_agent.py
-@@ -134,6 +134,31 @@ class TestMetadataAgent(base.BaseTestCase):
-             lnn.assert_called_once_with()
-             tdp.assert_called_once_with('3')
- 
-+    def test_sync_teardown_namespace_does_not_crash_on_error(self):
-+        """Test that sync tears down unneeded metadata namespaces.
-+        Even if that fails it continues to provision other datapaths
-+        """
-+        with mock.patch.object(
-+                self.agent, 'provision_datapath') as pdp,\
-+                mock.patch.object(
-+                    ip_lib, 'list_network_namespaces',
-+                    return_value=['ovnmeta-1', 'ovnmeta-2', 'ovnmeta-3',
-+                                  'ns1', 'ns2']) as lnn,\
-+                mock.patch.object(
-+                    self.agent, 'teardown_datapath',
-+                    side_effect=Exception()) as tdp:
-+            self.agent.sync()
-+
-+            pdp.assert_has_calls(
-+                [
-+                    mock.call(p.datapath)
-+                    for p in self.ports
-+                ],
-+                any_order=True
-+            )
-+            lnn.assert_called_once_with()
-+            tdp.assert_called_once_with('3')
-+
-     def test_get_networks_datapaths(self):
-         """Test get_networks_datapaths returns only datapath objects for the
-         networks containing vif ports of type ''(blank) and 'external'.
--- 
-2.34.1
diff --git a/images/neutron/patches/neutron/0001-fix-ovn-set-mtu-in-external_ids-correctly.patch b/images/neutron/patches/neutron/0001-fix-ovn-set-mtu-in-external_ids-correctly.patch
new file mode 100644
index 0000000..2605324
--- /dev/null
+++ b/images/neutron/patches/neutron/0001-fix-ovn-set-mtu-in-external_ids-correctly.patch
@@ -0,0 +1,38 @@
+From f8ec437329510ef59c81084712dbfe49528ef56d Mon Sep 17 00:00:00 2001
+From: Mohammed Naser <mnaser@vexxhost.com>
+Date: Thu, 28 Mar 2024 14:38:43 -0400
+Subject: [PATCH] fix(ovn): set mtu in external_ids correctly
+
+In the previous patch, we did account for the MTU showing up
+in the external IDs however the code only sets it if it's using
+a remote managed port binding.  This code instead sets the binding
+for all the inerface types instead.
+
+Related-Change-Id: I7ff300e9634e5e3fc68d70540392109fd8b9babc
+Closes-Bug: 2053274
+Change-Id: I0653c83c5fb595847bb61182223db39b2f7e98c6
+---
+ .../plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py   | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py
+index 3e7bc5c01f..6f9e90afde 100644
+--- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py
++++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py
+@@ -480,11 +480,13 @@ class OVNClient(object):
+         # HA Chassis Group will bind the port to the highest
+         # priority Chassis
+         if port_type != ovn_const.LSP_TYPE_EXTERNAL:
++            port_net = self._plugin.get_network(
++                context, port['network_id'])
++            mtu = str(port_net['mtu'])
+             if (vnic_type == portbindings.VNIC_REMOTE_MANAGED and
+                     ovn_const.VIF_DETAILS_PF_MAC_ADDRESS in binding_prof):
+                 port_net = self._plugin.get_network(
+                     context, port['network_id'])
+-                mtu = str(port_net['mtu'])
+                 options.update({
+                     ovn_const.LSP_OPTIONS_VIF_PLUG_TYPE_KEY: 'representor',
+                     ovn_const.LSP_OPTIONS_VIF_PLUG_MTU_REQUEST_KEY: mtu,
+-- 
+2.34.1
diff --git a/zuul.d/playbooks/buildset-registry/pre.yml b/images/nova-ssh/Dockerfile
similarity index 66%
copy from zuul.d/playbooks/buildset-registry/pre.yml
copy to images/nova-ssh/Dockerfile
index 81304bb..84f6889 100644
--- a/zuul.d/playbooks/buildset-registry/pre.yml
+++ b/images/nova-ssh/Dockerfile
@@ -12,9 +12,15 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-- name: Prepare host for building images
-  hosts: all
-  roles:
-    - ensure-docker
-    - run-buildset-registry
-    - use-buildset-registry
+FROM registry.atmosphere.dev/library/openstack-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    openssh-server \
+    openssh-client
+EOF
+RUN <<EOF bash -xe
+chown -R nova: /etc/ssh
+mkdir /var/run/sshd
+chmod 0755 /var/run/sshd
+EOF
diff --git a/images/nova-ssh/Earthfile b/images/nova-ssh/Earthfile
deleted file mode 100644
index 1b8df66..0000000
--- a/images/nova-ssh/Earthfile
+++ /dev/null
@@ -1,18 +0,0 @@
-VERSION 0.7
-
-platform-image:
-  FROM ../base+image
-  DO ../+CREATE_PROJECT_USER \
-    --PROJECT=nova \
-    --SHELL=/bin/bash
-  DO ../+APT_INSTALL \
-    --PACKAGES "openssh-server openssh-client"
-  RUN \
-    chown -R nova: /etc/ssh && \
-    mkdir /var/run/sshd && \
-    chmod 0755 /var/run/sshd
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push ${REGISTRY}/nova-ssh:latest
-
-image:
-  BUILD --platform linux/amd64 --platform linux/arm64 +platform-image
diff --git a/images/nova/Dockerfile b/images/nova/Dockerfile
new file mode 100644
index 0000000..36961bf
--- /dev/null
+++ b/images/nova/Dockerfile
@@ -0,0 +1,33 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG NOVA_GIT_REF=b4a69447e2a176fd3821abc427019339ec700f0c
+ADD --keep-git-dir=true https://opendev.org/openstack/nova.git#${NOVA_GIT_REF} /src/nova
+RUN git -C /src/nova fetch --unshallow
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/nova
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    ceph-common genisoimage iproute2 libosinfo-bin lsscsi ndctl nvme-cli openssh-client ovmf python3-libvirt python3-rados python3-rbd qemu-efi-aarch64 qemu-utils sysfsutils udev util-linux
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/nova/Earthfile b/images/nova/Earthfile
deleted file mode 100644
index 9e1cc3d..0000000
--- a/images/nova/Earthfile
+++ /dev/null
@@ -1,25 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=nova
-ARG --global RELEASE=zed
-ARG --global PROJECT_REF=226f3e95c1cdadd1845c7adee55f5c5f29f3a7a8
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF}
-
-platform-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  DO ../+APT_INSTALL \
-    --PACKAGES "ceph-common genisoimage iproute2 libosinfo-bin lsscsi ndctl nvme-cli openssh-client ovmf python3-libvirt python3-rados python3-rbd qemu-efi-aarch64 qemu-utils sysfsutils udev util-linux"
-  GIT CLONE --branch v1.4.0 https://github.com/novnc/noVNC.git /usr/share/novnc
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
-
-image:
-  BUILD --platform linux/amd64 --platform linux/arm64 +platform-image
diff --git a/images/nova/patches/nova/0000-libvirt-Stop-unconditionally-enabling-evmcs.patch b/images/nova/patches/nova/0000-libvirt-Stop-unconditionally-enabling-evmcs.patch
deleted file mode 100644
index 1191af1..0000000
--- a/images/nova/patches/nova/0000-libvirt-Stop-unconditionally-enabling-evmcs.patch
+++ /dev/null
@@ -1,66 +0,0 @@
-From 86a35e97d286cbb6e23f8cc7bec5a05f022da0cb Mon Sep 17 00:00:00 2001
-From: Artom Lifshitz <alifshit@redhat.com>
-Date: Tue, 31 Oct 2023 22:52:50 -0400
-Subject: [PATCH] libvirt: Stop unconditionally enabling evmcs
-
-In I008841988547573878c4e06e82f0fa55084e51b5 we started enabling a
-bunch of libvirt enlightenments for Windows unconditionally. Turns
-out, the `evmcs` enlightenment only works on Intel hosts, and we broke
-the ability to run Windows guests on AMD machines. Until we become
-smarter about conditionally enabling evmcs (with something like traits
-for host CPU features), just stop enabling it at all.
-
-Change-Id: I2ff4fdecd9dc69de283f0e52e07df1aeaf0a9048
-Closes-bug: 2009280
----
- nova/tests/unit/virt/libvirt/test_driver.py               | 5 ++++-
- nova/virt/libvirt/driver.py                               | 1 -
- ...p-unconditionally-enabling-evmcs-993a825641c4b9f3.yaml | 8 ++++++++
- 3 files changed, 12 insertions(+), 2 deletions(-)
- create mode 100644 releasenotes/notes/libvirt-enlightenments-stop-unconditionally-enabling-evmcs-993a825641c4b9f3.yaml
-
-diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py
-index d01b9c2677..ebba604ffa 100644
---- a/nova/tests/unit/virt/libvirt/test_driver.py
-+++ b/nova/tests/unit/virt/libvirt/test_driver.py
-@@ -27972,7 +27972,10 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
-         self.assertTrue(hv.reenlightenment)
-         self.assertTrue(hv.tlbflush)
-         self.assertTrue(hv.ipi)
--        self.assertTrue(hv.evmcs)
-+        # NOTE(artom) evmcs only works on Intel hosts, so we can't enable it
-+        # unconditionally. Until we become smarter about it, just don't enable
-+        # it at all. See bug 2009280.
-+        self.assertFalse(hv.evmcs)
- 
- 
- class LibvirtVolumeUsageTestCase(test.NoDBTestCase):
-diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
-index d03dc5fd67..1b28e50355 100644
---- a/nova/virt/libvirt/driver.py
-+++ b/nova/virt/libvirt/driver.py
-@@ -6234,7 +6234,6 @@ class LibvirtDriver(driver.ComputeDriver):
-             hv.reenlightenment = True
-             hv.tlbflush = True
-             hv.ipi = True
--            hv.evmcs = True
- 
-             # NOTE(kosamara): Spoofing the vendor_id aims to allow the nvidia
-             # driver to work on windows VMs. At the moment, the nvidia driver
-diff --git a/releasenotes/notes/libvirt-enlightenments-stop-unconditionally-enabling-evmcs-993a825641c4b9f3.yaml b/releasenotes/notes/libvirt-enlightenments-stop-unconditionally-enabling-evmcs-993a825641c4b9f3.yaml
-new file mode 100644
-index 0000000000..31609f2a2d
---- /dev/null
-+++ b/releasenotes/notes/libvirt-enlightenments-stop-unconditionally-enabling-evmcs-993a825641c4b9f3.yaml
-@@ -0,0 +1,8 @@
-+---
-+fixes:
-+  - |
-+    Bug 2009280 has been fixed by no longer enabling the evmcs enlightenment in
-+    the libvirt driver. evmcs only works on Intel CPUs, and domains with that
-+    enlightenment cannot be started on AMD hosts. There is a possible future
-+    feature to enable support for generating this enlightenment only when
-+    running on Intel hosts.
--- 
-2.34.1
-
diff --git a/images/nova/patches/nova/0001-libvirt-stop-enabling-hyperv-feature-reenlightenment.patch b/images/nova/patches/nova/0001-libvirt-stop-enabling-hyperv-feature-reenlightenment.patch
deleted file mode 100644
index 88ea631..0000000
--- a/images/nova/patches/nova/0001-libvirt-stop-enabling-hyperv-feature-reenlightenment.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-From e618e78edc6293d248a5fa2eb63b3fa636250fca Mon Sep 17 00:00:00 2001
-From: songjie <songjie_yewu@cmss.chinamobile.com>
-Date: Mon, 25 Dec 2023 16:59:36 +0800
-Subject: [PATCH] libvirt: stop enabling hyperv feature reenlightenment
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The 'reenlightenment' hyperv enlightenment will cause
-instances live-migration to fail (KVM currently doesn’t
-fully support reenlightenment notifications, see
-www.qemu.org/docs/master/system/i386/hyperv.html),
-so don't enable it now.
-
-Change-Id: I6821819450bc96e4304125ea3b76a0e462e6e33f
-Closes-Bug: #2046549
-Related-Bug: #2009280
----
- nova/tests/unit/virt/libvirt/test_driver.py | 4 +++-
- nova/virt/libvirt/driver.py                 | 1 -
- 2 files changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py
-index 868e024370..2e1d089898 100644
---- a/nova/tests/unit/virt/libvirt/test_driver.py
-+++ b/nova/tests/unit/virt/libvirt/test_driver.py
-@@ -28048,7 +28048,9 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
-         self.assertTrue(hv.synic)
-         self.assertTrue(hv.reset)
-         self.assertTrue(hv.frequencies)
--        self.assertTrue(hv.reenlightenment)
-+        # NOTE(jie) reenlightenment will cause instances live-migration
-+        # failure, so don't enable it now. See bug 2046549.
-+        self.assertFalse(hv.reenlightenment)
-         self.assertTrue(hv.tlbflush)
-         self.assertTrue(hv.ipi)
-         # NOTE(artom) evmcs only works on Intel hosts, so we can't enable it
-diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
-index 7f5f48c047..f8e3353110 100644
---- a/nova/virt/libvirt/driver.py
-+++ b/nova/virt/libvirt/driver.py
-@@ -6262,7 +6262,6 @@ class LibvirtDriver(driver.ComputeDriver):
-             hv.synic = True
-             hv.reset = True
-             hv.frequencies = True
--            hv.reenlightenment = True
-             hv.tlbflush = True
-             hv.ipi = True
-
--- 
-2.34.1
-
diff --git a/images/octavia/Dockerfile b/images/octavia/Dockerfile
new file mode 100644
index 0000000..bf8d7e7
--- /dev/null
+++ b/images/octavia/Dockerfile
@@ -0,0 +1,36 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG OCTAVIA_GIT_REF=000b577f3e9c9ff7cb893e9f6e635753017a78c6
+ADD --keep-git-dir=true https://opendev.org/openstack/octavia.git#${OCTAVIA_GIT_REF} /src/octavia
+RUN git -C /src/octavia fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/ovn-octavia-provider.git#stable/zed /src/ovn-octavia-provider
+RUN git -C /src/ovn-octavia-provider fetch --unshallow
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/octavia \
+        /src/ovn-octavia-provider
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    isc-dhcp-client openssh-client
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/octavia/Earthfile b/images/octavia/Earthfile
deleted file mode 100644
index 0fcb0d5..0000000
--- a/images/octavia/Earthfile
+++ /dev/null
@@ -1,22 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=octavia
-ARG --global RELEASE=2023.2
-ARG --global PROJECT_REF=3f31a50f264c0e58691b1be7e90d324c13588b63
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF} \
-    --PIP_PACKAGES="ovn-octavia-provider"
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  DO ../+APT_INSTALL \
-    --PACKAGES "isc-dhcp-client openssh-client"
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/images/octavia/patches/octavia/0000-fix-specify-endpoint-info.-for-neutron-client.patch b/images/octavia/patches/octavia/0000-fix-specify-endpoint-info.-for-neutron-client.patch
deleted file mode 100644
index f113d64..0000000
--- a/images/octavia/patches/octavia/0000-fix-specify-endpoint-info.-for-neutron-client.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From efd289b950b32d3e6ad160b7c7f2901bca7c7e55 Mon Sep 17 00:00:00 2001
-From: Mohammed Naser <mnaser@vexxhost.com>
-Date: Tue, 16 Jan 2024 17:13:19 -0500
-Subject: [PATCH] fix: specify endpoint info. for neutron client
-
-Closes bug: #2049551
-
-Change-Id: I80a266e500958415a70d462ddfe57e9e03e6ef13
----
- octavia/common/clients.py | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
-diff --git a/octavia/common/clients.py b/octavia/common/clients.py
-index b13642bb..2abcc67b 100644
---- a/octavia/common/clients.py
-+++ b/octavia/common/clients.py
-@@ -80,10 +80,16 @@ class NeutronAuth(object):
-         if not cls.neutron_client:
-             sess = ksession.get_session()
- 
--            kwargs = {}
-+            kwargs = {
-+                'region_name': CONF.neutron.region_name,
-+                'interface': CONF.neutron.valid_interfaces
-+            }
-             if CONF.neutron.endpoint_override:
-                 kwargs['network_endpoint_override'] = (
-                     CONF.neutron.endpoint_override)
-+                if CONF.neutron.endpoint_override.startswith("https"):
-+                    kwargs['insecure'] = CONF.neutron.insecure
-+                    kwargs['cacert'] = CONF.neutron.cafile
- 
-             conn = openstack.connection.Connection(
-                 session=sess, **kwargs)
--- 
-2.34.1
-
diff --git a/images/openstack-runtime/Dockerfile b/images/openstack-runtime/Dockerfile
new file mode 100644
index 0000000..3cf9ae4
--- /dev/null
+++ b/images/openstack-runtime/Dockerfile
@@ -0,0 +1,23 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+ARG FROM=registry.atmosphere.dev/library/ubuntu-cloud-archive:zed
+FROM ${FROM}
+ONBUILD ARG PROJECT
+ONBUILD ARG SHELL=/usr/sbin/nologin
+ONBUILD RUN \
+    groupadd -g 42424 ${PROJECT} && \
+    useradd -u 42424 -g 42424 -M -d /var/lib/${PROJECT} -s ${SHELL} -c "${PROJECT} User" ${PROJECT} && \
+    mkdir -p /etc/${PROJECT} /var/log/${PROJECT} /var/lib/${PROJECT} /var/cache/${PROJECT} && \
+    chown -Rv ${PROJECT}:${PROJECT} /etc/${PROJECT} /var/log/${PROJECT} /var/lib/${PROJECT} /var/cache/${PROJECT}
diff --git a/images/openstack-service/Earthfile b/images/openstack-service/Earthfile
deleted file mode 100644
index ae4ab49..0000000
--- a/images/openstack-service/Earthfile
+++ /dev/null
@@ -1,99 +0,0 @@
-VERSION 0.8
-
-PIP_INSTALL:
-  FUNCTION
-  ARG PACKAGES
-  RUN --mount=type=cache,target=/root/.cache \
-    /var/lib/openstack/bin/pip3 install \
-      --constraint /upper-constraints.txt \
-      ${PACKAGES}
-
-GIT_CHECKOUT:
-  FUNCTION
-  ARG PROJECT
-  ARG PROJECT_REPO=https://github.com/openstack/${PROJECT}
-  ARG PROJECT_REF
-  GIT CLONE --branch ${PROJECT_REF} ${PROJECT_REPO} /src
-  WORKDIR /src
-  RUN \
-    git remote set-url origin ${PROJECT_REPO} && \
-    git fetch --unshallow
-  COPY --if-exists patches/${PROJECT} /patches
-  IF [ -d /patches ]
-    RUN git apply --verbose /patches/*.patch
-  END
-
-BUILD_VENV:
-  FUNCTION
-  ARG PROJECT
-  ARG PROJECT_REPO=https://github.com/openstack/${PROJECT}
-  ARG PROJECT_REF
-  DO +GIT_CHECKOUT \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REPO=${PROJECT_REPO} \
-    --PROJECT_REF=${PROJECT_REF}
-  ARG EXTRAS=""
-  ARG PIP_PACKAGES=""
-  DO +PIP_INSTALL --PACKAGES "/src${EXTRAS} ${PIP_PACKAGES}"
-  SAVE ARTIFACT /var/lib/openstack venv
-
-requirements:
-  FROM ../base+image
-  ARG RELEASE
-  IF [ "${RELEASE}" = "master" ]
-    ARG BRANCH=master
-  ELSE
-    ARG BRANCH=stable/${RELEASE}
-  END
-  GIT CLONE --branch ${BRANCH} https://github.com/openstack/requirements /src
-  RUN \
-    sed -i 's/cryptography===36.0.2/cryptography===42.0.4/' /src/upper-constraints.txt && \
-    sed -i 's/cryptography===40.0.2/cryptography===42.0.4/' /src/upper-constraints.txt && \
-    sed -i 's/cryptography===41.0.7/cryptography===42.0.4/' /src/upper-constraints.txt && \
-    sed -i 's/Django===3.2.18/Django===3.2.24/' /src/upper-constraints.txt && \
-    sed -i 's/Flask===2.2.3/Flask===2.2.5/' /src/upper-constraints.txt && \
-    sed -i 's/Jinja2===3.1.2/Jinja2===3.1.3/' /src/upper-constraints.txt && \
-    sed -i 's/paramiko===2.11.0/paramiko===3.4.0/' /src/upper-constraints.txt && \
-    sed -i 's/paramiko===3.1.0/paramiko===3.4.0/' /src/upper-constraints.txt && \
-    sed -i 's/pyOpenSSL===22.0.0/pyOpenSSL===24.0.0/' /src/upper-constraints.txt && \
-    sed -i 's/pyOpenSSL===23.1.1/pyOpenSSL===24.0.0/' /src/upper-constraints.txt && \
-    sed -i 's/requests===2.28.1/requests===2.31.0/' /src/upper-constraints.txt && \
-    sed -i 's/requests===2.28.2/requests===2.31.0/' /src/upper-constraints.txt && \
-    sed -i 's/sqlparse===0.4.2/sqlparse===0.4.4/' /src/upper-constraints.txt && \
-    sed -i 's/urllib3===1.26.12/urllib3===1.26.18/' /src/upper-constraints.txt && \
-    sed -i 's/urllib3===1.26.15/urllib3===1.26.18/' /src/upper-constraints.txt && \
-    sed -i 's/Werkzeug===2.2.3/Werkzeug===2.3.8/' /src/upper-constraints.txt && \
-    sed -i '/glance-store/d' /src/upper-constraints.txt && \
-    sed -i '/horizon/d' /src/upper-constraints.txt
-  SAVE ARTIFACT /src/upper-constraints.txt
-
-builder:
-  ARG RELEASE
-  FROM ../cloud-archive-base+image --RELEASE=${RELEASE}
-  DO ../+APT_INSTALL --PACKAGES "\
-    build-essential \
-    curl \
-    git \
-    libldap2-dev \
-    libpcre3-dev \
-    libsasl2-dev \
-    libssl-dev \
-    lsb-release \
-    openssh-client \
-    python3 \
-    python3-dev \
-    python3-pip \
-    python3-venv"
-  RUN --mount type=cache,target=/root/.cache \
-    python3 -m venv --upgrade-deps --system-site-packages /var/lib/openstack
-  COPY \
-    (+requirements/upper-constraints.txt --RELEASE=${RELEASE}) \
-    /upper-constraints.txt
-  DO +PIP_INSTALL --PACKAGES "cryptography pymysql python-binary-memcached python-memcached uwsgi"
-
-image:
-  ARG --required RELEASE
-  FROM ../cloud-archive-base+image --RELEASE=${RELEASE}
-  ENV PATH=/var/lib/openstack/bin:$PATH
-  ARG --required PROJECT
-  DO ../+CREATE_PROJECT_USER --PROJECT=${PROJECT}
diff --git a/images/openstack-venv-builder/Dockerfile b/images/openstack-venv-builder/Dockerfile
new file mode 100644
index 0000000..2b154cf
--- /dev/null
+++ b/images/openstack-venv-builder/Dockerfile
@@ -0,0 +1,62 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/ubuntu-cloud-archive:zed AS requirements
+ADD https://releases.openstack.org/constraints/upper/zed /upper-constraints.txt
+RUN <<EOF sh -xe
+sed -i 's/cryptography===36.0.2/cryptography===42.0.4/' /upper-constraints.txt
+sed -i 's/Django===3.2.15/Django===3.2.24/' /upper-constraints.txt
+sed -i 's/Flask===2.2.2/Flask===2.2.5/' /upper-constraints.txt
+sed -i 's/Jinja2===3.1.2/Jinja2===3.1.3/' /upper-constraints.txt
+sed -i 's/oauthlib===3.2.0/oauthlib===3.2.2/' /upper-constraints.txt
+sed -i 's/paramiko===2.11.0/paramiko===3.4.0/' /upper-constraints.txt
+sed -i 's/protobuf===4.21.5/protobuf===4.21.6/' /upper-constraints.txt
+sed -i 's/pyOpenSSL===22.0.0/pyOpenSSL===24.0.0/' /upper-constraints.txt
+sed -i 's/requests===2.28.1/requests===2.31.0/' /upper-constraints.txt
+sed -i 's/sqlparse===0.4.2/sqlparse===0.4.4/' /upper-constraints.txt
+sed -i 's/urllib3===1.26.12/urllib3===1.26.18/' /upper-constraints.txt
+sed -i 's/Werkzeug===2.2.2/Werkzeug===2.3.8/' /upper-constraints.txt
+sed -i 's/zstd===1.5.2.5/zstd===1.5.4.0/' /upper-constraints.txt
+sed -i '/glance-store/d' /upper-constraints.txt
+sed -i '/horizon/d' /upper-constraints.txt
+EOF
+
+FROM registry.atmosphere.dev/library/python-base:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    build-essential \
+    git \
+    libldap2-dev \
+    libpcre3-dev \
+    libsasl2-dev \
+    libssl-dev \
+    lsb-release \
+    openssh-client \
+    python3 \
+    python3-dev \
+    python3-pip \
+    python3-venv
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+RUN python3 -m venv --upgrade-deps --system-site-packages /var/lib/openstack
+COPY --from=requirements --link /upper-constraints.txt /upper-constraints.txt
+RUN pip3 install \
+    --constraint /upper-constraints.txt \
+        cryptography \
+        pymysql \
+        python-binary-memcached \
+        python-memcached \
+        uwsgi
diff --git a/images/openvswitch/Dockerfile b/images/openvswitch/Dockerfile
new file mode 100644
index 0000000..2b360ea
--- /dev/null
+++ b/images/openvswitch/Dockerfile
@@ -0,0 +1,25 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM quay.io/centos/centos:stream9
+ARG OVS_SERIES=3.1
+ARG OVS_VERSION=${OVS_SERIES}.0-65
+RUN <<EOF sh -xe
+dnf -y --setopt=install_weak_deps=False --setopt=tsflags=nodocs install \
+    centos-release-nfv-openvswitch.noarch
+dnf -y --setopt=install_weak_deps=False --setopt=tsflags=nodocs install \
+    openvswitch${OVS_SERIES}-${OVS_VERSION}.el9s iptables
+dnf -y clean all
+rm -rf /var/cache/dnf
+EOF
diff --git a/images/openvswitch/Earthfile b/images/openvswitch/Earthfile
deleted file mode 100644
index 35c3b2e..0000000
--- a/images/openvswitch/Earthfile
+++ /dev/null
@@ -1,17 +0,0 @@
-VERSION 0.7
-
-ARG --global SERIES=3.1
-ARG --global VERSION=3.1.0-65
-
-platform-image:
-  FROM quay.io/centos/centos:stream9
-  LABEL org.opencontainers.image.source=https://github.com/vexxhost/atmosphere
-  DO ../+DNF_INSTALL --PACKAGES "centos-release-nfv-openvswitch.noarch"
-  DO ../+DNF_INSTALL --PACKAGES "openvswitch${SERIES}-${VERSION}.el9s iptables"
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/openvswitch:${SERIES} \
-    ${REGISTRY}/openvswitch:${VERSION}
-
-image:
-  BUILD --platform linux/amd64 --platform linux/arm64 +platform-image
diff --git a/images/ovn/Dockerfile b/images/ovn/Dockerfile
new file mode 100644
index 0000000..589322e
--- /dev/null
+++ b/images/ovn/Dockerfile
@@ -0,0 +1,44 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM golang:1.20 AS ovn-kubernetes
+ARG OVN_KUBERNETES_REF=cbff639b83af00e4887b540fc06b880108662780
+ADD https://github.com/ovn-org/ovn-kubernetes.git#${OVN_KUBERNETES_REF} /src
+COPY patches/ovn-kubernetes /patches/ovn-kubernetes
+RUN git -C /src apply --verbose /patches/ovn-kubernetes/*
+RUN <<EOF bash -xe
+cd /src/go-controller
+go build -o /usr/bin/ovn-kube-util ./cmd/ovn-kube-util
+EOF
+
+FROM registry.atmosphere.dev/library/openvswitch:zed
+ADD --chmod=755 https://dl.k8s.io/release/v1.29.3/bin/linux/amd64/kubectl /usr/local/bin/kubectl
+ARG OVN_SERIES=23.03
+ARG OVN_VERSION=${OVN_SERIES}.0-69
+RUN <<EOF sh -xe
+dnf -y --setopt=install_weak_deps=False --setopt=tsflags=nodocs install \
+    firewalld-filesystem hostname ovn${OVN_SERIES}-${OVN_VERSION}.el9s procps-ng
+dnf -y clean all
+rm -rf /var/cache/dnf
+EOF
+ARG OVN_COMPONENT
+RUN <<EOF sh -xe
+dnf -y --setopt=install_weak_deps=False --setopt=tsflags=nodocs install \
+    ovn${OVN_SERIES}-${OVN_COMPONENT}-${OVN_VERSION}.el9s
+dnf -y clean all
+rm -rf /var/cache/dnf
+EOF
+COPY --from=ovn-kubernetes --link /src/dist/images/ovndb-raft-functions.sh /root/ovndb-raft-functions.sh
+COPY --from=ovn-kubernetes --link /src/dist/images/ovnkube.sh /root/ovnkube.sh
+COPY --from=ovn-kubernetes --link /usr/bin/ovn-kube-util /usr/bin/ovn-kube-util
diff --git a/images/ovn/Earthfile b/images/ovn/Earthfile
deleted file mode 100644
index 327d73a..0000000
--- a/images/ovn/Earthfile
+++ /dev/null
@@ -1,47 +0,0 @@
-VERSION 0.7
-
-ARG --global SERIES=23.03
-ARG --global VERSION=23.03.0-69
-ARG --global PROJECT_REF=cbff639b83af00e4887b540fc06b880108662780
-
-ovn-kubernetes:
-  FROM --platform=linux/amd64 golang:1.20
-  GIT CLONE --branch ${PROJECT_REF} https://github.com/ovn-org/ovn-kubernetes /src
-  WORKDIR /src
-  COPY patches/ovn-kubernetes /patches
-  DO ../+APT_INSTALL --PACKAGES "git"
-  RUN git apply --verbose /patches/*.patch
-  SAVE ARTIFACT /src/dist/images/ovndb-raft-functions.sh
-  SAVE ARTIFACT /src/dist/images/ovnkube.sh
-  ARG GOOS=linux
-  ARG GOARCH=amd64
-  RUN \
-    cd /src/go-controller && \
-    go build -o /build/ovn-kube-util ./cmd/ovn-kube-util
-  SAVE ARTIFACT /build/ovn-kube-util
-
-component-image:
-  FROM ../openvswitch+platform-image
-  DO ../+DNF_INSTALL --PACKAGES "firewalld-filesystem hostname ovn${SERIES}-${VERSION}.el9s procps-ng"
-  ARG --required NAME
-  DO ../+DNF_INSTALL --PACKAGES "ovn${SERIES}-${NAME}-${VERSION}.el9s"
-  COPY ../kubernetes+image/kubectl /usr/local/bin/kubectl
-  COPY +ovn-kubernetes/ovndb-raft-functions.sh /root
-  COPY +ovn-kubernetes/ovnkube.sh /root
-  ARG TARGETARCH
-  ARG TARGETVARIANT
-  COPY (+ovn-kubernetes/ovn-kube-util --GOARCH=$TARGETARCH --VARIANT=$TARGETVARIANT) /usr/bin
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/ovn-${NAME}:${SERIES} \
-    ${REGISTRY}/ovn-${NAME}:${VERSION}
-
-central:
-  BUILD +component-image --NAME central
-
-host:
-  BUILD +component-image --NAME host
-
-images:
-  BUILD +central
-  BUILD --platform linux/amd64 --platform linux/arm64 +host
diff --git a/images/placement/Dockerfile b/images/placement/Dockerfile
new file mode 100644
index 0000000..2aeaf23
--- /dev/null
+++ b/images/placement/Dockerfile
@@ -0,0 +1,26 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG PLACEMENT_GIT_REF=d7ced6bd2fc82caf458f20b5652888164b1bbb70
+ADD --keep-git-dir=true https://opendev.org/openstack/placement.git#${PLACEMENT_GIT_REF} /src/placement
+RUN git -C /src/placement fetch --unshallow
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/placement
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/placement/Earthfile b/images/placement/Earthfile
deleted file mode 100644
index 5719453..0000000
--- a/images/placement/Earthfile
+++ /dev/null
@@ -1,19 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=placement
-ARG --global RELEASE=2023.2
-ARG --global PROJECT_REF=a361622d749d3b24aad638ec1b03a7d7124a87b3
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF}
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/zuul.d/playbooks/buildset-registry/pre.yml b/images/python-base/Dockerfile
similarity index 61%
copy from zuul.d/playbooks/buildset-registry/pre.yml
copy to images/python-base/Dockerfile
index 81304bb..0d4c8c4 100644
--- a/zuul.d/playbooks/buildset-registry/pre.yml
+++ b/images/python-base/Dockerfile
@@ -12,9 +12,15 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-- name: Prepare host for building images
-  hosts: all
-  roles:
-    - ensure-docker
-    - run-buildset-registry
-    - use-buildset-registry
+FROM registry.atmosphere.dev/library/ubuntu-cloud-archive:zed
+ENV PATH=/var/lib/openstack/bin:$PATH
+RUN \
+    apt-get update -qq && \
+    apt-get install -qq -y --no-install-recommends \
+        ca-certificates \
+        libpython3.10 \
+        lsb-release \
+        python3-distutils \
+        sudo && \
+    apt-get clean && \
+    rm -rf /var/lib/apt/lists/*
diff --git a/images/senlin/Dockerfile b/images/senlin/Dockerfile
new file mode 100644
index 0000000..f341d10
--- /dev/null
+++ b/images/senlin/Dockerfile
@@ -0,0 +1,26 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG SENLIN_GIT_REF=b6ef17b0f787fb7a0609ba36dc13097882a6a3ff
+ADD --keep-git-dir=true https://opendev.org/openstack/senlin.git#${SENLIN_GIT_REF} /src/senlin
+RUN git -C /src/senlin fetch --unshallow
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/senlin
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/senlin/Earthfile b/images/senlin/Earthfile
deleted file mode 100644
index 6d0e3de..0000000
--- a/images/senlin/Earthfile
+++ /dev/null
@@ -1,19 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=senlin
-ARG --global RELEASE=2023.2
-ARG --global PROJECT_REF=5382259276d6be6807634c58c7b69b03b57ad6f5
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF}
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/images/staffeln/Dockerfile b/images/staffeln/Dockerfile
new file mode 100644
index 0000000..da7b121
--- /dev/null
+++ b/images/staffeln/Dockerfile
@@ -0,0 +1,26 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG STAFFELN_GIT_REF=v2.2.3
+ADD --keep-git-dir=true https://github.com/vexxhost/staffeln.git#${STAFFELN_GIT_REF} /src/staffeln
+RUN git -C /src/staffeln fetch --unshallow
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/staffeln
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/staffeln/Earthfile b/images/staffeln/Earthfile
deleted file mode 100644
index 8cef127..0000000
--- a/images/staffeln/Earthfile
+++ /dev/null
@@ -1,20 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=staffeln
-ARG --global RELEASE=master
-ARG --global PROJECT_REF=v2.2.3
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REPO=https://github.com/vexxhost/${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF}
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +build/venv /var/lib/openstack
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/images/tempest/Dockerfile b/images/tempest/Dockerfile
new file mode 100644
index 0000000..ab4f183
--- /dev/null
+++ b/images/tempest/Dockerfile
@@ -0,0 +1,60 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+FROM golang:1.18 AS octavia-test-server
+ADD --keep-git-dir=true https://opendev.org/openstack/octavia-tempest-plugin.git#master /src
+RUN GO111MODULE=off CGO_ENABLED=0 GOOS=linux go build \
+    -a -ldflags '-s -w -extldflags -static' \
+    -o /build/test_server.bin \
+    /src/octavia_tempest_plugin/contrib/test_server/test_server.go
+
+FROM registry.atmosphere.dev/library/openstack-venv-builder:zed AS build
+ARG TEMPEST_GIT_REF=aeb9b13e930841c87b826d3ba917b224095f1d81
+ADD --keep-git-dir=true https://opendev.org/openstack/tempest.git#${TEMPEST_GIT_REF} /src/tempest
+RUN git -C /src/tempest fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/barbican-tempest-plugin.git#master /src/barbican-tempest-plugin
+RUN git -C /src/barbican-tempest-plugin fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/cinder-tempest-plugin.git#master /src/cinder-tempest-plugin
+RUN git -C /src/cinder-tempest-plugin fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/heat-tempest-plugin.git#master /src/heat-tempest-plugin
+RUN git -C /src/heat-tempest-plugin fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/keystone-tempest-plugin.git#master /src/keystone-tempest-plugin
+RUN git -C /src/keystone-tempest-plugin fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/neutron-tempest-plugin.git#master /src/neutron-tempest-plugin
+RUN git -C /src/neutron-tempest-plugin fetch --unshallow
+ADD --keep-git-dir=true https://opendev.org/openstack/octavia-tempest-plugin.git#master /src/octavia-tempest-plugin
+RUN git -C /src/octavia-tempest-plugin fetch --unshallow
+ADD https://releases.openstack.org/constraints/upper/master /upper-constraints.txt
+RUN --mount=type=cache,mode=0755,target=/root/.cache/pip,sharing=private <<EOF bash -xe
+pip3 install \
+    --constraint /upper-constraints.txt \
+        /src/tempest \
+        /src/barbican-tempest-plugin \
+        /src/cinder-tempest-plugin \
+        /src/heat-tempest-plugin \
+        /src/keystone-tempest-plugin \
+        /src/neutron-tempest-plugin \
+        /src/octavia-tempest-plugin
+EOF
+
+FROM registry.atmosphere.dev/library/openstack-python-runtime:zed
+RUN <<EOF bash -xe
+apt-get update -qq
+apt-get install -qq -y --no-install-recommends \
+    iputils-ping openssh-client
+apt-get clean
+rm -rf /var/lib/apt/lists/*
+EOF
+COPY --from=octavia-test-server --link /build/test_server.bin /opt/octavia-tempest-plugin/test_server.bin
+COPY --from=build --link /var/lib/openstack /var/lib/openstack
diff --git a/images/tempest/Earthfile b/images/tempest/Earthfile
deleted file mode 100644
index 02866ca..0000000
--- a/images/tempest/Earthfile
+++ /dev/null
@@ -1,49 +0,0 @@
-VERSION 0.7
-
-ARG --global PROJECT=tempest
-ARG --global RELEASE=master
-ARG --global PROJECT_REF=699749ec27897efe9bd7824664237c16c3339c03
-
-build.plugin:
-  ARG PLUGIN
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  DO ../openstack-service+GIT_CHECKOUT \
-    --PROJECT=${PLUGIN} \
-    --PROJECT_REF=${RELEASE}
-  SAVE ARTIFACT /src
-
-octavia-test-server:
-  FROM golang:1.18
-  COPY (+build.plugin/src --PLUGIN=octavia-tempest-plugin) /src
-  ENV GO111MODULE=off
-  ENV CGO_ENABLED=0
-  ENV GOOS=linux
-  RUN go build \
-    -a -ldflags '-s -w -extldflags -static' \
-    -o /build/test_server.bin \
-    /src/octavia_tempest_plugin/contrib/test_server/test_server.go
-  SAVE ARTIFACT /build/test_server.bin
-
-build:
-  FROM ../openstack-service+builder --RELEASE=${RELEASE}
-  COPY (+build.plugin/src --PLUGIN=barbican-tempest-plugin) /barbican-tempest-plugin
-  COPY (+build.plugin/src --PLUGIN=cinder-tempest-plugin) /cinder-tempest-plugin
-  COPY (+build.plugin/src --PLUGIN=heat-tempest-plugin) /heat-tempest-plugin
-  COPY (+build.plugin/src --PLUGIN=keystone-tempest-plugin) /keystone-tempest-plugin
-  COPY (+build.plugin/src --PLUGIN=neutron-tempest-plugin) /neutron-tempest-plugin
-  COPY (+build.plugin/src --PLUGIN=octavia-tempest-plugin) /octavia-tempest-plugin
-  DO ../openstack-service+BUILD_VENV \
-    --PROJECT=${PROJECT} \
-    --PROJECT_REF=${PROJECT_REF} \
-    --PIP_PACKAGES="/barbican-tempest-plugin /cinder-tempest-plugin /heat-tempest-plugin /keystone-tempest-plugin /neutron-tempest-plugin /octavia-tempest-plugin junitxml"
-
-image:
-  FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT}
-  COPY +octavia-test-server/test_server.bin /opt/octavia-tempest-plugin/test_server.bin
-  COPY +build/venv /var/lib/openstack
-  DO ../+APT_INSTALL \
-    --PACKAGES "iputils-ping openssh-client"
-  ARG REGISTRY=ghcr.io/vexxhost/atmosphere
-  SAVE IMAGE --push \
-    ${REGISTRY}/${PROJECT}:${RELEASE} \
-    ${REGISTRY}/${PROJECT}:${PROJECT_REF}
diff --git a/images/trivy/.trivyignore b/images/trivy/.trivyignore
deleted file mode 100644
index 5057f16..0000000
--- a/images/trivy/.trivyignore
+++ /dev/null
@@ -1,17 +0,0 @@
-# NOTE(mnaser): OpenStack used to be versioned based on years and Trivy gets
-#               confused since something like 2014.1.3 > 23.0.1.dev6 therefore
-#               we ignore those old CVEs.
-CVE-2012-3542
-CVE-2012-4413
-CVE-2013-2256
-CVE-2013-4179
-CVE-2014-3517
-CVE-2014-3608
-CVE-2014-3641
-CVE-2014-3708
-CVE-2015-0259
-CVE-2015-3221
-CVE-2015-3280
-CVE-2015-5251
-CVE-2015-5286
-CVE-2015-7713
diff --git a/images/trivy/Earthfile b/images/trivy/Earthfile
deleted file mode 100644
index 8f68625..0000000
--- a/images/trivy/Earthfile
+++ /dev/null
@@ -1,8 +0,0 @@
-VERSION 0.7
-
-image:
-  FROM aquasec/trivy:0.48.3
-  COPY .trivyignore /.trivyignore
-  # TODO(mnaser): Add automatic updates
-  RUN trivy image --download-db-only
-  RUN trivy image --download-java-db-only
diff --git a/zuul.d/playbooks/buildset-registry/pre.yml b/images/ubuntu-cloud-archive/Dockerfile
similarity index 67%
rename from zuul.d/playbooks/buildset-registry/pre.yml
rename to images/ubuntu-cloud-archive/Dockerfile
index 81304bb..43d3a1a 100644
--- a/zuul.d/playbooks/buildset-registry/pre.yml
+++ b/images/ubuntu-cloud-archive/Dockerfile
@@ -12,9 +12,8 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-- name: Prepare host for building images
-  hosts: all
-  roles:
-    - ensure-docker
-    - run-buildset-registry
-    - use-buildset-registry
+FROM registry.atmosphere.dev/library/ubuntu:zed
+COPY trusted.gpg.d/ubuntu-cloud-keyring.gpg /etc/apt/trusted.gpg.d/ubuntu-cloud-keyring.gpg
+COPY <<EOF /etc/apt/sources.list.d/cloudarchive.list
+deb http://ubuntu-cloud.archive.canonical.com/ubuntu jammy-updates/zed main
+EOF
diff --git a/images/ubuntu-cloud-archive/trusted.gpg.d/ubuntu-cloud-keyring.gpg b/images/ubuntu-cloud-archive/trusted.gpg.d/ubuntu-cloud-keyring.gpg
new file mode 100644
index 0000000..b59c283
--- /dev/null
+++ b/images/ubuntu-cloud-archive/trusted.gpg.d/ubuntu-cloud-keyring.gpg
Binary files differ
diff --git a/zuul.d/playbooks/molecule-keycloak/pre.yml b/images/ubuntu/Dockerfile
similarity index 84%
rename from zuul.d/playbooks/molecule-keycloak/pre.yml
rename to images/ubuntu/Dockerfile
index ab0c6e1..1ad0fc5 100644
--- a/zuul.d/playbooks/molecule-keycloak/pre.yml
+++ b/images/ubuntu/Dockerfile
@@ -12,7 +12,5 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-- name: Prepare host for Keycloak tests
-  hosts: all
-  roles:
-    - ensure-docker
+FROM ubuntu:jammy-20240227
+LABEL org.opencontainers.image.source=https://github.com/vexxhost/atmosphere
diff --git a/molecule/keycloak/create.yml b/molecule/keycloak/create.yml
new file mode 120000
index 0000000..5e5dbdc
--- /dev/null
+++ b/molecule/keycloak/create.yml
@@ -0,0 +1 @@
+../aio/create.yml
\ No newline at end of file
diff --git a/molecule/keycloak/group_vars b/molecule/keycloak/group_vars
new file mode 120000
index 0000000..6a6b2f1
--- /dev/null
+++ b/molecule/keycloak/group_vars
@@ -0,0 +1 @@
+../aio/group_vars
\ No newline at end of file
diff --git a/molecule/keycloak/host_vars b/molecule/keycloak/host_vars
new file mode 120000
index 0000000..6dd61d6
--- /dev/null
+++ b/molecule/keycloak/host_vars
@@ -0,0 +1 @@
+../aio/host_vars
\ No newline at end of file
diff --git a/molecule/keycloak/molecule.yml b/molecule/keycloak/molecule.yml
index 6446c65..d1e4346 120000
--- a/molecule/keycloak/molecule.yml
+++ b/molecule/keycloak/molecule.yml
@@ -1 +1 @@
-../shared/molecule.yml
\ No newline at end of file
+../aio/molecule.yml
\ No newline at end of file
diff --git a/molecule/keycloak/prepare.yml b/molecule/keycloak/prepare.yml
index b94b2ed..5edf407 100644
--- a/molecule/keycloak/prepare.yml
+++ b/molecule/keycloak/prepare.yml
@@ -12,8 +12,11 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-- import_playbook: ../shared/prepare/base.yml
-- import_playbook: ../shared/prepare/kubernetes.yml
+- name: Install Kubernetes
+  ansible.builtin.import_playbook: vexxhost.atmosphere.kubernetes
+
+- name: Install CSI
+  ansible.builtin.import_playbook: vexxhost.atmosphere.csi
 
 - hosts: controllers
   become: true
diff --git a/patches/2023.2/magnum/.gitkeep b/patches/2023.2/magnum/.gitkeep
deleted file mode 100644
index e69de29..0000000
--- a/patches/2023.2/magnum/.gitkeep
+++ /dev/null
diff --git a/roles/defaults/vars/main.yml b/roles/defaults/vars/main.yml
index dfb9d58..0b3860e 100644
--- a/roles/defaults/vars/main.yml
+++ b/roles/defaults/vars/main.yml
@@ -13,189 +13,189 @@
 # under the License.
 
 _atmosphere_images:
-  alertmanager: quay.io/prometheus/alertmanager:v0.26.0@sha256:361db356b33041437517f1cd298462055580585f26555c317df1a3caf2868552
-  barbican_api: registry.atmosphere.dev/library/barbican:2023.2@sha256:836d31f3d9b88d7da006478b9d0cd79390b5726042e31d27824599c7fe97acc9
-  barbican_db_sync: registry.atmosphere.dev/library/barbican:2023.2@sha256:836d31f3d9b88d7da006478b9d0cd79390b5726042e31d27824599c7fe97acc9
-  bootstrap: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  ceph_config_helper: ghcr.io/vexxhost/atmosphere/libvirtd:zed@sha256:5f349c9842535c27edbf94be42e4b5c07aa0ff62358cec4b61b1357554e9cf9c
-  ceph: quay.io/ceph/ceph:v16.2.11@sha256:1b9803c8984bef8b82f05e233e8fe8ed8f0bba8e5cc2c57f6efaccbeea682add
-  cert_manager_cainjector: quay.io/jetstack/cert-manager-cainjector:v1.7.1@sha256:985743eeed2b62f68ee06e583f1d5a371e1c35af4b1980a1b2571d29174cce47
-  cert_manager_cli: quay.io/jetstack/cert-manager-ctl:v1.7.1@sha256:af84513925d86d2de456b5d67dbccd2a34d93aa6fd4e1c8fe9f84182fef1b1b1
-  cert_manager_controller: quay.io/jetstack/cert-manager-controller:v1.7.1@sha256:51027a4cc4d30e197e3506daf3a4fa2d2a0bc2826469f8a87848dfd279e031c0
-  cert_manager_webhook: quay.io/jetstack/cert-manager-webhook:v1.7.1@sha256:a926d60b6f23553ca5d11ac9cd66bcc692136e838613c8bc0d60c6c35a3cbcfc
-  cilium_node: quay.io/cilium/cilium:v1.14.8@sha256:7fca3ba4b04af066e8b086b5c1a52e30f52db01ffc642e7db0a439514aed3ada
-  cilium_operator: quay.io/cilium/operator-generic:v1.14.8@sha256:56d373c12483c09964a00a29246595917603a077a298aa90a98e4de32c86b7dc
-  cinder_api: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:33fa168ec380d7f7f9aa144df2c63004403575c547462ab83198b31ddbbef73e
-  cinder_backup_storage_init: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:33fa168ec380d7f7f9aa144df2c63004403575c547462ab83198b31ddbbef73e
-  cinder_backup: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:33fa168ec380d7f7f9aa144df2c63004403575c547462ab83198b31ddbbef73e
-  cinder_db_sync: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:33fa168ec380d7f7f9aa144df2c63004403575c547462ab83198b31ddbbef73e
-  cinder_scheduler: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:33fa168ec380d7f7f9aa144df2c63004403575c547462ab83198b31ddbbef73e
-  cinder_storage_init: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:33fa168ec380d7f7f9aa144df2c63004403575c547462ab83198b31ddbbef73e
-  cinder_volume_usage_audit: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:33fa168ec380d7f7f9aa144df2c63004403575c547462ab83198b31ddbbef73e
-  cinder_volume: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:33fa168ec380d7f7f9aa144df2c63004403575c547462ab83198b31ddbbef73e
-  cluster_api_controller: registry.k8s.io/cluster-api/cluster-api-controller:v1.6.0@sha256:211632c5b695212bce78e0d35da5eb7b7672a3b2ff598883f8c60ebb557a7185
-  cluster_api_kubeadm_bootstrap_controller: registry.k8s.io/cluster-api/kubeadm-bootstrap-controller:v1.6.0@sha256:956876ee8825038b12133352686d86585afa2feb22ca3bf9e437659862db2d43
-  cluster_api_kubeadm_control_plane_controller: registry.k8s.io/cluster-api/kubeadm-control-plane-controller:v1.6.0@sha256:2c4ee52a70e19a0d2b55783bc72d6a63fca84f5da76a9dd1aef2630491277e6f
-  cluster_api_openstack_controller: registry.k8s.io/capi-openstack/capi-openstack-controller:v0.9.0@sha256:d5d5df3695d8b8785ac4ef00497ce0b969ff7dc291cb1647581bd2265b85cf51
-  csi_node_driver_registrar: registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.4.0@sha256:0174bf20d7ad8e9f131a045802ef1c43b4592a2ebc18ba07972b1ce8858d9cb7
-  csi_rbd_attacher: registry.k8s.io/sig-storage/csi-attacher:v3.4.0@sha256:adc2922c98c539f680c02af99042d968114746f973a49b529785d6b402134bbf
-  csi_rbd_plugin: quay.io/cephcsi/cephcsi:v3.5.1@sha256:28a674af1df2325fea415e32a7f93f083fce1f9c474912c45f025427fdc0aa10
-  csi_rbd_provisioner: registry.k8s.io/sig-storage/csi-provisioner:v3.1.0@sha256:92107bb668a9de58a09247596c337bc5b46a1d145685eb55ef489ae16952f5bd
-  csi_rbd_resizer: registry.k8s.io/sig-storage/csi-resizer:v1.3.0@sha256:35ec0c736ec8266bd4a46f9e942315f148f3139beed99879d0ad8b8e5074d641
-  csi_rbd_snapshotter: registry.k8s.io/sig-storage/csi-snapshotter:v4.2.0@sha256:bd7dafbd0d4fe81f23f01c9a7432de067bdf085f70d61492f5ffddd9c5264358
-  db_drop: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  db_init: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  dep_check: ghcr.io/vexxhost/atmosphere/kubernetes-entrypoint:latest@sha256:0c986164554331d5361f100a505695a45d9a7f63f8fb40f29a5ee026ce28b8b2
-  designate_api: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:cddae1e127cb570e8db3e155559b89307cdb7a5b65ace986c12fe3610ea03d9a
-  designate_central: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:cddae1e127cb570e8db3e155559b89307cdb7a5b65ace986c12fe3610ea03d9a
-  designate_db_sync: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:cddae1e127cb570e8db3e155559b89307cdb7a5b65ace986c12fe3610ea03d9a
-  designate_mdns: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:cddae1e127cb570e8db3e155559b89307cdb7a5b65ace986c12fe3610ea03d9a
-  designate_producer: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:cddae1e127cb570e8db3e155559b89307cdb7a5b65ace986c12fe3610ea03d9a
-  designate_sink: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:cddae1e127cb570e8db3e155559b89307cdb7a5b65ace986c12fe3610ea03d9a
-  designate_worker: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:cddae1e127cb570e8db3e155559b89307cdb7a5b65ace986c12fe3610ea03d9a
-  glance_api: ghcr.io/vexxhost/atmosphere/glance:2023.2@sha256:1b127d8bb8f5384050d0acabe623fa8fdb0bba7b6d31a43be68402916723fb1b
-  glance_db_sync: ghcr.io/vexxhost/atmosphere/glance:2023.2@sha256:1b127d8bb8f5384050d0acabe623fa8fdb0bba7b6d31a43be68402916723fb1b
-  glance_metadefs_load: ghcr.io/vexxhost/atmosphere/glance:2023.2@sha256:1b127d8bb8f5384050d0acabe623fa8fdb0bba7b6d31a43be68402916723fb1b
-  glance_registry: ghcr.io/vexxhost/atmosphere/glance:2023.2@sha256:1b127d8bb8f5384050d0acabe623fa8fdb0bba7b6d31a43be68402916723fb1b
-  glance_storage_init: ghcr.io/vexxhost/atmosphere/glance:2023.2@sha256:1b127d8bb8f5384050d0acabe623fa8fdb0bba7b6d31a43be68402916723fb1b
-  grafana_sidecar: quay.io/kiwigrid/k8s-sidecar:1.25.2@sha256:cb4c638ffb1fa1eb49678e0f0423564b39254533f63f4ca6a6c24260472e0c4f
-  grafana: docker.io/grafana/grafana:10.3.3@sha256:f8f7d338b2ecd278599e7f1cfc84a0a7bd4f549312218a54696edb38d709100d
-  haproxy: docker.io/library/haproxy:2.5@sha256:489dcc4385fd45813f3e9252b2f1f440db5749e4845d560250ce5083cc45eeb0
-  heat_api: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  heat_cfn: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  heat_cloudwatch: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  heat_db_sync: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  heat_engine_cleaner: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  heat_engine: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  heat_purge_deleted: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  horizon_db_sync: ghcr.io/vexxhost/atmosphere/horizon:2023.2@sha256:8b8cae26a00725c110bc597840925b66d942e2dd31335334dd8fb9ef3591f494
-  horizon: ghcr.io/vexxhost/atmosphere/horizon:2023.2@sha256:8b8cae26a00725c110bc597840925b66d942e2dd31335334dd8fb9ef3591f494
-  ingress_nginx_controller: registry.k8s.io/ingress-nginx/controller:v1.1.1@sha256:e16123f3932f44a2bba8bc3cf1c109cea4495ee271d6d16ab99228b58766d3ab
-  ingress_nginx_default_backend: registry.k8s.io/defaultbackend-amd64:1.5@sha256:4dc5e07c8ca4e23bddb3153737d7b8c556e5fb2f29c4558b7cd6e6df99c512c7
-  ingress_nginx_kube_webhook_certgen: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:23a03c9c381fba54043d0f6148efeaf4c1ca2ed176e43455178b5c5ebf15ad70 # noqa: yaml[line-length]
-  keepalived: us-docker.pkg.dev/vexxhost-infra/openstack/keepalived:2.0.19@sha256:4fe20cd5c200e301e1a790c9aca8c3fc651c8461afea9d37c56a462d3bfa48bb
-  keycloak: quay.io/keycloak/keycloak:22.0.1-0@sha256:5b872e841ea9e394d89bdf250146434532d9c2001404540d46621d60f87494e7
-  keystone_api: ghcr.io/vexxhost/atmosphere/keystone:2023.2@sha256:edb33b454d1dd0514c5f72613dddec2505e6b103aa7d5e56cb5e9eade119a33a
-  keystone_credential_cleanup: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  keystone_credential_rotate: ghcr.io/vexxhost/atmosphere/keystone:2023.2@sha256:edb33b454d1dd0514c5f72613dddec2505e6b103aa7d5e56cb5e9eade119a33a
-  keystone_credential_setup: ghcr.io/vexxhost/atmosphere/keystone:2023.2@sha256:edb33b454d1dd0514c5f72613dddec2505e6b103aa7d5e56cb5e9eade119a33a
-  keystone_db_sync: ghcr.io/vexxhost/atmosphere/keystone:2023.2@sha256:edb33b454d1dd0514c5f72613dddec2505e6b103aa7d5e56cb5e9eade119a33a
-  keystone_domain_manage: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  keystone_fernet_rotate: ghcr.io/vexxhost/atmosphere/keystone:2023.2@sha256:edb33b454d1dd0514c5f72613dddec2505e6b103aa7d5e56cb5e9eade119a33a
-  keystone_fernet_setup: ghcr.io/vexxhost/atmosphere/keystone:2023.2@sha256:edb33b454d1dd0514c5f72613dddec2505e6b103aa7d5e56cb5e9eade119a33a
-  ks_endpoints: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  ks_service: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  ks_user: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  kube_apiserver: registry.k8s.io/kube-apiserver:v1.22.17@sha256:d88d1c8f972e10ff4b4176f3185434e2832d3805c457fa9e8816f1da2fdf3b93
-  kube_controller_manager: registry.k8s.io/kube-controller-manager:v1.22.17@sha256:c3e041c8c8c9ffd33d421c8c1de1f42da52b616bfcf61880498e9efc9ec88005
-  kube_coredns: registry.k8s.io/coredns/coredns:v1.8.4@sha256:10683d82b024a58cc248c468c2632f9d1b260500f7cd9bb8e73f751048d7d6d4
-  kube_etcd: registry.k8s.io/etcd:3.5.6-0@sha256:b0fdb657c0bd10d8c96ed2ce762842384709a9fc54d532220d5252f1f99b4d1d
-  kube_proxy: registry.k8s.io/kube-proxy:v1.22.17@sha256:614ec43f14e16e077173afa61ee355f8a5d1cc5b1c5e8030766781dc5ccde171
-  kube_scheduler: registry.k8s.io/kube-scheduler:v1.22.17@sha256:f85dda445b7c8da197b8e39b0ca2b125b1e97a4a365d45c04d2759aefe935974
-  kube_state_metrics: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.10.1@sha256:50502264dbee17136b48d19404ce40d6e57ef9d38aafd95ceb1d977cc92e9519
-  kubectl: docker.io/bitnami/kubectl:1.27.3@sha256:876cebc2d9272d9eb42c2128c9a08c7e7715dbfe4f2eb2f0b3612df977fdd6b7
-  libvirt: ghcr.io/vexxhost/atmosphere/libvirtd:zed@sha256:5f349c9842535c27edbf94be42e4b5c07aa0ff62358cec4b61b1357554e9cf9c
-  libvirt_tls_sidecar: ghcr.io/vexxhost/atmosphere/libvirt-tls-sidecar:latest@sha256:32dab069c0c70e46a6bff5f0fd75ca646af4c4b46c83947c31804c30e8befec6
-  libvirt_exporter: docker.io/vexxhost/libvirtd-exporter:latest@sha256:1a0fdf89f80060bfdbb8cf45213295c5d9fb1f7ea7dbfe2b331f0649cc98df8e
-  local_path_provisioner_helper: docker.io/library/busybox:1.36.0@sha256:086417a48026173aaadca4ce43a1e4b385e8e62cc738ba79fc6637049674cac0
-  local_path_provisioner: docker.io/rancher/local-path-provisioner:v0.0.24@sha256:b7dea5221f06f6feed7788db0ad6b024a433c8f55533bd6cc792dc2079ff9ad2
-  loki_gateway: docker.io/nginxinc/nginx-unprivileged:1.19-alpine@sha256:bbd46452aae30a7cc7bc438f267af812c7a2b0f3b5bcd4cc55eb99669cea3f28
-  loki: docker.io/grafana/loki:2.7.3@sha256:8e3abbd89173066721fa07bddfee1c1a7a8fe59bed5b00a2fa09d2b3cef8758c
-  magnum_api: registry.atmosphere.dev/library/magnum:2023.2@sha256:5cc8854c18d5590238f9bfa28b8a4c9a07e0b1c9e69e9a9874fe78fef58454ff
-  magnum_cluster_api_proxy: registry.atmosphere.dev/library/magnum:2023.2@sha256:5cc8854c18d5590238f9bfa28b8a4c9a07e0b1c9e69e9a9874fe78fef58454ff
-  magnum_conductor: registry.atmosphere.dev/library/magnum:2023.2@sha256:5cc8854c18d5590238f9bfa28b8a4c9a07e0b1c9e69e9a9874fe78fef58454ff
-  magnum_db_sync: registry.atmosphere.dev/library/magnum:2023.2@sha256:5cc8854c18d5590238f9bfa28b8a4c9a07e0b1c9e69e9a9874fe78fef58454ff
-  magnum_registry: quay.io/vexxhost/magnum-cluster-api-registry:latest@sha256:caba380e193264f047651728cbc7905e87d7eee846d8576778b5e7d824ec609d
-  manila_api: ghcr.io/vexxhost/atmosphere/manila:2023.2@sha256:c14e65aca5d474fede5be312ce8bdb2d8bedb9841ac138f53bad5882f3f0f31c
-  manila_data: ghcr.io/vexxhost/atmosphere/manila:2023.2@sha256:c14e65aca5d474fede5be312ce8bdb2d8bedb9841ac138f53bad5882f3f0f31c
-  manila_db_sync: ghcr.io/vexxhost/atmosphere/manila:2023.2@sha256:c14e65aca5d474fede5be312ce8bdb2d8bedb9841ac138f53bad5882f3f0f31c
-  manila_scheduler: ghcr.io/vexxhost/atmosphere/manila:2023.2@sha256:c14e65aca5d474fede5be312ce8bdb2d8bedb9841ac138f53bad5882f3f0f31c
-  manila_share: ghcr.io/vexxhost/atmosphere/manila:2023.2@sha256:c14e65aca5d474fede5be312ce8bdb2d8bedb9841ac138f53bad5882f3f0f31c
-  memcached: docker.io/library/memcached:1.6.17@sha256:db45886d2d48f143be64f2d46407e224b0b61df3b0056b9d5b03e8bc6a7cd74e
-  netoffload: ghcr.io/vexxhost/atmosphere/netoffload:main@sha256:136b37811a4352ddb2d2aeeb52c1ee403cc043511ec59afda2c65f1a33a80e18
-  neutron_bagpipe_bgp: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_bgp_dragent: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_coredns: docker.io/coredns/coredns:1.9.3@sha256:bdb36ee882c13135669cfc2bb91c808a33926ad1a411fee07bd2dc344bb8f782
-  neutron_db_sync: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_dhcp: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_ironic_agent: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_l2gw: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_l3: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_linuxbridge_agent: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_metadata: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_netns_cleanup_cron: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_openvswitch_agent: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_ovn_metadata: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_server: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_sriov_agent_init: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  neutron_sriov_agent: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:621cf622cebc031bf367018a5c8104eb8043d2f72da0b7ac85946f58df54adc7
-  node_feature_discovery: registry.k8s.io/nfd/node-feature-discovery:v0.11.2@sha256:24b2abfb5956b6a2a9a0f4248232838d02235d65044078c43d8bdcf29344f141
-  nova_api: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  nova_archive_deleted_rows: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  nova_cell_setup_init: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  nova_cell_setup: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  nova_compute_ironic: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  nova_compute_ssh: ghcr.io/vexxhost/atmosphere/nova-ssh:latest@sha256:5ba950e9bd6aa07adae0befeb94a9f31cc088cc396e4e02e81c30fe5fd90a8b8
-  nova_compute: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  nova_conductor: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  nova_consoleauth: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  nova_db_sync: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  nova_novncproxy_assets: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  nova_novncproxy: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  nova_placement: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  nova_scheduler: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  nova_service_cleaner: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  nova_spiceproxy_assets: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  nova_spiceproxy: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:81ed65286167fd9ea2d6ad1129bdd36a7d8919ed24be442544e161c55083800b
-  oauth2_proxy: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0@sha256:dcb6ff8dd21bf3058f6a22c6fa385fa5b897a9cd3914c88a2cc2bb0a85f8065d
-  octavia_api: ghcr.io/vexxhost/atmosphere/octavia:2023.2@sha256:13ce44f4277e69e3ea3e2341d42378c9470fb5618329e87ca6f58cdee9c84d15
-  octavia_db_sync: ghcr.io/vexxhost/atmosphere/octavia:2023.2@sha256:13ce44f4277e69e3ea3e2341d42378c9470fb5618329e87ca6f58cdee9c84d15
-  octavia_health_manager_init: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:9a659c6a058f8c169affc5850a48870be179849f08e3586e3091e566cbc9543a
-  octavia_health_manager: ghcr.io/vexxhost/atmosphere/octavia:2023.2@sha256:13ce44f4277e69e3ea3e2341d42378c9470fb5618329e87ca6f58cdee9c84d15
-  octavia_housekeeping: ghcr.io/vexxhost/atmosphere/octavia:2023.2@sha256:13ce44f4277e69e3ea3e2341d42378c9470fb5618329e87ca6f58cdee9c84d15
-  octavia_worker: ghcr.io/vexxhost/atmosphere/octavia:2023.2@sha256:13ce44f4277e69e3ea3e2341d42378c9470fb5618329e87ca6f58cdee9c84d15
-  openvswitch_db_server: ghcr.io/vexxhost/atmosphere/openvswitch:3.1.0-65@sha256:f017715f72dc0a48c8cc8ff9a1da9cb2c17879065ffd6c377ffabd2cff28148a
-  openvswitch_vswitchd: ghcr.io/vexxhost/atmosphere/openvswitch:3.1.0-65@sha256:f017715f72dc0a48c8cc8ff9a1da9cb2c17879065ffd6c377ffabd2cff28148a
-  ovn_controller: ghcr.io/vexxhost/atmosphere/ovn-host:23.03.0-69@sha256:2eeeb70a7cd745e3fdbdd396f611cb2bd090228a6551b1b4b9b01d0ac6a8a121
-  ovn_northd: ghcr.io/vexxhost/atmosphere/ovn-central:23.03.0-69@sha256:171a020d3db924c25c3521844a309d5007316d07cd155111670ee291d6ffe39d
-  ovn_ovsdb_nb: ghcr.io/vexxhost/atmosphere/ovn-central:23.03.0-69@sha256:171a020d3db924c25c3521844a309d5007316d07cd155111670ee291d6ffe39d
-  ovn_ovsdb_sb: ghcr.io/vexxhost/atmosphere/ovn-central:23.03.0-69@sha256:171a020d3db924c25c3521844a309d5007316d07cd155111670ee291d6ffe39d
-  pause: registry.k8s.io/pause:3.9@sha256:7031c1b283388d2c2e09b57badb803c05ebed362dc88d84b480cc47f72a21097
-  percona_xtradb_cluster_haproxy: docker.io/percona/percona-xtradb-cluster-operator:1.13.0-haproxy@sha256:f04e4fea548bfc7cb0bfc73c75c7f2c64d299cf04125a07a8101a55f0f734fed
-  percona_xtradb_cluster_operator: docker.io/percona/percona-xtradb-cluster-operator:1.13.0@sha256:c674d63242f1af521edfbaffae2ae02fb8d010c0557a67a9c42d2b4a50db5243
-  percona_xtradb_cluster: docker.io/percona/percona-xtradb-cluster:8.0.32-24.2@sha256:1f978ab8912e1b5fc66570529cb7e7a4ec6a38adbfce1ece78159b0fcfa7d47a
-  percona_version_service: docker.io/perconalab/version-service:main-3325140@sha256:b7928130fca1e35ce7feaeec326fef836229a8b4de2f6f6ea5b6d2c7a48cd071
-  placement_db_sync: ghcr.io/vexxhost/atmosphere/placement:2023.2@sha256:c5bf2b2db697db1966c2fee0c6358dc79b6bac3542c619db5fb8002d666b16d3
-  placement: ghcr.io/vexxhost/atmosphere/placement:2023.2@sha256:c5bf2b2db697db1966c2fee0c6358dc79b6bac3542c619db5fb8002d666b16d3
-  prometheus_config_reloader: quay.io/prometheus-operator/prometheus-config-reloader:v0.71.2@sha256:9f0c16b8c95c908f761d45f95bc04da9dd6482adc8dc0d88dcbc24ceeb5879a1
-  prometheus_ipmi_exporter: us-docker.pkg.dev/vexxhost-infra/openstack/ipmi-exporter:1.4.0@sha256:4898da9cc11961a56363e8b3f3437d0f45b46585b20c79e33e97fbe7232e05d2
-  prometheus_memcached_exporter: quay.io/prometheus/memcached-exporter:v0.10.0@sha256:fa5a2de1a4744da66fb369bee81232f5ea52208bc643e409a60f66d699ac27b2
-  prometheus_mysqld_exporter: quay.io/prometheus/mysqld-exporter:v0.14.0@sha256:eb6fe170738bf9181c51f5bc89f93adb26672ec49ffdcb22f55c24834003b45d
-  prometheus_node_exporter: quay.io/prometheus/node-exporter:v1.7.0@sha256:4cb2b9019f1757be8482419002cb7afe028fdba35d47958829e4cfeaf6246d80
-  prometheus_openstack_database_exporter: ghcr.io/vexxhost/openstack-database-exporter:v0.2.0@sha256:286573f63840f961a6861982f7b3e8007b9a93eed77ec4476810af3286cb7fd9
-  prometheus_openstack_exporter: ghcr.io/openstack-exporter/openstack-exporter:1.7.0@sha256:e5146a7dd5153c035fd8060899e3504b25557756ef4a4d85860a409247404f97
-  prometheus_operator_kube_webhook_certgen: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20221220-controller-v1.5.1-58-g787ea74b6@sha256:5e6fdb9b2c74ad2576dd835b389d00d18ccfee21b547d1a79efb881009664099
-  prometheus_operator: quay.io/prometheus-operator/prometheus-operator:v0.71.2@sha256:bbf3c671e65b0c115d2196bbe7fed0bcdc59f44b7c93868cd40d1c90cbd3806e
-  prometheus_pushgateway: docker.io/prom/pushgateway:v1.4.2@sha256:f74ff5b7ad0b8fb60c24b77eaeab025d659e46ec15f32430adb976544305c01f
-  prometheus: quay.io/prometheus/prometheus:v2.49.1@sha256:beb5e30ffba08d9ae8a7961b9a2145fc8af6296ff2a4f463df7cd722fcbfc789
-  rabbit_init: docker.io/library/rabbitmq:3.10.2-management@sha256:350ab6d773e3af45183466488fe3259df36cd6ade437b4366a59e8052458cc3a
-  rabbitmq_cluster_operator: docker.io/rabbitmqoperator/cluster-operator:1.13.1@sha256:84ce21e9e2d6ceb8b93d9daf0b7cc1550b6ed86be5b3acd8b0816eddc1b87dc2
-  rabbitmq_credential_updater: docker.io/rabbitmqoperator/default-user-credential-updater:1.0.2@sha256:563908dd8d6b6ce768e463a2d9d7a9b9b4adbcd258fed02c0a8746395cfa3f0d
-  rabbitmq_server: docker.io/library/rabbitmq:3.10.2-management@sha256:350ab6d773e3af45183466488fe3259df36cd6ade437b4366a59e8052458cc3a
-  rabbitmq_topology_operator: docker.io/rabbitmqoperator/messaging-topology-operator:1.6.0@sha256:5052e8bdb26996c62315f0707c6fb291fd84492e360cca7351e2c3fdf659be43
-  rook_ceph: docker.io/rook/ceph:v1.10.10@sha256:2a65f6678c3f4e368046ee10695dce2c265cc81cd6bfd6258fc670dd18fbad5b
+  alertmanager: quay.io/prometheus/alertmanager:v0.26.0
+  barbican_api: registry.atmosphere.dev/library/barbican:zed
+  barbican_db_sync: registry.atmosphere.dev/library/barbican:zed
+  bootstrap: registry.atmosphere.dev/library/heat:zed
+  ceph_config_helper: registry.atmosphere.dev/library/libvirtd:zed
+  ceph: quay.io/ceph/ceph:v16.2.11
+  cert_manager_cainjector: quay.io/jetstack/cert-manager-cainjector:v1.7.1
+  cert_manager_cli: quay.io/jetstack/cert-manager-ctl:v1.7.1
+  cert_manager_controller: quay.io/jetstack/cert-manager-controller:v1.7.1
+  cert_manager_webhook: quay.io/jetstack/cert-manager-webhook:v1.7.1
+  cilium_node: quay.io/cilium/cilium:v1.14.8
+  cilium_operator: quay.io/cilium/operator-generic:v1.14.8
+  cinder_api: registry.atmosphere.dev/library/cinder:zed
+  cinder_backup_storage_init: registry.atmosphere.dev/library/cinder:zed
+  cinder_backup: registry.atmosphere.dev/library/cinder:zed
+  cinder_db_sync: registry.atmosphere.dev/library/cinder:zed
+  cinder_scheduler: registry.atmosphere.dev/library/cinder:zed
+  cinder_storage_init: registry.atmosphere.dev/library/cinder:zed
+  cinder_volume_usage_audit: registry.atmosphere.dev/library/cinder:zed
+  cinder_volume: registry.atmosphere.dev/library/cinder:zed
+  cluster_api_controller: registry.k8s.io/cluster-api/cluster-api-controller:v1.6.0
+  cluster_api_kubeadm_bootstrap_controller: registry.k8s.io/cluster-api/kubeadm-bootstrap-controller:v1.6.0
+  cluster_api_kubeadm_control_plane_controller: registry.k8s.io/cluster-api/kubeadm-control-plane-controller:v1.6.0
+  cluster_api_openstack_controller: registry.k8s.io/capi-openstack/capi-openstack-controller:v0.9.0
+  csi_node_driver_registrar: registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.4.0
+  csi_rbd_attacher: registry.k8s.io/sig-storage/csi-attacher:v3.4.0
+  csi_rbd_plugin: quay.io/cephcsi/cephcsi:v3.5.1
+  csi_rbd_provisioner: registry.k8s.io/sig-storage/csi-provisioner:v3.1.0
+  csi_rbd_resizer: registry.k8s.io/sig-storage/csi-resizer:v1.3.0
+  csi_rbd_snapshotter: registry.k8s.io/sig-storage/csi-snapshotter:v4.2.0
+  db_drop: registry.atmosphere.dev/library/heat:zed
+  db_init: registry.atmosphere.dev/library/heat:zed
+  dep_check: registry.atmosphere.dev/library/kubernetes-entrypoint:zed
+  designate_api: registry.atmosphere.dev/library/designate:zed
+  designate_central: registry.atmosphere.dev/library/designate:zed
+  designate_db_sync: registry.atmosphere.dev/library/designate:zed
+  designate_mdns: registry.atmosphere.dev/library/designate:zed
+  designate_producer: registry.atmosphere.dev/library/designate:zed
+  designate_sink: registry.atmosphere.dev/library/designate:zed
+  designate_worker: registry.atmosphere.dev/library/designate:zed
+  glance_api: registry.atmosphere.dev/library/glance:zed
+  glance_db_sync: registry.atmosphere.dev/library/glance:zed
+  glance_metadefs_load: registry.atmosphere.dev/library/glance:zed
+  glance_registry: registry.atmosphere.dev/library/glance:zed
+  glance_storage_init: registry.atmosphere.dev/library/glance:zed
+  grafana_sidecar: quay.io/kiwigrid/k8s-sidecar:1.25.2
+  grafana: docker.io/grafana/grafana:10.3.3
+  haproxy: docker.io/library/haproxy:2.5
+  heat_api: registry.atmosphere.dev/library/heat:zed
+  heat_cfn: registry.atmosphere.dev/library/heat:zed
+  heat_cloudwatch: registry.atmosphere.dev/library/heat:zed
+  heat_db_sync: registry.atmosphere.dev/library/heat:zed
+  heat_engine_cleaner: registry.atmosphere.dev/library/heat:zed
+  heat_engine: registry.atmosphere.dev/library/heat:zed
+  heat_purge_deleted: registry.atmosphere.dev/library/heat:zed
+  horizon_db_sync: registry.atmosphere.dev/library/horizon:zed
+  horizon: registry.atmosphere.dev/library/horizon:zed
+  ingress_nginx_controller: registry.k8s.io/ingress-nginx/controller:v1.1.1
+  ingress_nginx_default_backend: registry.k8s.io/defaultbackend-amd64:1.5
+  ingress_nginx_kube_webhook_certgen: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.1.1
+  keepalived: us-docker.pkg.dev/vexxhost-infra/openstack/keepalived:2.0.19
+  keycloak: quay.io/keycloak/keycloak:22.0.1-0
+  keystone_api: registry.atmosphere.dev/library/keystone:zed
+  keystone_credential_cleanup: registry.atmosphere.dev/library/heat:zed
+  keystone_credential_rotate: registry.atmosphere.dev/library/keystone:zed
+  keystone_credential_setup: registry.atmosphere.dev/library/keystone:zed
+  keystone_db_sync: registry.atmosphere.dev/library/keystone:zed
+  keystone_domain_manage: registry.atmosphere.dev/library/heat:zed
+  keystone_fernet_rotate: registry.atmosphere.dev/library/keystone:zed
+  keystone_fernet_setup: registry.atmosphere.dev/library/keystone:zed
+  ks_endpoints: registry.atmosphere.dev/library/heat:zed
+  ks_service: registry.atmosphere.dev/library/heat:zed
+  ks_user: registry.atmosphere.dev/library/heat:zed
+  kube_apiserver: registry.k8s.io/kube-apiserver:v1.22.17
+  kube_controller_manager: registry.k8s.io/kube-controller-manager:v1.22.17
+  kube_coredns: registry.k8s.io/coredns/coredns:v1.8.4
+  kube_etcd: registry.k8s.io/etcd:3.5.6-0
+  kube_proxy: registry.k8s.io/kube-proxy:v1.22.17
+  kube_scheduler: registry.k8s.io/kube-scheduler:v1.22.17
+  kube_state_metrics: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.10.1
+  kubectl: docker.io/bitnami/kubectl:1.27.3
+  libvirt: registry.atmosphere.dev/library/libvirtd:zed
+  libvirt_tls_sidecar: registry.atmosphere.dev/library/libvirt-tls-sidecar:zed
+  libvirt_exporter: docker.io/vexxhost/libvirtd-exporter:latest
+  local_path_provisioner_helper: docker.io/library/busybox:1.36.0
+  local_path_provisioner: docker.io/rancher/local-path-provisioner:v0.0.24
+  loki_gateway: docker.io/nginxinc/nginx-unprivileged:1.19-alpine
+  loki: docker.io/grafana/loki:2.7.3
+  magnum_api: registry.atmosphere.dev/library/magnum:zed
+  magnum_cluster_api_proxy: registry.atmosphere.dev/library/magnum:zed
+  magnum_conductor: registry.atmosphere.dev/library/magnum:zed
+  magnum_db_sync: registry.atmosphere.dev/library/magnum:zed
+  magnum_registry: quay.io/vexxhost/magnum-cluster-api-registry:latest
+  manila_api: registry.atmosphere.dev/library/manila:zed
+  manila_data: registry.atmosphere.dev/library/manila:zed
+  manila_db_sync: registry.atmosphere.dev/library/manila:zed
+  manila_scheduler: registry.atmosphere.dev/library/manila:zed
+  manila_share: registry.atmosphere.dev/library/manila:zed
+  memcached: docker.io/library/memcached:1.6.17
+  netoffload: registry.atmosphere.dev/library/netoffload:zed
+  neutron_bagpipe_bgp: registry.atmosphere.dev/library/neutron:zed
+  neutron_bgp_dragent: registry.atmosphere.dev/library/neutron:zed
+  neutron_coredns: docker.io/coredns/coredns:1.9.3
+  neutron_db_sync: registry.atmosphere.dev/library/neutron:zed
+  neutron_dhcp: registry.atmosphere.dev/library/neutron:zed
+  neutron_ironic_agent: registry.atmosphere.dev/library/neutron:zed
+  neutron_l2gw: registry.atmosphere.dev/library/neutron:zed
+  neutron_l3: registry.atmosphere.dev/library/neutron:zed
+  neutron_linuxbridge_agent: registry.atmosphere.dev/library/neutron:zed
+  neutron_metadata: registry.atmosphere.dev/library/neutron:zed
+  neutron_netns_cleanup_cron: registry.atmosphere.dev/library/neutron:zed
+  neutron_openvswitch_agent: registry.atmosphere.dev/library/neutron:zed
+  neutron_ovn_metadata: registry.atmosphere.dev/library/neutron:zed
+  neutron_server: registry.atmosphere.dev/library/neutron:zed
+  neutron_sriov_agent_init: registry.atmosphere.dev/library/neutron:zed
+  neutron_sriov_agent: registry.atmosphere.dev/library/neutron:zed
+  node_feature_discovery: registry.k8s.io/nfd/node-feature-discovery:v0.11.2
+  nova_api: registry.atmosphere.dev/library/nova:zed
+  nova_archive_deleted_rows: registry.atmosphere.dev/library/nova:zed
+  nova_cell_setup_init: registry.atmosphere.dev/library/heat:zed
+  nova_cell_setup: registry.atmosphere.dev/library/nova:zed
+  nova_compute_ironic: registry.atmosphere.dev/library/nova:zed
+  nova_compute_ssh: registry.atmosphere.dev/library/nova-ssh:zed
+  nova_compute: registry.atmosphere.dev/library/nova:zed
+  nova_conductor: registry.atmosphere.dev/library/nova:zed
+  nova_consoleauth: registry.atmosphere.dev/library/nova:zed
+  nova_db_sync: registry.atmosphere.dev/library/nova:zed
+  nova_novncproxy_assets: registry.atmosphere.dev/library/nova:zed
+  nova_novncproxy: registry.atmosphere.dev/library/nova:zed
+  nova_placement: registry.atmosphere.dev/library/nova:zed
+  nova_scheduler: registry.atmosphere.dev/library/nova:zed
+  nova_service_cleaner: registry.atmosphere.dev/library/heat:zed
+  nova_spiceproxy_assets: registry.atmosphere.dev/library/nova:zed
+  nova_spiceproxy: registry.atmosphere.dev/library/nova:zed
+  oauth2_proxy: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0
+  octavia_api: registry.atmosphere.dev/library/octavia:zed
+  octavia_db_sync: registry.atmosphere.dev/library/octavia:zed
+  octavia_health_manager_init: registry.atmosphere.dev/library/heat:zed
+  octavia_health_manager: registry.atmosphere.dev/library/octavia:zed
+  octavia_housekeeping: registry.atmosphere.dev/library/octavia:zed
+  octavia_worker: registry.atmosphere.dev/library/octavia:zed
+  openvswitch_db_server: registry.atmosphere.dev/library/openvswitch:zed
+  openvswitch_vswitchd: registry.atmosphere.dev/library/openvswitch:zed
+  ovn_controller: registry.atmosphere.dev/library/ovn-host:zed
+  ovn_northd: registry.atmosphere.dev/library/ovn-central:zed
+  ovn_ovsdb_nb: registry.atmosphere.dev/library/ovn-central:zed
+  ovn_ovsdb_sb: registry.atmosphere.dev/library/ovn-central:zed
+  pause: registry.k8s.io/pause:3.9
+  percona_xtradb_cluster_haproxy: docker.io/percona/percona-xtradb-cluster-operator:1.13.0-haproxy
+  percona_xtradb_cluster_operator: docker.io/percona/percona-xtradb-cluster-operator:1.13.0
+  percona_xtradb_cluster: docker.io/percona/percona-xtradb-cluster:8.0.32-24.2
+  percona_version_service: docker.io/perconalab/version-service:main-3325140
+  placement_db_sync: registry.atmosphere.dev/library/placement:zed
+  placement: registry.atmosphere.dev/library/placement:zed
+  prometheus_config_reloader: quay.io/prometheus-operator/prometheus-config-reloader:v0.71.2
+  prometheus_ipmi_exporter: us-docker.pkg.dev/vexxhost-infra/openstack/ipmi-exporter:1.4.0
+  prometheus_memcached_exporter: quay.io/prometheus/memcached-exporter:v0.10.0
+  prometheus_mysqld_exporter: quay.io/prometheus/mysqld-exporter:v0.14.0
+  prometheus_node_exporter: quay.io/prometheus/node-exporter:v1.7.0
+  prometheus_openstack_database_exporter: ghcr.io/vexxhost/openstack-database-exporter:v0.2.0
+  prometheus_openstack_exporter: ghcr.io/openstack-exporter/openstack-exporter:1.7.0
+  prometheus_operator_kube_webhook_certgen: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20221220-controller-v1.5.1-58-g787ea74b6
+  prometheus_operator: quay.io/prometheus-operator/prometheus-operator:v0.71.2
+  prometheus_pushgateway: docker.io/prom/pushgateway:v1.4.2
+  prometheus: quay.io/prometheus/prometheus:v2.49.1
+  rabbit_init: docker.io/library/rabbitmq:3.10.2-management
+  rabbitmq_cluster_operator: docker.io/rabbitmqoperator/cluster-operator:1.13.1
+  rabbitmq_credential_updater: docker.io/rabbitmqoperator/default-user-credential-updater:1.0.2
+  rabbitmq_server: docker.io/library/rabbitmq:3.10.2-management
+  rabbitmq_topology_operator: docker.io/rabbitmqoperator/messaging-topology-operator:1.6.0
+  rook_ceph: docker.io/rook/ceph:v1.10.10
   secretgen_controller: ghcr.io/carvel-dev/secretgen-controller@sha256:59ec05ce5847bfd70c8e04f08b5195e918c8f6fbb947ffc91b456494a2958fd5
-  senlin_api: ghcr.io/vexxhost/atmosphere/senlin:2023.2@sha256:fe825c07a9e4fb17282b47f978c3d3254e990352d55e359f51dd3d7f198b4f55
-  senlin_conductor: ghcr.io/vexxhost/atmosphere/senlin:2023.2@sha256:fe825c07a9e4fb17282b47f978c3d3254e990352d55e359f51dd3d7f198b4f55
-  senlin_db_sync: ghcr.io/vexxhost/atmosphere/senlin:2023.2@sha256:fe825c07a9e4fb17282b47f978c3d3254e990352d55e359f51dd3d7f198b4f55
-  senlin_engine_cleaner: ghcr.io/vexxhost/atmosphere/senlin:2023.2@sha256:fe825c07a9e4fb17282b47f978c3d3254e990352d55e359f51dd3d7f198b4f55
-  senlin_engine: ghcr.io/vexxhost/atmosphere/senlin:2023.2@sha256:fe825c07a9e4fb17282b47f978c3d3254e990352d55e359f51dd3d7f198b4f55
-  senlin_health_manager: ghcr.io/vexxhost/atmosphere/senlin:2023.2@sha256:fe825c07a9e4fb17282b47f978c3d3254e990352d55e359f51dd3d7f198b4f55
-  staffeln_db_sync: ghcr.io/vexxhost/atmosphere/staffeln:v2.2.3@sha256:9e6e65c11c6722a6fb76d876fac408570f6dc5d78eb6112d9a90b4f6bb88242c
-  staffeln_conductor: ghcr.io/vexxhost/atmosphere/staffeln:v2.2.3@sha256:9e6e65c11c6722a6fb76d876fac408570f6dc5d78eb6112d9a90b4f6bb88242c
-  staffeln_api: ghcr.io/vexxhost/atmosphere/staffeln:v2.2.3@sha256:9e6e65c11c6722a6fb76d876fac408570f6dc5d78eb6112d9a90b4f6bb88242c
-  tempest_run_tests: ghcr.io/vexxhost/atmosphere/tempest:master@sha256:fb60541043884a5f5850ad225a3ff989bf667edc034ab5767f15109afc00b5dc
-  vector: docker.io/timberio/vector:0.27.0-debian@sha256:29f23dab76fa306b67b10eac3e9decdb01c906f8aa3b00a2f5b2e8ae088b84e0
+  senlin_api: registry.atmosphere.dev/library/senlin:zed
+  senlin_conductor: registry.atmosphere.dev/library/senlin:zed
+  senlin_db_sync: registry.atmosphere.dev/library/senlin:zed
+  senlin_engine_cleaner: registry.atmosphere.dev/library/senlin:zed
+  senlin_engine: registry.atmosphere.dev/library/senlin:zed
+  senlin_health_manager: registry.atmosphere.dev/library/senlin:zed
+  staffeln_db_sync: registry.atmosphere.dev/library/staffeln:zed
+  staffeln_conductor: registry.atmosphere.dev/library/staffeln:zed
+  staffeln_api: registry.atmosphere.dev/library/staffeln:zed
+  tempest_run_tests: registry.atmosphere.dev/library/tempest:zed
+  vector: docker.io/timberio/vector:0.27.0-debian
 
 atmosphere_images: '{{ _atmosphere_images | combine(atmosphere_image_overrides, recursive=True)
   }}'
diff --git a/zuul.d/container-images/barbican.yaml b/zuul.d/container-images/barbican.yaml
new file mode 100644
index 0000000..15c371c
--- /dev/null
+++ b/zuul.d/container-images/barbican.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-barbican
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-barbican
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-barbican
+
+- job:
+    name: atmosphere-build-container-image-barbican
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-barbican
+      container_images:
+        - context: images/barbican
+          repository: registry.atmosphere.dev/library/barbican
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=barbican
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/barbican/.*
+
+- job:
+    name: atmosphere-upload-container-image-barbican
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-barbican
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/base.yaml b/zuul.d/container-images/base.yaml
new file mode 100644
index 0000000..6e33526
--- /dev/null
+++ b/zuul.d/container-images/base.yaml
@@ -0,0 +1,65 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-buildset-registry
+    gate:
+      jobs:
+        - atmosphere-buildset-registry
+
+- job:
+    name: atmosphere-buildset-registry
+    parent: ci-buildset-registry
+
+- job:
+    name: atmosphere-build-container-image
+    parent: ci-build-container-image
+    abstract: true
+    dependencies:
+      - name: atmosphere-buildset-registry
+        soft: false
+    vars: &image_vars
+      container_command: docker
+      promote_container_image_method: intermediate-registry
+      buildset_registry_namespaces:
+        - ['docker.io', 'https://registry-1.docker.io']
+        - ['quay.io', 'https://quay.io']
+        - ['gcr.io', 'https://gcr.io']
+        - ['registry.atmosphere.dev', 'https://registry.atmosphere.dev']
+
+- job:
+    name: atmosphere-upload-container-image
+    parent: ci-upload-container-image
+    abstract: true
+    dependencies:
+      - name: atmosphere-buildset-registry
+        soft: false
+    secrets:
+      name: container_registry_credentials
+      secret: atmosphere-registry-credentials
+      pass-to-parent: true
+    vars: *image_vars
+
+- job:
+    name: atmosphere-promote-container-image
+    parent: ci-promote-container-image
+    secrets:
+      name: container_registry_credentials
+      secret: atmosphere-registry-credentials
+      pass-to-parent: true
+    nodeset:
+      nodes: []
+    vars: *image_vars
diff --git a/zuul.d/container-images/cinder.yaml b/zuul.d/container-images/cinder.yaml
new file mode 100644
index 0000000..3878407
--- /dev/null
+++ b/zuul.d/container-images/cinder.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-cinder
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-cinder
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-cinder
+
+- job:
+    name: atmosphere-build-container-image-cinder
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-cinder
+      container_images:
+        - context: images/cinder
+          repository: registry.atmosphere.dev/library/cinder
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=cinder
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/cinder/.*
+
+- job:
+    name: atmosphere-upload-container-image-cinder
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-cinder
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/cluster-api-provider-openstack.yaml b/zuul.d/container-images/cluster-api-provider-openstack.yaml
new file mode 100644
index 0000000..5788c88
--- /dev/null
+++ b/zuul.d/container-images/cluster-api-provider-openstack.yaml
@@ -0,0 +1,51 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-cluster-api-provider-openstack
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-cluster-api-provider-openstack
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-cluster-api-provider-openstack
+
+- job:
+    name: atmosphere-build-container-image-cluster-api-provider-openstack
+    parent: atmosphere-build-container-image
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-cluster-api-provider-openstack
+      container_images:
+        - context: images/cluster-api-provider-openstack
+          repository: registry.atmosphere.dev/library/capi-openstack-controller
+          arch:
+            - linux/amd64
+          tags:
+            - zed
+    files: &container_image_files
+      - images/cluster-api-provider-openstack/.*
+
+- job:
+    name: atmosphere-upload-container-image-cluster-api-provider-openstack
+    parent: atmosphere-upload-container-image
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-cluster-api-provider-openstack
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/designate.yaml b/zuul.d/container-images/designate.yaml
new file mode 100644
index 0000000..eeb2fd1
--- /dev/null
+++ b/zuul.d/container-images/designate.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-designate
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-designate
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-designate
+
+- job:
+    name: atmosphere-build-container-image-designate
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-designate
+      container_images:
+        - context: images/designate
+          repository: registry.atmosphere.dev/library/designate
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=designate
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/designate/.*
+
+- job:
+    name: atmosphere-upload-container-image-designate
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-designate
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/glance.yaml b/zuul.d/container-images/glance.yaml
new file mode 100644
index 0000000..e2ec62c
--- /dev/null
+++ b/zuul.d/container-images/glance.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-glance
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-glance
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-glance
+
+- job:
+    name: atmosphere-build-container-image-glance
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-glance
+      container_images:
+        - context: images/glance
+          repository: registry.atmosphere.dev/library/glance
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=glance
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/glance/.*
+
+- job:
+    name: atmosphere-upload-container-image-glance
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-glance
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/heat.yaml b/zuul.d/container-images/heat.yaml
new file mode 100644
index 0000000..5490356
--- /dev/null
+++ b/zuul.d/container-images/heat.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-heat
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-heat
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-heat
+
+- job:
+    name: atmosphere-build-container-image-heat
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-heat
+      container_images:
+        - context: images/heat
+          repository: registry.atmosphere.dev/library/heat
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=heat
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/heat/.*
+
+- job:
+    name: atmosphere-upload-container-image-heat
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-heat
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/horizon.yaml b/zuul.d/container-images/horizon.yaml
new file mode 100644
index 0000000..096d510
--- /dev/null
+++ b/zuul.d/container-images/horizon.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-horizon
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-horizon
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-horizon
+
+- job:
+    name: atmosphere-build-container-image-horizon
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-horizon
+      container_images:
+        - context: images/horizon
+          repository: registry.atmosphere.dev/library/horizon
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=horizon
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/horizon/.*
+
+- job:
+    name: atmosphere-upload-container-image-horizon
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-horizon
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/ironic.yaml b/zuul.d/container-images/ironic.yaml
new file mode 100644
index 0000000..8727807
--- /dev/null
+++ b/zuul.d/container-images/ironic.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-ironic
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-ironic
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-ironic
+
+- job:
+    name: atmosphere-build-container-image-ironic
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-ironic
+      container_images:
+        - context: images/ironic
+          repository: registry.atmosphere.dev/library/ironic
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=ironic
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/ironic/.*
+
+- job:
+    name: atmosphere-upload-container-image-ironic
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-ironic
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/keystone.yaml b/zuul.d/container-images/keystone.yaml
new file mode 100644
index 0000000..2c83223
--- /dev/null
+++ b/zuul.d/container-images/keystone.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-keystone
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-keystone
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-keystone
+
+- job:
+    name: atmosphere-build-container-image-keystone
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-keystone
+      container_images:
+        - context: images/keystone
+          repository: registry.atmosphere.dev/library/keystone
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=keystone
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/keystone/.*
+
+- job:
+    name: atmosphere-upload-container-image-keystone
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-keystone
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/kubernetes-entrypoint.yaml b/zuul.d/container-images/kubernetes-entrypoint.yaml
new file mode 100644
index 0000000..40ec23a
--- /dev/null
+++ b/zuul.d/container-images/kubernetes-entrypoint.yaml
@@ -0,0 +1,51 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-kubernetes-entrypoint
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-kubernetes-entrypoint
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-kubernetes-entrypoint
+
+- job:
+    name: atmosphere-build-container-image-kubernetes-entrypoint
+    parent: atmosphere-build-container-image
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-kubernetes-entrypoint
+      container_images:
+        - context: images/kubernetes-entrypoint
+          repository: registry.atmosphere.dev/library/kubernetes-entrypoint
+          arch:
+            - linux/amd64
+          tags:
+            - zed
+    files: &container_image_files
+      - images/kubernetes-entrypoint/.*
+
+- job:
+    name: atmosphere-upload-container-image-kubernetes-entrypoint
+    parent: atmosphere-upload-container-image
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-kubernetes-entrypoint
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/libvirt-tls-sidecar.yaml b/zuul.d/container-images/libvirt-tls-sidecar.yaml
new file mode 100644
index 0000000..a3e4757
--- /dev/null
+++ b/zuul.d/container-images/libvirt-tls-sidecar.yaml
@@ -0,0 +1,56 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-libvirt-tls-sidecar
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-libvirt-tls-sidecar
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-libvirt-tls-sidecar
+
+- job:
+    name: atmosphere-build-container-image-libvirt-tls-sidecar
+    parent: atmosphere-build-container-image
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-libvirt-tls-sidecar
+      container_images:
+        - context: .
+          target: libvirt-tls-sidecar
+          repository: registry.atmosphere.dev/library/libvirt-tls-sidecar
+          arch:
+            - linux/amd64
+          tags:
+            - zed
+    files: &container_image_files
+      - go.mod
+      - go.sum
+      - cmd/.*
+      - internal/.*
+      - Dockerfile
+
+- job:
+    name: atmosphere-upload-container-image-libvirt-tls-sidecar
+    parent: atmosphere-upload-container-image
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-libvirt-tls-sidecar
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/libvirtd.yaml b/zuul.d/container-images/libvirtd.yaml
new file mode 100644
index 0000000..6713e4b
--- /dev/null
+++ b/zuul.d/container-images/libvirtd.yaml
@@ -0,0 +1,69 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-libvirtd
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-libvirtd
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-libvirtd
+
+- job:
+    name: atmosphere-build-container-image-libvirtd
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-openstack-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-libvirtd
+      container_images:
+        - context: images/libvirtd
+          repository: registry.atmosphere.dev/library/libvirtd
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=nova
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/openstack-runtime/.*
+
+- job:
+    name: atmosphere-upload-container-image-libvirtd
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-libvirtd
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/magnum.yaml b/zuul.d/container-images/magnum.yaml
new file mode 100644
index 0000000..96eb257
--- /dev/null
+++ b/zuul.d/container-images/magnum.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-magnum
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-magnum
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-magnum
+
+- job:
+    name: atmosphere-build-container-image-magnum
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-magnum
+      container_images:
+        - context: images/magnum
+          repository: registry.atmosphere.dev/library/magnum
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=magnum
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/magnum/.*
+
+- job:
+    name: atmosphere-upload-container-image-magnum
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-magnum
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/manila.yaml b/zuul.d/container-images/manila.yaml
new file mode 100644
index 0000000..11bca93
--- /dev/null
+++ b/zuul.d/container-images/manila.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-manila
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-manila
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-manila
+
+- job:
+    name: atmosphere-build-container-image-manila
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-manila
+      container_images:
+        - context: images/manila
+          repository: registry.atmosphere.dev/library/manila
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=manila
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/manila/.*
+
+- job:
+    name: atmosphere-upload-container-image-manila
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-manila
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/netoffload.yaml b/zuul.d/container-images/netoffload.yaml
new file mode 100644
index 0000000..0d8fde1
--- /dev/null
+++ b/zuul.d/container-images/netoffload.yaml
@@ -0,0 +1,51 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-netoffload
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-netoffload
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-netoffload
+
+- job:
+    name: atmosphere-build-container-image-netoffload
+    parent: atmosphere-build-container-image
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-netoffload
+      container_images:
+        - context: images/netoffload
+          repository: registry.atmosphere.dev/library/netoffload
+          arch:
+            - linux/amd64
+          tags:
+            - zed
+    files: &container_image_files
+      - images/netoffload/.*
+
+- job:
+    name: atmosphere-upload-container-image-netoffload
+    parent: atmosphere-upload-container-image
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-netoffload
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/neutron.yaml b/zuul.d/container-images/neutron.yaml
new file mode 100644
index 0000000..2c46f2a
--- /dev/null
+++ b/zuul.d/container-images/neutron.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-neutron
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-neutron
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-neutron
+
+- job:
+    name: atmosphere-build-container-image-neutron
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-neutron
+      container_images:
+        - context: images/neutron
+          repository: registry.atmosphere.dev/library/neutron
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=neutron
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/neutron/.*
+
+- job:
+    name: atmosphere-upload-container-image-neutron
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-neutron
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/nova-ssh.yaml b/zuul.d/container-images/nova-ssh.yaml
new file mode 100644
index 0000000..68a40c7
--- /dev/null
+++ b/zuul.d/container-images/nova-ssh.yaml
@@ -0,0 +1,70 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-nova-ssh
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-nova-ssh
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-nova-ssh
+
+- job:
+    name: atmosphere-build-container-image-nova-ssh
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-openstack-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-nova-ssh
+      container_images:
+        - context: images/nova-ssh
+          repository: registry.atmosphere.dev/library/nova-ssh
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=nova
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/openstack-runtime/.*
+      - images/nova-ssh/.*
+
+- job:
+    name: atmosphere-upload-container-image-nova-ssh
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-nova-ssh
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/nova.yaml b/zuul.d/container-images/nova.yaml
new file mode 100644
index 0000000..b78c251
--- /dev/null
+++ b/zuul.d/container-images/nova.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-nova
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-nova
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-nova
+
+- job:
+    name: atmosphere-build-container-image-nova
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-nova
+      container_images:
+        - context: images/nova
+          repository: registry.atmosphere.dev/library/nova
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=nova
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/nova/.*
+
+- job:
+    name: atmosphere-upload-container-image-nova
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-nova
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/octavia.yaml b/zuul.d/container-images/octavia.yaml
new file mode 100644
index 0000000..1fc3a46
--- /dev/null
+++ b/zuul.d/container-images/octavia.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-octavia
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-octavia
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-octavia
+
+- job:
+    name: atmosphere-build-container-image-octavia
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-octavia
+      container_images:
+        - context: images/octavia
+          repository: registry.atmosphere.dev/library/octavia
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=octavia
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/octavia/.*
+
+- job:
+    name: atmosphere-upload-container-image-octavia
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-octavia
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/openstack-python-runtime.yaml b/zuul.d/container-images/openstack-python-runtime.yaml
new file mode 100644
index 0000000..efb1efa
--- /dev/null
+++ b/zuul.d/container-images/openstack-python-runtime.yaml
@@ -0,0 +1,70 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-openstack-python-runtime
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-openstack-python-runtime
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-openstack-python-runtime
+
+- job:
+    name: atmosphere-build-container-image-openstack-python-runtime
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-openstack-python-runtime
+      container_images:
+        - context: images/openstack-runtime
+          repository: registry.atmosphere.dev/library/openstack-python-runtime
+          arch:
+            - linux/amd64
+          build_args:
+            - FROM=registry.atmosphere.dev/library/python-base:zed
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-runtime/.*
+
+- job:
+    name: atmosphere-upload-container-image-openstack-python-runtime
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-openstack-python-runtime
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/openstack-runtime.yaml b/zuul.d/container-images/openstack-runtime.yaml
new file mode 100644
index 0000000..379074a
--- /dev/null
+++ b/zuul.d/container-images/openstack-runtime.yaml
@@ -0,0 +1,63 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-openstack-runtime
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-openstack-runtime
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-openstack-runtime
+
+- job:
+    name: atmosphere-build-container-image-openstack-runtime
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-openstack-runtime
+      container_images:
+        - context: images/openstack-runtime
+          repository: registry.atmosphere.dev/library/openstack-runtime
+          arch:
+            - linux/amd64
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/openstack-runtime/.*
+
+- job:
+    name: atmosphere-upload-container-image-openstack-runtime
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-openstack-runtime
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/openstack-venv-builder.yaml b/zuul.d/container-images/openstack-venv-builder.yaml
new file mode 100644
index 0000000..376d68e
--- /dev/null
+++ b/zuul.d/container-images/openstack-venv-builder.yaml
@@ -0,0 +1,68 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-openstack-venv-builder
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-openstack-venv-builder
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-openstack-venv-builder
+
+- job:
+    name: atmosphere-build-container-image-openstack-venv-builder
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-openstack-venv-builder
+      container_images:
+        - context: images/openstack-venv-builder
+          repository: registry.atmosphere.dev/library/openstack-venv-builder
+          arch:
+            - linux/amd64
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+
+- job:
+    name: atmosphere-upload-container-image-openstack-venv-builder
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-openstack-venv-builder
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/openvswitch.yaml b/zuul.d/container-images/openvswitch.yaml
new file mode 100644
index 0000000..2938381
--- /dev/null
+++ b/zuul.d/container-images/openvswitch.yaml
@@ -0,0 +1,51 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-openvswitch
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-openvswitch
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-openvswitch
+
+- job:
+    name: atmosphere-build-container-image-openvswitch
+    parent: atmosphere-build-container-image
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-openvswitch
+      container_images:
+        - context: images/openvswitch
+          repository: registry.atmosphere.dev/library/openvswitch
+          arch:
+            - linux/amd64
+          tags:
+            - zed
+    files: &container_image_files
+      - images/openvswitch/.*
+
+- job:
+    name: atmosphere-upload-container-image-openvswitch
+    parent: atmosphere-upload-container-image
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-openvswitch
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/ovn.yaml b/zuul.d/container-images/ovn.yaml
new file mode 100644
index 0000000..6650af8
--- /dev/null
+++ b/zuul.d/container-images/ovn.yaml
@@ -0,0 +1,68 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-ovn
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-ovn
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-ovn
+
+- job:
+    name: atmosphere-build-container-image-ovn
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-openvswitch
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-ovn
+      container_images:
+        - context: images/ovn
+          repository: registry.atmosphere.dev/library/ovn-central
+          arch:
+            - linux/amd64
+          build_args:
+            - OVN_COMPONENT=central
+          tags:
+            - zed
+        - context: images/ovn
+          repository: registry.atmosphere.dev/library/ovn-host
+          arch:
+            - linux/amd64
+          build_args:
+            - OVN_COMPONENT=host
+          tags:
+            - zed
+    files: &container_image_files
+      - images/openvswitch/.*
+      - images/ovn/.*
+
+- job:
+    name: atmosphere-upload-container-image-ovn
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-openvswitch
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-ovn
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/placement.yaml b/zuul.d/container-images/placement.yaml
new file mode 100644
index 0000000..f4fbd80
--- /dev/null
+++ b/zuul.d/container-images/placement.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-placement
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-placement
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-placement
+
+- job:
+    name: atmosphere-build-container-image-placement
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-placement
+      container_images:
+        - context: images/placement
+          repository: registry.atmosphere.dev/library/placement
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=placement
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/placement/.*
+
+- job:
+    name: atmosphere-upload-container-image-placement
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-placement
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/python-base.yaml b/zuul.d/container-images/python-base.yaml
new file mode 100644
index 0000000..22fef49
--- /dev/null
+++ b/zuul.d/container-images/python-base.yaml
@@ -0,0 +1,63 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-python-base
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-python-base
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-python-base
+
+- job:
+    name: atmosphere-build-container-image-python-base
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-python-base
+      container_images:
+        - context: images/python-base
+          repository: registry.atmosphere.dev/library/python-base
+          arch:
+            - linux/amd64
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+
+- job:
+    name: atmosphere-upload-container-image-python-base
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-python-base
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/senlin.yaml b/zuul.d/container-images/senlin.yaml
new file mode 100644
index 0000000..fb77c5d
--- /dev/null
+++ b/zuul.d/container-images/senlin.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-senlin
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-senlin
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-senlin
+
+- job:
+    name: atmosphere-build-container-image-senlin
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-senlin
+      container_images:
+        - context: images/senlin
+          repository: registry.atmosphere.dev/library/senlin
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=senlin
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/senlin/.*
+
+- job:
+    name: atmosphere-upload-container-image-senlin
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-senlin
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/staffeln.yaml b/zuul.d/container-images/staffeln.yaml
new file mode 100644
index 0000000..5cf8dee
--- /dev/null
+++ b/zuul.d/container-images/staffeln.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-staffeln
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-staffeln
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-staffeln
+
+- job:
+    name: atmosphere-build-container-image-staffeln
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-staffeln
+      container_images:
+        - context: images/staffeln
+          repository: registry.atmosphere.dev/library/staffeln
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=staffeln
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/staffeln/.*
+
+- job:
+    name: atmosphere-upload-container-image-staffeln
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-staffeln
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/tempest.yaml b/zuul.d/container-images/tempest.yaml
new file mode 100644
index 0000000..86cf038
--- /dev/null
+++ b/zuul.d/container-images/tempest.yaml
@@ -0,0 +1,80 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-tempest
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-tempest
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-tempest
+
+- job:
+    name: atmosphere-build-container-image-tempest
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+      - name: atmosphere-build-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-build-container-image-python-base
+        soft: true
+      - name: atmosphere-build-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-build-container-image-openstack-python-runtime
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-tempest
+      container_images:
+        - context: images/tempest
+          repository: registry.atmosphere.dev/library/tempest
+          arch:
+            - linux/amd64
+          build_args:
+            - PROJECT=tempest
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+      - images/python-base/.*
+      - images/openstack-venv-builder/.*
+      - images/openstack-python-runtime/.*
+      - images/tempest/.*
+
+- job:
+    name: atmosphere-upload-container-image-tempest
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+      - name: atmosphere-upload-container-image-ubuntu-cloud-archive
+        soft: true
+      - name: atmosphere-upload-container-image-python-base
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-venv-builder
+        soft: true
+      - name: atmosphere-upload-container-image-openstack-python-runtime
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-tempest
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/ubuntu-cloud-archive.yaml b/zuul.d/container-images/ubuntu-cloud-archive.yaml
new file mode 100644
index 0000000..fc10eab
--- /dev/null
+++ b/zuul.d/container-images/ubuntu-cloud-archive.yaml
@@ -0,0 +1,58 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-ubuntu-cloud-archive
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-ubuntu-cloud-archive
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-ubuntu-cloud-archive
+
+- job:
+    name: atmosphere-build-container-image-ubuntu-cloud-archive
+    parent: atmosphere-build-container-image
+    dependencies:
+      - name: atmosphere-build-container-image-ubuntu
+        soft: true
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-ubuntu-cloud-archive
+      container_images:
+        - context: images/ubuntu-cloud-archive
+          repository: registry.atmosphere.dev/library/ubuntu-cloud-archive
+          arch:
+            - linux/amd64
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+      - images/ubuntu-cloud-archive/.*
+
+- job:
+    name: atmosphere-upload-container-image-ubuntu-cloud-archive
+    parent: atmosphere-upload-container-image
+    dependencies:
+      - name: atmosphere-upload-container-image-ubuntu
+        soft: true
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-ubuntu-cloud-archive
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/container-images/ubuntu.yaml b/zuul.d/container-images/ubuntu.yaml
new file mode 100644
index 0000000..466079a
--- /dev/null
+++ b/zuul.d/container-images/ubuntu.yaml
@@ -0,0 +1,51 @@
+# Copyright (c) 2024 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- project:
+    check:
+      jobs:
+        - atmosphere-build-container-image-ubuntu
+    gate:
+      jobs:
+        - atmosphere-upload-container-image-ubuntu
+    promote:
+      jobs:
+        - atmosphere-promote-container-image-ubuntu
+
+- job:
+    name: atmosphere-build-container-image-ubuntu
+    parent: atmosphere-build-container-image
+    vars: &container_image_vars
+      promote_container_image_job: atmosphere-upload-container-image-ubuntu
+      container_images:
+        - context: images/ubuntu
+          repository: registry.atmosphere.dev/library/ubuntu
+          arch:
+            - linux/amd64
+          tags:
+            - zed
+    files: &container_image_files
+      - images/ubuntu/.*
+
+- job:
+    name: atmosphere-upload-container-image-ubuntu
+    parent: atmosphere-upload-container-image
+    vars: *container_image_vars
+    files: *container_image_files
+
+- job:
+    name: atmosphere-promote-container-image-ubuntu
+    parent: atmosphere-promote-container-image
+    vars: *container_image_vars
+    files: *container_image_files
diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml
index 9a33828..0ba4adb 100644
--- a/zuul.d/jobs.yaml
+++ b/zuul.d/jobs.yaml
@@ -13,35 +13,12 @@
 # under the License.
 
 - job:
-    name: atmosphere-buildset-registry
-    pre-run: zuul.d/playbooks/buildset-registry/pre.yml
-    run: zuul.d/playbooks/buildset-registry/run.yml
-    ansible-split-streams: true
-
-- job:
-    name: atmosphere-upload-images
-    parent: atmosphere-buildset-registry
-    run: zuul.d/playbooks/buildset-registry/run.yml
-    secrets:
-      - registry_credentials
-      - cosign_key
-
-- job:
     name: atmosphere-molecule
     parent: tox
     abstract: true
     pre-run: zuul.d/playbooks/molecule/pre.yml
     run: zuul.d/playbooks/molecule/run.yml
     post-run: zuul.d/playbooks/molecule/post.yml
-    dependencies:
-      - atmosphere-buildset-registry
-
-- job:
-    name: atmosphere-molecule-keycloak
-    parent: atmosphere-molecule
-    pre-run: zuul.d/playbooks/molecule-keycloak/pre.yml
-    vars:
-      tox_envlist: molecule-keycloak
 
 - job:
     name: atmosphere-molecule-csi
@@ -64,11 +41,22 @@
     name: atmosphere-molecule-aio
     parent: atmosphere-molecule
     abstract: true
-    timeout: 7200
     pre-run: zuul.d/playbooks/molecule-aio/pre.yml
     post-run: zuul.d/playbooks/molecule-aio/post.yml
     roles:
       - zuul: openstack/openstack-helm-infra
+
+- job:
+    name: atmosphere-molecule-aio-keycloak
+    parent: atmosphere-molecule-aio
+    vars:
+      tox_envlist: molecule-keycloak
+
+- job:
+    name: atmosphere-molecule-aio-full
+    parent: atmosphere-molecule-aio
+    abstract: true
+    timeout: 7200
     nodeset:
       nodes:
         - name: ubuntu-jammy
@@ -76,13 +64,13 @@
 
 - job:
     name: atmosphere-molecule-aio-openvswitch
-    parent: atmosphere-molecule-aio
+    parent: atmosphere-molecule-aio-full
     vars:
       tox_envlist: molecule-aio-openvswitch
 
 - job:
     name: atmosphere-molecule-aio-ovn
-    parent: atmosphere-molecule-aio
+    parent: atmosphere-molecule-aio-full
     # NOTE(mnaser): https://github.com/vexxhost/atmosphere/issues/662
     voting: false
     vars:
diff --git a/zuul.d/playbooks/buildset-registry/run.yml b/zuul.d/playbooks/buildset-registry/run.yml
deleted file mode 100644
index 7f8118c..0000000
--- a/zuul.d/playbooks/buildset-registry/run.yml
+++ /dev/null
@@ -1,159 +0,0 @@
-# Copyright (c) 2024 VEXXHOST, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-- name: Build images
-  hosts: all
-  tasks:
-    # NOTE(mnaser): This can be removed once the following merges
-    #               https://review.opendev.org/c/zuul/zuul-jobs/+/915025
-    - name: Load "buildset_registry" fact
-      block:
-        - name: Check for results.json
-          stat:
-            path: "{{ zuul.executor.result_data_file }}"
-          register: result_json_stat
-          delegate_to: localhost
-        - name: Load information from zuul_return
-          no_log: true
-          set_fact:
-            buildset_registry: "{{ (lookup('file', zuul.executor.result_data_file) | from_json)['secret_data']['buildset_registry'] }}"
-          when:
-            - buildset_registry is not defined
-            - result_json_stat.stat.exists
-            - result_json_stat.stat.size > 0
-            - "'buildset_registry' in (lookup('file', zuul.executor.result_data_file) | from_json).get('secret_data')"
-
-    - name: Configure Buildkit certificates
-      when: buildset_registry is defined and buildset_registry.cert
-      become: true
-      block:
-        - name: Create a folder for the certificates
-          ansible.builtin.file:
-            path: "/etc/docker/certs.d/{{ buildset_registry.host }}:{{ buildset_registry.port }}"
-            state: directory
-        - name: Copy the certificate
-          ansible.builtin.copy:
-            content: "{{ buildset_registry.cert }}"
-            dest: "/etc/docker/certs.d/{{ buildset_registry.host }}:{{ buildset_registry.port }}/ca.crt"
-        - name: Create a buildkitd.toml file
-          ansible.builtin.copy:
-            dest: /etc/buildkitd.toml
-            content: |
-              [registry."{{ buildset_registry.host }}:{{ buildset_registry.port }}"]
-                ca=["/etc/docker/certs.d/{{ buildset_registry.host }}:{{ buildset_registry.port }}/ca.crt"]
-
-    - name: Create builder
-      ansible.builtin.shell: docker buildx create --name=atmosphere --driver=docker-container {% if buildset_registry.cert %}--config /etc/buildkitd.toml{% endif %}
-
-    - name: Point registry to Atmosphere if in post pipeline
-      when: zuul.pipeline == 'post'
-      no_log: true
-      ansible.builtin.set_fact:
-        buildset_registry:
-          host: registry.atmosphere.dev
-          port: 443
-          username: "{{ registry_credentials.username }}"
-          password: "{{ registry_credentials.password }}"
-
-    - name: Log into registry
-      docker_login:
-        registry: "{{ buildset_registry.host }}{% if buildset_registry.port != 443 %}:{{ buildset_registry.port }}{% endif %}"
-        username: "{{ buildset_registry.username }}"
-        password: "{{ buildset_registry.password }}"
-
-    - name: Build images
-      ansible.builtin.shell: |
-        docker buildx bake --builder=atmosphere --provenance --sbom=true --push
-      args:
-        chdir: "{{ zuul.project.src_dir }}"
-      environment:
-        REGISTRY: "{{ buildset_registry.host }}{% if buildset_registry.port != 443 %}:{{ buildset_registry.port }}{% endif %}/library"
-        PUSH_TO_CACHE: "{{ zuul.pipeline == 'post' }}"
-
-    - name: Get list of images built
-      ansible.builtin.shell: docker buildx bake --print
-      args:
-        chdir: "{{ zuul.project.src_dir }}"
-      environment:
-        REGISTRY: "{{ buildset_registry.host }}{% if buildset_registry.port != 443 %}:{{ buildset_registry.port }}{% endif %}/library"
-      register: images_built_json
-
-    - name: Set fact with list of images
-      set_fact:
-        images_built: "{{ images_built_json.stdout | from_json | json_query('target.*.tags[?@] | []') }}"
-
-    - name: Sign images
-      when: zuul.pipeline == 'post'
-      block:
-        - name: Download cosign binary
-          become: true
-          ansible.builtin.get_url:
-            url: https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64
-            dest: /usr/local/bin/cosign
-            mode: 0755
-
-        - name: Determine the digest for the images
-          ansible.builtin.shell: |
-            cosign triangulate --type=digest {{ item }}
-          loop: "{{ images_built }}"
-          register: cosign_digest
-
-        - name: Copy the cosign public key
-          copy:
-            content: "{{ cosign_key.public }}"
-            dest: cosign.pub
-
-        - name: Verify which images are signed
-          ignore_errors: true
-          ansible.builtin.shell: |
-            cosign verify --key cosign.pub --output json {{ item }}
-          loop: "{{ cosign_digest.results | map(attribute='stdout') | list | unique }}"
-          register: cosign_verify
-
-        - name: Copy the cosign private key
-          copy:
-            content: "{{ cosign_key.private }}"
-            dest: cosign.key
-
-        - name: Sign images
-          ansible.builtin.shell: |
-            cosign sign -y --recursive --key cosign.key {{ item }}
-          loop: "{{ cosign_verify.results | selectattr('failed', 'equalto', true) | map(attribute='item') | list }}"
-
-        - name: Delete the cosign private key
-          file:
-            path: cosign.key
-            state: absent
-
-    - name: Return Zuul artifacts for images
-      zuul_return:
-        data:
-          zuul:
-            artifacts:
-              - name: "{{ item }}"
-                url: "docker://{{ item }}"
-                metadata:
-                  type: container_image
-                  repository: "{{ item.split(':')[0] }}"
-                  tag: "{{ item.split(':')[1] }}"
-      loop: "{{ images_built }}"
-
-- name: Yield to other jobs
-  hosts: localhost
-  tasks:
-    - name: Pause the job
-      zuul_return:
-        data:
-          zuul:
-            pause: true
diff --git a/zuul.d/playbooks/molecule/pre.yml b/zuul.d/playbooks/molecule/pre.yml
index f9f2213..a4bc692 100644
--- a/zuul.d/playbooks/molecule/pre.yml
+++ b/zuul.d/playbooks/molecule/pre.yml
@@ -59,8 +59,15 @@
         - name: Replace the registry in image manifest
           ansible.builtin.replace:
             path: "{{ zuul.project.src_dir }}/roles/defaults/vars/main.yml"
-            regexp: "registry.atmosphere.dev/library/([^@]*)@sha256:[a-fA-F0-9]{64}"
-            replace: '{{ buildset_registry.host }}:{{ buildset_registry.port }}/library/\1'
+            regexp: "{{ repo }}:{{ tag }}"
+            replace: '{{ buildset_registry.host }}:{{ buildset_registry.port }}/{{ repo }}:{{ tag }}'
+          loop: "{{ zuul.artifacts | default([]) }}"
+          loop_control:
+            loop_var: zj_zuul_artifact
+          when: "'metadata' in zj_zuul_artifact and zj_zuul_artifact.metadata.type | default('') == 'container_image'"
+          vars:
+            repo: "{{ zj_zuul_artifact.metadata.repository }}"
+            tag: "{{ zj_zuul_artifact.metadata.tag }}"
 
     # TODO(mnaser): Drop this when we move to PBR
     - name: Add current folder to Git's safe directories
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 55e21fa..51aba1a 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -13,14 +13,128 @@
 # under the License.
 
 - project:
+    merge-mode: squash-merge
     check:
       jobs:
-        - atmosphere-buildset-registry
-        - atmosphere-molecule-aio-openvswitch
-        - atmosphere-molecule-aio-ovn
-        - atmosphere-molecule-csi-local-path-provisioner
-        - atmosphere-molecule-csi-rbd
-        - atmosphere-molecule-keycloak
-    post:
+        - atmosphere-molecule-aio-keycloak:
+            dependencies: &molecule_check_dependencies
+              - name: atmosphere-build-container-image-barbican
+                soft: true
+              - name: atmosphere-build-container-image-cinder
+                soft: true
+              - name: atmosphere-build-container-image-cluster-api-provider-openstack
+                soft: true
+              - name: atmosphere-build-container-image-designate
+                soft: true
+              - name: atmosphere-build-container-image-glance
+                soft: true
+              - name: atmosphere-build-container-image-heat
+                soft: true
+              - name: atmosphere-build-container-image-horizon
+                soft: true
+              - name: atmosphere-build-container-image-ironic
+                soft: true
+              - name: atmosphere-build-container-image-keystone
+                soft: true
+              - name: atmosphere-build-container-image-kubernetes-entrypoint
+                soft: true
+              - name: atmosphere-build-container-image-libvirt-tls-sidecar
+                soft: true
+              - name: atmosphere-build-container-image-libvirtd
+                soft: true
+              - name: atmosphere-build-container-image-magnum
+                soft: true
+              - name: atmosphere-build-container-image-manila
+                soft: true
+              - name: atmosphere-build-container-image-netoffload
+                soft: true
+              - name: atmosphere-build-container-image-neutron
+                soft: true
+              - name: atmosphere-build-container-image-nova
+                soft: true
+              - name: atmosphere-build-container-image-nova-ssh
+                soft: true
+              - name: atmosphere-build-container-image-octavia
+                soft: true
+              - name: atmosphere-build-container-image-openvswitch
+                soft: true
+              - name: atmosphere-build-container-image-ovn
+                soft: true
+              - name: atmosphere-build-container-image-placement
+                soft: true
+              - name: atmosphere-build-container-image-senlin
+                soft: true
+              - name: atmosphere-build-container-image-staffeln
+                soft: true
+              - name: atmosphere-build-container-image-tempest
+                soft: true
+        - atmosphere-molecule-aio-openvswitch:
+            dependencies: *molecule_check_dependencies
+        - atmosphere-molecule-aio-ovn:
+            dependencies: *molecule_check_dependencies
+        - atmosphere-molecule-csi-local-path-provisioner:
+            dependencies: *molecule_check_dependencies
+        - atmosphere-molecule-csi-rbd:
+            dependencies: *molecule_check_dependencies
+    gate:
       jobs:
-        - atmosphere-upload-images
+        - atmosphere-molecule-aio-keycloak:
+            dependencies: &molecule_gate_dependencies
+              - name: atmosphere-upload-container-image-barbican
+                soft: true
+              - name: atmosphere-upload-container-image-cinder
+                soft: true
+              - name: atmosphere-upload-container-image-cluster-api-provider-openstack
+                soft: true
+              - name: atmosphere-upload-container-image-designate
+                soft: true
+              - name: atmosphere-upload-container-image-glance
+                soft: true
+              - name: atmosphere-upload-container-image-heat
+                soft: true
+              - name: atmosphere-upload-container-image-horizon
+                soft: true
+              - name: atmosphere-upload-container-image-ironic
+                soft: true
+              - name: atmosphere-upload-container-image-keystone
+                soft: true
+              - name: atmosphere-upload-container-image-kubernetes-entrypoint
+                soft: true
+              - name: atmosphere-upload-container-image-libvirt-tls-sidecar
+                soft: true
+              - name: atmosphere-upload-container-image-libvirtd
+                soft: true
+              - name: atmosphere-upload-container-image-magnum
+                soft: true
+              - name: atmosphere-upload-container-image-manila
+                soft: true
+              - name: atmosphere-upload-container-image-netoffload
+                soft: true
+              - name: atmosphere-upload-container-image-neutron
+                soft: true
+              - name: atmosphere-upload-container-image-nova
+                soft: true
+              - name: atmosphere-upload-container-image-nova-ssh
+                soft: true
+              - name: atmosphere-upload-container-image-octavia
+                soft: true
+              - name: atmosphere-upload-container-image-openvswitch
+                soft: true
+              - name: atmosphere-upload-container-image-ovn
+                soft: true
+              - name: atmosphere-upload-container-image-placement
+                soft: true
+              - name: atmosphere-upload-container-image-senlin
+                soft: true
+              - name: atmosphere-upload-container-image-staffeln
+                soft: true
+              - name: atmosphere-upload-container-image-tempest
+                soft: true
+        - atmosphere-molecule-aio-openvswitch:
+            dependencies: *molecule_gate_dependencies
+        - atmosphere-molecule-aio-ovn:
+            dependencies: *molecule_gate_dependencies
+        - atmosphere-molecule-csi-local-path-provisioner:
+            dependencies: *molecule_gate_dependencies
+        - atmosphere-molecule-csi-rbd:
+            dependencies: *molecule_gate_dependencies
diff --git a/zuul.d/secrets.yaml b/zuul.d/secrets.yaml
index 9cbc362..5208efb 100644
--- a/zuul.d/secrets.yaml
+++ b/zuul.d/secrets.yaml
@@ -13,20 +13,21 @@
 # under the License.
 
 - secret:
-    name: registry_credentials
+    name: atmosphere-registry-credentials
     data:
-      username: robot$zuul
-      password: !encrypted/pkcs1-oaep
-        - OOykjodZE21qsYYLpzplp+PV0QbsKQ1B3+kI7bY97VQI/d5RlewqlNABc10eQnyYFSDvq
-          z2gSigSHxaVcV5qKJLTNVDgzSBHBj349OaTh6dXsxplvoArehfYMMZGuNmFlucoeN8K6w
-          yLRViN7tCS39CAYdjeNX1X7mQ7gBC61jUQ++JB+R5MhXmALJxzPfQRl9jsYmjx9ZXjEwE
-          tjKLSyQifQU20eXbhZOUW2nr+ItTikS3AOSo6Ja6jCI1c9lj6mJtUOorGsuxfdhEigPws
-          Qnz539imGcyqySSxvbJvgoEYxhE3dHFV5cJkomoHHHwLH0wbjAgBQtCMX3CvpxNX8sBfJ
-          MxvUkxY8VWt3CtJkdq+/eaCovCRn6GN5enI5tlUJgpAyV+PO6PvkTan6yC8lHMM5pD4jX
-          Hdo6gt6m9WyA5VxUHdoYYMaDO/rvCxxrUevzPn8do5I96madr9S9lFARqw74mgXG5I6pZ
-          M7zDXnorUFyv9dUIB2rOZrp7o0OC2thujjDTKXb4qfmfXGOwlkNmtCLo6BaDo9pSdRN8p
-          k0YnUAItZ64qUR7paEUKGy4rzsZjDYvIj7DrCFvLL2CXcyjPGcmcblpSHe5vJ15CFVH8X
-          o39FIIhSmehvrYJziGYUgf4JY1B6ktBtFc9l78WeoJRHNce+viSSkBj1fhbUaI=
+      registry.atmosphere.dev:
+        username: robot$zuul
+        password: !encrypted/pkcs1-oaep
+          - OOykjodZE21qsYYLpzplp+PV0QbsKQ1B3+kI7bY97VQI/d5RlewqlNABc10eQnyYFSDvq
+            z2gSigSHxaVcV5qKJLTNVDgzSBHBj349OaTh6dXsxplvoArehfYMMZGuNmFlucoeN8K6w
+            yLRViN7tCS39CAYdjeNX1X7mQ7gBC61jUQ++JB+R5MhXmALJxzPfQRl9jsYmjx9ZXjEwE
+            tjKLSyQifQU20eXbhZOUW2nr+ItTikS3AOSo6Ja6jCI1c9lj6mJtUOorGsuxfdhEigPws
+            Qnz539imGcyqySSxvbJvgoEYxhE3dHFV5cJkomoHHHwLH0wbjAgBQtCMX3CvpxNX8sBfJ
+            MxvUkxY8VWt3CtJkdq+/eaCovCRn6GN5enI5tlUJgpAyV+PO6PvkTan6yC8lHMM5pD4jX
+            Hdo6gt6m9WyA5VxUHdoYYMaDO/rvCxxrUevzPn8do5I96madr9S9lFARqw74mgXG5I6pZ
+            M7zDXnorUFyv9dUIB2rOZrp7o0OC2thujjDTKXb4qfmfXGOwlkNmtCLo6BaDo9pSdRN8p
+            k0YnUAItZ64qUR7paEUKGy4rzsZjDYvIj7DrCFvLL2CXcyjPGcmcblpSHe5vJ15CFVH8X
+            o39FIIhSmehvrYJziGYUgf4JY1B6ktBtFc9l78WeoJRHNce+viSSkBj1fhbUaI=
 
 - secret:
     name: cosign_key