<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Timothée B.</title>
    <description>The latest articles on DEV Community by Timothée B. (@restray).</description>
    <link>https://dev.to/restray</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F861569%2Faac1e032-76e8-44e7-a130-7261062fa8f8.png</url>
      <title>DEV Community: Timothée B.</title>
      <link>https://dev.to/restray</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/restray"/>
    <language>en</language>
    <item>
      <title>Here is my first article ever! I hope you'll enjoy reading it. I will be very happy to respond to any comments you may have. :)</title>
      <dc:creator>Timothée B.</dc:creator>
      <pubDate>Tue, 24 Jun 2025 09:57:51 +0000</pubDate>
      <link>https://dev.to/restray/here-is-my-first-article-ever-i-hope-youll-enjoy-reading-it-i-will-be-very-happy-to-respond-to-2oc</link>
      <guid>https://dev.to/restray/here-is-my-first-article-ever-i-hope-youll-enjoy-reading-it-i-will-be-very-happy-to-respond-to-2oc</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/neomi/transition-to-a-robust-infrastructure-terraform-and-argocd-in-action-gnc" class="crayons-story__hidden-navigation-link"&gt;Transition to a Robust Infrastructure - Terraform and ArgoCD in Action&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/neomi"&gt;
            &lt;img alt="Neomi.immo logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F10887%2F01dbd93d-f01b-40ab-ae42-9cf0d7772b44.png" class="crayons-logo__image"&gt;
          &lt;/a&gt;

          &lt;a href="/restray" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F861569%2Faac1e032-76e8-44e7-a130-7261062fa8f8.png" alt="restray profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/restray" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Timothée B.
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Timothée B.
                
              
              &lt;div id="story-author-preview-content-2510691" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/restray" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F861569%2Faac1e032-76e8-44e7-a130-7261062fa8f8.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Timothée B.&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/neomi" class="crayons-story__secondary fw-medium"&gt;Neomi.immo&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/neomi/transition-to-a-robust-infrastructure-terraform-and-argocd-in-action-gnc" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 24 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/neomi/transition-to-a-robust-infrastructure-terraform-and-argocd-in-action-gnc" id="article-link-2510691"&gt;
          Transition to a Robust Infrastructure - Terraform and ArgoCD in Action
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devops"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devops&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/terraform"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;terraform&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/cicd"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;cicd&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/kubernetes"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;kubernetes&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/neomi/transition-to-a-robust-infrastructure-terraform-and-argocd-in-action-gnc" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;11&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/neomi/transition-to-a-robust-infrastructure-terraform-and-argocd-in-action-gnc#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            9 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>devops</category>
      <category>terraform</category>
      <category>cicd</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Transition to a Robust Infrastructure - Terraform and ArgoCD in Action</title>
      <dc:creator>Timothée B.</dc:creator>
      <pubDate>Tue, 24 Jun 2025 08:58:21 +0000</pubDate>
      <link>https://dev.to/neomi/transition-to-a-robust-infrastructure-terraform-and-argocd-in-action-gnc</link>
      <guid>https://dev.to/neomi/transition-to-a-robust-infrastructure-terraform-and-argocd-in-action-gnc</guid>
      <description>&lt;p&gt;Learn how we improved our deployment techniques using Terraform and ArgoCD to manage infrastructure and continuous service deployment. Understand the challenges and solutions we implemented to enhance our Kubernetes deployment processes.&lt;/p&gt;

&lt;p&gt;This article is the first in a series aimed at sharing and explaining the technical efforts we are implementing so that you can draw inspiration from them or discuss them with us.&lt;/p&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;This blog article is intended to be read by technical profiles with a basic understanding of Kubernetes (though nothing prevents you from reading it and documenting as you go).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The objective of this article is to explain how we've enhanced our deployment techniques by implementing best practices for infrastructure reinstallation and continuous service deployment, leveraging Terraform and ArgoCD effectively.&lt;/p&gt;

&lt;p&gt;This article will explain all our considerations to arrive at this architecture diagram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fum1uagnbzpxz3sfvj8np.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fum1uagnbzpxz3sfvj8np.png" alt="Image description" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Context
&lt;/h1&gt;

