apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: shop
namespace: flux-system
spec:
interval: 10m
sourceRef:
kind: OCIRepository
name: shop-manifests
path: ./
prune: true
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: OCIRepository
metadata:
name: shop-manifests
namespace: flux-system
spec:
interval: 5m
url: oci://ghcr.io/acme/manifests/shop
ref:
tag: latest
layerSelector:
mediaType: application/vnd.cncf.flux.content.v1.tar+gzip
operation: extract
---
apiVersion: v1
kind: Pod
metadata:
name: inference
namespace: ml
spec:
containers:
- name: server
image: ghcr.io/acme/inference-server:3.2.0
volumeMounts:
- name: model
mountPath: /models/sentiment
readOnly: true
volumes:
- name: model
image:
reference: ghcr.io/acme/models/sentiment:2026-10
pullPolicy: IfNotPresentHelm graph
OCI artifacts: Helm charts, Flux artifacts and image volumes
Three kinds of content in one registry, each a manifest with its own media types: a Helm chart pulled by helm, a Flux artifact pulled by an OCIRepository, and a data image mounted into a Pod as an image volume.
A registry doesn't care whether a manifest describes a container. It stores a config blob and layer blobs, and the media types say what they are. Helm, Flux and many other tools use that to ship their own formats through the registry you already run, with the same authentication, replication and digests.
Each client reads the manifest, picks the layer whose media type it understands and downloads only that blob. The third example is a plain image used as data: Kubernetes 1.36 can mount it as a read-only volume.
Interactive graph
Click a resource to see what it does, or follow the setup step by step.
How it works
All 12 resources and what they do
- Client helm CLI
- Runs
helm install shop oci://ghcr.io/acme/charts/shop --version 0.9.0. It resolves the tag0.9.0, reads the manifest and downloads the chart layer. Noindex.yamlis involved. - Image manifest charts/shop:0.9.0
- Written by
helm push. The config media typeapplication/vnd.cncf.helm.config.v1+jsonis how registries and tools recognize it as a chart. - Config Chart.yaml as JSON
- The chart's metadata: name, version, appVersion, description. Tools can show it without downloading the chart itself.
- Layer shop-0.9.0.tgz
- The packaged chart, byte for byte the
.tgzthathelm packagemade, with the media typeapplication/vnd.cncf.helm.chart.content.v1.tar+gzip. A signed chart has a second layer,application/vnd.cncf.helm.chart.provenance.v1.prov. - Kustomization shopkustomize.toolkit.fluxcd.io/v1
- Applies the manifests from the OCIRepository's artifact. The cluster never talks to Git. CI pushed the manifests to the registry instead.
- OCIRepository shop-manifestssource.toolkit.fluxcd.io/v1
- source-controller checks the
latesttag every 5 minutes. When its digest changes, it downloads the layer thatlayerSelectornames and, withoperation: extract, unpacks it as the new artifact. - Image manifest manifests/shop:4f2c8e1
- Written by
flux push artifactin CI, then taggedlatestwithflux tag artifact. The annotations record the Git source and revision, which Flux shows as the artifact's origin. - Layer deploy/ as tar.gz
- The
./deploydirectory from the app repo, packed byflux push artifact --path=./deploy. source-controller unpacks it and serves it to the Kustomization. - Pod inferencev1
- Runs the inference server from one image and mounts the model from another with an
imagevolume. Updating the model means pushing a new model image, not rebuilding the server. - Container runtime containerd 2.1+
- Pulls the volume image like any image, unpacks its layers into a snapshot and mounts it read-only into the Pod. Image volumes need containerd 2.1 or CRI-O 1.31 or later. CRI-O can also mount artifacts that aren't images.
- Image manifest models/sentiment:2026-10
- An ordinary image manifest, built
FROM scratchwith a singleCOPYof the model files. It has no entrypoint and never runs. The kubelet only needs its filesystem. - Layer model files, 256 MB
- The model weights and tokenizer, compressed with zstd. Nodes that already have this digest skip the download, so rolling out a new server version doesn't move the model again.
Common mistakes
- Some registries reject manifests with media types they don't know. All the major ones accept artifacts now, but older self-hosted registries and some proxies may need configuration.
- Helm stores version
1.2.3+build.4under the tag1.2.3_build.4, because tags can't contain+. Tools that compute the tag themselves have to do the same. - An OCIRepository without
layerSelectortakes the first layer. That works for Flux artifacts, but for a chart with a provenance layer, select the chart's media type explicitly. - Image volumes are read-only, and files keep the owner and mode they have in the image. Set ownership and permissions when you build the image, so the container's user can read them.
- A moving tag like
latestin an image volume withpullPolicy: IfNotPresentkeeps the old content on nodes that already pulled it. Use dated or versioned tags, or a digest.
The manifests you write
Everything above that is marked "You write it", in one file. The rest comes from add-ons and controllers.
Keep going
More graphs
- Deployment, Service and Ingress: how a request reaches your Pods
- Gateway API: GatewayClass, Gateway and HTTPRoute with a canary split
- PVC, StorageClass and CSI: how a cloud disk ends up in your Pod
- RBAC: how a ServiceAccount gets its permissions
- cert-manager with Let's Encrypt: Certificate, CertificateRequest, Order and Challenge
- A private CA with cert-manager and trust-manager
- Istio traffic management: Gateway, VirtualService, DestinationRule and policies
- Flux dependencies: Git and OCI sources, Kustomizations and HelmReleases
- Argo CD: ApplicationSet, AppProject and the Applications it generates
- Inside an OCI image: tag, index, manifests, config and layers