---
slug: kustomize
title: Kustomize
description: Holos makes it easy to Kustomize configuration.
sidebar_position: 45
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Kustomize

## Overview

In the previous tutorial, we learned how Holos simplifies the holistic
integration of the [prometheus] and [blackbox] charts, ensuring they are
configured in sync.

In this tutorial, we'll go a step further by integrating the [httpbin] service
with Prometheus and Blackbox to automatically probe for availability.

We'll also explore how Holos manages [kustomize] bases, similar to the Helm kind
covered in the [Helm Values] tutorial.

## The Code

### Generating the structure

<Tabs>
  <TabItem value="optional" label="Optional">
:::note Skip this step if you completed the [Helm Values] tutorial.

Otherwise click the **Generate** tab to generate a blank platform now.
:::
  </TabItem>
  <TabItem value="generate" label="Generate">

Use `holos` to generate a minimal platform directory structure. First, create
and navigate into a blank directory. Then, run the `holos init platform`
command.

```shell
mkdir holos-kustomize-tutorial
cd holos-kustomize-tutorial
holos init platform v1alpha5
```

Make a commit to track changes.

```bash
git init . && git add . && git commit -m initial
```

  </TabItem>
</Tabs>

### Managing the Component

Create the `httpbin` component directory, and add the `httpbin.cue` and
`httpbin.yaml` files to it for configuration and setup.

<Tabs groupId="800C3AE7-E7F8-4AFC-ABF1-6AFECD945958">
  <TabItem value="setup" label="Setup">
```bash
mkdir -p components/httpbin
```
  </TabItem>
  <TabItem value="components/httpbin/httpbin.cue" label="httpbin.cue">
```bash
cat <<EOF > components/httpbin/httpbin.cue
```
```cue showLineNumbers
package holos

// Produce a Kustomize BuildPlan for Holos
holos: Kustomize.BuildPlan

// https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/README.md
Kustomize: #Kustomize & {
	KustomizeConfig: {
		// Files tells Holos to copy the file from the component path to the
		// temporary directory Holos uses for BuildPlan execution.
		Files: {
			"httpbin.yaml": _
		}
		CommonLabels: {
			"app.kubernetes.io/name": "httpbin"
		}
		// Kustomization represents a kustomization.yaml file in CUE.  Holos
		// marshals this field into a `kustomization.yaml` while processing a
		// BuildPlan.  See
		// https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
		Kustomization: {
			images: [{name: "mccutchen/go-httpbin"}]
			// Use a hidden field to compose patches easily with a struct.  Hidden
			// fields are not included in exported structures.
			_patches: {}
			// Convert the hidden struct to a list.
			patches: [for x in _patches {x}]
		}
	}
}
```
```bash
EOF
```
  </TabItem>
  <TabItem value="components/httpbin/httpbin.yaml" label="httpbin.yaml">
```bash
cat <<EOF > components/httpbin/httpbin.yaml
```
```yaml showLineNumbers
# https://github.com/mccutchen/go-httpbin/blob/v2.15.0/kustomize/resources.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
spec:
  template:
    spec:
      containers:
        - name: httpbin
          image: mccutchen/go-httpbin
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /status/200
              port: http
          readinessProbe:
            httpGet:
              path: /status/200
              port: http
          resources: {}
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
spec:
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
      appProtocol: http
```
```bash
EOF
```
  </TabItem>
</Tabs>

Holos knows the `httpbin.yaml` file is part of the BuildPlan because of the
`KustomizeConfig: Files: "httpbin.yaml": _` line in the `httpbin.cue`.

### Register the Components

Register `httpbin` with the platform by adding the following file to the
platform directory.

```bash
cat <<EOF > platform/httpbin.cue
```
```cue showLineNumbers
package holos

Platform: Components: {
	httpbin: {
		name: "httpbin"
		path: "components/httpbin"
	}
}
```
```bash
EOF
```

Render the platform.

<Tabs groupId="B120D5D1-0EAB-41E0-AD21-15526EBDD53D">
  <TabItem value="command" label="Command">
```bash
holos render platform
```
  </TabItem>
  <TabItem value="output" label="Output">
```txt
rendered httpbin in 707.554666ms
rendered platform in 707.9845ms
```
  </TabItem>
</Tabs>

Commit the results.

<Tabs groupId="446CC550-A634-45C0-BEC7-992E5C56D4FA">
  <TabItem value="command" label="Command">
```bash
git add . && git commit -m 'add httpbin'
```
  </TabItem>
  <TabItem value="output" label="Output">
```txt
[main c05f9ef] add httpbin
 4 files changed, 118 insertions(+)
 create mode 100644 components/httpbin/httpbin.cue
 create mode 100644 components/httpbin/httpbin.yaml
 create mode 100644 deploy/components/httpbin/httpbin.gen.yaml
 create mode 100644 platform/httpbin.cue
```
  </TabItem>
</Tabs>

### Inspecting the Build Plan

We can see the [BuildPlan] exported to `holos` by the `holos:
Kustomize.BuildPlan` line in `httpbin.cue`. Holos processes this build plan to
produce the fully rendered manifests.

<Tabs groupId="DD697D65-5BEC-4B92-BB33-59BE4FEC112F">
  <TabItem value="command" label="Command">
```bash
holos cue export --expression holos --out=yaml ./components/httpbin
```
  </TabItem>
  <TabItem value="output" label="Output">
