Deploy Manifests with Deployer
This guide shows how to deploy raw Kubernetes manifests from an OCM component version using the OCM Controllers’ built-in Deployer. This approach requires only the OCM Controllers—no kro or Flux needed.
A Podinfo application (single pod) deployed directly from a Kubernetes Deployment manifest stored in an OCM component.
Prerequisites
- Controller environment with OCM Controllers installed
- OCM CLI installed
- Access to an OCI registry (e.g., ghcr.io)
- A GitHub account with a personal access token
- Any extra RBAC configured by following Custom RBAC guide
Environment Setup
Set environment variables for your GitHub username and OCM repository:
export GITHUB_USERNAME=<your-github-username>
export OCM_REPO=ghcr.io/$GITHUB_USERNAME/ocm-tutorialCreate the Component Version
Create a working directory
mkdir /tmp/manifest-deploy && cd /tmp/manifest-deployCreate the deployment manifest
Create a
deployment.yamlfile:apiVersion: apps/v1 kind: Deployment metadata: name: podinfo spec: minReadySeconds: 3 revisionHistoryLimit: 5 progressDeadlineSeconds: 60 strategy: rollingUpdate: maxUnavailable: 0 type: RollingUpdate selector: matchLabels: app: podinfo template: metadata: annotations: prometheus.io/scrape: "true" prometheus.io/port: "9797" labels: app: podinfo spec: containers: - name: podinfod image: ghcr.io/stefanprodan/podinfo:6.11.1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 9898 protocol: TCP - name: http-metrics containerPort: 9797 protocol: TCP - name: grpc containerPort: 9999 protocol: TCP command: - ./podinfo - --port=9898 - --port-metrics=9797 - --grpc-port=9999 - --grpc-service-name=podinfo - --level=info - --random-delay=false - --random-error=false env: - name: PODINFO_UI_COLOR value: "#34577c" livenessProbe: exec: command: - podcli - check - http - localhost:9898/healthz initialDelaySeconds: 5 timeoutSeconds: 5 readinessProbe: exec: command: - podcli - check - http - localhost:9898/readyz initialDelaySeconds: 5 timeoutSeconds: 5 resources: limits: cpu: 2000m memory: 512Mi requests: cpu: 100m memory: 64Mi volumeMounts: - name: data mountPath: /data volumes: - name: data emptyDir: {}Create the component constructor
Create a
component-constructor.yamlfile:components: - name: ocm.software/ocm-k8s-toolkit/simple provider: name: ocm.software version: "1.0.0" resources: - name: deployment-resource type: blob version: "1.0.0" input: type: file path: ./deployment.yamlBuild and push
ocm add cv --repository $OCM_REPOYou should see this output
COMPONENT │ VERSION │ PROVIDER ────────────────────────────────────┼─────────┼────────────── ocm.software/ocm-k8s-toolkit/simple │ 1.0.0 │ ocm.softwarePrivate registriesBy default, packages in GitHub Container Registry are private. Either make your package public after upload, or
configure credentials for the OCM controller resources before deploying.
Verify the upload
ocm get cv $OCM_REPO//ocm.software/ocm-k8s-toolkit/simple:1.0.0You should see this output
COMPONENT │ VERSION │ PROVIDER ────────────────────────────────────┼─────────┼────────────── ocm.software/ocm-k8s-toolkit/simple │ 1.0.0 │ ocm.software
Deploy with the OCM Controllers
Create the bootstrap resources
Create a
bootstrap.yamlfile with the controller resources:apiVersion: delivery.ocm.software/v1alpha1 kind: Repository metadata: name: bootstrap-repository spec: repositorySpec: baseUrl: $OCM_REPO type: OCIRegistry interval: 1m --- apiVersion: delivery.ocm.software/v1alpha1 kind: Component metadata: name: bootstrap-component spec: component: ocm.software/ocm-k8s-toolkit/simple repositoryRef: name: bootstrap-repository semver: 1.0.0 interval: 1m --- apiVersion: delivery.ocm.software/v1alpha1 kind: Resource metadata: name: bootstrap-deployment namespace: default spec: componentRef: name: bootstrap-component resource: byReference: resource: name: deployment-resource interval: 1m --- apiVersion: delivery.ocm.software/v1alpha1 kind: Deployer metadata: name: bootstrap-deployer namespace: default spec: resourceRef: name: bootstrap-deployment namespace: defaultThe resource chain works as follows:
- Repository — points to the OCM repository
- Component — references a specific component version
- Resource — selects the manifest resource from the component
- Deployer — downloads, verifies, and applies the manifest using server-side apply with ApplySets
For details on how the Deployer uses ApplySets, see
Substitute and apply
Replace the
$OCM_REPOplaceholder with your actual repository URL and apply:envsubst < bootstrap.yaml > deployment-subst.yaml kubectl apply -f deployment-subst.yamlVerify the deployment
Check the controller resources:
kubectl get resource,deployer,component,repository -owideYou should see this output
NAME READY AGE resource.delivery.ocm.software/bootstrap-deployment Applied version 1.0.0 20s NAME AGE deployer.delivery.ocm.software/bootstrap-deployer 20s NAME READY AGE component.delivery.ocm.software/bootstrap-component Applied version 1.0.0 20s NAME READY AGE repository.delivery.ocm.software/bootstrap-repository Successfully reconciled OCM repository 20sCheck the deployed pod:
kubectl get pods -l app=podinfoYou should see this output
NAME READY STATUS RESTARTS AGE podinfo-86b758c4bf-c44qk 1/1 Running 0 109s
Troubleshooting
Authentication Errors
If you see 401: unauthorized errors, your registry package is private. Either:
- Make the package public in GitHub Package settings
- Configure credentials for the controller resources
Resource Not Reconciling
If resources stay in a pending state, check controller logs:
kubectl logs -n ocm-k8s-toolkit-system deployment/ocm-k8s-toolkit-controller-managerCleanup
Delete the controller resources to remove all tracked objects:
kubectl delete -f deployment-subst.yamlThe Deployer uses ApplySets, so deleting the resources automatically cleans up the deployed manifest:
kubectl get pods -l app=podinfo
# No resources found in default namespace.Next Steps
- Tutorial: Deploy Helm Charts with Bootstrap — Advanced deployment with kro and Flux orchestration
- How-to: Configure Credentials for Controllers — Set up private registry access
- How-to: Custom RBAC — Configure permissions for Deployer