&lt;p&gt;We have always favored infrastructure-as-code over manual administration via graphical interfaces, particularly for its reproducibility and maintenance properties.&lt;br&gt;
ArgoCD and Terraform are two perfect candidates for applying these principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terraform for all projects to be installed in a "one-shot" manner&lt;/li&gt;
&lt;li&gt;ArgoCD for projects that would be in constant evolution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the initial configuration we had before generalizing ArgoCD to our technical services:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvtagrylo5j2r8cvtuiao.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvtagrylo5j2r8cvtuiao.png" alt="Image description" width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A Terraform manages operations to be performed only once:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The creation of the cluster (Azure Kubernetes Service)&lt;/li&gt;
&lt;li&gt;The installations of Helm Charts:

&lt;ul&gt;
&lt;li&gt;The CNI&lt;/li&gt;
&lt;li&gt;The observability stack (Prometheus for metrics and Loki for logs)&lt;/li&gt;
&lt;li&gt;The HTTP stack (Ingress and Cert-Manager)&lt;/li&gt;
&lt;li&gt;Our secrets stack&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The installation of ArgoCD and the initialization of its applications
Subsequently, ArgoCD will take care of continuously deploying our applications.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;A CNI (Container Network Interface) enables Kubernetes networking capabilities.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Our Issues
&lt;/h1&gt;

&lt;p&gt;Several problems arise with our current setup:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to avoid errors during the installation of the Terraform project?&lt;/li&gt;
&lt;li&gt;
How to properly update the installed charts?

&lt;ul&gt;
&lt;li&gt;Bonus: How can a CI application notify us of new versions?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How (and why) to persist IP addresses through cluster recreations?&lt;/li&gt;
&lt;li&gt;How to persist logs during cluster recreations?&lt;/li&gt;
&lt;li&gt;How to make this transition without recreating a cluster?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We will address these questions in dedicated sections.&lt;/p&gt;
&lt;h1&gt;
  
  
  1. Terraform &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;How to avoid errors during the installation of the Terraform project?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To begin, Terraform is a tool that allows you to shape infrastructure on a cloud provider using code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is very useful when you want to reproduce identical infrastructure and avoid forgetting things (especially when recreating it months or years later).&lt;/p&gt;

&lt;p&gt;I will say Terraform in this article, but we use "OpenTofu," an open-source fork. To find out why, I refer you to this section of their FAQ: &lt;a href="https://opentofu.org/faq/#why-use-opentofu" rel="noopener noreferrer"&gt;OpenTofu FAQ&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Terraform is primarily intended to create and maintain infrastructure rather than software (though it is perfectly capable of doing so).&lt;/p&gt;

&lt;p&gt;Another issue with Terraform is that it must save a state of its installation (in the form of a file called &lt;code&gt;terraform.tfstate&lt;/code&gt;), and this state can be cumbersome to maintain or share with a team for future developments or maintenance.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are solutions to save and share this state with a team (for example: Hashicorp, Gitlab Terraform, or in an S3), but this option is too sophisticated for our use case.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another point is that Terraform is very sensitive to errors; it will stop as soon as it encounters one. The later an error occurs in the installation process, the longer it will take to restart all previous steps.&lt;/p&gt;

&lt;p&gt;For all these reasons, we need Terraform to only handle cloud infrastructures (machine, network) and the initialization of the installation of our continuous deployment software (ArgoCD).&lt;/p&gt;

&lt;p&gt;If we revisit our diagram, it would look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flv1qe0jburlgmfygiluy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flv1qe0jburlgmfygiluy.png" alt="Image description" width="800" height="249"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  2. ArgoCD and Helm Charts &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;How to properly update the installed charts?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;New problems (and thus new solutions): how do we install all the Helm Charts that Terraform was handling?&lt;/p&gt;

