{"id":103586,"date":"2024-09-30T17:48:16","date_gmt":"2024-09-30T17:48:16","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=103586"},"modified":"2024-08-27T18:05:50","modified_gmt":"2024-08-27T18:05:50","slug":"a-unified-approach-to-managing-deployments-in-kubernetes-with-kluctl","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/devops\/containers-and-virtualization\/a-unified-approach-to-managing-deployments-in-kubernetes-with-kluctl\/","title":{"rendered":"A Unified Approach to Managing Deployments in Kubernetes with Kluctl"},"content":{"rendered":"<p>Applications built today pass through different phases before going live; most organizations use development, testing, and production, while others employ development, staging, and then production. Regardless of the number of phases, it all follows the multi-environment concept. In <a href=\"https:\/\/kubernetes.io\/\">Kubernetes<\/a>, this is no different; however, Kubernetes is already complex as it is, so adhering to the concept of multi-environments again is not a piece of cake. But there are two well-known options; <a href=\"https:\/\/helm.sh\/\">Helm<\/a> and <a href=\"https:\/\/kustomize.io\/\">Kustomize<\/a>.<\/p>\n<p>Helm simplifies the process of deploying applications, which is good for managing packaged applications across different environments. On the other hand, Kustomize excels at customizing configurations without altering the original templates. But then, there is Kluctl.<\/p>\n<h2><a id=\"post-103586-_lu5j69kt2ux1\"><\/a>What is Kluctl<\/h2>\n<p>For every phase or environment in which you run your applications, there are configurations, resource requirements, or other settings that are unique to each environment. Kluctl allows you to define environment-specific parameters and configurations in a structured and maintainable way. To reduce the risk of human error and to ensure consistency across environments, Kluctl can automatically apply the correct configurations for each environment during deployment. It achieves this through a declarative approach, where you define the desired state of your applications and services, and Kluctl ensures that the Kubernetes cluster reflects this state.<\/p>\n<p>Kluctl is robust in the sense that teams already utilizing the package management capabilities of Helm or the configuration customization features of Kustomize can combine them with Kluctl. Kluctl integrates seamlessly with these tools and even enhances their capabilities by providing a higher level of abstraction for managing deployments. This integration ensures that you can leverage the features of these tools while also enjoying the simplified, unified management interface that Kluctl offers. This method minimizes manual intervention, supports reproducibility and traceability, which are crucial for maintaining system reliability and compliance in complex deployments.<\/p>\n<h2><a id=\"post-103586-_h51nxwfdpnu6\"><\/a>Prerequisites<\/h2>\n<p>The following sections will be hands-on. To follow along be sure to meet the following requirements:<\/p>\n<ul>\n<li>A Kubernetes cluster up and running. Either a local or cloud-based cluster will work fine.<\/li>\n<li>Kluctl, Helm and Kustomize installed, see the following guide from their official documentation respectively<a href=\"https:\/\/kluctl.io\/docs\/kluctl\/kluctl-project\/\"> kluctl-project<\/a>,<a href=\"https:\/\/helm.sh\/docs\/intro\/install\/\"> helm install<\/a> and<a href=\"https:\/\/kustomize.io\/\"> kustomize site<\/a>.<\/li>\n<\/ul>\n<h2><a id=\"post-103586-_x9r6z2b8hhpo\"><\/a>Using Kluctl<\/h2>\n<p>Kluctl is not a standalone deployment tool in the sense that it doesn&#8217;t replace the functionalities of Helm or Kustomize. Instead, Kluctl is designed to work with these tools, and then enhance the management of deployments that are defined using Helm charts or Kustomize configurations.<\/p>\n<p>Therefore, to fully utilize Kluctl, you would typically have your deployment configurations already set up in Helm or Kustomize, and then use Kluctl to orchestrate these deployments across different environments or manage complex scenarios more seamlessly.<\/p>\n<p>Begin by checking the version of Kluctl using the following command:<\/p>\n<pre class=\"lang:none theme:none\">kluctl --version<\/pre>\n<p>As of this writing the latest version is 2.24.1 as shown below in the expected output from that statement (with different prompt value, of course):<\/p>\n<pre class=\"lang:none theme:none\">mercy@mercy:~$ kluctl --version\nkluctl version 2.24.1<\/pre>\n<h3><a id=\"post-103586-_t8pmb5vc1m0k\"><\/a>Using Kluctl with Kustomize<\/h3>\n<p>The official Kluctl documentation provides example projects to demonstrate the use of Kluctl. To begin, you will be using the<a href=\"https:\/\/github.com\/kluctl\/kluctl-examples\/tree\/main\/simple\"> Simple<\/a> project from the examples repository to see how Kluctl works with Kustomize.<\/p>\n<p>Clone the repository using the command below:<\/p>\n<pre class=\"lang:none theme:none\">git clone git@github.com:kluctl\/kluctl-examples.git<\/pre>\n<p>Once cloned, <strong>cd<\/strong> into the <em>kluctl-examples\/simple<\/em> directory and run the <em>tree<\/em> command to see the project structure:<\/p>\n<pre class=\"lang:none theme:none\">cd kluctl-examples\/simple\ntree<\/pre>\n<p>You should have the following output:<\/p>\n<pre class=\"lang:none theme:none\">mercy@mercy:~\/kluctl-examples\/simple$ tree\n.\n\u251c\u2500\u2500 deployment\n\u2502   \u251c\u2500\u2500 deployment.yml\n\u2502   \u2514\u2500\u2500 nginx\n\u2502       \u251c\u2500\u2500 deploy.yml\n\u2502       \u251c\u2500\u2500 kustomization.yml\n\u2502       \u251c\u2500\u2500 namespace.yml\n\u2502       \u2514\u2500\u2500 service.yml\n\u2514\u2500\u2500 deployment.yml\n2 directories, 6 files\nmercy@mercy:~\/kluctl-examples\/simple$<\/pre>\n<p>Here\u2019s a brief explanation of what is contained in the Simple project directory:<\/p>\n<ul>\n<li>The **deployment** directory: Located within this directory is a <code>deployment.yml <\/code>file that provides configurations more specific to the resources being managed. It directs Kluctl to deploy resources specifically defined within the <code>nginx<\/code> subdirectory, focusing on the specific components necessary for the Nginx service.<\/li>\n<li>The **nginx** subdirectory: This subdirectory contains all necessary files for deploying an Nginx service:\n<ul>\n<li><code>deploy.yml<\/code>: Defines the Kubernetes Deployment for Nginx, specifying the deployment&#8217;s desired state, including replicas, container image, and ports.<\/li>\n<li><code>kustomization.yml<\/code>: A Kustomize configuration file that aggregates all related Kubernetes resources to be applied together, such as namespace, deployment, and service.<\/li>\n<li><code>namespace.yml<\/code>: Defines a Kubernetes Namespace, with its name dynamically set based on the <code>environment<\/code> argument passed from <code>.kluctl.yml<\/code>.<\/li>\n<li><code>service.yml<\/code>: Outlines a Kubernetes Service to expose the Nginx deployment externally on port 80.<\/li>\n<\/ul>\n<\/li>\n<li>**deployment.yml**: This file is located at the root of the <code>simple<\/code> directory and serves as the primary entry point for deployment configurations. It uses the <code>include<\/code> directive to incorporate deployments from the <code>deployment<\/code> directory, ensuring a modular approach to resource management. Additionally, it defines <code>commonLabels<\/code> that are applied across all resources managed by this project, aiding in resource identification and management.<\/li>\n<li>**.kluctl.yml**: This configuration file is what Kluctl watches out for defining deployment targets and providing necessary arguments to them. It includes multiple targets named <code>simple<\/code> and <code>another<\/code>, each configured with an <code>environment<\/code> argument to adapt to different deployment scenarios. The <code>discriminator<\/code> field uniquely identifies deployments from this project, beneficial in complex environments with multiple ongoing deployments.<\/li>\n<\/ul>\n<p>Navigate to <code>simple\/.kluctl.yml<\/code> and add a context in the targets section to <a href=\"https:\/\/fig.io\/manual\/minikube\">minikube<\/a> like so, this enables Kluctl deployments to work with different Kubernetes environments:<\/p>\n<p>&#8230;<\/p>\n<pre class=\"lang:none theme:none\">targets:\n  - name: simple\n    context: minikube\n ...\nIf you are using kind instead of minikube modify the context as follows:\n...\ntargets:\n  - name: simple\n    context: kind-kind\n ...<\/pre>\n<p>For cloud-based clusters, add the appropriate context, you can find out using the following command:<\/p>\n<pre class=\"lang:none theme:none\">kubectl config get-contexts<\/pre>\n<p>Next, we deploy the sample project using the following Kluctl command:<\/p>\n<pre class=\"lang:none theme:none\">kluctl deploy -t simple<\/pre>\n<p>Kluctl begins to initialize various steps including updating Kluctl, loading the project, rendering templates and Helm charts, and building Kustomize objects. Once the differences are displayed and you&#8217;re prompted to proceed, type <strong>y<\/strong> to confirm and Kluctl will finalize the deployment by applying the necessary Kubernetes objects such as namespaces, services, and deployments, confirming each step along the way.<\/p>\n<p>Once this process is done, you should have something very similar to the following (chose Y (yes) when prompted if you do):<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1585\" height=\"927\" class=\"wp-image-103587\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/08\/word-image-103586-1.png\" \/><strong>Fig 1: Creating a Kluctl deployment<\/strong><\/p>\n<p>View the deployments, pods and services created by Kluctl using the following kubectl commands:<\/p>\n<pre class=\"lang:none theme:none\">kubectl -n simple get deployments\nkubectl -n simple get pods\nkubectl -n simple get svc<\/pre>\n<p>Your output should be something like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1424\" height=\"207\" class=\"wp-image-103588\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/08\/word-image-103586-2.png\" \/><\/p>\n<p><strong>Fig 2: Viewing pods <\/strong><\/p>\n<p>Modify the replica count in your deployment, adjust the <code>replicas<\/code> field in the <code>deployment\/nginx\/deploy.yml<\/code> file from <code>3<\/code> to <code>1<\/code>. After updating the file, redeploy the project by executing the same Kluctl command: <code>kluctl deploy -t simple<\/code>.<\/p>\n<p>This will apply the updated configuration and reflect the new number of replicas in your deployment. You should a diff showing the following output:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1784\" height=\"1334\" class=\"wp-image-103589\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/08\/word-image-103586-3.png\" \/><\/p>\n<p><strong>Fig 3: Creating a Kluctl deployment and viewing diff<\/strong><\/p>\n<p>From the output above, during the deployment with Kluctl detected a change in the <code>nginx-deployment<\/code> within the <code>simple<\/code> project. Specifically, the number of replicas specified in the deployment configuration was reduced from <code>3<\/code> to <code>1<\/code>. Kluctl highlighted this change in a diff output showing a decrease in <code>spec.replicas<\/code> from <code>3<\/code> to <code>1<\/code>.<\/p>\n<h2><a id=\"post-103586-_ixev5pmsp4js\"><\/a>Running Multi-environment deployments<\/h2>\n<p>The true power of Kluctl lies in managing configurations effectively across multi-environment deployments. To see this capability in action, navigate to the <code>kluctl-examples\/simple-helm<\/code> directory and edit the <code>.kluctl.yml<\/code> file as shown below:<\/p>\n<pre class=\"lang:none theme:none\">discriminator: kluctl-examples-simple-helm-{{ target.name }}\ntargets:\n  - name: simple-helm\n    args:\n      environment: simple-helm\n      env_type: simple-helm\n  - name: testing\n    args:\n      environment: testing\n      env_type: testing\n  - name: production\n    args:\n      environment: production\n      env_type: production\n      \nargs:\n  - name: environment<\/pre>\n<p>This configuration in the .<code>kluctl.yml<\/code> file establishes three distinct deployment targets for managing different stages of the application lifecycle: <code>simple-helm<\/code>, <code>testing<\/code>, and <code>production<\/code>. Each target is associated with its own set of arguments, specifically <code>environment<\/code> and <code>env_type<\/code>, which will be used to dynamically tailor the deployment settings according to the specific needs of each stage.<\/p>\n<p>Head over to the <code>kluctl-examples\/simple-helm\/deployment.yml<\/code> and add both a vars section and a new line in the <em>commonLabels<\/em> section:<\/p>\n<pre class=\"lang:none theme:none\">vars: #add this section\n  - file: .\/vars\/{{args.env_type }}.yml\n...\ncommonLabels:\n  ...\n  # Add this line\n  examples.kluctl.io\/deployment-target: \"{{ target.name }}\"<\/pre>\n<p>The <code>Vars<\/code> section represents a dynamic way to inject configuration variables based on the environment or deployment target. In this case, it will be used to load environment-specific settings from variable files located in the <code>.\/vars\/<\/code> directory you will create later, where each file is named after the <code>env_type<\/code> argument of each target. This enables the deployment to adjust parameters like replica counts, resource limits, and other configurable aspects of the Helm charts based on the specific needs of each environment.<\/p>\n<p>A common label on the other hand is what Kluctl uses to uniquely identify and manage resources across different deployments. Without these labels, accurate tracking and differentiation of resources deployed under varying conditions would not be possible, which will lead to potential conflicts and management difficulties.<\/p>\n<p>At the root of the <code>simple-helm<\/code> directory create a <code>vars<\/code> directory and populate it with <code>yml <\/code>files for all deployment targets; <code>simple-helm.yml<\/code>, <code>testing.yml<\/code> and <code>prod.yml<\/code><em>.<\/em> Paste the following configuration settings in each target yml file as shown below:<\/p>\n<pre class=\"lang:none theme:none\">#simple-helm.yml\nnginx:\n  replicas: 2\n  \n# production.yml\nnginx:\n  replicas: 4\n  \n# testing.yml\nnginx:\n  replicas: 4<\/pre>\n<p>Finally, go into the <code>deployment\/nginx<\/code> directory and edit the <code>helm-values.yml<\/code> file to include the following setting; to dynamically adjust the <code>replicaCoun<\/code>t based on the environment-specific variable.<\/p>\n<pre class=\"lang:none theme:none\">replicaCount: {{ nginx.replicas }}\nresources:\n...<\/pre>\n<p>Create these deployments using the following commands:<\/p>\n<pre class=\"lang:none theme:none\">kluctl deploy -t simple-helm\nkluctl deploy -t testing\nkluctl deploy -t production<\/pre>\n<p>Execute the following commands to confirm the number of nginx instances (pods) deployed for each target:<\/p>\n<pre class=\"lang:none theme:none\">kubectl get pods -n simple-helm\nkubectl get pods -n testing\nkubectl get pods -n production<\/pre>\n<p>You should see something very similar to the following output:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1617\" height=\"552\" class=\"wp-image-103590\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/08\/word-image-103586-4.png\" \/><\/p>\n<p><strong>Fig 4: Viewing pods for all targets<\/strong><\/p>\n<p>From the output above, <code>simple-helm<\/code> target has two pods, <code>testing<\/code> has three pods and <code>production<\/code> has four pods which is what is expected.<\/p>\n<h2><a id=\"post-103586-_mlp2ar8uydfx\"><\/a>Running the Kluctl WebUi<\/h2>\n<p>Kluctl also offers a Web UI that provides a visual interface to manage and monitor your deployments more intuitively. This is particularly helpful if you prefer a graphical interface over the command-line.<\/p>\n<p>To run the Kluctl Web UI, you have two options either running it<a href=\"https:\/\/kluctl.io\/docs\/webui\/running-locally\/\"> locally<\/a> or<a href=\"https:\/\/kluctl.io\/docs\/webui\/installation\/\"> installing<\/a> it in your kubernetes cluster. A quick walk around is to run it locally using the following command:<\/p>\n<pre class=\"lang:none theme:none\">kluctl webui run<\/pre>\n<p>This command will start the Kluctl Web UI server and will provide a URL where you can access the Web UI, such as <code>http:\/\/localhost:8080<\/code> as shown below:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"2048\" height=\"779\" class=\"wp-image-103591\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/08\/word-image-103586-5.png\" \/><\/p>\n<p><strong>Fig 5: Initiating kluctl web UI<\/strong><\/p>\n<p>When you visit the URL in your preferred web browser you should see the deployments you created with Kluctl and their respective targets:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"2048\" height=\"528\" class=\"wp-image-103592\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/08\/word-image-103586-6.png\" \/><\/p>\n<p><strong>Fig 6: Viewing targets for <em>kluctl-examples\/simple<\/em> deployment<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"2048\" height=\"973\" class=\"wp-image-103593\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/08\/word-image-103586-7.png\" \/><\/p>\n<p><strong>Fig 7: Viewing targets for kluctl-example\/simple-helm deployment<\/strong><\/p>\n<p>To view the summary of the targets, you can click on the target, and you should have a pop up like the one below:<\/p>\n<p><strong><img loading=\"lazy\" decoding=\"async\" width=\"2048\" height=\"559\" class=\"wp-image-103594\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2024\/08\/word-image-103586-8.png\" \/><\/strong><\/p>\n<p><strong>Fig 8: Viewing summary of <em>kluctl-examples\/simple<\/em> target<\/strong><\/p>\n<p><strong>Conclusion<\/strong><\/p>\n<p>In this article, I have covered how Kluctl enhances Kubernetes deployment management across multiple environments, leveraging the integration of tools like Helm and Kustomize to provide a robust, unified deployment strategy. With Kluctl you have a simplified deployment process, reduce the potential for human error, and ensure consistency across all deployment stages from development through production.<\/p>\n<p>However, you still have Kluctl GitOps to uncover. With Kluctl GitOps, you can integrate your deployment workflows directly with your version control system. This integration enhances transparency, traceability and roll backs when working with Kluctl. To find out more about Kluctl GitOps visit the <a href=\"https:\/\/kluctl.io\/docs\/gitops\/\">Kluctl official documentation<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Applications built today pass through different phases before going live; most organizations use development, testing, and production, while others employ development, staging, and then production. Regardless of the number of phases, it all follows the multi-environment concept. In Kubernetes, this is no different; however, Kubernetes is already complex as it is, so adhering to the&#8230;&hellip;<\/p>\n","protected":false},"author":341730,"featured_media":103595,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143513,53],"tags":[159149,159150,159074,159148],"coauthors":[158989],"class_list":["post-103586","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-containers-and-virtualization","category-featured","tag-helm","tag-kluctl","tag-kubernetes","tag-kustomize"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/103586","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/341730"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=103586"}],"version-history":[{"count":1,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/103586\/revisions"}],"predecessor-version":[{"id":103596,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/103586\/revisions\/103596"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media\/103595"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=103586"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=103586"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=103586"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=103586"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}