<?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: Katia HIMEUR</title>
    <description>The latest articles on DEV Community by Katia HIMEUR (@katiatalhi).</description>
    <link>https://dev.to/katiatalhi</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%2F428045%2Fb12b1158-bebc-47b5-a6c9-ad71fc26fdb9.jpg</url>
      <title>DEV Community: Katia HIMEUR</title>
      <link>https://dev.to/katiatalhi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/katiatalhi"/>
    <language>en</language>
    <item>
      <title>Introduction to Kustomize - How to customize Kubernetes objects</title>
      <dc:creator>Katia HIMEUR</dc:creator>
      <pubDate>Thu, 08 Jul 2021 19:00:49 +0000</pubDate>
      <link>https://dev.to/katiatalhi/introduction-to-kustomize-how-to-customize-kubernetes-objects-3e08</link>
      <guid>https://dev.to/katiatalhi/introduction-to-kustomize-how-to-customize-kubernetes-objects-3e08</guid>
      <description>&lt;h2&gt;
  
  
  What is Kustomize?
&lt;/h2&gt;

&lt;p&gt;Kustomize is a tool used to customize Kubernetes objects in a template-free way. It provides several features that allow us to customize the application’s configuration.&lt;/p&gt;

&lt;p&gt;We can use Kustomize in two ways: use the standalone version of Kustomize or use kubectl. Kustomize is a part of Kubectl since version 1.14.&lt;/p&gt;

&lt;p&gt;Kustomize is easy to learn and use because the customization file is the same as the Kubernetes manifest. It is very handy when you work with Kubernetes. That makes the learning curve low.&lt;/p&gt;

&lt;p&gt;One advantage of Kustomize is that it uses a kustomization.yaml file to customize Kubernetes manifests. That avoid us editing directly the manifests. So we can use the original manifests without needing Kustomize.&lt;/p&gt;

&lt;p&gt;We will see above, the main features of Kustomize.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. secretGenerator and configMapGenerator
&lt;/h3&gt;

&lt;p&gt;With Kustomize, we can generate secrets and configMaps from literals or files and rolling out changes. This is possible through the use of secretGenerator and configMapGenerator.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example : Using Kustomize to generate Kubernetes secret to store tls certificate and key file.
&lt;/h4&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;kustomize.config.k8s.io/v1beta1&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;Kustomization&lt;/span&gt;

&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;namespace.yaml&lt;/span&gt;

&lt;span class="na"&gt;secretGenerator&lt;/span&gt;&lt;span class="pi"&gt;:&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;my-tls&lt;/span&gt;
 &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cert/tls.cert&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cert/tls.key&lt;/span&gt;
 &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kubernetes.io/tls"&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;my-app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example: Using Kustomize to generate Kubernetes secret to store database password.
&lt;/h4&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;kustomize.config.k8s.io/v1beta1&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;Kustomization&lt;/span&gt;

&lt;span class="na"&gt;secretGenerator&lt;/span&gt;&lt;span class="pi"&gt;:&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;database-password&lt;/span&gt;
 &lt;span class="na"&gt;literals&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;password=pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For secretGenerator, as we see, we can specify the namespace where we want to store the secrets. We can also specify the type of secret and add labels and annotations.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example : Generate a configMap YAML:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# config-file.cnf
character-set-server=utf8mb4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# kustomization.yaml&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;kustomize.config.k8s.io/v1beta1&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;Kustomization&lt;/span&gt;
&lt;span class="na"&gt;configMapGenerator&lt;/span&gt;&lt;span class="pi"&gt;:&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;database-config-file&lt;/span&gt;
  &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;config-file.cnf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Container image
&lt;/h3&gt;

&lt;p&gt;Kustomize allows us to override container's name and version. We can specify a tag or a digest for container's version.&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="c1"&gt;# deployment.yaml&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;apps/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;Deployment&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;my-deployment&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;template&lt;/span&gt;&lt;span class="pi"&gt;:&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;containers&lt;/span&gt;&lt;span class="pi"&gt;:&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;app-one&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-one:latest&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;app-two&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-two:latest&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;app-three&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-three:latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# kustomization.yaml&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;kustomize.config.k8s.io/v1beta1&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;Kustomization&lt;/span&gt;

&lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="pi"&gt;:&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;app-one&lt;/span&gt;
  &lt;span class="na"&gt;newName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main-application&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;app-two&lt;/span&gt;
  &lt;span class="na"&gt;newTag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.0.1&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;app-three&lt;/span&gt;
  &lt;span class="na"&gt;digest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3&lt;/span&gt;

&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deployment.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Namespaces and names
&lt;/h3&gt;

&lt;p&gt;We can use Kustomize, to set for all resources within a project or for a group of resources, namespace, name prefix, or name suffix.&lt;/p&gt;

&lt;p&gt;If a namespace is already set, Kustomize will override it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example: Set namespace with Kustomize
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# kustomization.yaml&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;kustomize.config.k8s.io/v1beta1&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;Kustomization&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;backend-services&lt;/span&gt;
&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deployment.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example: Prepends the value to the names of all resources and references.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# kustomization.yaml&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;kustomize.config.k8s.io/v1beta1&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;Kustomization&lt;/span&gt;

&lt;span class="na"&gt;namePrefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging-&lt;/span&gt;

&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deployment.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example : Appends the value to the names of all resources and references
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# kustomization.yaml&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;kustomize.config.k8s.io/v1beta1&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;Kustomization&lt;/span&gt;

&lt;span class="na"&gt;nameSuffix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-beta&lt;/span&gt;

&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deployment.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Set labels and annotations
&lt;/h3&gt;

&lt;p&gt;We can use Kustomize to set labels and annotations for a group of resources. To do that, use commonLabels and commonAnnotations.&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="c1"&gt;# kustomization.yaml&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;kustomize.config.k8s.io/v1beta1&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;Kustomization&lt;/span&gt;
&lt;span class="na"&gt;commonLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;
&lt;span class="na"&gt;commonAnnotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;imageregistry&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://hub.docker.com/"&lt;/span&gt;
&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deployment.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Bases
&lt;/h3&gt;

&lt;p&gt;When we use Kustomize, we need a directory, called the base. In this directory, we put a set of resources and a kustomization.yaml file.&lt;/p&gt;

&lt;p&gt;To avoid rewriting the base content and to enable reusability, the base content can be versioned in a remote repository. Make sure there is a kustomization file inside the repository.&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="c1"&gt;# kustomization.yaml&lt;/span&gt;
&lt;span class="na"&gt;bases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="c1"&gt;# GitHub URL&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;github.com/example/kustomize/bases/staging/?ref=v1.1.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Overlays
&lt;/h3&gt;

&lt;p&gt;An overlay is a directory with a kustomization.yaml that refers to one or multiple bases directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Inline patches
&lt;/h3&gt;

&lt;p&gt;Kustomize uses patches to introduce environment specific changes on an already existing standard config file without disturbing it.&lt;/p&gt;