```yaml showLineNumbers
kind: BuildPlan
apiVersion: v1alpha5
metadata:
  name: no-name
spec:
  artifacts:
    - artifact: components/no-name/no-name.gen.yaml
      generators:
        - kind: Resources
          output: resources.gen.yaml
          resources: {}
        - kind: File
          output: httpbin.yaml
          file:
            source: httpbin.yaml
      transformers:
        - kind: Kustomize
          inputs:
            - resources.gen.yaml
            - httpbin.yaml
          output: components/no-name/no-name.gen.yaml
          kustomize:
            kustomization:
              labels:
                - includeSelectors: false
                  pairs:
                    app.kubernetes.io/name: httpbin
              patches: []
              images:
                - name: mccutchen/go-httpbin
              resources:
                - resources.gen.yaml
                - httpbin.yaml
              kind: Kustomization
              apiVersion: kustomize.config.k8s.io/v1beta1
source:
  component:
    name: no-name
    path: no-path
    parameters: {}
```
  </TabItem>
</Tabs>

### Transforming Manifests

Review the BuildPlan exported in the previous command:

1. The [File Generator] copies the plain `httpbin.yaml` file into the build.
2. The [Kustomize Transformer] uses `httpbin.yaml` as an input resource.
3. The final artifact is the output from Kustomize.

This BuildPlan transforms the raw YAML by labeling all of the resources with
`"app.kubernetes.io/name": "httpbin"` using the [KustomizeConfig] `CommonLabels`
field.

To complete the integration with Prometheus, annotate the Service with
`prometheus.io/probe: "true"`. Holos makes this easier with CUE, so there's no
need to edit any YAML files manually.

Add a new `patches.cue` file to the `httpbin` component with the following
content.

```bash
cat <<EOF > components/httpbin/patches.cue
```
```cue showLineNumbers
package holos

import "encoding/yaml"

// Mix in a Kustomize patch to the configuration.
Kustomize: KustomizeConfig: Kustomization: _patches: {
	probe: {
		target: kind: "Service"
		target: name: "httpbin"
		patch: yaml.Marshal([{
			op:    "add"
			path:  "/metadata/annotations/prometheus.io~1probe"
			value: "true"
		}])
	}
}
```
```bash
EOF
```

:::note
We use a hidden `_patches` field to easily unify data into a struct, then
convert the struct into a list for export.
:::

## Reviewing Changes

Render the platform to see the result of the kustomization patch.

<Tabs groupId="5D1812DD-8E7B-4F97-B349-275214F38B6E">
  <TabItem value="command" label="Command">
```bash
holos render platform
```
  </TabItem>
  <TabItem value="output" label="Output">
```txt
rendered httpbin in 197.030208ms
rendered platform in 197.416416ms
```
  </TabItem>
</Tabs>

Holos is configuring Kustomize to patch the plain `httpbin.yaml` file with the
annotation.

<Tabs groupId="3D80279E-8EDE-4B3E-9269-50F5D1C1CA42">
  <TabItem value="command" label="Command">
```bash
git diff
```
  </TabItem>
  <TabItem value="output" label="Output">
```diff
diff --git a/deploy/components/httpbin/httpbin.gen.yaml b/deploy/components/httpbin/httpbin.gen.yaml
index 298b9a8..a16bd1a 100644
--- a/deploy/components/httpbin/httpbin.gen.yaml
+++ b/deploy/components/httpbin/httpbin.gen.yaml
@@ -1,6 +1,8 @@
 apiVersion: v1
 kind: Service
 metadata:
+  annotations:
+    prometheus.io/probe: "true"
   labels:
     app.kubernetes.io/name: httpbin
   name: httpbin

```
  </TabItem>
</Tabs>

Add and commit the final changes.

<Tabs groupId="54C335C8-B382-4277-AE87-0D6556921955">
  <TabItem value="command" label="Command">
```bash
git add . && git commit -m 'annotate httpbin for prometheus probes'
```
  </TabItem>
  <TabItem value="output" label="Output">
```txt
[main 6eeeadb] annotate httpbin for prometheus probes
 2 files changed, 3 insertions(+), 1 deletion(-)
```
  </TabItem>
</Tabs>

## Trying Locally

Optionally, apply the manifests rendered by Holos to a [Local Cluster] for
testing and validation.

## Next Steps

In this tutorial, we learned how Holos simplifies managing [httpbin], which is
distributed as a Kustomize base. We used a Kustomize component similar to the
Helm component covered previously. Holos provides a straightforward way to
customize any component, demonstrated by patching an annotation onto the
`httpbin` Service.

Continue with the tutorial to learn how Holos facilitates certificate management
and makes services accessible outside of a cluster.

[httpbin]: https://github.com/mccutchen/go-httpbin/tree/v2.15.0
[prometheus]: https://github.com/prometheus-community/helm-charts/tree/prometheus-25.27.0/charts/prometheus
[blackbox]: https://github.com/prometheus-community/helm-charts/tree/prometheus-blackbox-exporter-9.0.1/charts/prometheus-blackbox-exporter
[kustomize]: https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/

[Helm Values]: ./helm-values.mdx
[File Generator]: ../api/core.md#File
[Kustomize Transformer]: ../api/core.md#Kustomize
[BuildPlan]: ../api/core.md#BuildPlan
[KustomizeConfig]: ../api/author.md#KustomizeConfig
[Local Cluster]: ../topics/local-cluster.mdx
