Skip to content

Get Started

This guide shows you how to use Kustomizer to publish and deploy a sample application.

To follow this guide you'll need a GitHub account and a Kubernetes cluster version 1.20 or newer.

Prerequisites

Install the Kustomizer CLI

Install the latest release on macOS or Linux with:

brew install stefanprodan/tap/kustomizer

For other installation methods, see the CLI install documentation.

Login to GitHub Container Registry

Generate a personal access token (PAT) with read and write access to GitHub Container Registry (GHCR).

Export you GitHub username:

export GITHUB_USER="YOUR-GITHUB-USERNAME"

Use the PAT to sign in to the container registry service at ghcr.io:

echo <PAT> | docker login ghcr.io -u ${GITHUB_USER} --password-stdin

Other container registries

Besides GHCR, Kustomizer is compatible with Docker Hub, ACR, ECR, GCR, Artifactory, self-hosted Docker Registry v2 and any other registry that conforms to the Open Container Initiative.

Publish the app config

You'll be using a sample web application composed of two podinfo instances called frontend and backend, and a redis instance called cache.

Clone the demo app repository

Clone the Kustomizer Git repository locally:

git clone https://github.com/stefanprodan/kustomizer
cd kustomizer

The sample application configuration is a Kustomize overlay located at ./examples/demo-app.

Build and push the app config to GHCR

Export the config image URL and version:

export CONFIG_IMAGE="ghcr.io/${GITHUB_USER}/kustomizer-demo-app"
export CONFIG_VERSION="1.0.0"

Push the config image to your GHCR repository:

$ kustomizer push artifact oci://${CONFIG_IMAGE}:${CONFIG_VERSION} \
    -k ./examples/demo-app/
building manifests...
Namespace/kustomizer-demo-app
ConfigMap/kustomizer-demo-app/redis-config-bd2fcfgt6k
Service/kustomizer-demo-app/backend
Service/kustomizer-demo-app/cache
Service/kustomizer-demo-app/frontend
Deployment/kustomizer-demo-app/backend
Deployment/kustomizer-demo-app/cache
Deployment/kustomizer-demo-app/frontend
HorizontalPodAutoscaler/kustomizer-demo-app/backend
HorizontalPodAutoscaler/kustomizer-demo-app/frontend
pushing image ghcr.io/stefanprodan/kustomizer-demo-app:1.0.0
published digest ghcr.io/stefanprodan/kustomizer-demo-app@sha256:91d2bd8e0f1620e17e9d4c308ab87903644a952969d8ff52b601be0bffdca096

With the above command, Kustomizer builds the Kustomize overlay at ./examples/demo-app/, packages the resulting multi-doc YAML as an OCI artifact and pushes the image to GHCR.

After you run the command, the image repository can be accessed at https://github.com/users/<YOUR USERNAME>/packages.

Generating Kubernetes manifests

Besides Kustomize overlays, Kustomizer can package plain Kuberentes manifests.

If you're using Cue to define your app config, export the manifests to a multi-doc YAML file and pass the path to Kustomizer with -f <path to .yaml> e.g.:

cue export -p my-app -o yaml > my-app.yaml
kustomizer push artifact oci://docker.io/my-org/my-app:1.0.0 -f my-app.yaml

Publish app updates

Change the Redis container image tag with yq:

yq eval '.images[1].newTag="6.2.1"' -i ./examples/demo-app/kustomization.yaml

Bump the config version:

export CONFIG_VERSION="1.0.1"

Push the new version to GHCR:

kustomizer push artifact oci://${CONFIG_IMAGE}:${CONFIG_VERSION} \
  -k ./examples/demo-app/ 

Tag the config image as latest:

kustomizer tag artifact oci://${CONFIG_IMAGE}:${CONFIG_VERSION} latest

Deploy the app on Kubernetes

List the app versions

List all the available versions of the app config ordered by semver:

$ kustomizer list artifacts oci://${CONFIG_IMAGE} --semver="*"
VERSION URL                                                  
1.0.1   oci://ghcr.io/stefanprodan/kustomizer-demo-app:1.0.1    
1.0.0   oci://ghcr.io/stefanprodan/kustomizer-demo-app:1.0.0

Install the app

Apply the 1.0.0 version of the Kubernetes configuration from the GHCR repository:

$ kustomizer apply inventory kustomizer-demo-app --wait --prune \
  --artifact oci://${CONFIG_IMAGE}:1.0.0 \
  --source ${CONFIG_IMAGE} \
  --revision 1.0.0
pulling ghcr.io/stefanprodan/kustomizer-demo-app:1.0.0
applying 10 manifest(s)...
Namespace/kustomizer-demo-app created
ConfigMap/kustomizer-demo-app/redis-config-bd2fcfgt6k created
Service/kustomizer-demo-app/backend created
Service/kustomizer-demo-app/cache created
Service/kustomizer-demo-app/frontend created
Deployment/kustomizer-demo-app/backend created
Deployment/kustomizer-demo-app/cache created
Deployment/kustomizer-demo-app/frontend created
HorizontalPodAutoscaler/kustomizer-demo-app/backend created
HorizontalPodAutoscaler/kustomizer-demo-app/frontend created
waiting for resources to become ready...
all resources are ready

With the above command, Kustomizer pulls the artifact from GHCR, extracts the Kubernetes resources and validates them against the Kubernetes API, applies the resources with server-side apply, then waits for the workloads to become ready.

List inventories with:

$ kustomizer get inventories -n default
NAME                ENTRIES SOURCE                                      REVISION    LAST APPLIED         
kustomizer-demo-app 10      ghcr.io/stefanprodan/kustomizer-demo-app    1.0.0       2021-12-16T10:33:10Z