&lt;p&gt;There are 3 ways for patching a kustomization file :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strategic Merge patch
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# kustomization.yaml&lt;/span&gt;
&lt;span class="na"&gt;patchesStrategicMerge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
  &lt;span class="s"&gt;apiVersion: apps/v1&lt;/span&gt;
  &lt;span class="s"&gt;kind: Deployment&lt;/span&gt;
  &lt;span class="s"&gt;metadata:&lt;/span&gt;
    &lt;span class="s"&gt;name: deploy&lt;/span&gt;
  &lt;span class="s"&gt;spec:&lt;/span&gt;
    &lt;span class="s"&gt;template:&lt;/span&gt;
      &lt;span class="s"&gt;spec:&lt;/span&gt;
        &lt;span class="s"&gt;containers:&lt;/span&gt;
        &lt;span class="s"&gt;- name: nginx&lt;/span&gt;
          &lt;span class="s"&gt;image: nginx:1.20.0-alpine&lt;/span&gt;
        &lt;span class="s"&gt;- $patch: replace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Json patch
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# kustomization.yaml&lt;/span&gt;
&lt;span class="na"&gt;patchesJSON6902&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps&lt;/span&gt;
    &lt;span class="na"&gt;version&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;Deployment&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;deploy&lt;/span&gt;
  &lt;span class="na"&gt;patch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
    &lt;span class="s"&gt;- op: replace&lt;/span&gt;
      &lt;span class="s"&gt;path: /spec/template/spec/containers/0/image&lt;/span&gt;
      &lt;span class="s"&gt;value: nginx:1.20.0-alpine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;A list of patches&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There are many ways to customize Kubernetes objects, and the purpose of this post is to introduce Kustomize and show how to customize Kubernetes objects with kustomization files.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>kustomize</category>
      <category>devops</category>
      <category>yaml</category>
    </item>
    <item>
      <title>Why and How we should include Database Delivery in CI/CD processes?</title>
      <dc:creator>Katia HIMEUR</dc:creator>
      <pubDate>Fri, 18 Sep 2020 06:52:01 +0000</pubDate>
      <link>https://dev.to/katiatalhi/why-and-how-we-should-include-database-delivery-in-ci-cd-processes-446a</link>
      <guid>https://dev.to/katiatalhi/why-and-how-we-should-include-database-delivery-in-ci-cd-processes-446a</guid>
      <description>&lt;h1&gt;
  
  
  1. Context
&lt;/h1&gt;

&lt;p&gt;Often, in development teams, the Database changes in the production environment are stressful. If something goes wrong, rollbacks can be very painful and difficult, especially when these changes result in data loss or unavailability of applications.  &lt;/p&gt;

&lt;p&gt;Once the database is deployed, its state will constantly change. In case of failure, you can’t simply deploy a new database and start from scratch. There is data to back up and you should be able to restore the database if needed. You should be able to identify the risks associated with database modifications and be able to react very quickly if an outage occurs. Especially when the frequency of deployment is high. &lt;/p&gt;

&lt;p&gt;To go further, we will see two scenarios that show why we should include Database Delivery in CI/CD processes. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario 1:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A new version of an application must be deployed in production. This version requires a change in the database’s schema. The team used to do all modifications manually. After the deployment, they notice that there is a bug and they have to do a rollback because the application is unavailable. Everyone is very stressed. The developer has to restore the database to its previous state in a difficult context. The risk of making a mistake increase. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Scenario 2:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The development team implemented the Canary Release pattern to reduce the risk of deploying a new version of the application in production. They are used to deploy new versions with confidence. However, this time, the source code includes a migration script to update the database schema. The script is automatically executed after the deployment. This new application's version has a bug and all the traffic is routed to the previous version. But now, the database has been changed and it is no longer compatible with the previous version of the application causing unavailability of production.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These two scenarios show us why databases can be an important point of failure and why we should take database delivery into account when we design CI/CD processes. If the database changes are not well managed, the productivity of development teams decreases. Conversely, the risk and duration of downtime in production increase, quite the opposite of what we are trying to achieve by adopting the DevOps philosophy and agile methodologies. &lt;/p&gt;

&lt;p&gt;In what follows, we will see how we can include Database Delivery in CI/CD processes and what best practices we can follow to secure database changes &lt;/p&gt;




&lt;h1&gt;
  
  
  2. Database Delivery
&lt;/h1&gt;

&lt;p&gt;The first thing that we have to do before thinking about industrialization or how we can include database delivery in our CI/CD pipelines is choosing a database delivery approach: State-based or Migration-based deployment. To be able to choose, I will give you a description of these two mechanisms. &lt;/p&gt;

&lt;h2&gt;
  
  
  2.1. State-based deployment
&lt;/h2&gt;

&lt;p&gt;In this approach, every database object (tables, views...) is described in the SQL file. If you want to modify the database, you need to modify the concerned SQL files. You have to choose a Compare tool that will generate automatically the ALTER requests to modify the database.  &lt;/p&gt;