&lt;p&gt;For this, we quickly turned to the ArgoCD documentation to realize that this software supports the (continuous) deployment of Helm projects 🥳&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before continuing, and for those who are not familiar with ArgoCD, here is how it works: you create a Kubernetes resource called "Application" (which resides in "projects") that defines its type (Yaml file, Kustomization, Helm Chart, or others), where ArgoCD should find it, and its configuration (auto-synchronization, automatic pruning of undefined resources, etc.). Subsequently, ArgoCD will regularly synchronize these applications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is the structure of an application, for example &lt;a href="https://github.com/k8tz/k8tz" rel="noopener noreferrer"&gt;K8TZ&lt;/a&gt; (a Kubernetes utility that allows setting the timezone of pods):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Application&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8tz&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;infra&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8tz&lt;/span&gt;
    &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://k8tz.github.io/k8tz/&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.18.0&lt;/span&gt;
    &lt;span class="na"&gt;helm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;releaseName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8tz&lt;/span&gt;
      &lt;span class="na"&gt;valuesObject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8tz&lt;/span&gt;
        &lt;span class="na"&gt;injectionStrategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;initContainer&lt;/span&gt;
        &lt;span class="na"&gt;timezone&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Europe/Paris&lt;/span&gt;
        &lt;span class="na"&gt;injectAll&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://kubernetes.default.svc"&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8tz&lt;/span&gt;
  &lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Breaking it down, here is the information for ArgoCD:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Application&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8tz&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;infra&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://kubernetes.default.svc"&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingress&lt;/span&gt;
  &lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is the information for the Helm Chart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8tz&lt;/span&gt;
    &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://k8tz.github.io/k8tz/&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.18.0&lt;/span&gt;
    &lt;span class="na"&gt;helm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;releaseName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8tz&lt;/span&gt;
      &lt;span class="na"&gt;valuesObject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8tz&lt;/span&gt;
        &lt;span class="na"&gt;injectionStrategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;initContainer&lt;/span&gt;
        &lt;span class="na"&gt;timezone&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Europe/Paris&lt;/span&gt;
        &lt;span class="na"&gt;injectAll&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;valuesObject&lt;/code&gt; contains the &lt;code&gt;values.yaml&lt;/code&gt; usually passed to Helm with the &lt;code&gt;-f&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;The advantage of this type of installation is that it can be easily adapted to different environments (thanks to overlays), for example, with a patch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Application&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8tz&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.17.2&lt;/span&gt;
    &lt;span class="na"&gt;helm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;valuesObject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;timezone&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Europe/Berlin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we change the version of the Helm Chart and override the timezone to Berlin.&lt;/p&gt;

&lt;p&gt;You can find the complete example in this repo: &lt;a href="https://github.com/restray/neomi-article-argocd" rel="noopener noreferrer"&gt;neomi-article-argocd&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  3. IPs &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;How (and why) to persist IP addresses through cluster recreations?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's start with the "Why" by asking the question: What is the use of IP addresses?&lt;/p&gt;

&lt;p&gt;At Azure, by default, the cluster is created with an IP that it uses to make requests over the Internet.&lt;br&gt;
Additionally, we create another IP for Ingress requests to add a level of security (since this IP will be dedicated to receiving HTTP/s traffic).&lt;/p&gt;

&lt;p&gt;The IP we are interested in here is the second one, as we need to direct the Cloudflare traffic to it. To avoid adding a new step in Terraform (and especially to avoid DNS modifications).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbk721isrtl5mxfygprpn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbk721isrtl5mxfygprpn.png" alt="Image description" width="570" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this, what we can do is create a resource group (for example: &lt;code&gt;neomi-ips&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az group create &lt;span class="nt"&gt;--name&lt;/span&gt; neomi-ips &lt;span class="nt"&gt;--location&lt;/span&gt; france-central
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we can create a "Public IP Address":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az network public-ip create &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--name&lt;/span&gt; neomi-ip-dev &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--resource-group&lt;/span&gt; neomi-ips &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--allocation-method&lt;/span&gt; Static &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--ddos-protection-mode&lt;/span&gt; Disabled &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--dns-name&lt;/span&gt; neomi-ip-dev &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt; france-central &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--sku&lt;/span&gt; Standard &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--tier&lt;/span&gt; Regional &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--version&lt;/span&gt; IPv4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, we can simply edit the Kubernetes service to our Ingress:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;service.beta.kubernetes.io/azure-load-balancer-resource-group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;neomi-ips&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingress-nginx-controller&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingress&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;loadBalancerIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;previously created IP&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;appProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
    &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30209&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
    &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;appProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https&lt;/span&gt;
    &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;31433&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
    &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(The best approach is to persist this IP in an overlay that patches a deployment, for example, a Helm Chart managed by ArgoCD 😜)&lt;/p&gt;

