Skip to content

OCM Image Management Guide

This guide provides practical instructions for replacing and updating container images in Platform-Mesh using the Open Component Model (OCM).

Overview

Platform-Mesh uses OCM for component packaging and distribution. Images are defined in component-constructor.yaml files with Go template syntax for version management.

Repository: platform-mesh/ocm

Prerequisites

Required Tools

# Install OCM CLI
brew install open-component-model/tap/ocm

# Verify installation
ocm version

Required Access

  • GitHub repository write access to platform-mesh/ocm
  • OCI registry credentials (ghcr.io/platform-mesh)
  • Chainguard registry access (for Chainguard images)

OCM Architecture

┌──────────────────────────────────────────────────────────────┐
│                  Component Constructor                       │
│         (constructor/component-constructor.yaml)             │
│                                                              │
│  • Defines component metadata and resources                  │
│  • Uses Go template variables: `{{ .VERSION }}`              │
└──────────────────────────┬───────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│                     Package & Build                          │
│        (GitHub Actions: package_transfer.yaml)               │
│                                                              │
│  • Resolves template variables                               │
│  • Creates CTF archive                                       │
│  • Validates component descriptor                            │
└──────────────────────────┬───────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│                      OCI Registry                            │
│              (ghcr.io/platform-mesh/*)                       │
│                                                              │
│  • Stores versioned components                               │
│  • Multi-registry support                                    │
└──────────────────────────┬───────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│                       Deployment                             │
│                                                              │
│  • Flux CD pulls from OCI registry                           │
│  • KRO ResourceGraphDefinition orchestrates                  │
│  • ConfigMaps provide runtime configuration                  │
└──────────────────────────────────────────────────────────────┘

Component Constructor Structure

Basic Syntax

components:
  - name: <component-name>
    version: { { .COMPONENT_VERSION } }
    provider:
      name: platform-mesh
    resources:
      - name: <image-name>
        type: ociImage
        relation: external
        version: { { .IMAGE_VERSION } }
        access:
          type: ociArtifact
          imageReference: "<registry>/<image>:{{ .IMAGE_VERSION }}"

Real Example (Traefik)

components:
  - name: traefik
    version: { { .TRAEFIK_VERSION } }
    provider:
      name: platform-mesh
    resources:
      - name: traefik-image
        type: ociImage
        relation: external
        version: { { .TRAEFIK_IMAGE_VERSION } }
        access:
          type: ociArtifact
          imageReference: "traefik:{{ .TRAEFIK_IMAGE_VERSION }}"

How to Replace an Image

Step-by-Step Process

1. Update Component Constructor

Location: constructor/component-constructor.yaml

# Before (current image)
- name: traefik-image
  type: ociImage
  version: { { .TRAEFIK_IMAGE_VERSION } }
  access:
    type: ociArtifact
    imageReference: "docker.io/traefik:{{ .TRAEFIK_IMAGE_VERSION }}"

# After (Chainguard replacement)
- name: traefik-image
  type: ociImage
  version: { { .TRAEFIK_IMAGE_VERSION } }
  access:
    type: ociArtifact
    imageReference: "cgr.dev/chainguard-private/traefik:{{ .TRAEFIK_IMAGE_VERSION }}"

2. Update Template Variables

Template variables are typically defined in:

  • GitHub Actions workflow files (.github/workflows/*.yml)
  • Environment configuration files
  • CI/CD pipeline variables

Example workflow update:

# .github/workflows/package_transfer.yaml
env:
  TRAEFIK_VERSION: "v3.6.7"
  TRAEFIK_IMAGE_VERSION: "v3.6.7"

3. Add ImagePullSecrets (if using private registry)

For Chainguard images:

# In Helm chart values or KRO ResourceGraphDefinition
imagePullSecrets:
  - name: chainguard-registry-creds

# Create the secret
kubectl create secret docker-registry chainguard-registry-creds \
  --docker-server=cgr.dev \
  --docker-username=<username> \
  --docker-password=<password> \
  --namespace=platform-mesh-system
# Clone repository
git clone https://github.com/platform-mesh/ocm.git
cd ocm

# Create local CTF archive
ocm add componentversions --create --file ./build/ctf component-constructor.yaml

# Inspect the component
ocm get componentversions -o yaml ./build/ctf

5. Commit and Push

git checkout -b feat/replace-traefik-image
git add constructor/component-constructor.yaml
git commit -m "feat: replace Traefik with Chainguard image"
git push origin feat/replace-traefik-image

6. Automated Packaging

GitHub Actions automatically:

  • Validates the component constructor
  • Builds ConfigMaps from Helmfile configurations
  • Packages the OCM component
  • Transfers to OCI registry (on merge to main)

Quick Reference Commands

OCM CLI Commands

# Create component from constructor file
ocm add componentversions --create --file <archive> <constructor.yaml>

# List components in archive
ocm get componentversions <archive>

# Inspect component descriptor
ocm get componentversions -o yaml <archive>

# Transfer component to registry
ocm transfer ctf <archive> <oci-repo>

# Download component from registry
ocm download componentversion <component> <version>

Common Tasks

Replace Single Infrastructure Image

# 1. Edit constructor
vim constructor/component-constructor.yaml

# 2. Update imageReference
# 3. Commit changes
git add constructor/component-constructor.yaml
git commit -m "feat: update cert-manager to v1.19.2"
git push

# 4. Monitor GitHub Actions for packaging

Batch Update Multiple Images

# 1. Create feature branch
git checkout -b feat/update-infrastructure-images

# 2. Update multiple imageReferences in constructor
# 3. Update version variables in workflow files
vim .github/workflows/package_transfer.yaml

# 4. Commit and push
git add -A
git commit -m "feat: batch update infrastructure images"
git push origin feat/update-infrastructure-images

Migrate to Chainguard Image

# 1. Verify Chainguard image availability
docker pull cgr.dev/chainguard-private/postgres:latest

# 2. Update component constructor
sed -i 's|ghcr.io/platform-mesh/upstream-images/postgresql|cgr.dev/chainguard-private/postgres|g' \
  constructor/component-constructor.yaml

# 3. Add imagePullSecrets to deployment manifests
# 4. Test in KIND cluster
# 5. Commit and push

Best Practices

Version Pinning

DO: Use specific version tags

imageReference: "traefik:v3.6.7"

DON'T: Use latest or untagged images

imageReference: "traefik:latest" # Unsafe!

Template Variables

DO: Centralize version definitions

# .env or central config file
TRAEFIK_VERSION=v3.6.7
POSTGRES_VERSION=17.6.0

DO: Keep component version and image version synchronized

- name: traefik
  version: { { .TRAEFIK_VERSION } } # v3.6.7
  resources:
    - name: traefik-image
      version: { { .TRAEFIK_VERSION } } # v3.6.7 (same)

Registry Configuration

DO: Use full registry paths

imageReference: "cgr.dev/chainguard-private/postgres:17.6.0"

DO: Configure registry authentication

# In deployment manifests
imagePullSecrets:
  - name: registry-creds

Testing

DO: Test in local KIND cluster first

kind create cluster --config kind-config.yaml
kubectl apply -f updated-manifests/

DO: Validate image pull before deployment

docker pull <new-image-reference>

Troubleshooting

Image Pull Errors

Problem: ErrImagePull or ImagePullBackOff

Solutions:

# Verify image exists
docker pull <image-reference>

# Check imagePullSecrets
kubectl get secrets -n platform-mesh-system

# Verify secret is referenced in deployment
kubectl get deployment <name> -o yaml | grep imagePullSecrets

Template Variable Not Resolved

Problem: Literal {{ .VERSION }} in deployed manifests

Solution: Ensure variables are defined in GitHub Actions workflow:

env:
  VERSION: "v1.2.3"

Component Validation Failed

Problem: OCM CLI rejects component constructor

Solution:

# Validate against schema
ocm validate component-constructor.yaml

# Check YAML syntax
yamllint component-constructor.yaml

Migration Example: Traefik → Chainguard

Complete example of migrating Traefik to Chainguard image:

Before

- name: traefik
  version: { { .TRAEFIK_VERSION } }
  resources:
    - name: traefik-image
      type: ociImage
      version: { { .TRAEFIK_IMAGE_VERSION } }
      access:
        type: ociArtifact
        imageReference: "docker.io/traefik:{{ .TRAEFIK_IMAGE_VERSION }}"

After

- name: traefik
  version: { { .TRAEFIK_VERSION } }
  resources:
    - name: traefik-image
      type: ociImage
      version: { { .TRAEFIK_IMAGE_VERSION } }
      access:
        type: ociArtifact
        imageReference: "cgr.dev/chainguard-private/traefik:{{ .TRAEFIK_IMAGE_VERSION }}"

Additional Configuration

# In KRO ResourceGraphDefinition or Helm values
spec:
  imagePullSecrets:
    - name: chainguard-registry-creds

Results

  • Before: 4 critical CVEs, 20 high CVEs
  • After: 0 critical CVEs, 0 high CVEs
  • Improvement: 100% CVE reduction

Last Updated: 2026-01-30 Maintainer: Platform-Mesh Team