&lt;p&gt;The source of truth is the source code. If you want to know the state of the database, you can read the SQL files. &lt;/p&gt;

&lt;p&gt;With this approach, it is difficult to work simultaneously on the development of more than one version of the same application because you can’t modify simultaneously the same files without encounter conflicts. &lt;/p&gt;

&lt;h2&gt;
  
  
  2.2. Transformational or Migration-based deployment
&lt;/h2&gt;

&lt;p&gt;The most common approach. You start with the script creating the database. Then, each time you want to modify the database, you create a new script that will migrate its state from a version to another. Over time, we end up with several migration scripts. These scripts must be executed incrementally. &lt;/p&gt;

&lt;p&gt;With this approach, we encourage small changes, encouraged by DevOps philosophy, which, unlike big changes, reduce the risks associated with deploying new versions. To further reduce the risk of errors in performing migrations, automate its execution. In this way,  you will be able to integrate this step into your CI / CD pipelines. &lt;/p&gt;

&lt;p&gt;These migration scripts keep track of all changes made to the database since its creation. &lt;/p&gt;

&lt;p&gt;This approach fits with parallel development. &lt;/p&gt;

&lt;p&gt;The system of truth is the database itself. So, to determine the state of the database, you have to connect to it. &lt;/p&gt;




&lt;h1&gt;
  
  
  3. Best practices
&lt;/h1&gt;

&lt;h3&gt;
  
  
  3.1. Collaboration
&lt;/h3&gt;

&lt;p&gt;If there is a DBA team, they should collaborate closely with developers.  &lt;/p&gt;

&lt;h3&gt;
  
  
  3.2. Backup before any modification
&lt;/h3&gt;

&lt;p&gt;Always backup your database before performing any modification. &lt;/p&gt;

&lt;h3&gt;
  
  
  3.3. Avoid manual changes
&lt;/h3&gt;

&lt;p&gt;It is well known; automation reduces the risk of human errors and makes the deployment faster. So, automate the execution of the databases related scripts. &lt;/p&gt;

&lt;h3&gt;
  
  
  3.4. Every change in the database should be done with a versioned script
&lt;/h3&gt;

&lt;p&gt;All databases artifacts should be version controlled. And every change in the database should be done with a versioned script. This allows you to keep track of the changes made. &lt;/p&gt;

&lt;h3&gt;
  
  
  3.5. Follow the Code Review Process
&lt;/h3&gt;

&lt;p&gt;The human is not infallible. This is why it is important to follow the Code Review process with the migration scripts to limit the risk of errors. As for the applications. If there is a DBA team, make them participate in the code review process &lt;/p&gt;

&lt;h3&gt;
  
  
  3.6. Test before release
&lt;/h3&gt;

&lt;p&gt;Always test before releasing in production. However, make sure that your staging data are as similar as possible to your production database to avoid nasty surprises. &lt;/p&gt;

&lt;h3&gt;
  
  
  3.7. Allow only additive changes
&lt;/h3&gt;

&lt;p&gt;If you have to remove a database object, like deleting a column or table, the rollback is more difficult because of the loss of data. Consider the strategy consisting of allowing only additive changes. &lt;/p&gt;

&lt;h3&gt;
  
  
  3.8. You should be able to recreate the database if needed
&lt;/h3&gt;

&lt;p&gt;Databases are not recreated after each deployment. Modifications are made on the existent database. But what if it is accidentally deleted? How we can restore it? Make backups of databases and have an action plan to restore it.  &lt;/p&gt;

&lt;h3&gt;
  
  
  3.9. Consider Blue/Green deployment for big changes
&lt;/h3&gt;

&lt;p&gt;If you need to make big changes on the database, consider the Blue/Green deployment pattern to reduce risks. You will run two environments side by side and configure your application to use the new one. &lt;/p&gt;




&lt;h1&gt;
  
  
  4. Conclusion
&lt;/h1&gt;