&lt;p&gt;Thanks to this, we can add a DNS zone in Cloudflare like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkotsgotjhlzqs9eldn4r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkotsgotjhlzqs9eldn4r.png" alt="Image description" width="800" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Target: &lt;code&gt;[DNS name given at IP creation].[IP location].cloudapp.azure.com&lt;/code&gt;)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why use a CNAME? When modifying an IP, Azure changes the DNS to point to the modified IP, and we won't have to manually edit the DNS in Cloudflare.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  4. Persist Our Logs  &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;How to persist logs during cluster recreations?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before starting this section, let's describe our constraints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We want to use storage that is easily backable to another cloud provider&lt;/li&gt;
&lt;li&gt;We need storage that supports encryption with a customer key&lt;/li&gt;
&lt;li&gt;This storage should not reside in the cluster's resource group (which may be destroyed during cluster recreation)&lt;/li&gt;
&lt;li&gt;Be able to instruct Loki to use this storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The answer to these criteria is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a disk with an encryption option in a new resource group&lt;/li&gt;
&lt;li&gt;Create a new resource group for Loki disks for each environment&lt;/li&gt;
&lt;li&gt;Change the Loki Helm deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the first two points, we can simply create a new resource group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az group create &lt;span class="nt"&gt;--name&lt;/span&gt; neomi-loki-disks &lt;span class="nt"&gt;--location&lt;/span&gt; france-central
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And create a new disk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az disk create &lt;span class="nt"&gt;--name&lt;/span&gt; neomi-loki-dev &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="nt"&gt;--resource-group&lt;/span&gt; neomi-loki-disks &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="nt"&gt;--disk-encryption-set&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;your encryption &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="nt"&gt;--encryption-type&lt;/span&gt; EncryptionAtRestWithCustomerKey &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="nt"&gt;--location&lt;/span&gt; france-central &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="nt"&gt;--os-type&lt;/span&gt; Linux &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="nt"&gt;--size-gb&lt;/span&gt; 200 &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="nt"&gt;--sku&lt;/span&gt; Premium_LRS &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="nt"&gt;--tier&lt;/span&gt; P15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's take our Loki Helm Chart deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;loki&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;commonConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;replication_factor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;schemaConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2024-04-01"&lt;/span&gt;
        &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tsdb&lt;/span&gt;
        &lt;span class="na"&gt;object_store&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;filesystem&lt;/span&gt;
        &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v13&lt;/span&gt;
        &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;loki_index_&lt;/span&gt;
          &lt;span class="na"&gt;period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;24h&lt;/span&gt;
  &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;filesystem'&lt;/span&gt;
&lt;span class="na"&gt;singleBinary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# We use a small deployment rather than a scalable infrastructure&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;persistence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;# We disable it to be able to mount our own disk&lt;/span&gt;
  &lt;span class="na"&gt;extraVolumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Here we specify that we are using a disk created by us&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storage&lt;/span&gt;
      &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storage-loki-0&lt;/span&gt;
  &lt;span class="na"&gt;extraVolumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Here we specify the disk mount&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storage&lt;/span&gt;
      &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/loki&lt;/span&gt;

&lt;span class="c1"&gt;# We reduce the default allocated resources so that the deployment does not request (CPU and memory) too large a share of the machine&lt;/span&gt;
&lt;span class="na"&gt;chunksCache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allocatedMemory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
&lt;span class="na"&gt;resultsCache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allocatedMemory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And to complete the deployment, we need to create the persistent volume and its claim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolume&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;pv.kubernetes.io/provisioned-by&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;disk.csi.azure.com&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pv-loki&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;capacity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;200Gi&lt;/span&gt;
  &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ReadWriteOnce&lt;/span&gt;
  &lt;span class="na"&gt;persistentVolumeReclaimPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Retain&lt;/span&gt;
  &lt;span class="na"&gt;storageClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;managed-csi&lt;/span&gt;
  &lt;span class="na"&gt;csi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;disk.csi.azure.com&lt;/span&gt;
    &lt;span class="na"&gt;volumeHandle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/subscriptions/[subscription id]/resourceGroups/[resource group name]/providers/Microsoft.Compute/disks/[disk name]&lt;/span&gt;
    &lt;span class="na"&gt;volumeAttributes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;fsType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ext4&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolumeClaim&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storage-loki-0&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;loki&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ReadWriteOnce&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;200Gi&lt;/span&gt;
  &lt;span class="na"&gt;volumeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pv-loki&lt;/span&gt;
  &lt;span class="na"&gt;storageClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;managed-csi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thus, our disk will not be deleted through recreations and will be automatically attached to the Loki pod upon cluster creation!&lt;/p&gt;

&lt;h1&gt;
  
  
  5. On-the-Fly Maintenance &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;How to make this transition without recreating a cluster?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One of our constraints after all these operations was not having to recreate our clusters to apply these changes.&lt;br&gt;
