{"id":23185,"date":"2024-08-03T17:32:48","date_gmt":"2024-08-03T14:32:48","guid":{"rendered":"https:\/\/kifarunix.com\/?p=23185"},"modified":"2024-08-03T17:32:53","modified_gmt":"2024-08-03T14:32:53","slug":"kubernetes-kustomize-101-introduction-and-basics","status":"publish","type":"post","link":"https:\/\/kifarunix.com\/kubernetes-kustomize-101-introduction-and-basics\/","title":{"rendered":"Kubernetes Kustomize 101: Introduction and Basics"},"content":{"rendered":"\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1000\" height=\"559\" src=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/kubectl-kustomize.png?v=1722695307\" alt=\"Kubernetes Kustomize 101: Introduction and Basics\" class=\"wp-image-23248\" title=\"\" srcset=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/kubectl-kustomize.png?v=1722695307 1000w, https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/kubectl-kustomize-768x429.png?v=1722695307 768w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>This guide provides a foundational understanding of Kubernetes <a href=\"https:\/\/kustomize.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">Kustomize<\/a>. It will introduce you to Kustomize&#8217;s core concepts and the basics. With more organizations increasingly adopting the use of Kubernetes as the de facto standard for container orchestration, managing Kubernetes configurations across different environments such development, staging, production often requiring repetitive adjustments and configurations, can become cumbersome to manage. Kubernetes Kustomize addresses this challenge by offering a declarative approach to managing Kubernetes manifests. It simplifies the process of customizing configurations without the need for extensive templating or duplication of YAML files.<\/p>\n\n\n\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>Table of Contents<\/h2><nav><ul><li><a href=\"#kubernetes-kustomize-101-introduction-and-basics\">Kubernetes Kustomize 101: Introduction and Basics<\/a><ul><li><a href=\"#what-is-kubernetes-kustomize\">What is Kubernetes Kustomize?<\/a><\/li><li><a href=\"#key-concepts-in-kustomize\">Key Concepts in Kustomize<\/a><\/li><li><a href=\"#why-use-kubernetes-kustomize\">Why use Kubernetes Kustomize?<\/a><\/li><li><a href=\"#common-use-cases-of-kubernetes-kustomize\">Common Use cases of Kubernetes Kustomize<\/a><\/li><li><a href=\"#getting-started-with-kustomize\">Getting Started with Kustomize<\/a><ul><li><a href=\"#installing-kubernetes-kustomize\">Installing Kubernetes Kustomize<\/a><\/li><li><a href=\"#running-stand-alone-kustomize-tool\">Running StandAlone Kustomize Tool<\/a><\/li><li><a href=\"#using-kustomize-to-generate-resources-from-other-sources\">Using Kustomize to Generate Resources from Other Sources<\/a><\/li><\/ul><\/li><li><a href=\"#customizing-kubernetes-resources-with-kustomize-overlays\">Customizing Kubernetes Resources with Kustomize Overlays<\/a><ul><li><a href=\"#base-configuration\">Base Configuration<\/a><\/li><li><a href=\"#overlay-configuration\">Overlay Configuration<\/a><\/li><\/ul><\/li><li><a href=\"#conclusion\">Conclusion<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"kubernetes-kustomize-101-introduction-and-basics\">Kubernetes Kustomize 101: Introduction and Basics<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"what-is-kubernetes-kustomize\">What is Kubernetes Kustomize?<\/h3>\n\n\n\n<p>Kubernetes Kustomize is a tool used to customize Kubernetes YAML configurations without the need to use templating engines like Helm. It provides a declarative way to manage Kubernetes manifests by overlaying patches on top of a base configuration, i.e without duplicating or modifying the base YAML files directly. It provides a way to manage configuration drifts hence maintaining consistency across deployments.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"key-concepts-in-kustomize\">Key Concepts in Kustomize<\/h3>\n\n\n\n<p>Some of the key concepts that allows Kubernetes customize to simplify configuration management across different environments include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Base<\/strong>:\n<ul class=\"wp-block-list\">\n<li>This is the foundational directory in a Kustomize project where the original or default Kubernetes application manifests reside. It represents the base configuration of your application.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Overlay<\/strong>:\n<ul class=\"wp-block-list\">\n<li>An <code>overlay<\/code> is a directory that contains additional or modified Kubernetes manifests that overlay (or apply on top of) the <code>base<\/code> configuration.<\/li>\n\n\n\n<li>They allow customization of the <code>base<\/code> configuration for different environments, regions, or specific use cases without modifying the original <code>base<\/code> files directly.<\/li>\n\n\n\n<li>You can create separate overlay directories (e.g., <code>overlays\/dev<\/code>, <code>overlays\/prod<\/code>) where you can add or override resources, apply environment-specific configurations (like different resource limits, environment variables, etc.), and manage variations in configurations.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Patch<\/strong>:\n<ul class=\"wp-block-list\">\n<li>Patches are configurations that specifies the changes to apply to a resource. They provide a mechanism to modify or extend existing Kubernetes resources without directly modifying the original YAML files.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Kustomization file<\/strong>:\n<ul class=\"wp-block-list\">\n<li>kustomization.yaml file is the recipe for building a customized deployment configuration in Kustomize. It tells Kustomize what resources to include (base manifests, overlays, additional YAMLs), how to modify them (patches), and where to deploy them (namespace) within your Kubernetes cluster.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"why-use-kubernetes-kustomize\">Why use Kubernetes Kustomize?<\/h3>\n\n\n\n<p>Kubernetes Kustomize offers different benefits including:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Makes it easy to manage configurations for different environments. With Kubernetes Kustomize, you can create a base manifest with common configurations and then use overlays to apply environment-specific updates, keeping your base manifests clean and reusable.<\/li>\n\n\n\n<li>Since Kubernetes Kustomize allows you to maintain a base manifest that can be customized whenever a need arises, it reduces the hussle of having to duplicate entire manifests for different environments.<\/li>\n\n\n\n<li>The flexibility of Kubernetes Kustomize provides easy configurations version control thus ensuring clear traceability and reproducibility of your deployments.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"common-use-cases-of-kubernetes-kustomize\">Common Use cases of Kubernetes Kustomize<\/h3>\n\n\n\n<p>Some of the common use cases of Kubernetes Kustomize include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Composing and Customizing resources.<\/li>\n\n\n\n<li>Generating ConfigMaps and Secrets<\/li>\n\n\n\n<li>Applying Cross-Cutting Fields for example to set common labels, annotations, or namespaces for all resources in a project.<\/li>\n<\/ul>\n\n\n\n<p>Read more on <a href=\"https:\/\/kubernetes.io\/docs\/tasks\/manage-kubernetes-objects\/kustomization\/#overview-of-kustomize\" target=\"_blank\" rel=\"noreferrer noopener\">Kustomize overview<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"getting-started-with-kustomize\">Getting Started with Kustomize<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"installing-kubernetes-kustomize\">Installing Kubernetes Kustomize<\/h4>\n\n\n\n<p>From Kubernetes v1.14, Kustomize is integrated directly into <strong>kubectl<\/strong>, so you can use it without needing to install additional tools.<\/p>\n\n\n\n<p>To check if Kustomize is installed, just check the version of kubectl;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl version<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>Client Version: v1.30.2\nKustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3\nServer Version: v1.30.2\n<\/code><\/pre>\n\n\n\n<p>Therefore, you can view resources available in a directory using the command;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl kustomize &lt;kustomization_file_directory><\/code><\/pre>\n\n\n\n<p>Or apply resources in a directory using the command;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply &#91;-k|--kustomize] &lt;kustomization_directory&gt;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"running-stand-alone-kustomize-tool\">Running StandAlone Kustomize Tool<\/h4>\n\n\n\n<p>If you want, you can install a standalone Kustomize tool on your system.<\/p>\n\n\n\n<p>The installation steps have been extensively described in the documentation, link given below.<\/p>\n\n\n\n<p><a href=\"https:\/\/kubectl.docs.kubernetes.io\/installation\/kustomize\/\" target=\"_blank\" rel=\"noreferrer noopener\">Install Kustomize<\/a><\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"using-kustomize-to-generate-resources-from-other-sources\">Using Kustomize to Generate Resources from Other Sources<\/h4>\n\n\n\n<p>Kustomize can be used to dynamically generate Kubernetes resources from files or literals, simplifying resource management and avoiding hard-coded values.<\/p>\n\n\n\n<p>As an example, Kustomize can be used to generate ConfigMaps and Secrets using Kustomize <strong>configMapGenerator<\/strong> and <strong>secretGenerator<\/strong> features respectively. Similarly, it can be used to generate other Kubernetes resources such as deployments, services, etc<\/p>\n\n\n\n<p>We will be creating our resources on our custom namespace, <strong>kube-kustomize-base<\/strong>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl create namespace kube-kustomize-base<\/code><\/pre>\n\n\n\n<p>Then, let&#8217;s create our base configuration file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir base<\/code><\/pre>\n\n\n\n<p>Within the directory, we will create the Kustomization file and config directory for storing configMaps and Secrets.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir base\/config<\/code><\/pre>\n\n\n\n<p>In our example, we will be using a simple Nginx app serving the following content;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat base\/config\/index.html<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>&lt;html&gt;\n&lt;head&gt;\n    &lt;style&gt;\n        body {\n            text-align: center; \/* Centers text and inline elements *\/\n            font-family: Arial, sans-serif; \/* Optional: sets a nicer font *\/\n        }\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;h1&gt;Kube Kustomize Base Environment!&lt;\/h1&gt;\n    &lt;p&gt;This is the base version of our web app.&lt;\/p&gt;\n    &lt;p&gt;Feel free to explore and innovate!&lt;\/p&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n\n\n\n<p>And Nginx configuration with basic authentication.<\/p>\n\n\n\n<pre class=\"scroll-box\"><code>server {\n    listen 80;\n\n    location \/ {\n        auth_basic \"Restricted Access\";\n        auth_basic_user_file \/etc\/nginx\/.htpasswd;\n        root \/usr\/share\/nginx\/html;\n        index index.html;\n    }\n}\n<\/code><\/pre>\n\n\n\n<p>So, we will store the basic authentication password in a file (<strong>base\/config\/.htpasswd<\/strong>);<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>htpasswd -c base\/config\/.htpasswd admin<\/code><\/pre>\n\n\n\n<p>Next, let&#8217;s create Kubernetes <strong>kustomization file<\/strong> in the base directory. The Kustomization file defines how to use the <strong>configMapGenerator<\/strong> and <strong>secretGenerator<\/strong> to generate the configMap and Secrets.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat base\/kustomization.yaml<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>namespace: kube-kustomize-base\nconfigMapGenerator:\n  - name: nginx-config\n    files:\n      - config\/nginx.conf\n      - config\/index.html\n\nsecretGenerator:\n  - name: nginx-auth\n    files:\n      - htpasswd=config\/.htpasswd\n\ngeneratorOptions:\n  disableNameSuffixHash: true\n<\/code><\/pre>\n\n\n\n<p>The:<\/p>\n\n\n\n<p><strong><code>configMapGenerator<\/code> Section:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>name: nginx-config<\/code><\/strong>: Creates a ConfigMap named <code>nginx-config<\/code>.<\/li>\n\n\n\n<li><strong><code>files:<\/code><\/strong>: Includes <code>nginx.conf<\/code> and <code>index.html<\/code> in the ConfigMap.<\/li>\n<\/ul>\n\n\n\n<p><strong><code>secretGenerator<\/code> Section:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>name: nginx-auth<\/code><\/strong>: Creates a Secret named <code>nginx-auth<\/code>.<\/li>\n\n\n\n<li><strong><code>files:<\/code><\/strong>: Reads <code>config\/.htpasswd<\/code> and adds it to the Secret under the key <code>htpasswd<\/code>.<\/li>\n<\/ul>\n\n\n\n<p><strong><code>generatorOptions<\/code><\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The option <code>disableNameSuffixHash<\/code> is used to avoid adding a hash suffix to the names of generated ConfigMaps and Secrets. This is useful if you want to keep the names consistent and predictable.<\/li>\n<\/ul>\n\n\n\n<p>Note that you can generate your configMaps\/Secrets from the literals or even the environment variables.<\/p>\n\n\n\n<p>Thus, this is our basic base directory structure;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tree -a base<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>base\n\u251c\u2500\u2500 config\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .htpasswd\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 index.html\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 nginx.conf\n\u2514\u2500\u2500 kustomization.yaml\n\n2 directories, 4 files\n<\/code><\/pre>\n\n\n\n<p>You can examine the configMap and Secret to be generated using the command;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl kustomize base<\/code><\/pre>\n\n\n\n<p>Sample output;<\/p>\n\n\n\n<pre class=\"scroll-box\"><code>apiVersion: v1\ndata:\n  index.html: |\n    &lt;html&gt;\n    &lt;head&gt;\n        &lt;style&gt;\n            body {\n                text-align: center; \/* Centers text and inline elements *\/\n                font-family: Arial, sans-serif; \/* Optional: sets a nicer font *\/\n            }\n        &lt;\/style&gt;\n    &lt;\/head&gt;\n    &lt;body&gt;\n        &lt;h1&gt;Kube Kustomize Base Environment!&lt;\/h1&gt;\n        &lt;p&gt;This is the base version of our web app.&lt;\/p&gt;\n        &lt;p&gt;Feel free to explore and innovate!&lt;\/p&gt;\n    &lt;\/body&gt;\n    &lt;\/html&gt;\n  nginx.conf: |\n    server {\n        listen 80;\n\n        location \/ {\n            auth_basic \"Restricted Access\";\n            auth_basic_user_file \/etc\/nginx\/.htpasswd;\n            root \/usr\/share\/nginx\/html;\n            index index.html;\n        }\n    }\nkind: ConfigMap\nmetadata:\n  name: nginx-config\n  namespace: kube-kustomize-base\n---\napiVersion: v1\ndata:\n  .htpasswd: |\n    YWRtaW46JDJ5JDEwJG5uc25kTFozSTYzWENNOVRxbFF2bi45LzRWVC8vbGxWajRKSWY1UW\n    M4RlFGYmEwS1JOSlptCg==\nkind: Secret\nmetadata:\n  name: nginx-auth\n  namespace: kube-kustomize-base\ntype: Opaque\n<\/code><\/pre>\n\n\n\n<p>To create the configMap and Secrets, simply apply using kustomize;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply &#91;-k|--kustomize] &lt;path to directory containing kustomization yaml><\/code><\/pre>\n\n\n\n<p>E.g<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -k base<\/code><\/pre>\n\n\n\n<p>Sample output;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>configmap\/nginx-config created\nsecret\/nginx-auth created<\/code><\/pre>\n\n\n\n<p>You can customize how the resources are generated with <a href=\"https:\/\/kubernetes.io\/docs\/tasks\/manage-kubernetes-objects\/kustomization\/#generatoroptions\" target=\"_blank\" rel=\"noreferrer noopener\">generator options<\/a>.<\/p>\n\n\n\n<p>View the created configMap and Secret;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get configmap,secrets -n kube-kustomize-base<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>NAME                                DATA   AGE\nconfigmap\/kube-root-ca.crt          1      7m26s\nconfigmap\/nginx-config              1      104s\n\nNAME                           TYPE     DATA   AGE\nsecret\/nginx-auth              Opaque   1      104s\n<\/code><\/pre>\n\n\n\n<p>Now, let&#8217;s add a deployment that will utilize the configMap and Secrets above, as well a service that exposes the Deployment.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat base\/deployment.yaml<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: nginx-deployment\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - name: nginx\n        image: nginx:latest\n        ports:\n        - containerPort: 80\n        volumeMounts:\n        - name: nginx-auth\n          mountPath: \/etc\/nginx\/.htpasswd\n          subPath: .htpasswd\n          readOnly: true\n        - name: nginx-config\n          mountPath: \/etc\/nginx\/conf.d\/default.conf\n          subPath: nginx.conf\n        - name: nginx-config\n          mountPath: \/usr\/share\/nginx\/html\/index.html\n          subPath: index.html\n      volumes:\n      - name: nginx-auth\n        secret:\n          secretName: nginx-auth\n      - name: nginx-config\n        configMap:\n          name: nginx-config\n<\/code><\/pre>\n\n\n\n<p>And the service to expose our deployment via the NodePort.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat base\/service.yaml<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>apiVersion: v1\nkind: Service\nmetadata:\n  name: nginx-service\nspec:\n  selector:\n    app: nginx\n  ports:\n    - protocol: TCP\n      port: 80\n      targetPort: 80\n  type: NodePort\n<\/code><\/pre>\n\n\n\n<p>At this point, these are all the files in my base directory;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tree -a base<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>base\n\u251c\u2500\u2500 config\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .htpasswd\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 index.html\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 nginx.conf\n\u251c\u2500\u2500 deployment.yaml\n\u251c\u2500\u2500 kustomization.yaml\n\u2514\u2500\u2500 service.yaml\n\n2 directories, 6 files\n<\/code><\/pre>\n\n\n\n<p>Next, include the Deployment and Service resources in the <strong>kustomization<\/strong> file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat base\/kustomization.yaml<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>namespace: kube-kustomize-base\nconfigMapGenerator:\n  - name: nginx-config\n    files:\n      - config\/nginx.conf\n      - config\/index.html\n\nsecretGenerator:\n  - name: nginx-auth\n    files:\n      - config\/.htpasswd\n\ngeneratorOptions:\n  disableNameSuffixHash: true\n\n<strong>resources:\n- deployment.yaml\n- service.yaml<\/strong>\n<\/code><\/pre>\n\n\n\n<p>To see what the final YAML output would look like after all customizations are applied. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl kustomize base\/<\/code><\/pre>\n\n\n\n<p>To apply the customizations into Kubernetes cluster;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -k base\/<\/code><\/pre>\n\n\n\n<p>You can check the Deployment and Service created.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get deployment,svc -n kube-kustomize-base<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>NAME                               READY   UP-TO-DATE   AVAILABLE   AGE\ndeployment.apps\/nginx-deployment   1\/1     1            1           31s\n\nNAME                    TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE\nservice\/nginx-service   NodePort   10.110.182.223   &lt;none&gt;        80:32169\/TCP   31s\n<\/code><\/pre>\n\n\n\n<p>Your basic Nginx app is now running.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1162\" height=\"291\" src=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/base-nginX-app.png?v=1722688819\" alt=\"\" class=\"wp-image-23241\" title=\"\" srcset=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/base-nginX-app.png?v=1722688819 1162w, https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/base-nginX-app-768x192.png?v=1722688819 768w\" sizes=\"(max-width: 1162px) 100vw, 1162px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"customizing-kubernetes-resources-with-kustomize-overlays\">Customizing Kubernetes Resources with Kustomize Overlays<\/h3>\n\n\n\n<p>To update the above Nginx app to reflect different environments (dev, staging, production) using Kustomize overlays, you can create a configuration that includes patches to modify the content served by Nginx or any specific configuration that reflects specific environment of the app.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"base-configuration\">Base Configuration<\/h4>\n\n\n\n<p>In the base configuration above, we have the app configuration directory which contains the Secrets, ConfigMap, the deployment and service manifest and the kustomization file. We have used Kubernetes Kustomize to generate Secrets, ConfigMaps, and our Nginx deployment and service.<\/p>\n\n\n\n<p>Base Directory Structure:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tree -a base<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>base\n\u251c\u2500\u2500 config\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .htpasswd\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 index.html\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 nginx.conf\n\u251c\u2500\u2500 deployment.yaml\n\u251c\u2500\u2500 kustomization.yaml\n\u2514\u2500\u2500 service.yaml\n\n2 directories, 6 files\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"overlay-configuration\">Overlay Configuration<\/h4>\n\n\n\n<p>To demonstrate how you can use Kustomize to customize\/patch the app for each environment (dev, staging, production), we will update our ConfigMap using patches to customize the base configuration without altering the original files.<\/p>\n\n\n\n<p>We already have a base directory with base configurations. Next, let&#8217;s create overlays directory for the three environments:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir -p overlays\/{dev,staging,production}<\/code><\/pre>\n\n\n\n<p>Each overlay will provide a patch to modify the <code>index.html<\/code> content for that environment.<\/p>\n\n\n\n<p>Similarly, I will put each environment under its own namespace. So, let&#8217;s create three namespaces.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl create ns kube-kustomize-dev<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl create ns kube-kustomize-staging<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl create ns kube-kustomize-production<\/code><\/pre>\n\n\n\n<p>In summary, this is what we want to try out:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Customize the <code>nginx<\/code> default page for each environment.<\/li>\n\n\n\n<li>Set different replica counts for development, staging, and production.<\/li>\n\n\n\n<li>Deploy to different namespaces for each environment.<\/li>\n<\/ul>\n\n\n\n<p>Overlay directory structure:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tree -a overlays<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>overlays\/\n\u251c\u2500\u2500 dev\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 configmap-patch.yaml\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 deployment-patch.yaml\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 kustomization.yaml\n\u251c\u2500\u2500 production\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 configmap-patch.yaml\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 deployment-patch.yaml\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 kustomization.yaml\n\u2514\u2500\u2500 staging\n    \u251c\u2500\u2500 configmap-patch.yaml\n    \u251c\u2500\u2500 deployment-patch.yaml\n    \u2514\u2500\u2500 kustomization.yaml\n\n4 directories, 9 files\n<\/code><\/pre>\n\n\n\n<p>In general, this is how our custom app directory structure is like;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tree -a kustomize-app\/<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>kustomize-app\/\n\u251c\u2500\u2500 base\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 config\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 .htpasswd\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 index.html\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 nginx.conf\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 deployment.yaml\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 kustomization.yaml\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 service.yaml\n\u2514\u2500\u2500 overlays\n    \u251c\u2500\u2500 dev\n    \u2502\u00a0\u00a0 \u251c\u2500\u2500 configmap-patch.yaml\n    \u2502\u00a0\u00a0 \u251c\u2500\u2500 deployment-patch.yaml\n    \u2502\u00a0\u00a0 \u2514\u2500\u2500 kustomization.yaml\n    \u251c\u2500\u2500 production\n    \u2502\u00a0\u00a0 \u251c\u2500\u2500 configmap-patch.yaml\n    \u2502\u00a0\u00a0 \u251c\u2500\u2500 deployment-patch.yaml\n    \u2502\u00a0\u00a0 \u2514\u2500\u2500 kustomization.yaml\n    \u2514\u2500\u2500 staging\n        \u251c\u2500\u2500 configmap-patch.yaml\n        \u251c\u2500\u2500 deployment-patch.yaml\n        \u2514\u2500\u2500 kustomization.yaml\n\n7 directories, 15 files\n<\/code><\/pre>\n\n\n\n<div class=\"info-panel\">\n    <div class=\"info-panel-header\">Info\n    <\/div>\n    <div class=\"info-panel-content\"> According to the <a href=\"https:\/\/github.com\/kubernetes-sigs\/kustomize\/blob\/master\/examples\/patchMultipleObjects.md\" target=\"_blank\" rel=\"noopener\">Kubernetes Documentation<\/a>, Kustomize supports two types of patches:\n    <ul>\n        <li><strong>Strategic merge patches<\/strong>: These are partial representations of a resource that merge with the existing resource, specified by a list of file paths. Each file should be resolved to a strategic merge patch. The names inside the patches must match Resource names that are already loaded. Small patches that do one thing are recommended<\/li>\n        <li><strong>JSON6902 patches<\/strong>: These are JSON patches that can modify specific fields in a resource.<\/li><\/ul>    \n    <\/div>\n<\/div>\n\n\n\n<p>Development Overlays:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat overlays\/dev\/kustomization.yaml<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>namespace: kube-kustomize-dev\n\nresources:\n  - ..\/..\/base\n\npatches:\n  - path: deployment-patch.yaml\n  - path: configmap-patch.yaml\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>cat overlays\/dev\/deployment-patch.yaml<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: nginx-deployment\nspec:\n  replicas: 1\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>cat overlays\/dev\/configmap-patch.yaml<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: nginx-config\ndata:\n  index.html: |\n    &lt;html&gt;\n    &lt;head&gt;\n        &lt;style&gt;\n            body {\n                text-align: center;\n                font-family: Arial, sans-serif;\n            }\n        &lt;\/style&gt;\n    &lt;\/head&gt;\n    &lt;body&gt;\n        &lt;h1&gt;Kube Kustomize Dev Environment!&lt;\/h1&gt;\n        &lt;p&gt;This is the Development version of our web app.&lt;\/p&gt;\n        &lt;p&gt;Feel free to explore and innovate!&lt;\/p&gt;\n    &lt;\/body&gt;\n    &lt;\/html&gt;\n<\/code><\/pre>\n\n\n\n<p>Now, you can review your patches;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl kustomize overlays\/dev<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>apiVersion: v1\ndata:\n  index.html: |\n    &lt;html&gt;\n    &lt;head&gt;\n        &lt;style&gt;\n            body {\n                text-align: center;\n                font-family: Arial, sans-serif;\n            }\n        &lt;\/style&gt;\n    &lt;\/head&gt;\n    &lt;body&gt;\n        &lt;h1&gt;Kube Kustomize Dev Environment!&lt;\/h1&gt;\n        &lt;p&gt;This is the Development version of our web app.&lt;\/p&gt;\n        &lt;p&gt;Feel free to explore and innovate!&lt;\/p&gt;\n    &lt;\/body&gt;\n    &lt;\/html&gt;\n  nginx.conf: |\n    server {\n        listen 80;\n\n        location \/ {\n            auth_basic \"Restricted Access\";\n            auth_basic_user_file \/etc\/nginx\/.htpasswd;\n            root \/usr\/share\/nginx\/html;\n            index index.html;\n        }\n    }\nkind: ConfigMap\nmetadata:\n  name: nginx-config\n  namespace: kube-kustomize-dev\n---\napiVersion: v1\ndata:\n  .htpasswd: |\n    YWRtaW46JDJ5JDEwJG5uc25kTFozSTYzWENNOVRxbFF2bi45LzRWVC8vbGxWajRKSWY1UW\n    M4RlFGYmEwS1JOSlptCg==\nkind: Secret\nmetadata:\n  name: nginx-auth\n  namespace: kube-kustomize-dev\ntype: Opaque\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: nginx-service\n  namespace: kube-kustomize-dev\nspec:\n  ports:\n  - port: 80\n    protocol: TCP\n    targetPort: 80\n  selector:\n    app: nginx\n  type: NodePort\n---\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: nginx-deployment\n  namespace: kube-kustomize-dev\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - image: nginx:latest\n        name: nginx\n        ports:\n        - containerPort: 80\n        volumeMounts:\n        - mountPath: \/etc\/nginx\/.htpasswd\n          name: nginx-auth\n          readOnly: true\n          subPath: .htpasswd\n        - mountPath: \/etc\/nginx\/conf.d\/default.conf\n          name: nginx-config\n          subPath: nginx.conf\n        - mountPath: \/usr\/share\/nginx\/html\/index.html\n          name: nginx-config\n          subPath: index.html\n      volumes:\n      - name: nginx-auth\n        secret:\n          secretName: nginx-auth\n      - configMap:\n          name: nginx-config\n        name: nginx-config\n<\/code><\/pre>\n\n\n\n<p>The apply if all is good.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -k overlays\/dev<\/code><\/pre>\n\n\n\n<p>List all resources in the Development namespace.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get all -n kube-kustomize-dev<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>NAME                                   READY   STATUS    RESTARTS   AGE\npod\/nginx-deployment-85c575f57-kjn24   1\/1     Running   0          53s\n\nNAME                    TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE\nservice\/nginx-service   NodePort   10.105.39.168   &lt;none&gt;        80:32056\/TCP   53s\n\nNAME                               READY   UP-TO-DATE   AVAILABLE   AGE\ndeployment.apps\/nginx-deployment   1\/1     1            1           53s\n\nNAME                                         DESIRED   CURRENT   READY   AGE\nreplicaset.apps\/nginx-deployment-85c575f57   1         1         1       53s\n<\/code><\/pre>\n\n\n\n<p>You can access your app via port 32056. Remember we didnt change the basic auth password. So use the one set in the base configuration.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1180\" height=\"320\" src=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/base-nginx-app-dev-overlay.png?v=1722693127\" alt=\"kubernetes kustomize overlays\" class=\"wp-image-23243\" title=\"\" srcset=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/base-nginx-app-dev-overlay.png?v=1722693127 1180w, https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/base-nginx-app-dev-overlay-768x208.png?v=1722693127 768w\" sizes=\"(max-width: 1180px) 100vw, 1180px\" \/><\/figure>\n\n\n\n<p>If you want, you can update other settings as you see fit.<\/p>\n\n\n\n<p>For our production, this is how we customized the app: 4 replicas and updated web page.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat overlays\/production\/kustomization.yaml<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>namespace: kube-kustomize-production\n\nresources:\n  - ..\/..\/base\n\npatches:\n  - path: deployment-patch.yaml\n  - path: configmap-patch.yaml\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>cat overlays\/production\/deployment-patch.yaml<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: nginx-deployment\nspec:\n  replicas: 4\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>overlays\/production\/configmap-patch.yaml<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: nginx-config\ndata:\n  index.html: |\n    &lt;html lang=\"en\"&gt;\n    &lt;head&gt;\n        &lt;meta charset=\"UTF-8\"&gt;\n        &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"&gt;\n        &lt;style&gt;\n            body {\n                font-family: Arial, sans-serif;\n                text-align: center;\n                padding: 50px;\n            }\n            h1 {\n                color: #009688;\n            }\n            p {\n                color: #607d8b;\n            }\n            .container {\n                margin-top: 30px;\n                display: flex;\n                justify-content: center;\n                align-items: center;\n            }\n            .kube-logo {\n                width: 150px;\n                height: 150px;\n                margin-right: 20px;\n            }\n        &lt;\/style&gt;\n    &lt;\/head&gt;\n    &lt;body&gt;\n        &lt;h1&gt;Welcome to Kubernetes Kustomize Basics!&lt;\/h1&gt;\n        &lt;div class=\"container\"&gt;\n            &lt;img class=\"kube-logo\" src=\"https:\/\/raw.githubusercontent.com\/kubernetes\/kubernetes\/master\/logo\/logo.png\" alt=\"Kubernetes Logo\"&gt;\n            &lt;p&gt;This is the Production Kustomize Overlay with an updated web page and with four replicas!&lt;\/p&gt;\n        &lt;\/div&gt;\n        &lt;p&gt;Feel free to explore and innovate!&lt;\/p&gt;\n    &lt;\/body&gt;\n    &lt;\/html&gt;\n<\/code><\/pre>\n\n\n\n<p>You can review the changes;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl kustomize overlays\/production<\/code><\/pre>\n\n\n\n<p>Then apply;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply --kustomize overlays\/production<\/code><\/pre>\n\n\n\n<p>View resources;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get all -n kube-kustomize-production<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>NAME                                   READY   STATUS    RESTARTS   AGE\npod\/nginx-deployment-85c575f57-2rl9k   1\/1     Running   0          13s\npod\/nginx-deployment-85c575f57-2vt49   1\/1     Running   0          13s\npod\/nginx-deployment-85c575f57-4x656   1\/1     Running   0          13s\npod\/nginx-deployment-85c575f57-t9ggv   1\/1     Running   0          13s\n\nNAME                    TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE\nservice\/nginx-service   NodePort   10.107.20.199   <none>        80:31487\/TCP   13s\n\nNAME                               READY   UP-TO-DATE   AVAILABLE   AGE\ndeployment.apps\/nginx-deployment   4\/4     4            4           13s\n\nNAME                                         DESIRED   CURRENT   READY   AGE\nreplicaset.apps\/nginx-deployment-85c575f57   4         4         4       13s\n<\/code><\/pre>\n\n\n\n<p>And there you go!<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1156\" height=\"388\" src=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/base-nginx-app-production-overlay.png?v=1722694163\" alt=\"kubernetes kustomize overlays\" class=\"wp-image-23245\" title=\"\" srcset=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/base-nginx-app-production-overlay.png?v=1722694163 1156w, https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/base-nginx-app-production-overlay-768x258.png?v=1722694163 768w\" sizes=\"(max-width: 1156px) 100vw, 1156px\" \/><\/figure>\n\n\n\n<p>And that closes our basic guide on Kubernetes Kustomize 101.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"conclusion\">Conclusion<\/h3>\n\n\n\n<p>Kustomize provides robust features for managing Kubernetes configurations, including:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Generating Resources from Other Sources<\/strong>: Combine and reuse configurations to create complex deployments.<\/li>\n\n\n\n<li><strong>Setting Cross-Cutting Fields for Resources<\/strong>: Apply consistent settings such as labels and annotations across multiple resources.<\/li>\n\n\n\n<li><strong>Composing and Customizing Collections of Resources<\/strong>: Build and manage complex configurations in a modular and flexible manner.<\/li>\n<\/ul>\n\n\n\n<p>Read more on <a href=\"https:\/\/github.com\/kubernetes-sigs\/kustomize\/?tab=readme-ov-file#kustomize\" target=\"_blank\" rel=\"noreferrer noopener\">Kustomize page<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This guide provides a foundational understanding of Kubernetes Kustomize. It will introduce you to Kustomize&#8217;s core concepts and the basics. With more organizations increasingly adopting<\/p>\n","protected":false},"author":10,"featured_media":23248,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"rank_math_lock_modified_date":false,"footnotes":""},"categories":[1668,1076,121],"tags":[7570,7574,7571,7572,7573],"class_list":["post-23185","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-kubernetes","category-containers","category-howtos","tag-how-to-use-kubernetes-kustomize","tag-kustomization-yaml","tag-kustomize-base","tag-overlay","tag-patches","generate-columns","tablet-grid-50","mobile-grid-100","grid-parent","grid-50","resize-featured-image"],"_links":{"self":[{"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/posts\/23185"}],"collection":[{"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/users\/10"}],"replies":[{"embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/comments?post=23185"}],"version-history":[{"count":23,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/posts\/23185\/revisions"}],"predecessor-version":[{"id":23250,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/posts\/23185\/revisions\/23250"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/media\/23248"}],"wp:attachment":[{"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/media?parent=23185"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/categories?post=23185"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/tags?post=23185"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}