&lt;p&gt;If you want to gain agility and productivity, it is very important to quickly integrate database delivery into the design of your CI/CD processes. &lt;/p&gt;

</description>
      <category>database</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>Provision ephemeral Kubernetes clusters on AWS EKS using Terraform and Gitlab CI/CD</title>
      <dc:creator>Katia HIMEUR</dc:creator>
      <pubDate>Wed, 15 Jul 2020 20:07:45 +0000</pubDate>
      <link>https://dev.to/katiatalhi/provision-ephemeral-kubernetes-clusters-on-aws-eks-using-terraform-and-gitlab-ci-cd-3f74</link>
      <guid>https://dev.to/katiatalhi/provision-ephemeral-kubernetes-clusters-on-aws-eks-using-terraform-and-gitlab-ci-cd-3f74</guid>
      <description>&lt;h1&gt;
  
  
  1. Introduction
&lt;/h1&gt;

&lt;p&gt;In software development, tests are very important. Tests help detect bugs before they occur in production environments. They reduce the risk of regression when the software is updated. They are a great tool to secure the delivery and deployment processes. Today, we cannot dissociate continuous deployment or continuous delivery from tests. &lt;/p&gt;

&lt;p&gt;Testing locally is good, but testing in an environment as similar to production as possible is even better. Having a staging environment seems like a minimum to have. However, what if you want to test several versions of the same application at the same time? &lt;/p&gt;

&lt;p&gt;Also, add to that, many companies want to reduce IT costs, and they see in digital sobriety a way to achieve this goal. So, having one or more staging environments running when we don't need them is not acceptable. &lt;/p&gt;

&lt;p&gt;This is why we will see how we can provision ephemeral Kubernetes clusters on AWS EKS using Terraform and Gitlab CI/CD. &lt;/p&gt;

&lt;h1&gt;
  
  
  2. Provision Kubernetes clusters on AWS EKS with Terraform
&lt;/h1&gt;

&lt;p&gt;Terraform is described by its creators as a tool for building, changing, and versioning infrastructure safely and efficiently. It is very simple to learn and use. This is why I choose it t to manage our infrastructure.  &lt;/p&gt;

&lt;p&gt;The infrastructure in this example consists of: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A VPC (Virtual Private Cloud); &lt;/li&gt;
&lt;li&gt;An Amazon EKS cluster; &lt;/li&gt;
&lt;li&gt;An Amazon Elastic Container Registry (ECR) to store Docker images; &lt;/li&gt;
&lt;li&gt;A DNS record that routes traffic to the deployed application. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the source code here: &lt;a href="https://gitlab.com/ephemeral-aws-eks-clusters/terraform-ephemeral-aws-eks-clusters"&gt;https://gitlab.com/ephemeral-aws-eks-clusters/terraform-ephemeral-aws-eks-clusters &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And, if you want to learn more about Terraform, you can begin with the official documentation: &lt;a href="https://www.terraform.io/docs/index.html"&gt;https://www.terraform.io/docs/index.html&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Build the application example
&lt;/h1&gt;

&lt;p&gt;We will build a custom Nginx docker image with an index.html file. This application will display the name of the git branch from which it was built. We need to define the index.html and the Dockerfile. &lt;/p&gt;

&lt;h2&gt;
  
  
  Content of index.html file
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Hello from BRANCH_NAME&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    Hello, &lt;span class="nt"&gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    The version of this app is: BRANCH_NAME
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Content of Dockerfile
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginx:1.19.0-alpine&lt;/span&gt;

&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; BRANCH_NAME=master&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; index.html /usr/share/nginx/html/&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"s/BRANCH_NAME/&lt;/span&gt;&lt;span class="nv"&gt;$BRANCH_NAME&lt;/span&gt;&lt;span class="s2"&gt;/g"&lt;/span&gt; /usr/share/nginx/html/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The complete source code is here: &lt;a href="https://gitlab.com/ephemeral-aws-eks-clusters/example-app-for-ephemeral-eks-clusters"&gt;https://gitlab.com/ephemeral-aws-eks-clusters/example-app-for-ephemeral-eks-clusters&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  4. Deployment workflow
&lt;/h1&gt;