The advantage is that we limited this maintenance to Helm Charts, so we can simply uninstall them and ensure that the used namespaces are deleted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# We delete ArgoCD to prevent it from creating resources that we will intentionally delete&lt;/span&gt;
kubectl delete namespace argocd &lt;span class="nt"&gt;--cascade&lt;/span&gt;
&lt;span class="c"&gt;# We delete the Helm Charts by deleting the NS&lt;/span&gt;
kubectl delete namespace cert-manager &lt;span class="nt"&gt;--cascade&lt;/span&gt;
kubectl delete namespace monitoring &lt;span class="nt"&gt;--cascade&lt;/span&gt;
kubectl delete namespace loki &lt;span class="nt"&gt;--cascade&lt;/span&gt;
&lt;span class="c"&gt;# A specific use case for K8TZ is to also delete the Helm Chart as it deploys resources outside its namespace&lt;/span&gt;
kubectl delete namespace k8tz &lt;span class="nt"&gt;--cascade&lt;/span&gt;
helm &lt;span class="nt"&gt;-n&lt;/span&gt; default delete k8tz
&lt;span class="c"&gt;# And for ingress, we will also delete its ValidatingWebhookConfigurations&lt;/span&gt;
kubectl delete namespace ingress &lt;span class="nt"&gt;--cascade&lt;/span&gt;
kubectl delete &lt;span class="nt"&gt;-A&lt;/span&gt; validatingwebhookconfigurations.admissionregistration.k8s.io ingress-nginx-admission
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the cluster becomes inaccessible to clients, so we need to hurry to reinstantiate ArgoCD!&lt;br&gt;
And the loop is complete!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ArgoCD will create all the resources we deleted and ensure their proper deployment.&lt;br&gt;
I will not show the installation and initialization script for ArgoCD because there is nothing interesting. You can find this in their &lt;a href="https://argo-cd.readthedocs.io/en/stable/getting_started/" rel="noopener noreferrer"&gt;Getting started&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  BONUS: Fully Automate Helm Chart Updates &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;How can a CI application notify us of new versions?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As explained earlier, we use declarative definitions to specify the desired state of our cluster. To store all this, we use a GitLab repository.&lt;br&gt;
We can therefore create a step in our CI to run &lt;a href="https://docs.renovatebot.com/" rel="noopener noreferrer"&gt;Renovate&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Renovate is a program that reads Git repos, scans dependencies, and if it finds new versions: creates a new Merge Request (Pull Request for GitHub).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I will not go through all the steps of instantiating and running a CI and Renovate.&lt;br&gt;
Here are the resources for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instantiating Renovate: &lt;a href="https://gitlab.com/renovate-bot/renovate-runner#renovate-runner" rel="noopener noreferrer"&gt;Renovate Runner&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Configuring Renovate to read your ArgoCD Helm declarations: &lt;a href="https://docs.renovatebot.com/modules/manager/argocd/" rel="noopener noreferrer"&gt;Renovate ArgoCD&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;And don't forget to schedule the pipeline: &lt;a href="https://docs.renovatebot.com/modules/manager/argocd/" rel="noopener noreferrer"&gt;Renovate Scheduling&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;This transition now allows us to deploy continuously (during the day and without service interruptions for our clients). It unifies our technical stack and simplifies its understanding to enable new team members to quickly and easily grasp the functioning of our clusters.&lt;/p&gt;

&lt;p&gt;If you enjoyed this article, you can follow us to be the first to know when we publish our future articles.&lt;/p&gt;

&lt;h4&gt;
  
  
  Acknowledgments
&lt;/h4&gt;

&lt;p&gt;Thanks to &lt;a class="mentioned-user" href="https://dev.to/louisneomi"&gt;@louisneomi&lt;/a&gt;, &lt;a class="mentioned-user" href="https://dev.to/nabil_y"&gt;@nabil_y&lt;/a&gt;, &lt;a href="https://github.com/Camozor" rel="noopener noreferrer"&gt;Camille Vauchel&lt;/a&gt; and &lt;a href="https://fr.linkedin.com/in/xavier-laurent-neomi" rel="noopener noreferrer"&gt;Xavier Laurent&lt;/a&gt; for reviewing the article and their advice.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>terraform</category>
      <category>cicd</category>
      <category>kubernetes</category>
    </item>
  </channel>
</rss>
