> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Flux Pull and Deploy from OCI Registry

> Guide to using Flux to pull a private OCI artifact from GHCR and deploy its Kubernetes manifests with an OCIRepository source and Kustomization, including registry auth and health checks

In this walkthrough you'll use Flux's Source Controller to pull an OCI artifact from an OCI registry (GitHub Container Registry / GHCR) and deploy it with a Kustomization. The demo pulls the `bb-app` image from GHCR, configures authentication for a private registry, creates an `OCIRepository` source, and deploys the manifests produced by that artifact.

![A GitHub user profile/packages page in dark mode with a large circular avatar on the left and a list of two private packages on the right. The avatar shows a smiling person.](https://mintcdn.com/kodekloud-c4ac6d9a/AyhVWHpoMIYCWiei/images/GitOps-with-FluxCD/Helm-Controller-and-OCI-Registry/Demo-Flux-Pull-and-Deploy-from-OCI-Registry/github-user-packages-dark-smiling-avatar.jpg?fit=max\&auto=format\&n=AyhVWHpoMIYCWiei\&q=85\&s=3799611dc707f3145eb3d0967fd2d871)

Prerequisites

* A Kubernetes cluster with Flux installed (source-controller and kustomize-controller).
* Access to the private GHCR repository and a GitHub personal access token with package read scope.
* flux CLI and kubectl configured to your cluster.
* (Optional) cosign or other supply-chain tooling if you prefer digest-based references.

Quick local test
Pull the image locally to confirm the image/tag exist:

```bash theme={null}
docker pull ghcr.io/sidd-harth-2/bb-app:7.7.0-0bb2691
```

Step 1 — Create an OCIRepository (Flux source)
From your cluster repo (example: `flux-clusters/dev-cluster`) use the flux CLI to create an OCIRepository resource and export the YAML:

```bash theme={null}
cd ../block-buster/flux-clusters/dev-cluster/
flux create source oci 7-demo-source-oci-bb-app-7-7-0 \
  --url oci://ghcr.io/sidd-harth-2/bb-app \
  --tag 7.7.0-xxxxxxxxxxxxxxxxxxxxxxxx \
  --secret-ref ghcr-auth \
  --provider generic \
  --export > 7-demo-source-oci-bb-app-7-7-0.yml
```

This generates an `OCIRepository` resource (Flux’s source type for OCI registries). Replace the `--tag` placeholder with the exact tag or digest you want to track. Example exported YAML:

```yaml theme={null}
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
  name: 7-demo-source-oci-bb-app-7-7-0
  namespace: flux-system
spec:
  interval: 1m0s
  provider: generic
  ref:
    tag: 7.7.0-xxxxxxxxxxxxxxxxxx
  secretRef:
    name: ghcr-auth
  url: oci://ghcr.io/sidd-harth-2/bb-app
```

Find the exact tag or digest
You can copy the tag/digest from the registry UI or from the `docker pull` output. For this demo:

* Tag: `7.7.0-0bb2691`
* Digest: `sha256:379024c535859545876ae260f5a2367f8b34a758528fc6074d58c8ec9fbbf28c`

Tip: If you use signed images (cosign), referencing the digest is preferred for stronger immutability guarantees.

Step 2 — Create registry credentials for Flux
Flux requires a registry secret so the source-controller can authenticate to GHCR. Use flux to create a Kubernetes `dockerconfigjson` secret:

```bash theme={null}
flux create secret oci ghcr-auth \
  --url ghcr.io \
  --username sidd-harth-2 \
  --password ghp_tQbUTJ0tJeoOJNw7SOF2Up0GcNklsLF1vK1tH \
  --namespace flux-system \
  --export > ghcr-auth-secret.yml
```

Replace `--username` and `--password` with your registry username and personal access token. Alternatively you can create a standard `kubernetes.io/dockerconfigjson` secret yourself.

Verify the secret exists in `flux-system`:

```bash theme={null}
kubectl -n flux-system get secrets
```

Example output:

```bash theme={null}
NAME                                                                  TYPE                           DATA   AGE
flux-system                                                           Opaque                         3      17h
ghcr-auth                                                             kubernetes.io/dockerconfigjson 1      6s
minio-crds                                                            Opaque                         2      145m
...
```

Resource summary

| Resource | Purpose | Example name |
| - | - | - |
| OCIRepository | Flux source that points to an OCI registry | `7-demo-source-oci-bb-app-7-7-0` |
| Secret | Container registry credentials (dockerconfigjson) | `ghcr-auth` |
| Kustomization | Applies/manages manifests provided by the OCI source | `7-demo-kustomize-oci-bb-app-7-7-0` |

Step 3 — Create the Kustomization to deploy the manifests
Create a Kustomization that references the `OCIRepository` source. This demo uses a few useful options:

* `healthChecks` — instructs Flux to verify rollout/health status of specific resources.
* `dependsOn` — make this Kustomization wait for other Kustomizations (e.g., infra) to be ready.
* `timeout` — maximum wait time for health checks.

Kustomization YAML used in this demo:

```yaml theme={null}
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
  name: 7-demo-kustomize-oci-bb-app-7-7-0
  namespace: flux-system
spec:
  dependsOn:
    - name: infra-database-kustomize-git-mysql
  healthChecks:
    - kind: Deployment
      name: block-buster-7-7-0
      namespace: 7-demo
  interval: 10s
  path: ./
  prune: true
  sourceRef:
    kind: OCIRepository
    name: 7-demo-source-oci-bb-app-7-7-0
  targetNamespace: 7-demo
  timeout: 2m0s
```

If your OCI artifact is private, ensure the referenced `OCIRepository` includes a `secretRef` pointing to a registry secret in the `flux-system` namespace (or adjust namespaces so the secret is visible to the source-controller).

Health check examples

* Check a Deployment rollout:

```yaml theme={null}
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
  name: backend
  namespace: default
spec:
  interval: 5m
  prune: true
  sourceRef:
    kind: GitRepository
    name: webapp
  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: backend
      namespace: dev
```

* Check HelmRelease objects (Flux Helm support):

```yaml theme={null}
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
  name: webapp
  namespace: default
spec:
  interval: 15m
  path: "./releases/"
  prune: true
  sourceRef:
    kind: GitRepository
    name: webapp
  healthChecks:
    - apiVersion: helm.toolkit.fluxcd.io/v2beta1
      kind: HelmRelease
      name: frontend
      namespace: dev
    - apiVersion: helm.toolkit.fluxcd.io/v2beta1
      kind: HelmRelease
      name: backend
      namespace: dev
  timeout: 5m
```

dependsOn usage
Use `dependsOn` when an application requires infra resources (databases, secrets) to be present before deployment:

```yaml theme={null}
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
  name: 7-demo-kustomize-oci-bb-app-7-7-0
  namespace: flux-system
spec:
  dependsOn:
    - name: infra-database-kustomize-git-mysql
  ...
```

Commit and push
Commit the `OCIRepository`, `ghcr-auth` secret (if exported), and the `Kustomization` YAML to your Git repo so Flux picks them up.

Reconciliation and debugging

1. Check Kustomization status via Flux:

```bash theme={null}
flux get kustomizations 7-demo-kustomize-oci-bb-app-7-7-0 --namespace flux-system
```

Example output when reconciliation starts:

```bash theme={null}
NAME                                 REVISION   SUSPENDED   READY     MESSAGE
7-demo-kustomize-oci-bb-app-7-7-0                False       Unknown   Reconciliation in progress
```

2. If the Kustomization is `Unknown` or stalled, inspect the resource status in Kubernetes to get health check messages:

```bash theme={null}
kubectl -n flux-system get kustomizations.kustomize.toolkit.fluxcd.io 7-demo-kustomize-oci-bb-app-7-7-0 -o yaml
```

Look for status conditions messages such as:

```yaml theme={null}
message: Running health checks for revision 7.7.0-0bb2691@sha256:... with a timeout of 2m0s
```

Common health check issue
If a health check times out, verify the exact resource `name` and `namespace` listed in `healthChecks`. Matching is literal — any mismatch prevents Flux from locating the resource. In this demo the initial health check referenced the wrong Deployment name; updating it to `block-buster-7-7-0` fixed the timeout.

3. After fixing the health check, trigger reconciliation or wait for automatic reconcile:

```bash theme={null}
flux reconcile source oci 7-demo-source-oci-bb-app-7-7-0 --namespace flux-system
flux reconcile kustomization 7-demo-kustomize-oci-bb-app-7-7-0 --namespace flux-system
flux get kustomizations 7-demo-kustomize-oci-bb-app-7-7-0 --namespace flux-system
```

Successful status example:

```bash theme={null}
NAME                                   REVISION                             SUSPENDED  READY  MESSAGE
7-demo-kustomize-oci-bb-app-7-7-0      7.7.0-0bb2691@sha256:379024c5       False      True   Applied revision: 7.7.0-0bb2691@sha256:379024c5
```

4. Validate resources in the target namespace:

```bash theme={null}
kubectl -n 7-demo get all
```

Example output:

```bash theme={null}
NAME                                        READY   STATUS    RESTARTS   AGE
pod/block-buster-7-7-0-7687446b59-879jt     1/1     Running   0          11m

NAME                                        TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)         AGE
service/block-buster-service-7-7-0          NodePort   10.105.73.12   <none>        80:30770/TCP    11m

NAME                                        READY UP-TO-DATE AVAILABLE   AGE
deployment.apps/block-buster-7-7-0          1/1   1            1           11m
```

Verify the app in the browser
Open the application URL (NodePort / Ingress) and confirm the version deployed. This demo intentionally includes a bug where the new "high score" value is not persisted; that will be addressed in a later release.

![A browser screenshot of a block-breaker arcade game showing rows of multicolored bricks, a paddle and ball at the bottom, plus score and level indicators. A small "Game Over" alert popup is visible near the top.](https://mintcdn.com/kodekloud-c4ac6d9a/AyhVWHpoMIYCWiei/images/GitOps-with-FluxCD/Helm-Controller-and-OCI-Registry/Demo-Flux-Pull-and-Deploy-from-OCI-Registry/brick-breaker-arcade-screenshot-game-over.jpg?fit=max\&auto=format\&n=AyhVWHpoMIYCWiei\&q=85\&s=197770e455c089e285f4fe7e5275d75c)

Wrap-up
You have now:

* Created an `OCIRepository` source that points to an OCI artifact in GHCR.
* Configured a registry secret so Flux can pull private OCI artifacts.
* Created a `Kustomization` to deploy manifests from the OCI source.
* Used `healthChecks` and `dependsOn` to control rollout order and verify deployment health.
* Troubleshot common reconciliation and health check issues.

Further reading

* Flux documentation: [https://fluxcd.io/docs/](https://fluxcd.io/docs/)
* GitHub Container Registry: [https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry)
* Cosign (image signing and verification): [https://docs.sigstore.dev/cosign/](https://docs.sigstore.dev/cosign/)

> **[Watch Video](https://learn.kodekloud.com/user/courses/gitops-with-fluxcd/module/205ec7c7-4cb6-4ecb-9bb5-fa50419f1e68/lesson/b1d4efe5-a36b-4214-89ba-64e0fe859a29)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.