&lt;p&gt;We develop a web application with a single index.html file. We will package this application in a Docker image. For every new feature, we create a new git branch. Every time we create a merge request, we want to be able to test this new version of the application in an Amazon EKS Cluster. When the request is merged, we want to be able to destroy this cluster. Below the deployment workflow described above: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Amazon EKS cluster is created; &lt;/li&gt;
&lt;li&gt;The Docker image’s application is built; &lt;/li&gt;
&lt;li&gt;The new Docker image is pushed in Amazon Elastic Container Registry (ECR); &lt;/li&gt;
&lt;li&gt;The new version of our application is deployed in the Kubernetes cluster with a “kubectl” command. &lt;/li&gt;
&lt;li&gt;A record DNS is created or updated with the load balancer hostname that routes traffic to our application 
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3jmo8LsA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/84wb51nk0ofs7qejbdwy.png" alt="Deloyment workflow" width="705" height="998"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  5. Continuous Delivery with Gitlab CI/CD
&lt;/h1&gt;

&lt;p&gt;Now, after we define the deployment workflow, we need to automate it. Gitlab CI/CD is an open-source project integrated to Gitlab. It allows us to configure CI/CD pipelines with a “.gitlab-ci.yml” file located at the repository’s root directory. &lt;/p&gt;

&lt;p&gt;We will define two “.gitlab-ci.yml” files: one in application repository and another in the Terraform repository. We will use triggers. &lt;/p&gt;

&lt;h2&gt;
  
  
  .gitlab-ci.yml file of Terraform's repository
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;image&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;hashicorp/terraform:0.12.28&lt;/span&gt;
  &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/env'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'&lt;/span&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;provision&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;clean&lt;/span&gt;

&lt;span class="s"&gt;cluster:provision:&lt;/span&gt;
  &lt;span class="s"&gt;stage&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;provision&lt;/span&gt;
  &lt;span class="s"&gt;rules&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"trigger"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$AWS_ELB_HOSTNAME&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;null&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$CLEAN_ENV&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;null'&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "Cluster name $CLUSTER_PREFIX_NAME"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform init -var=cluster_prefix_name=$CLUSTER_PREFIX_NAME&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform workspace new "$CLUSTER_PREFIX_NAME" || terraform workspace select "$CLUSTER_PREFIX_NAME"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform apply -var=cluster_prefix_name=$CLUSTER_PREFIX_NAME -auto-approve&lt;/span&gt;

&lt;span class="s"&gt;elb:provision:&lt;/span&gt;
  &lt;span class="s"&gt;stage&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;provision&lt;/span&gt;
  &lt;span class="s"&gt;rules&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"trigger"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$AWS_ELB_HOSTNAME&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;!=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;null&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$CLEAN_ENV&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;null'&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "Cluster name $CLUSTER_PREFIX_NAME"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform init -var=cluster_prefix_name=$CLUSTER_PREFIX_NAME&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform workspace new "$CLUSTER_PREFIX_NAME" || terraform workspace select "$CLUSTER_PREFIX_NAME"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform apply -var=cluster_prefix_name=$CLUSTER_PREFIX_NAME&lt;/span&gt;
    &lt;span class="s"&gt;-var cluster_prefix_name="${CI_COMMIT_REF_SLUG}"&lt;/span&gt;
    &lt;span class="s"&gt;-var aws_elb_hostname=${AWS_ELB_HOSTNAME}&lt;/span&gt;
    &lt;span class="s"&gt;-var aws_zone_id=${AWS_ZONE_ID}&lt;/span&gt;
    &lt;span class="s"&gt;-var route53_record_name=${ROUTE53_RECORD_NAME}&lt;/span&gt;
    &lt;span class="s"&gt;-target=aws_route53_record.www -auto-approve&lt;/span&gt;

