Skip to content

Commit

Permalink
feat: 8.7 Declarative Configuration (#585)
Browse files Browse the repository at this point in the history
* feat: added 8.7 for declarative k8s config and 8.7.1 for kustomize

* chore: tidy up linter errors

* fix: more iterations

* chore: fix linter error

* feat: added exercise on configMapGenerator and base/overlay pattern

* chore: minor touchup to exercise 6

* fix: added front-matter for new exercises

* chore: fix typo

* chore: Update docs/8-kubernetes-container-orchestration/8.7.1-kustomize.md

Co-authored-by: Joshua <[email protected]>

* chore: Update docs/8-kubernetes-container-orchestration/8.7.1-kustomize.md

Co-authored-by: Joshua <[email protected]>

* chore: fix linter error

---------

Co-authored-by: Joshua <[email protected]>
  • Loading branch information
cfculler and jburns24 authored Oct 10, 2024
1 parent a264cc9 commit 9fdd865
Show file tree
Hide file tree
Showing 6 changed files with 391 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# 8.7 Declarative Configuration

Until now, you've only interacted with Kubernetes clusters imperatively through a handful of `kubectl` commands. While it is crucial that you understand how and why these work, executing a series of commands isn't feasible for idempotency, configuration management, versioning of code, or fast development cycles.

Interacting with your _personal_ cluster imperatively is completely doable, as you've seen up until now, but it can quickly get out of hand when managing a broader kubernetes platform as part of a team. This section will teach you how to move some of the functionality around interacting with your cluster away from the CLI, and into files as code.
279 changes: 279 additions & 0 deletions docs/8-kubernetes-container-orchestration/8.7.1-kustomize.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
---
docs/8-kubernetes-container-orchestration/8.7.1-kustomize.md:
category: Container Orchestration
estReadingMinutes: 20
exercises:
- name: General Use-Case
description: Organize a few manifest files and use Kustomize to build them all at once. Learn how to inspect build outputs and apply manifests with Kustomize.
estMinutes: 15
technologies:
- Kubernetes
- Kustomize
- name: Simple Modifications
description: Learn to use Kustomize's "namespace", "commonLabels", and "images" operators.
estMinutes: 30
technologies:
- Kubernetes
- Kustomize
- name: Patches
description: Learn to write Kustomize pathes, and the difference between StrategicMergePatch and Json6902 patches.
estMinutes: 30
technologies:
- Kubernetes
- Kustomize
- name: Secret Management
description: Learn to use the "secretGenerator" Kustomize operator and create another Kustomize patch to include the secret as an environment variable in a container.
estMinutes: 30
technologies:
- Kubernetes
- Kustomize
- name: Script Embedding
description: Modify the Nginx server frontend by mounting an HTML script to the container. Use the Kustomize configMapGenerator to create the ConfigMap that holds the script.
estMinutes: 40
technologies:
- Kubernetes
- Kustomize
- name: Bases and Overlays
description: See what a more productionalized Kustomize structure looks like with the base/overlays pattern.
estMinutes: 20
technologies:
- Kubernetes
- Kustomize

---

# 8.7.1 Kustomize

**Kustomize** is a configuration tool for bundling and customizing Kubernetes resources, with all configurations being declarative code chunks. As far as what customizations Kustomize is capable of making to your resources, the sky is just about the limit! When it comes to organizing Kubernetes manifests, Kustomize isn't just a way to do it, it's *the* way to do it. You will hardly *ever* find Kubernetes resources that aren't accompanied by Kustomize. This section will walk you through how to set up a series of kustomization configurations, and show you some of the things that it's capable of.

At any point, feel free to refer to the [Kustomize Feature List](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization) for more details about the capabilities shown in this section.

**Setup**: Before the following exercises, set up a fresh Kubernetes cluster that you can deploy resources to.

## Exercise 1: General Use-Case

Until now, you have applied resources to your clusters by running `kubectl apply -f <path/to/filename>` on all resource files. This approach has two potential issues:
1. If you list all of your resources in one file, then you only need to apply once. However, this results in large monolothic files, and has major downsides when it comes to code differentials in git and separated artifact versions in the case of monorepos.
2. You can solve the above by breaking your resources into multiple files, but that comes with the cost of needing several applies, and needing the know the proper order to apply them in.

Kustomize is the middle ground of the above two scenarios. Because it bundles resources together, you can break your manifests into separate files to gain readability and differential benefits, but only need to apply once.

* Start off by creating the following files to setup a standard Nginx deployment:

```bash
.
├── kustomization.yaml
├── deployment.yaml
└── service.yaml
```

`kustomization.yaml`
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- deployment.yaml
- service.yaml
```
`deployment.yaml`
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
env:
- name: apprentice
value: REDACTED
```

`service.yaml`
```yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
app: nginx
```

* Build/inspect your resources by running `kustomize build <path/to/kustomization.yaml>`, and then deploy all resources to your cluster by running `kustomize build <path/to/kustomization.yaml> | kubectl apply -f -` (The second "-" treats the output of the kustomize build as the "file" to be applied).
> You can do the same by running `kubectl apply -k <path/to/kustomization.yaml>` but there will be circumstances at times that require editing the build output before applying (ie separating CustomResourceDefinitions from standard resources), which this method does not allow for. You will also have a harder time inspecting build outputs before applying. For these reasons, separating the build from the apply is debatably the better habit to build.

* Verify that you can port-forward to the service and access your Nginx server.

?> Note that in this example we are only including local files as resources, but that doesn't need to be the case. Trying adding the following resource to your `kustomization.yaml` and inspect the outputs of the build. No need to keep the resource or even apply anything to your cluster, just be aware that Kustomize can source external resources.
`- https://raw.githubusercontent.com/argoproj/argo-cd/v2.7.2/manifests/install.yaml`

## Exercise 2: Simple Modifications

* Create the following file, and then using the `kustomization.yaml` file *only*, change the deployment and the service to use the new namespace:

`namespace.yaml`
```yaml
apiVersion: v1
kind: Namespace
metadata:
name: nginx
```
?> You can experiment with specifying a different namespace in the resources themselves. Take note of which namespace takes precedence.
> Also, take note that once you changed the namespace, the deployment and service in the `default` namespace remained there. A common misconception is that Kustomize will *manage the lifecycle* of resources, but that is not true. Kustomize is only for operating on resources *before* applying them. The management of existing resources is still left to `kubectl`, and *automatic* management (ie removal of resources no longer defined) is a GitOps responsibility for tools like ArgoCD or Flux CD.

* Using the `kustomization.yaml` file *only*, add the following label to all three resources: `liatr: io`

* Using the `kustomization.yaml` file *only*, pin the `nginx` image to a specific version.

## Exercise 3: Patches

Sometimes you need to make modifications to resources that go outside of the basic Kustomize Transformers that you experimented with above. Kustomize `patches` allow you to modify *anything* you want about your resource definitions, and provide a few different methods of doing so.

* Using the `kustomization.yaml` file *only*, change the `REDACTED` env value in the deployment to your name. Do this via a `strategicMergePatch`.

* Using the `kustomization.yaml` file *only*, add the following `resources` section to the container in the deployment. Do this via a `JSON6902` patch.
```yaml
resources:
limits:
memory: 1Gi
requests:
memory: 512Mi
cpu: 100m
```

> Note that many documentation sources will have `patchesStrategicMerge` and `patchesJson6902` as Kustomize operators, but recent versions of Kustomize have simplified both to `patches`. The underlying usage of both hasn't changed, just what they're actually called in your `kustomization.yaml`.

> Also note that some fields are immutable in Kubernetes. You may need to delete your resources and reapply. Delete by running `kustomize build . | kubectl delete -f -`

## Exercise 4: Secret Management

Often times, you need to create/apply secrets into your Kubernetes cluster so different containers can access them. While under the right circumstances, it's okay for the secrets to be visible locally and on your cluster (ie not completely hidden), it is never okay for them to be pushed to GitHub. Kustomize can help you structure your resources in a way that the secret *existence* will be visible in GitHub, but not the secret content itself.

* Start off by creating a `.env` file and place a key,value pair inside of it. This file will only be stored locally, and should never be pushed to GitHub.

`.env`
```bash
SECRET=123456
```

`.gitignore`
```bash
.env
```

* Now that your secret information is stored locally, look into the Kustomize `secretGenerator` to, well, generate a secret that contains your key,value pair.
> Note that the secret will be created with base64 encoded information, so you'll need to decode it to actually read the contents of the secret.

* Finally, write a Kustomize `patch` (either method from above) to add the following entry to your container's `env` list in the deployment:

```yaml
- name: SECRET
valueFrom:
secretKeyRef:
name: <The name you gave your secret>
key: SECRET
```

* Exec into your container running in the cluster and run `env` to confirm that your environment variable is present and holding the correct information.
> Since you cannot change a containers base env list after booting, you may need to delete your deployment before applying this change.

* Now that your secret exists, update your key,value pair in your `.env` file and reapply. Did your secret get updated? If so, good. If it didn't and instead a *new* secret was created with your change, figure out how to correct that.

## Exercise 5: Script Embedding

Earlier in the chapter, we introduced the ConfigMap resource. As a refresher, a ConfigMap is used to store unstructured data, typically in the form of key-value pairs. This data can include configuration files, environment variables, or any other external configuration you want to decouple from your container images. By externalizing configuration, you avoid baking it directly into the image, allowing for more flexibility and easier updates. ConfigMaps can also be used to inject configuration files or scripts into containers, supporting dynamic adjustments to application behavior without needing to rebuild images.

However, writing ConfigMaps can be cumbersome because you often need to embed data as a single long string within the ConfigMap fields. This approach causes IDEs to treat the data as plain text, resulting in the loss of helpful features like syntax highlighting, intellisense, and language-specific support that you would normally get when working with typed files (e.g., .sh, .css, .html). This makes managing and editing complex configuration data more challenging.

Yep, you guessed it. Kustomize solves this problem. For this exercise, we're going to leverage Kustomize to overwrite the frontend for the Nginx server.

* Start by creating an `index.html` file, and include some HTML code similar to the following:
```html
<html>
<body>
<h1>Apprentices Are Real People Too</h1>
This is my super cool Nginx Server
</body>
</html>
```

* Next, similar to the previous exercise, explore the `configMapGenerator` Kustomize operator to embed the script inside of a ConfigMap.
> The script should be stored inside of a data field identical to the file name: `index.html`. This should happen automatically, so don't confuse the behavior for it being incorrect.

* Now that a ConfigMap exists that holds your script, mount it to your deployment's container at the path `/usr/share/nginx/html/`

* Reload your Nginx deployment and verify that your HTML changes have been made.

## Exercise 6: Bases and Overlays

The first 5 exercises have focused on a very minimal file structure for Kustomize, but in practice it's typically a bit more complex than that. This simple exercise will help you transform your simple example into a more productionalized one, using overlays for both `dev` and `prod` environments.

* To begin, tear down your existing resources with `kustomize build . | kubectl delete -f -` and then move all of what you have so far into a `base` folder

* Then, make an `overlays` folder beside `base`. Inside `overlays`, create a `dev` folder and add a `kustomization.yaml` inside of it that builds the contents of `base`.
* All resources should have a name prefix of `dev-`, as well as deploy to a dev specific namespace.

* Repeat for `prod`, but with a name prefix on all resources of `prod-`.
* In addition, write a patch to change the deployment replica count to 3 for high availability.

```base
.
├── base
│ ├── deployment.yaml
│ ├── index.html
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── service.yaml
└── overlays
├── dev
│ └── kustomization.yaml
└── prod
└── kustomization.yaml
```

From there, simply run your `kustomize build` commands from inside of `dev` and `prod` to generate your resources.

## Recap

Now that you have gone through 6 exercises that each slightly modified your resources, take a moment to compare them all. Read your initial resources from the beginning of this section and then compare them to the outputs of your final build. These are just some of the many modifications that you'll use Kustomize for over the course of your career!

## Cleanup

To tear down your resources, run `kustomize build . | kubectl delete -f -` in each of the `dev` and `prod` folders.

## Knowledge Check

<div class="quizdown">
<div id="chapter-8/8.7.1/kustomize-quiz.js"></div>
</div>

## Deliverables

* How is it that Kustomize can build the ArgoCD resources found in the `raw.githubusercontent.com` url from exercise 1? What do you see if you navigate to the url?
* What are some pros/cons around this approach vs having all the manifests inside of local files?
* Explain how Kustomize's `secretGenerator` helps in managing sensitive data without exposing it in version control.
* Highlight any potential security risks with this approach and how they can be mitigated.
* What was needed in order for the existing secret to be replaced with any changes instead of a new one being created? Why would you want this outcome instead of a new secret being created?
* Compare the strategic merge patching with Json6902 patching.
* When should you use one over the other?
* What advantage does the `configMapGenerator` provide, specifically in the context of writing scripts?
55 changes: 55 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,61 @@ docs/8-kubernetes-container-orchestration/8.6-webhooks.md:
technologies:
- Kubernetes
- Python
docs/8-kubernetes-container-orchestration/8.7.1-kustomize.md:
category: Container Orchestration
estReadingMinutes: 20
exercises:
- name: General Use-Case
description: >-
Organize a few manifest files and use Kustomize to build them all at
once. Learn how to inspect build outputs and apply manifests with
Kustomize.
estMinutes: 15
technologies:
- Kubernetes
- Kustomize
- name: Simple Modifications
description: >-
Learn to use Kustomize's "namespace", "commonLabels", and "images"
operators.
estMinutes: 30
technologies:
- Kubernetes
- Kustomize
- name: Patches
description: >-
Learn to write Kustomize pathes, and the difference between
StrategicMergePatch and Json6902 patches.
estMinutes: 30
technologies:
- Kubernetes
- Kustomize
- name: Secret Management
description: >-
Learn to use the "secretGenerator" Kustomize operator and create another
Kustomize patch to include the secret as an environment variable in a
container.
estMinutes: 30
technologies:
- Kubernetes
- Kustomize
- name: Script Embedding
description: >-
Modify the Nginx server frontend by mounting an HTML script to the
container. Use the Kustomize configMapGenerator to create the ConfigMap
that holds the script.
estMinutes: 40
technologies:
- Kubernetes
- Kustomize
- name: Bases and Overlays
description: >-
See what a more productionalized Kustomize structure looks like with the
base/overlays pattern.
estMinutes: 20
technologies:
- Kubernetes
- Kustomize
docs/8-kubernetes-container-orchestration/8.8-hello-k8s.md:
category: Container Orchestration
estReadingMinutes: 15
Expand Down
4 changes: 3 additions & 1 deletion docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@
- [8.4 - RBAC](8-kubernetes-container-orchestration/8.4-rbac.md)
- [8.5 - HPAs](8-kubernetes-container-orchestration/8.5-hpas.md)
- [8.6 - Webhooks](8-kubernetes-container-orchestration/8.6-webhooks.md)
- [8.7 - Hello K8s](8-kubernetes-container-orchestration/8.7-hello-k8s.md)
- [8.7 - Declarative Configuration](8-kubernetes-container-orchestration/8.7-declarative-configuration.md)
- [8.7.1 - Kustomize](8-kubernetes-container-orchestration/8.7.1-kustomize.md)
- [8.8 - Hello K8s](8-kubernetes-container-orchestration/8.8-hello-k8s.md)

- **Chapter 9**

Expand Down
Loading

0 comments on commit 9fdd865

Please sign in to comment.