At apply time, Kustomizer creates an inventory to keep track of the set of resources applied together. The inventory is stored inside the cluster in a ConfigMap object and contains metadata such as the resources IDs, provenance and revision.

Inspect the inventory with:

$ kustomizer inspect inv kustomizer-demo-app -n default
Inventory: default/kustomizer-demo-app
LastAppliedAt: 2021-12-20T23:05:45Z
Source: oci://ghcr.io/stefanprodan/kustomizer-demo-app
Revision: 1.0.0
Artifacts:
- oci://ghcr.io/stefanprodan/kustomizer-demo-app@sha256:19ded6e1dbe3eb859bd0f0fa6aa1960f6975097af8f19e252b951cf3e9e9e6e2
Resources:
- Namespace/kustomizer-demo-app
- ConfigMap/kustomizer-demo-app/redis-config-bd2fcfgt6k
- Service/kustomizer-demo-app/backend
- Service/kustomizer-demo-app/cache
- Service/kustomizer-demo-app/frontend
- Deployment/kustomizer-demo-app/backend
- Deployment/kustomizer-demo-app/cache
- Deployment/kustomizer-demo-app/frontend
- HorizontalPodAutoscaler/kustomizer-demo-app/backend
- HorizontalPodAutoscaler/kustomizer-demo-app/frontend

At apply time, Kustomizer saves the artifact SHA-2 digest in the inventory.

Using digests

For deterministic and repeatable apply operations, you can specify the digest instead of the image tag e.g.:

kustomizer apply inventory kustomizer-demo-app --wait --prune \
  --artifact oci://ghcr.io/stefanprodan/kustomizer-demo-app@sha256:19ded6e1dbe3eb859bd0f0fa6aa1960f6975097af8f19e252b951cf3e9e9e6e2

Update the app

Pull the latest version and review the changes to the live version:

$ kustomizer diff inventory kustomizer-demo-app --prune \
    --artifact oci://${CONFIG_IMAGE}:latest 
► Deployment/kustomizer-demo-app/cache drifted
@@ -5,7 +5,7 @@
     deployment.kubernetes.io/revision: "1"
     env: demo
   creationTimestamp: "2021-12-13T19:50:26Z"
-  generation: 1
+  generation: 2
   labels:
     app.kubernetes.io/instance: webapp
     inventory.kustomizer.dev/name: kustomizer-demo-app
@@ -36,7 +36,7 @@
       - command:
         - redis-server
         - /redis-master/redis.conf
-        image: public.ecr.aws/docker/library/redis:6.2.0
+        image: public.ecr.aws/docker/library/redis:6.2.1
         imagePullPolicy: IfNotPresent
         livenessProbe:
           failureThreshold: 3

With the above command, Kustomizer performs a server-side apply dry-run for each resource, compares the result with the live version and prints the diff. If there are Kubernetes secrets in the diff output, their values will be masked. With --prune, the diff command will print all the stale objects that would be garbage collected at apply time.

Apply the latest configuration on your cluster:

$ kustomizer apply inventory kustomizer-demo-app --wait --prune \
  --artifact oci://${CONFIG_IMAGE}:latest \
  --source ${CONFIG_IMAGE} \
  --revision 1.0.1
pulling ghcr.io/stefanprodan/kustomizer-demo-app:latest
applying 10 manifest(s)...
Namespace/kustomizer-demo-app unchanged
ConfigMap/kustomizer-demo-app/redis-config-bd2fcfgt6k unchanged
Service/kustomizer-demo-app/backend unchanged
Service/kustomizer-demo-app/cache unchanged
Service/kustomizer-demo-app/frontend unchanged
Deployment/kustomizer-demo-app/backend unchanged
Deployment/kustomizer-demo-app/cache configured
Deployment/kustomizer-demo-app/frontend unchanged
HorizontalPodAutoscaler/kustomizer-demo-app/backend unchanged
HorizontalPodAutoscaler/kustomizer-demo-app/frontend unchanged
waiting for resources to become ready...
all resources are ready

For deterministic and repeatable apply operations, you can specify the artifact's digest instead of a mutable tag like latest e.g. --artifact oci://registry/repo/app@sha256:hash.

Inspect the latest version to find its digest:

$ kustomizer inspect artifact oci://${CONFIG_IMAGE}:latest | grep oci://
Artifact: oci://ghcr.io/stefanprodan/kustomizer-demo-app@sha256:19ded6e1dbe3eb859bd0f0fa6aa1960f6975097af8f19e252b951cf3e9e9e6e2

Uninstall the app

Delete all the Kubernetes resources from an inventory including the inventory storage:

$ kustomizer delete inventory kustomizer-demo-app --wait
retrieving inventory...
deleting 10 manifest(s)...
HorizontalPodAutoscaler/kustomizer-demo-app/frontend deleted
HorizontalPodAutoscaler/kustomizer-demo-app/backend deleted
Deployment/kustomizer-demo-app/frontend deleted
Deployment/kustomizer-demo-app/cache deleted
Deployment/kustomizer-demo-app/backend deleted
Service/kustomizer-demo-app/frontend deleted
Service/kustomizer-demo-app/cache deleted
Service/kustomizer-demo-app/backend deleted
ConfigMap/kustomizer-demo-app/redis-config-bd2fcfgt6k deleted
Namespace/kustomizer-demo-app deleted
ConfigMap/default/kustomizer-demo-app deleted
waiting for resources to be terminated...
all resources have been deleted