&lt;span class="s"&gt;deploy:app:&lt;/span&gt;
  &lt;span class="s"&gt;stage&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="s"&gt;rules&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"trigger"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$AWS_ELB_HOSTNAME&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;null&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$CLEAN_ENV&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;null&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apk add -U curl&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl -X POST -F token="${PIPELINE_TRIGGER_TOKEN}"&lt;/span&gt;
    &lt;span class="s"&gt;-F ref=${BRANCH_NAME}&lt;/span&gt;
    &lt;span class="s"&gt;"${PIPELINE_TRIGGER_URL}"&lt;/span&gt;

&lt;span class="s"&gt;cluster:clean:&lt;/span&gt;
  &lt;span class="s"&gt;stage&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clean&lt;/span&gt;
  &lt;span class="s"&gt;rules&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"trigger"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$CLEAN_ENV&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;!=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;null&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$CLUSTER_PREFIX_NAME&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;!=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;null'&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform init -var=cluster_prefix_name=${CLUSTER_PREFIX_NAME}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform workspace new ${CLUSTER_PREFIX_NAME} || terraform workspace select "$CLUSTER_PREFIX_NAME"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform destroy -auto-approve -var=cluster_prefix_name=${CLUSTER_PREFIX_NAME}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  .gitlab-ci.yml file of the application's repository
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;provision&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;release&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;clean&lt;/span&gt;

&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ephemeral-eks&lt;/span&gt;
  &lt;span class="na"&gt;AWS_REGION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eu-west-1&lt;/span&gt;
  &lt;span class="na"&gt;DOCKER_IMAGE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/my-app&lt;/span&gt;
  &lt;span class="na"&gt;DOCKER_IMAGE_TAG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${CI_COMMIT_REF_SLUG}&lt;/span&gt;

&lt;span class="s"&gt;provision:cluster:&lt;/span&gt;
  &lt;span class="s"&gt;stage&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;provision&lt;/span&gt;
  &lt;span class="s"&gt;rules&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"merge_request_event"'&lt;/span&gt;
&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apk add -U curl&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl -X POST&lt;/span&gt;
      &lt;span class="s"&gt;-F token="${PIPELINE_TRIGGER_TOKEN}"&lt;/span&gt;
      &lt;span class="s"&gt;-F variables[CLUSTER_PREFIX_NAME]="${CI_COMMIT_REF_SLUG}"&lt;/span&gt;
      &lt;span class="s"&gt;-F variables[BRANCH_NAME]="$CI_COMMIT_REF_NAME"&lt;/span&gt;
      &lt;span class="s"&gt;-F ref=master "${PIPELINE_TRIGGER_URL}"&lt;/span&gt;

&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"trigger"'&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker build --build-arg BRANCH_NAME="${DOCKER_IMAGE_TAG}" -t ${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG} .&lt;/span&gt;

&lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"trigger"'&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apk add -U --no-cache python3 py-pip&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip3 install awscli --upgrade&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker push ${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}&lt;/span&gt;

&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ROUTE53_RECORD_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${CI_COMMIT_REF_SLUG}.${DOMAIN_NAME}&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"trigger"'&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apk add --no-cache -U curl jq python3 py-pip gettext&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip3 install awscli --upgrade&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chmod +x ./kubectl &amp;amp;&amp;amp; mv ./kubectl /usr/local/bin/kubectl&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mkdir -p $HOME/.kube&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo -n $KUBE_CONFIG | base64 -d &amp;gt; $HOME/.kube/config&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;aws eks --region ${AWS_REGION} update-kubeconfig --name ${CLUSTER_NAME}-${CI_COMMIT_REF_SLUG}&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cat myapp-service.yaml | envsubst | kubectl apply -f -&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export AWS_ELB_HOSTNAME=$(kubectl get svc my-service -n my-namespace --template="{{range .status.loadBalancer.ingress}}{{.hostname}}{{end}}")&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl -X POST -F token="${PIPELINE_TRIGGER_TOKEN}"&lt;/span&gt;
      &lt;span class="s"&gt;-F variables[CLUSTER_PREFIX_NAME]=${CI_COMMIT_REF_SLUG}&lt;/span&gt;
      &lt;span class="s"&gt;-F variables[AWS_ELB_HOSTNAME]=${AWS_ELB_HOSTNAME}&lt;/span&gt;
      &lt;span class="s"&gt;-F variables[AWS_ZONE_ID]=${AWS_ROUTE53_ZONE_ID}&lt;/span&gt;
      &lt;span class="s"&gt;-F variables[ROUTE53_RECORD_NAME]=${ROUTE53_RECORD_NAME}&lt;/span&gt;
      &lt;span class="s"&gt;-F ref=master&lt;/span&gt;
      &lt;span class="s"&gt;"${PIPELINE_TRIGGER_URL}"&lt;/span&gt;

