Skip to main content
A State Store System is the canonical source for the desired state of your system: configurations, application manifests, and infrastructure definitions. In GitOps workflows this authoritative state is most commonly a Git repository because Git provides provenance, immutability, branching, and pull requests for collaborative change management. However, Git is not the only option. OCI (Open Container Initiative) registries can act as a unified state store for many artifact types used in Kubernetes ecosystems — container images, Helm charts, plain manifests, overlays, policy bundles, and more — letting you reuse the same registry, authentication, and access controls across those artifact types. Why use OCI as a state store?
  • Consolidates multiple artifact types into a single registry.
  • Reuses existing authentication/authorization and lifecycle tooling.
  • Enables GitOps operators (Flux, Argo CD) to pull artifacts from registries that support OCI artifacts.
OCI defines standards for container image formats and runtimes. The OCI Artifact model extends container images so registries can store arbitrary artifact types (images, Helm charts, manifest bundles, policies) as first-class artifacts.
The image explains OCI Artifacts, showing how various data types like images, Helm charts, and Kubernetes manifests are stored and distributed using OCI registries. It includes a diagram illustrating the structure of a registry with different artifact versions.
A single OCI registry can host multiple repositories; each repository can contain multiple artifacts and versions. Common OCI registry providers include GitHub Container Registry, Docker Hub, Azure Container Registry, and Google Artifact Registry. Table: Typical storage locations vs. OCI as a consolidated option
Resource typeTypical storageOCI alternative
Container imagesContainer registries (e.g., Docker Hub)OCI registry repository (image manifests)
Helm chartsChart repositories or registriesHelm charts stored as OCI artifacts
Kubernetes manifests / overlaysGit repositories (manifests, kustomize overlays)Manifest bundles pushed as OCI artifacts (Flux/others)
Policy bundles (e.g., OPA)Policy stores / GitPolicies packaged and stored as OCI artifacts
Callouts
Using a single OCI registry for multiple artifact types simplifies access management: you can reuse the same credentials, RBAC rules, and audit trails for images, charts, and other artifacts.
Do not embed long-lived credentials in scripts. Prefer short-lived tokens, OIDC-based flows, or CI/CD secret managers. Always revoke or rotate Personal Access Tokens (PATs) used for registry access.
Below are practical examples showing how to push images, Helm charts, and plain Kubernetes manifests into an OCI-compliant registry. The examples use GitHub Container Registry (ghcr.io) but the commands and concepts apply to other OCI registries (Docker Hub, Azure Container Registry, Google Artifact Registry).

Pushing container images to an OCI registry

Steps:
  1. Authenticate to the registry (use a Personal Access Token or other secure credentials).
  2. Tag the local image using the registry repository name.
  3. Push the tagged image.
Example (replace <<GITHUB_PERSONAL_ACCESS_TOKEN>> with your token):
# Log in (one-time per host/session)
$ docker login ghcr.io \
  --username sidd-harth \
  --password <<GITHUB_PERSONAL_ACCESS_TOKEN>>
Login Succeeded

# Confirm the local image (example: nginx)
$ docker images nginx
REPOSITORY   TAG       IMAGE ID    CREATED        SIZE
nginx        latest    8873639     8 days ago     142MB

# Tag the local image with your registry path and version
$ docker tag nginx ghcr.io/sidd-harth/nginx:1.1.0

# Push the image to the OCI registry
$ docker push ghcr.io/sidd-harth/nginx:1.1.0
6cffb086835: Pushed
2d75b87993c: Pushed
ec43a899918: Pushed
sha256:a4a4a4d...: digest: sha256:a4a4a4d... size: 1570
Once pushed, Kubernetes workloads (or other consumers) can pull the image using the ghcr.io/sidd-harth/nginx:1.1.0 reference provided they have access.

Pushing Helm charts to an OCI registry

Modern Helm supports saving and pushing charts as OCI artifacts. Typical flow:
  1. Create or have a chart (e.g., helm create app1).
  2. Package the chart as a .tgz.
  3. Login to the registry with Helm.
  4. Save/push the chart as an OCI artifact.
Example (replace <<GITHUB_PERSONAL_ACCESS_TOKEN>> with your token):
# Create a chart scaffold
$ helm create app1
Creating app1

# Package the chart to a tgz
$ helm package app1
Successfully packaged chart and saved it to: ./app1-1.0.0.tgz

# Login to the registry using Helm
$ helm registry login ghcr.io \
  --username sidd-harth \
  --password <<GITHUB_PERSONAL_ACCESS_TOKEN>>
Login Succeeded

# Save and push the chart as an OCI artifact (Helm >=3.7+)
$ helm chart save ./app1-1.0.0.tgz ghcr.io/sidd-harth/app1:1.0.0
$ helm chart push ghcr.io/sidd-harth/app1:1.0.0
Pushed: ghcr.io/sidd-harth/app1:1.0.0
Digest: sha256:81de917eaf38356b1145bdde2984dc2fdf14...
After pushing, consumers can pull the chart directly from the OCI registry using Helm’s OCI registry support.

Publishing plain Kubernetes manifests to an OCI registry (using Flux)

You can package a directory of Kubernetes manifests and push it as an OCI artifact. Flux provides flux push artifact to create a manifest bundle and push it to an OCI registry; a GitOps operator can then reference that bundle. Example using Flux (replace <<GITHUB_PERSONAL_ACCESS_TOKEN>> with your token):
# Ensure Docker login (if your registry requires it)
$ docker login ghcr.io \
  --username sidd-harth \
  --password <<GITHUB_PERSONAL_ACCESS_TOKEN>>
Login Succeeded

# Example manifests tree
$ tree nginx/
nginx/
└── manifests
    ├── deployment.yaml
    └── service.yaml

# Push manifests as an OCI artifact with Flux
$ flux push artifact oci://ghcr.io/sidd-harth/nginx-2:$(git rev-parse --short HEAD) \
  --path="./nginx/manifests/" \
  --source="$(git config --get remote.origin.url)" \
  --revision="$(git branch --show-current)/$(git rev-parse HEAD)"
pushing to ghcr.io/sidd-harth/nginx-2:1b31558
artifact successfully pushed to ghcr.io/sidd-harth/nginx-2@sha256:235b486df4a38f0151...
Once the manifest bundle is published, configure your GitOps operator (e.g., Flux or Argo CD) to reference the OCI artifact location and reconciliation will apply those manifests to your cluster.

How GitOps operators consume OCI artifacts

  • Argo CD and Flux both support pulling from OCI registries:
    • Argo CD: supports OCI images and some extensions for OCI-based applications.
    • Flux: has first-class support for Kustomization/HelmRepository using oci:// sources and flux push artifact.
  • Typical operator flow: fetch OCI artifact → verify digest/revision → render/apply manifests or charts → report status.
ProviderNotes
GitHub Container Registry (ghcr.io)Supports OCI artifacts and fine-grained permissions
Docker HubPopular image registry with OCI support
Azure Container RegistryEnterprise-grade registry with RBAC and ACR Tasks
Google Artifact RegistrySupports multiple artifact formats including OCI

Best practices

  • Consolidate related artifacts under predictable repository paths (e.g., ghcr.io/<org>/<app>).
  • Use image and artifact digests (sha256) in production manifests to guarantee immutability.
  • Use short-lived credentials or OIDC where possible; avoid embedding PATs in long-lived scripts.
  • Apply RBAC and least privilege on the registry to limit artifact access.

References

That’s all for this lesson.

Watch Video