&lt;span class="s"&gt;destroy:cluster:&lt;/span&gt;
  &lt;span class="s"&gt;stage&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clean&lt;/span&gt;
  &lt;span class="s"&gt;rules&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"merge_request_event"'&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manual&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apk add --no-cache -U curl jq python3 py-pip gettext&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip3 install awscli --upgrade&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chmod +x ./kubectl &amp;amp;&amp;amp; mv ./kubectl /usr/local/bin/kubectl&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mkdir -p $HOME/.kube&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo -n $KUBE_CONFIG | base64 -d &amp;gt; $HOME/.kube/config&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;aws eks --region ${AWS_REGION} update-kubeconfig --name ${CLUSTER_NAME}-${CI_COMMIT_REF_SLUG}&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cat myapp-service.yaml | envsubst | kubectl delete -f -&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl -X POST&lt;/span&gt;
      &lt;span class="s"&gt;-F token="${PIPELINE_TRIGGER_TOKEN}"&lt;/span&gt;
      &lt;span class="s"&gt;-F variables[CLUSTER_PREFIX_NAME]="${CI_COMMIT_REF_SLUG}"&lt;/span&gt;
      &lt;span class="s"&gt;-F variables[CLEAN_ENV]=true&lt;/span&gt;
      &lt;span class="s"&gt;-F ref=master "${PIPELINE_TRIGGER_URL}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  6. Deploy a new staging environment
&lt;/h1&gt;

&lt;p&gt;We pushed a new git branch “feature/one” and we create a merge request. A new pipeline is automatically created. The first job running trigger another pipeline in the infrastructure repository’s code. The first step is to provision a new Amazon EKS Cluster. A clean job is created. We will need it only in the end when we will want to destroy this staging environment. It will be run manually. &lt;/p&gt;

&lt;p&gt;It takes about fifteen minutes to have an active Kubernetes cluster on AWS. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bQMu8mbz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zbigql54rlnlrix7ro1f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bQMu8mbz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zbigql54rlnlrix7ro1f.png" alt="Provision cluster pipeline" width="430" height="163"&gt;&lt;/a&gt;&lt;br&gt;
After the Kubernetes cluster is active and the Amazon ECR is created, a second pipeline is triggered. Three new jobs are created for building, release, and deploy the new Docker image app. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XLUMuVaS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qlh8397do6qp1y25pu12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XLUMuVaS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qlh8397do6qp1y25pu12.png" alt="Deploy app pipeline" width="651" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At last, A record DNS is created or updated if already exists with the load balancer hostname that routes traffic to our application. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FOtyl618--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ypq01a4c6h7tol54td68.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FOtyl618--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ypq01a4c6h7tol54td68.png" alt="Provision Elastic Load Balancer" width="211" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The web application is now accessible to other users from a custom DNS name: &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7myMzACD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rbsw67eokic7uetsyvsg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7myMzACD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rbsw67eokic7uetsyvsg.png" alt="Application" width="880" height="749"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  7. Spot instances
&lt;/h1&gt;

&lt;p&gt;To go further, we can use spot instances to reduce costs. However, keep in mind that with spot instances, there is a risk to have no instance available if Amazon EC2 doesn't have the capacity in the Spot Instance pool. &lt;/p&gt;

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