<?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>Forem: Kaye Alvarado</title>
    <description>The latest articles on Forem by Kaye Alvarado (@kayea).</description>
    <link>https://forem.com/kayea</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%2F791057%2F498e844a-c38e-4cf9-b445-c3f3389dd32d.jpg</url>
      <title>Forem: Kaye Alvarado</title>
      <link>https://forem.com/kayea</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kayea"/>
    <language>en</language>
    <item>
      <title>How to Pass the AZ-204 Microsoft Azure Developer Associate Exam</title>
      <dc:creator>Kaye Alvarado</dc:creator>
      <pubDate>Thu, 29 Jan 2026 05:21:54 +0000</pubDate>
      <link>https://forem.com/kayea/how-to-pass-the-az-204-microsoft-azure-developer-associate-exam-2jpb</link>
      <guid>https://forem.com/kayea/how-to-pass-the-az-204-microsoft-azure-developer-associate-exam-2jpb</guid>
      <description>&lt;p&gt;I was 10 months into a DevOps role (using Azure) before I took the AZ-204 Azure Developer Associate certification exam. I also had 6+ years of experience with AWS cloud with 6 AWS certifications under my belt (most of which has expired in the last year).&lt;/p&gt;

&lt;p&gt;Comparing the two (AWS vs Microsoft), I can say that &lt;strong&gt;Microsoft&lt;/strong&gt; has a better exam format that tests not just your ability to answer multiple-type and multi-select questions, but also your &lt;em&gt;analysis&lt;/em&gt;, &lt;em&gt;developer&lt;/em&gt;, and &lt;em&gt;architecting&lt;/em&gt; capabilities. The exam format is 100 minutes long, with 48 questions (10 for two case studies, 38 for generic questions). There are simple coding questions (finding the right commands), selecting the right service, and implementation steps questions ensuring mastery of Azure development before gaining the coveted certification.&lt;/p&gt;

&lt;p&gt;It was definitely harder than most of the AWS exams I took before (with the exception of &lt;em&gt;AWS DevOps Professional&lt;/em&gt;, which is expected as the latter is pro-level). I am sharing a few tips below to give an overview of the exam.&lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Study, study, study!
&lt;/h2&gt;

&lt;p&gt;This is not an exam that you can pass through memorization. It is better to be familiar with services (what they do and when to use them), navigation through the Azure portal, and real life implementation (may incur costs even with a free account). It is also recommended to be familiar with a few recommended cloud or hybrid architectures to be able to handle the *&lt;em&gt;case study *&lt;/em&gt; sections well.&lt;/p&gt;

&lt;p&gt;The path I took when studying goes like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go through the &lt;a href="https://learn.microsoft.com/en-us/credentials/certifications/azure-developer/?practice-assessment-type=certification" rel="noopener noreferrer"&gt;Azure Developer Associate preparation&lt;/a&gt; in Microsoft Learn.&lt;/li&gt;
&lt;li&gt;Take the practice assessment multiple times until you consistently earn around 78% or above in score.&lt;/li&gt;
&lt;li&gt;Take the practice tests of Tutorials Dojo for Microsoft Azure Developer Associate. For me, TD has created a very similar experience to the actual exam having questions that are drag-and-drop, multi-select and drop-down for coding. Having gone through it definitely helped a lot in what to expect in the actual exam.&lt;/li&gt;
&lt;li&gt;Take notes when reviewing your practice exams. Understand why an answer is incorrect and not just why something fits. It helps in the process of elimination during the exam.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Be familiar with Microsoft Learn Documentation
&lt;/h2&gt;

&lt;p&gt;I didn't realize that Microsoft Learn can be accessed during the exam and just discovered it about 30 minutes in! Despite this, the exam is still time-crunched so being familiar with how to search through Microsoft documentation fast will help add in points.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Make use of &lt;em&gt;marked for review&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Always reserve time to review items that you are not 100% certain of. Sometimes, going through the whole exam will help you determine if you answered a few questions incorrectly (especially on question formats that are in series).&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Do actual practice
&lt;/h2&gt;

&lt;p&gt;The exam is not foundational, meaning it would be extremely hard to pass without an actual cloud experience. Be sure to at least create an Azure portal account and follow labs before taking the exam. Be sure to also be familiar with basic az commands as these appear pretty frequently in the exam.&lt;/p&gt;




&lt;p&gt;If you have any questions for me, feel free to drop them in the comments section. Good luck!&lt;/p&gt;

</description>
      <category>microsoft</category>
      <category>azure</category>
    </item>
    <item>
      <title>Containers and Kubernetes</title>
      <dc:creator>Kaye Alvarado</dc:creator>
      <pubDate>Mon, 12 May 2025 12:46:18 +0000</pubDate>
      <link>https://forem.com/aws-builders/containers-and-kubernetes-3ha1</link>
      <guid>https://forem.com/aws-builders/containers-and-kubernetes-3ha1</guid>
      <description>&lt;p&gt;One of the more advanced topics in DevOps is Kubernetes. I have been in a DevOps role for a while before I truly grasped the concept. In this blog, I attempt to explain the concept (hopefully it's clear!).&lt;/p&gt;

&lt;p&gt;First, let us clarify some terminologies where a lot of engineers get confused. &lt;/p&gt;

&lt;h2&gt;
  
  
  Containers, Images, and Kubernetes
&lt;/h2&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%2Fevnadwho34c8pyoauudy.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%2Fevnadwho34c8pyoauudy.png" alt="Image description" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Containers&lt;/strong&gt; - are lightweight deployable packages that has the minimum required dependencies, code, and configuration to run an application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image&lt;/strong&gt; - is the blueprint of containers. Basically, it is a non-running container and is usually stored in a &lt;em&gt;container registry&lt;/em&gt; like ECR (Elastic Container Registry), Artifactory, or Docker Hub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt; - is a container orchestration "platform". It manages containers through all it's magic across clusters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubectl Commands
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Kubectl&lt;/strong&gt; is a command line tool that allows interaction with a Kubernetes cluster. Before you can interact with Kubernetes in the cloud, you would need to setup a &lt;code&gt;kubeconfig&lt;/code&gt; file in your local machine with either &lt;code&gt;aws eks&lt;/code&gt; (for AWS) or &lt;code&gt;az aks&lt;/code&gt; (for Azure).&lt;/p&gt;

&lt;p&gt;For AWS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws configure
aws eks update-kubeconfig --region &amp;lt;aws-region&amp;gt; --name &amp;lt;cluster-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Replace  with your AWS region (ex. us-east-1).&lt;/li&gt;
&lt;li&gt;Replace  with your EKS cluster name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Azure&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az login
az aks get-credentials --resource-group &amp;lt;resource-group&amp;gt; --name &amp;lt;cluster-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Replace  with your Azure Resource Group name.&lt;/li&gt;
&lt;li&gt;Replace  with your AKS cluster name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After running these commands, you should have a kubeconfig file setup. For MAC, this usually lives on the following path: &lt;strong&gt;~/.KUBE/config&lt;/strong&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Below are some of the common &lt;code&gt;kubectl&lt;/code&gt; commands to know:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;kubectl apply -f &amp;lt;file.yaml&amp;gt; -n &amp;lt;namespace&amp;gt;&lt;/code&gt; → Deploy a resource from a YAML manifest&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl logs -f &amp;lt;pod-name&amp;gt; -n &amp;lt;namespace&amp;gt;&lt;/code&gt; → View logs from a pod&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl exec -it &amp;lt;pod-name&amp;gt; -n &amp;lt;namespace&amp;gt; -- bash&lt;/code&gt; → Open an interactive shell in a running container&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get events&lt;/code&gt; → Displays events such as pod scheduling, container creation, scaling actions, failures, or errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  All the Commands
&lt;/h2&gt;

&lt;p&gt;Below are some basic kubernetes resources and their corresponding kubectl commands.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pod&lt;/strong&gt; – The smallest deployable unit in Kubernetes.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#List all pods
kubectl get pods -n &amp;lt;namespace&amp;gt;
#Get detailed info on a specific pod
kubectl describe pod &amp;lt;pod-name&amp;gt; -n &amp;lt;namespace&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt; – Manages replicated pods and ensures their availability.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#List all deployments
kubectl get deployments -n &amp;lt;namespace&amp;gt;
#Detailed view of a deployment
kubectl describe deployment &amp;lt;deployment-name&amp;gt; -n &amp;lt;namespace&amp;gt;
#Save a definition to a file
kubectl get deployment &amp;lt;deployment-name&amp;gt; -n &amp;lt;namespace&amp;gt; -o yaml &amp;gt;&amp;gt; &amp;lt;file_name&amp;gt;
#Edit the deployment directly
kubectl edit deployment &amp;lt;deployment-name&amp;gt; -n &amp;lt;namespace&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ReplicaSet&lt;/strong&gt; – Ensures a specified number of pod replicas run at all times.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#View all replica sets
kubectl get replicasets 
#Get details on a specific ReplicaSet
kubectl describe replicaset &amp;lt;replicaset-name&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Service&lt;/strong&gt; – Provides network access to a set of pods.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#View all services
kubectl get services 
#Get detailed info on a service
kubectl describe service &amp;lt;service-name&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ConfigMap&lt;/strong&gt; – Stores configuration data in key-value pairs.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#List all ConfigMaps
kubectl get configmaps 
#View details of a ConfigMap
kubectl describe configmap &amp;lt;configmap-name&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Secret&lt;/strong&gt; – Stores sensitive information like passwords or API keys.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#List all secrets
kubectl get secrets 
#Get details on a secret
kubectl describe secret &amp;lt;secret-name&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;*&lt;em&gt;PersistentVolume (PV) *&lt;/em&gt;– Represents storage in Kubernetes.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#View available persistent volumes
kubectl get pv 
#Get details on a specific PV
kubectl describe pv &amp;lt;pv-name&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PersistentVolumeClaim (PVC)&lt;/strong&gt; – Requests storage from a PersistentVolume.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#View all PVCs
kubectl get pvc 
#Get details of a PVC
kubectl describe pvc &amp;lt;pvc-name&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Namespace&lt;/strong&gt; – Provides a way to logically separate resources.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#View all namespaces
kubectl get namespaces 
#Get details on a namespace
kubectl describe namespace &amp;lt;namespace-name&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node&lt;/strong&gt; – Represents a worker machine in the cluster.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#View all nodes in the cluster
kubectl get nodes
#Get details on a node
kubectl describe node &amp;lt;node-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As always, concepts are easier to understand as you build a project in Kubernetes. Here is another blog I wrote previously that shows the container deployments with DevOps concepts: &lt;a href="https://dev.to/aws-builders/build-a-container-package-for-your-react-app-with-docker-and-github-actions-4nf5"&gt;https://dev.to/aws-builders/build-a-container-package-for-your-react-app-with-docker-and-github-actions-4nf5&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>containers</category>
      <category>docker</category>
    </item>
    <item>
      <title>Creating Signed mTLS Certificates</title>
      <dc:creator>Kaye Alvarado</dc:creator>
      <pubDate>Fri, 14 Feb 2025 12:53:55 +0000</pubDate>
      <link>https://forem.com/kayea/creating-signed-mtls-certificates-4pj6</link>
      <guid>https://forem.com/kayea/creating-signed-mtls-certificates-4pj6</guid>
      <description>&lt;p&gt;First, generate a &lt;strong&gt;private key&lt;/strong&gt; file with 2048 or 4096 key size. This will prompt you for a passphrase for the private key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openssl genrsa -aes256 -out privatekey.pem 4096
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optionally, you can decrypt this private key. This will prompt you for the &lt;strong&gt;passphrase&lt;/strong&gt; to decode the key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openssl rsa -in privatekey.pem -out privatekey-decrypted.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to directly create an (unencrypted) private key, you may run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openssl genrsa -out privatekey.pem 2048
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, create a Certificate Signing Request from the private key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openssl req -new -sha256 -key privatekey.pem -out request.csr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using this, you can then use a signer tool such as &lt;strong&gt;Venafi&lt;/strong&gt; to sign the key. A certificate authority, can sign the certificate (essentially, adding a chain to the certificate).&lt;/p&gt;

&lt;p&gt;For self-signed certificates, you may use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openssl x509 -req -days 365 -in request.csr -signkey privatekey.pem -out publiccertificate.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>certificate</category>
    </item>
    <item>
      <title>All the MongoDB Commands that You Need to Know</title>
      <dc:creator>Kaye Alvarado</dc:creator>
      <pubDate>Fri, 24 Jan 2025 08:44:45 +0000</pubDate>
      <link>https://forem.com/devsatasurion/all-the-mongodb-commands-that-you-need-to-know-dlm</link>
      <guid>https://forem.com/devsatasurion/all-the-mongodb-commands-that-you-need-to-know-dlm</guid>
      <description>&lt;p&gt;Here is a collection of common NoSQL queries and the mongodb commands needed for them:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Exact Match
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Collection Name:&lt;/strong&gt; users&lt;br&gt;
&lt;strong&gt;Object  Field:&lt;/strong&gt; first_name&lt;br&gt;
&lt;strong&gt;Search for:&lt;/strong&gt; Kaye&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;db.getCollection&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.find&lt;span class="o"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;"first_name"&lt;/span&gt;:&lt;span class="s2"&gt;"Kaye"&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Like Match
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Collection Name:&lt;/strong&gt; users&lt;br&gt;
&lt;strong&gt;Object  Field:&lt;/strong&gt; last_name&lt;br&gt;
&lt;strong&gt;Search for:&lt;/strong&gt; varad&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;db.getCollection&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.find&lt;span class="o"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;"last_name"&lt;/span&gt;:/varad/&lt;span class="o"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>database</category>
      <category>development</category>
    </item>
    <item>
      <title>All the Git Commands that You Need to Know</title>
      <dc:creator>Kaye Alvarado</dc:creator>
      <pubDate>Tue, 07 Jan 2025 05:29:52 +0000</pubDate>
      <link>https://forem.com/devsatasurion/all-the-git-commands-you-need-to-know-caj</link>
      <guid>https://forem.com/devsatasurion/all-the-git-commands-you-need-to-know-caj</guid>
      <description>&lt;p&gt;Here is a collection of common scenarios of code management and the git commands needed for them:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Clone a repository to your local branch
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/&amp;lt;organization&amp;gt;/&amp;lt;repository_name&amp;gt;.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Check if the current state of your local branch
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Commit a change from your local to the remote repository
&lt;/h3&gt;

&lt;p&gt;After doing edits (add/update/delete) to the files in your local repository, you can make them available to other developers by pushing your changes to the remote branch. First, stage the changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add &amp;lt;path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Alternatives&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git add --all&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git add .&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git add ../subpath&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can then add a commit message to your check-in. Some developer teams follow the &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/#summary" rel="noopener noreferrer"&gt;Conventional Commit&lt;/a&gt; specification  when adding commit messages, which dovetails &lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;SemVer&lt;/a&gt; and makes it easier to publish release notes based on widely known standards.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git commit -m "commit message"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After adding a commit messsage, you can then push the change to a remote repository. If the &lt;em&gt;remote_branch_name&lt;/em&gt; already exists in the remote repository, a simple &lt;code&gt;git push&lt;/code&gt; command will do.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -u origin &amp;lt;remote_branch_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Revert to a previous commit in the remote branch
&lt;/h3&gt;

&lt;p&gt;There are times when you accidentally push a commit to an incorrect remote branch and wishes to revert to a previous commit. You can follow the following steps in order to do this.&lt;br&gt;
First identify the commit id by checking the git history&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then switch your local to an older &lt;code&gt;commit_id&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git reset --hard &amp;lt;commit_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, force push the current state of the branch to the remote branch. Make sure that there are no restrictions in the remote branch against force pushes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -f origin &amp;lt;remote_branch_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Reset commit history in a git repository
&lt;/h3&gt;

&lt;p&gt;These sequence of steps will essentially reset the git commit history of the remote repository by overwriting the main branch (which contains all commit history) with a fresh branch that contains all the files of the main branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout --orphan temp-branch
git add -A
git commit -m "reset history"
git checkout main
git reset --hard temp-branch
git branch -D temp-branch
git push -f origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Deleting local and remote branches
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[for local branch]
git branch -D [branch-name]
[for remote branch]
git push origin -d [branch-name]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Squash multiple commits
&lt;/h3&gt;

&lt;p&gt;View the list of commits in the current branch with &lt;code&gt;git log&lt;/code&gt;, then identify the start of the commit that needs to be squashed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;222bb33  Adjust tests
99aa111  add feature
def5678  fix: type
abc1234  initial commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the results above, I want to combine the commits from &lt;code&gt;def5678&lt;/code&gt; to &lt;code&gt;222bb33&lt;/code&gt; to a single commit. With this,  start interactive rebase with the commit before the first in the range which should be &lt;code&gt;abc1234&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git rebase -i abc1234
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the editor that opens, change the top commit as &lt;code&gt;pick&lt;/code&gt; and change the subsequent ones that needs to be squashed to that commit as &lt;code&gt;squash&lt;/code&gt;. Then, save and exit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick def5678  fix: type
squash 99aa111  add feature
squash 222bb33  Adjust tests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Push to the remote branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push --force-with-lease
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;And that's it! Let me know if you have questions in any of the use-cases!&lt;/p&gt;

&lt;p&gt;Are there any other common scenarios in code management that is useful to you? Leave them at the comment section for others!&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
    </item>
    <item>
      <title>Build a Container Package for your React App with Docker and GitHub Actions</title>
      <dc:creator>Kaye Alvarado</dc:creator>
      <pubDate>Thu, 10 Oct 2024 06:52:15 +0000</pubDate>
      <link>https://forem.com/aws-builders/build-a-container-package-for-your-react-app-with-docker-and-github-actions-4nf5</link>
      <guid>https://forem.com/aws-builders/build-a-container-package-for-your-react-app-with-docker-and-github-actions-4nf5</guid>
      <description>&lt;p&gt;This is the first part of a series for &lt;strong&gt;Code Pipeline: Deploying a React App in AWS&lt;/strong&gt;. There's a lot of blogs already around this topic but there's a particular use-case that I want to document in an easy-to-follow guide for DevOps Engineers.&lt;/p&gt;

&lt;p&gt;Below are some of the technologies that I will briefly touch on in the entirety of this series (some at a later point): #containers #docker #dockerfile #react #GitHubActions #ecr #ecs #fargate #iam&lt;/p&gt;

&lt;h1&gt;
  
  
  What am I Doing?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fgc3esl6755e47364lxmb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fgc3esl6755e47364lxmb.png" alt="Image description" width="669" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above depicts the sequence of steps that we're trying to do here. Taking from a &lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;React UI&lt;/a&gt; code, we will build a simple pipeline in &lt;strong&gt;Github Actions&lt;/strong&gt; to package it into a container using a &lt;strong&gt;Dockerfile&lt;/strong&gt; and store the package in &lt;strong&gt;Amazon ECR (Elastic Container Registry)&lt;/strong&gt; for future deployment which we'll tackle in the next parts of the series.&lt;/p&gt;

&lt;h1&gt;
  
  
  Create a React Application
&lt;/h1&gt;

&lt;p&gt;React has a Quick Start guide &lt;a href="https://react.dev/learn" rel="noopener noreferrer"&gt;here&lt;/a&gt; to do the first step. In my case, I want to create a React App based on a TypeScript template so I will append &lt;code&gt;--template typescript&lt;/code&gt; to the creation command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app react-ui &lt;span class="nt"&gt;--template&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a directory called &lt;code&gt;react-ui&lt;/code&gt; in the current folder with an initial project structure of the application. Navigate to the folder and from here, run the app locally on your machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd react-ui
npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.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%2Fjw6bn2p3xm4aye28f1no.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fjw6bn2p3xm4aye28f1no.png" alt="Image description" width="548" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's create a &lt;code&gt;Dockerfile&lt;/code&gt; in the same directory and put the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:20-alpine as build
WORKDIR /app
ENV PATH=/app/node_modules/.bin:$PATH
COPY ./package*.json /app/
RUN npm install
COPY . /app
RUN npm run build

EXPOSE 3000

CMD ["npm", "start"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;npm install&lt;/code&gt; ensures that all dependencies are installed in the container runtime. As best practice, we can add a &lt;code&gt;.dockerignore&lt;/code&gt; file in the react-ui directory so that the script will explicitly ignore files or directories that are not needed when moving files around. For example, I can add &lt;code&gt;node_modules&lt;/code&gt; in .dockerignore so that it will not be copied in the container being built when I run the copy command.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build and Tag the Image:&lt;/strong&gt; From the root directory, run the following command to build and tag the image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -f Dockerfile -t react-ui:latest .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, check the details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker image ls
REPOSITORY   TAG         IMAGE ID       CREATED         SIZE
react-ui     latest      63ac15re6a37   1 minute ago    135MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Test Run the Application:&lt;/strong&gt; Run the container using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it -p 80:3000 --rm react-ui:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use any port when running the container to route to the exposed port 3000. You can then use this same port when testing the application in a web browser &lt;a href="http://localhost:80" rel="noopener noreferrer"&gt;http://localhost:80&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Think like a DevOps Engineer: Build a Pipeline for Reusability
&lt;/h1&gt;

&lt;p&gt;Now, everytime a software developer updates the react app code, it doesn't make sense for someone to manually run these commands on their machine to deploy the changes to a production server.&lt;/p&gt;

&lt;p&gt;It is recommended to store the code in a repository like GitHub. Then we can make use of a workflow to automatically run scripts ensuring accuracy in deployments.&lt;/p&gt;

&lt;p&gt;In my &lt;em&gt;GitHub Workflow&lt;/em&gt;, I will trigger a pipeline that has the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checkout the react code from GitHub to the GitHub runner&lt;/li&gt;
&lt;li&gt;Generate a random tag to the package&lt;/li&gt;
&lt;li&gt;Build the image, then push the image to ECR&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Checkout the Code from GitHub
&lt;/h3&gt;

&lt;p&gt;The action below is one of the commonly used actions in building a GitHub Actions pipeline. This will simply download the code being built to the GitHub runner that spins up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: Checkout
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
          ref: ${{ github.ref_name }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generate a Random Tag to the Package
&lt;/h3&gt;

&lt;p&gt;There are several ways on how to uniquely tag a package in ECR. For my use-case, I'd like a simple logic to add a date in the tag so I will add an action to pull the date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: "Get current date"
        id: date
        run: echo "::set-output name=date::$(date +'%Y%m%d')"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using this, I can create an environment variable that can be used on other actions with this string, along with another random number such as the &lt;code&gt;github.run_number&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IMAGE_TAG: ${{ steps.date.outputs.date }}-${{ github.run_number }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's slightly modify the &lt;code&gt;Dockerfile&lt;/code&gt; with a few more commands. Assume that the react application now includes packages that needs to be downloaded from 3rd party package repositories. We would need to include an &lt;code&gt;.npmrc&lt;/code&gt; file temporarily to the Dockerfile to allow the image runtime to pull the package with authorization to the package repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:20-alpine AS build
ARG AUTH
ARG EMAIL
WORKDIR /app
ENV PATH=/app/node_modules/.bin:$PATH
COPY ./package*.json /app/
COPY ./.npmrc /app/
RUN echo "//registry.npmjs.org/:_auth=$AUTH" &amp;gt;&amp;gt; .npmrc &amp;amp;&amp;amp; \
    echo "email = $EMAIL" &amp;gt;&amp;gt; .npmrc &amp;amp;&amp;amp; \
    echo "always-auth = true" &amp;gt;&amp;gt; .npmrc &amp;amp;&amp;amp; \    
    npm install --force &amp;amp;&amp;amp; \
    rm -f .npmrc
COPY . /app

FROM node:20-alpine 
WORKDIR /app
COPY --from=build /app /app

RUN npm run build

EXPOSE 3000

CMD ["npm", "start"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice here that I added two arguments to pass the authentication at runtime. I will then remove the .npmrc file from the package after the &lt;code&gt;npm install&lt;/code&gt;. I also added another stage to also remove the auth from the docker history (basically doing multi-stage builds as explained &lt;a href="https://www.alexandraulsh.com/2018/06/25/docker-npmrc-security/" rel="noopener noreferrer"&gt;here&lt;/a&gt;). There are other more modern ways to solve this like using &lt;a href="https://www.alexandraulsh.com/2019/02/24/docker-build-secrets-and-npmrc/" rel="noopener noreferrer"&gt;Docker build secrets&lt;/a&gt;, details are also explained on the linked blog. Wow, I like saying "also"! 😅&lt;/p&gt;

&lt;h3&gt;
  
  
  Build the Image and Push it to Amazon ECR
&lt;/h3&gt;

&lt;p&gt;Now that everything is ready let's continue with the pipeline. To further interact with other AWS services from the runner, we will need to authenticate in AWS and also (also?!) login to Amazon ECR.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: "Configure AWS credentials"
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }}
          aws-region: us-east-1
          role-session-name: ReactDeployment
          role-duration-seconds: 3600
          role-skip-session-tagging: true

      - name: "Login to Amazon ECR"
        id: ecr-config
        uses: aws-actions/amazon-ecr-login@v1
        with:
          mask-password: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now my docker commands will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: "Build &amp;amp; tag, then push image to Amazon ECR"
        env:
          ECR_REGISTRY: ${{ steps.ecr-config.outputs.registry }}
          ECR_REPOSITORY: ${{ env.IMAGE_NAME }}
          IMAGE_TAG: ${{ steps.date.outputs.date }}-${{ github.run_number }}
        run: |
          docker build -f Dockerfile --build-arg AUTH=${{ secrets.AUTH }} --build-arg EMAIL=${{ secrets.EMAIL }} -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a bonus, I added some logic below on how I intend to identify my "latest" image in ECR, which is based on the date that it was pushed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: Get latest image tag
        id: get-latest-tag
        run: |
          image=$(aws ecr describe-images \
            --repository-name react-ui \
            --output text \
            --query 'sort_by(imageDetails,&amp;amp;imagePushedAt)[-1].imageTags[0]')
          echo "latest=$image" &amp;gt;&amp;gt; $GITHUB_ENV
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! Stay tuned on the next part of this series where I intend to explain one of the options to deploy this image in AWS. See you then!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>react</category>
      <category>docker</category>
      <category>devops</category>
    </item>
    <item>
      <title>K8s QuickBites: Helm Basics</title>
      <dc:creator>Kaye Alvarado</dc:creator>
      <pubDate>Mon, 26 Aug 2024 01:12:00 +0000</pubDate>
      <link>https://forem.com/devsatasurion/k8s-quickbites-helm-basics-25hj</link>
      <guid>https://forem.com/devsatasurion/k8s-quickbites-helm-basics-25hj</guid>
      <description>&lt;p&gt;Hey there! Welcome to another quick bites blog on Kubernetes. Read time, 2 minutes! I like to keep it short and serve as quick references only when doing common tasks as a K8s administrator.&lt;/p&gt;

&lt;p&gt;The focus of this discussion is on &lt;em&gt;Helm&lt;/em&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is Helm?
&lt;/h2&gt;

&lt;p&gt;Think about bringing up an end-to-end application in Kubernetes with multiple yaml files that includes various resources such as deployments, service accounts, secrets, and others. A simple application would have some complexity in management, but as it becomes larger, it would be very difficult to manage. This is what helm is trying to solve.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;&lt;em&gt;Helm&lt;/em&gt;&lt;/a&gt; is nothing but a package manager for Kubernetes. Helm is used to manage Charts, which are packages of pre-configured Kubernetes resources making application management in Kubernetes way easier.&lt;/p&gt;

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

&lt;p&gt;Installation of helm is pretty straightforward and options can be viewed &lt;a href="https://helm.sh/docs/intro/install/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Helm Commands
&lt;/h2&gt;

&lt;p&gt;First, search and download from a helm repository to your local machine. You can also update it if it already exists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$helm search repo &amp;lt;repository&amp;gt;
$helm repo update &amp;lt;repository&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To view the existing repositories on your local machine, you can use the list command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$helm ls 
NAME         CHART VERSION   APP VERSION.  DESCRIPTION                                       
chart/name   1.0.0           1.0.0         App Description
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install Helm Charts
&lt;/h2&gt;

&lt;p&gt;You can install a helm chart overriding the default values with a values.yaml file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$helm install &amp;lt;chart&amp;gt; &amp;lt;repo&amp;gt; -n &amp;lt;namespace&amp;gt; -f &amp;lt;path to values.yaml file&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, you can then verify the deployments, daemonsets, or other resources that was installed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$kubectl get deploy -n &amp;lt;namespace&amp;gt;
$kubectl get ds -n &amp;lt;namespace&amp;gt;
$kubectl get pods -n &amp;lt;namespace&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use the values used in the helm installation and modify this for a later update&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$helm get values &amp;lt;release-name&amp;gt; -n &amp;lt;namespace&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Upgrade Helm Charts
&lt;/h2&gt;

&lt;p&gt;Everytime you upgrade a helm chart, a revision is added and this allows you to easily rollback to a previous version if an upgrade becomes problematic. List the versions with the list command (for the current deployed chart), or the history command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$helm list -n &amp;lt;namespace&amp;gt;
NAME   NAMESPACE  REVISION  UPDATED     STATUS   CHART  
chart  namespace  2         &amp;lt;datetime&amp;gt;  deployed chart-1.0.0
$helm history &amp;lt;chart&amp;gt; -n &amp;lt;namespace&amp;gt;
REVISION    UPDATED                     STATUS      CHART                   APP VERSION DESCRIPTION     
1           Thu May 23 18:53:23 2024    superseded  chart-0.9.9 0.9.9       Install complete
2           Mon Jun  3 19:52:28 2024    superseded  chart-1.0.0 1.0.0       Upgrade complete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To rollback to a previous version, you can use the rollback command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$helm rollback &amp;lt;chart&amp;gt; &amp;lt;version&amp;gt; -n &amp;lt;namespace&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There may be times when a simple upgrade will fail due to a major change in the helm package. An option here is to do an uninstall and install.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$helm uninstall &amp;lt;chart&amp;gt; -n &amp;lt;namespace&amp;gt;
$helm install &amp;lt;chart&amp;gt; &amp;lt;repo&amp;gt; -n &amp;lt;namespace&amp;gt; -f &amp;lt;path to values.yaml file&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;...and that's it! Happy helming! 😄&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>helm</category>
      <category>cncf</category>
      <category>devops</category>
    </item>
    <item>
      <title>K8s QuickBites: Creating Secure TLS Certificates for Kubernetes Deployments</title>
      <dc:creator>Kaye Alvarado</dc:creator>
      <pubDate>Wed, 21 Aug 2024 12:50:47 +0000</pubDate>
      <link>https://forem.com/devsatasurion/k8-quickbites-creating-secure-tls-certificates-for-kubernetes-deployments-gfb</link>
      <guid>https://forem.com/devsatasurion/k8-quickbites-creating-secure-tls-certificates-for-kubernetes-deployments-gfb</guid>
      <description>&lt;p&gt;This is the first of a series of blogs about Kubernetes Fundamentals, providing a quick step-by-step guide for each management scenario that is relevant when maintaining K8s workloads.&lt;/p&gt;

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

&lt;p&gt;A Kubernetes application can be secured by adding a an SSL certificate to the deployment configuration. This quick bites shows how to manually do this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-requisites
&lt;/h2&gt;

&lt;p&gt;It is assumed that the reader has set up their &lt;em&gt;kube config file&lt;/em&gt; in addition to having the following tools available in their machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;openssl&lt;/li&gt;
&lt;li&gt;kubectl&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's dive in to the steps!&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Private Key and Certificate Files
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;em&gt;private key file&lt;/em&gt; using an encryption of your choice
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openssl genrsa -aes256 -out privatekey.pem 4096 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now, create a &lt;em&gt;certificate signing request (csr)&lt;/em&gt; from the key. A series of questions will come after this command prompting for details of the certificate such as country, state, city, domain name, etc.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openssl req -new -sha256 -key privatekey.pem -out certreq.csr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Then get a trusted certificate authority (CA) to sign your certificate. Optionally, you can also make the certificate self-signed.  Download the generated crt &lt;code&gt;tls.crt&lt;/code&gt; and key file. To get the unencrypted privatekey, decrypt it. You can use openssl to do this.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#for CA-signed
openssl rsa -in privatekey.pem -out tls.key
#for self-signed
$ openssl req -x509 -new -nodes -days 365 -key privatekey.pem -out tls.crt -subj "/CN=domain.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Rename the private key to &lt;code&gt;tis.key&lt;/code&gt;. By this time you would have the two files needed for the K8s deployment.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ls tls*
tls.crt tls.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now, create the secret in the namespace that you need it for, replacing &lt;code&gt;secretname&lt;/code&gt; and &lt;code&gt;namespace&lt;/code&gt; with the proper values respectively
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create secret tls &amp;lt;secretname&amp;gt; --cert=tls.crt --key=tls.key -n &amp;lt;namespace&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;A secret will be created in the namespace you specified. You can verify this with the commands below:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get secrets -n &amp;lt;namespace&amp;gt;
kubectl get secret &amp;lt;secretname&amp;gt; -n &amp;lt;namespace&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The secret will have values for &lt;code&gt;tls.crt&lt;/code&gt; and &lt;code&gt;tls.key&lt;/code&gt;. You can decode this using base64 to view the value.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo &amp;lt;tls.crt value&amp;gt;|base64 --decode
echo &amp;lt;tls.key value&amp;gt;|base64 --decode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding the TLS secret to the Deployment&lt;br&gt;
—--&lt;br&gt;
The second part is how you will update the K8s deployment to include the certificate files and update the config to use this as the application’s certificate.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, get the deployment name that you need to edit. Then open the file for editing.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get deployments -n &amp;lt;namespace&amp;gt;
kubectl edit deployment &amp;lt;deployment_name&amp;gt; -n &amp;lt;namespace&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In the volumes section, add an item for the secret
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      volumes:
      - name: &amp;lt;secretname_used_for_deployment&amp;gt;
        secret:
          defaultMode: 420
          secretName: &amp;lt;secretname_in_secrets&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In the volumeMounts section, add the mount path where the certs will be stored
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        volumeMounts:
        - mountPath: /etc/ssl/certs
          name: &amp;lt;secretname_used_for_deployment&amp;gt;
          readOnly: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Once done, you can quickly verify if the certificate is present in the path you provided.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get pods -n &amp;lt;namespace&amp;gt;
kubectl exec -it &amp;lt;gateway_pod_name&amp;gt; -- ls /etc/ssl/certs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the configuration of the deployment, you can point it to pick up the certificate from the path of the certificate and private key paths. Deployments may use different directories so just replace the &lt;code&gt;/etc/ssl/certs&lt;/code&gt; directory when applicable.&lt;/p&gt;

&lt;p&gt;...and that's it!&lt;/p&gt;




&lt;p&gt;Let me know if there are any quick bites requests you want me to publish next!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>secret</category>
      <category>yaml</category>
      <category>devops</category>
    </item>
    <item>
      <title>Using GenerativeAI as a Mentor for your Career Growth</title>
      <dc:creator>Kaye Alvarado</dc:creator>
      <pubDate>Wed, 22 Nov 2023 14:05:55 +0000</pubDate>
      <link>https://forem.com/devsatasurion/using-generativeai-as-a-mentor-for-your-career-growth-19hi</link>
      <guid>https://forem.com/devsatasurion/using-generativeai-as-a-mentor-for-your-career-growth-19hi</guid>
      <description>&lt;p&gt;I have been mentoring for the AWS community for a while now, specifically on helping people get &lt;strong&gt;AWS certified&lt;/strong&gt;, and the &lt;em&gt;most common question&lt;/em&gt; asked by learners revolves around which appropriate certification to take. Right now, there are &lt;strong&gt;11 distinct AWS certifications&lt;/strong&gt; across the foundational, associate, professional, and specialty levels to choose from. These certifications cover a broad range of AWS cloud knowledge areas including architecture, operations, security, machine learning, networking, databases, data analytics, and development.&lt;/p&gt;

&lt;p&gt;If you ask me, there simply is not one answer to this question. When I first started learning AWS, this was a question I also asked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Does Not Have All the Answers!
&lt;/h2&gt;

&lt;p&gt;Now, this is not the first time when I tried to search for the answer online, but the amount of results is &lt;strong&gt;too overwhelming&lt;/strong&gt;. Instead of the results helping me, it ended up with me having to sort through the results. I had to spend a &lt;em&gt;few minutes or hours&lt;/em&gt; reading about each article, get different perspectives, and then finally decide on which certification to take (my original question).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---k1liMDk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yoil5jkywegaf0xkl3ti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---k1liMDk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yoil5jkywegaf0xkl3ti.png" alt="Image description" width="728" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can add more keywords to my search, but this proves to be a mistake at times as it starts to get more articles related to words I put in the search bar, which aren't really relevant to what I'm looking for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Art of Prompt Engineering
&lt;/h2&gt;

&lt;p&gt;With the not-so-recent AI boom, we are introduced to an advanced Large Language Model that is &lt;strong&gt;ChatGPT&lt;/strong&gt;. It is an &lt;em&gt;artificial intelligence system&lt;/em&gt; that can interact in a conversation through natural language. &lt;/p&gt;

&lt;p&gt;Now, why are LLMs better than a normal browser search? LLMs have conversational ability. It can clarify context and has the ability for conversation. You can ask follow-up questions if you are not satisfied with the initial answer.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Srwi_vFy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8w49a0gj3gw9o5fg3x5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Srwi_vFy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8w49a0gj3gw9o5fg3x5j.png" alt="Image description" width="800" height="601"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With LLMs, &lt;strong&gt;prompt engineering&lt;/strong&gt; comes into play. It is important to know the HOW of asking or structuring text to be best interpreted by a generative AI model.&lt;/p&gt;

&lt;p&gt;Chatbots is just one of the advances made with AI. There are also other technologies of &lt;strong&gt;GenAI&lt;/strong&gt; like &lt;em&gt;Image or Text Generation&lt;/em&gt; that already proved to be useful in a lot of ways.&lt;/p&gt;

&lt;p&gt;Exploring AI is also becoming easier each day. Recently, AWS announced the release of &lt;a href="https://aws.amazon.com/about-aws/whats-new/2023/11/partyrock-amazon-bedrock-playground/#:~:text=Today%2C%20AWS%20announced%20PartyRock%2C%20an,to%20experiment%20with%20generative%20AI."&gt;&lt;strong&gt;PartyRock&lt;/strong&gt;&lt;/a&gt;, an Amazon Bedrock Playground. &lt;strong&gt;Amazon Bedrock&lt;/strong&gt; is a fully managed service that makes base models from Amazon and third-party model providers accessible through an API. With &lt;strong&gt;PartyRock&lt;/strong&gt; and even with zero code, you can build apps that can generate text or images based on pre-defined prompts depending on your use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  If AI is so smart, it can answer my hardest questions!
&lt;/h2&gt;

&lt;p&gt;Going back to the original question that I get asked a lot, how do I start learning for the &lt;strong&gt;AWS Career Path&lt;/strong&gt; that I want to take? With this, I created the &lt;strong&gt;AWS Career Path Learning Guide&lt;/strong&gt; (using PartyRock). It uses pre-made prompts that will guide the user on a study plan toward a recommended &lt;strong&gt;AWS Certification&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PartyRock:&lt;/strong&gt; &lt;a href="https://partyrock.aws/u/kayea/vT62aROcc/AWS-Career-Path-Learning-Guide"&gt;https://partyrock.aws/u/kayea/vT62aROcc/AWS-Career-Path-Learning-Guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pZBdZ8b9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ynb9qzxvnk7jswem0idm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pZBdZ8b9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ynb9qzxvnk7jswem0idm.png" alt="Image description" width="800" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app also suggests a study guide depending on the amount of time you want to allocate in achieving the AWS certification.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t7tue_gd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/11guaqjuc25x007ax4wy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t7tue_gd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/11guaqjuc25x007ax4wy.png" alt="Image description" width="800" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It provides resources to assist in your study plan&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ASK0M_gh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/49ot6uaiyez6pj8f5cfk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ASK0M_gh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/49ot6uaiyez6pj8f5cfk.png" alt="Image description" width="800" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, there is a chatbox to ask additional questions on the recommendations:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4yrJ5Ofu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qyh2ygogv8qiibd9tkj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4yrJ5Ofu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qyh2ygogv8qiibd9tkj3.png" alt="Image description" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can &lt;strong&gt;remix&lt;/strong&gt; any existing app created by other users, or create your own app from scratch. Try to explore &lt;em&gt;#partyrock&lt;/em&gt;  on your own and let me know what you think about it in the comments!&lt;/p&gt;

</description>
      <category>genai</category>
      <category>aws</category>
      <category>amazonbedrock</category>
      <category>partyrock</category>
    </item>
    <item>
      <title>Building a Pipeline to Deploy Terraform Updates</title>
      <dc:creator>Kaye Alvarado</dc:creator>
      <pubDate>Sun, 10 Sep 2023 14:43:41 +0000</pubDate>
      <link>https://forem.com/aws-builders/building-a-pipeline-to-deploy-terraform-updates-1do8</link>
      <guid>https://forem.com/aws-builders/building-a-pipeline-to-deploy-terraform-updates-1do8</guid>
      <description>&lt;p&gt;This is the last part of the series for &lt;strong&gt;Infrastructure as Code: Deploying a Demo App on EC2 with AWS Image Builder and Terraform&lt;/strong&gt;. On this part, I will focus more on GitHub Actions and how to utilize this CI/CD platform to deploy updates to your Infrastructure code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with a Pre-defined Workflow File
&lt;/h2&gt;

&lt;p&gt;GitHub Actions already provides a sample template to start. Simply search for the sample template in Actions tab, and click on the &lt;strong&gt;Configure&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Feykp3zspvttd9ac04a0q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Feykp3zspvttd9ac04a0q.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will create a terraform.yml file with all the required steps for a Terraform deployment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fknzwhhaz2aw21dzpwcsu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fknzwhhaz2aw21dzpwcsu.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's walk through each one.&lt;br&gt;
&lt;strong&gt;1. The Trigger&lt;/strong&gt;&lt;br&gt;
This part indicates different GitHub actions to trigger the workflow. The default actions triggers it with a &lt;em&gt;push&lt;/em&gt; and &lt;em&gt;pull request&lt;/em&gt; action. Since I want to trigger the workflow manually, I added a &lt;em&gt;workflow dispatch&lt;/em&gt; action.&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Terraform'&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Jobs&lt;/strong&gt;&lt;br&gt;
The next part will be the actions that will run. Below is the initialization of the GitHub runner (ubuntu-latest image) that will be spun up as the workflow runs.&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;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;terraform&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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Terraform'&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&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;production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The other parts below have definitions in the sample file on what their purpose is:&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;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Checkout the repository to the GitHub Actions runner&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;Checkout&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

    &lt;span class="c1"&gt;# Install the latest version of Terraform CLI and configure the Terraform CLI configuration file with a Terraform Cloud user API token&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;Setup Terraform&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/setup-terraform@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;cli_config_credentials_token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.TF_API_TOKEN }}&lt;/span&gt;

    &lt;span class="c1"&gt;# Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc.&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;Terraform Init&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init&lt;/span&gt;

    &lt;span class="c1"&gt;# Checks that all Terraform configuration files adhere to a canonical format&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;Terraform Format&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform fmt -check&lt;/span&gt;

    &lt;span class="c1"&gt;# Generates an execution plan for Terraform&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;Terraform Plan&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform plan -input=false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One customization that needs to be done is to create the Terraform API token (TF_API_TOKEN) which will be saved in GitHub secrets as it is an authentication header that will be used. We can generate a token by following this Terraform documentation: &lt;a href="https://developer.hashicorp.com/terraform/tutorials/cloud-get-started/cloud-login" rel="noopener noreferrer"&gt;https://developer.hashicorp.com/terraform/tutorials/cloud-get-started/cloud-login&lt;/a&gt;. Type &lt;code&gt;terraform login&lt;/code&gt; and type yes on the prompt.&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="nv"&gt;$ &lt;/span&gt;terraform login
Terraform will request an API token &lt;span class="k"&gt;for &lt;/span&gt;app.terraform.io using your browser.

If login is successful, Terraform will store the token &lt;span class="k"&gt;in &lt;/span&gt;plain text &lt;span class="k"&gt;in
&lt;/span&gt;the following file &lt;span class="k"&gt;for &lt;/span&gt;use by subsequent commands:
    C:&lt;span class="se"&gt;\U&lt;/span&gt;sers&lt;span class="se"&gt;\k&lt;/span&gt;ayea&lt;span class="se"&gt;\A&lt;/span&gt;ppData&lt;span class="se"&gt;\R&lt;/span&gt;oaming&lt;span class="se"&gt;\t&lt;/span&gt;erraform.d&lt;span class="se"&gt;\c&lt;/span&gt;redentials.tfrc.json

Do you want to proceed?
  Only &lt;span class="s1"&gt;'yes'&lt;/span&gt; will be accepted to confirm.

  Enter a value: &lt;span class="nb"&gt;yes&lt;/span&gt;


&lt;span class="nt"&gt;---------------------------------------------------------------------------------&lt;/span&gt;

Terraform must now open a web browser to the tokens page &lt;span class="k"&gt;for &lt;/span&gt;app.terraform.io.

If a browser does not open this automatically, open the following URL to proceed:
    https://app.terraform.io/app/settings/tokens?source&lt;span class="o"&gt;=&lt;/span&gt;terraform-login


&lt;span class="nt"&gt;---------------------------------------------------------------------------------&lt;/span&gt;

Generate a token using your browser, and copy-paste it into this prompt.

Terraform will store the token &lt;span class="k"&gt;in &lt;/span&gt;plain text &lt;span class="k"&gt;in &lt;/span&gt;the following file
&lt;span class="k"&gt;for &lt;/span&gt;use by subsequent commands:
    C:&lt;span class="se"&gt;\U&lt;/span&gt;sers&lt;span class="se"&gt;\k&lt;/span&gt;ayea&lt;span class="se"&gt;\A&lt;/span&gt;ppData&lt;span class="se"&gt;\R&lt;/span&gt;oaming&lt;span class="se"&gt;\t&lt;/span&gt;erraform.d&lt;span class="se"&gt;\c&lt;/span&gt;redentials.tfrc.json

Token &lt;span class="k"&gt;for &lt;/span&gt;app.terraform.io:
  Enter a value:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the browser, login to Terraform cloud, and you will be redirected to this page. You can type a name to identify this token, and set various expiration dates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fdsuw5xpv8yazqz4ab7vx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fdsuw5xpv8yazqz4ab7vx.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can now save this token under GitHub Secrets&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F7hxmvxv9oy64vndjw8di.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F7hxmvxv9oy64vndjw8di.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go back to the GitHub actions template and commit the change:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F2dbit9br0iet06steupj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F2dbit9br0iet06steupj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the &lt;code&gt;push&lt;/code&gt; action triggers the workflow, you would see that updating the code will trigger the action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F55qad13lfnlaoud8qz78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F55qad13lfnlaoud8qz78.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Create an AWS credential&lt;/strong&gt;&lt;br&gt;
You'll notice that on the initial run, this would immediately fail on Terraform initialize. This is because we haven't configured any AWS credentials on the workflow. We can follow this &lt;a href="https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;, or follow along below:&lt;/p&gt;

&lt;p&gt;Before this can be done, we need to create an IAM role. Go to the AWS management console and create a role for Web Identity, adding the fields.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F06v96bvzbdiav1ikuv0x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F06v96bvzbdiav1ikuv0x.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS also made it available to pre-generate the trust policy to be added to the role&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sts:AssumeRoleWithWebIdentity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Federated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::111111111111:oidc-provider/token.actions.githubusercontent.com"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"token.actions.githubusercontent.com:aud"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"sts.amazonaws.com"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"StringLike"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"token.actions.githubusercontent.com:sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"repo:coderkaye/*"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now add the GitHub action below and add the ARN of the role created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Configure AWS credentials from Test account
      uses: aws-actions/configure-aws-credentials@v3
      with:
        role-to-assume: arn:aws:iam::11111111111:role/aws-githubactions
        aws-region: us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also need to update the permissions of id-token to write&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;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On this run, it will not automatically apply the Terraform code, but show the plan. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Ff4524qs5f5wpxmlmfavl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ff4524qs5f5wpxmlmfavl.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;4. Final Updates&lt;/strong&gt;&lt;br&gt;
You can now update your pipeline to add specific GitHub Actions triggers. Some best practices for Infrastructure pipeline are below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set a manual trigger of the workflow. We do not ever want to accidentally deploy infrastructure without proper review.&lt;/li&gt;
&lt;li&gt;Add tests. One Terraform feature is to be able to test the linting of your terraform code. This is one good test to add on top of other tests.&lt;/li&gt;
&lt;li&gt;Add approval checks. You can add notifications to your CI/CD pipeline to ensure that someone in authority is able to review the infrastructure being deployed before the infrastructure is actually updated.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;If you have any questions or if any part is unclear, feel free to shoot a comment below! &lt;/p&gt;

</description>
      <category>aws</category>
      <category>terraform</category>
      <category>devops</category>
    </item>
    <item>
      <title>Building a Highly Available EC2 Infrastructure with Terraform</title>
      <dc:creator>Kaye Alvarado</dc:creator>
      <pubDate>Mon, 14 Aug 2023 15:31:15 +0000</pubDate>
      <link>https://forem.com/aws-builders/building-a-highly-available-ec2-infrastructure-with-terraform-m36</link>
      <guid>https://forem.com/aws-builders/building-a-highly-available-ec2-infrastructure-with-terraform-m36</guid>
      <description>&lt;p&gt;This is a getting started guide that extends &lt;a href="https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-build" rel="noopener noreferrer"&gt;Terraform's Infrastructure as Code (IaC) Build Tutorial&lt;/a&gt; to building a CD (Continuous Delivery) pipeline in order to update an infrastructure based on updates to the IaC code. I will go through the same tutorial in order for the reader to follow through without having to go back and forth across both guides. I will also be using an AMI (Amazon Machine Image) that was created as an output of the blog on the first part of this series.&lt;/p&gt;

&lt;p&gt;The following infrastructure will be built based on this guide:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F9bm88f8xl0lsl86zbhsg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F9bm88f8xl0lsl86zbhsg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://learn.hashicorp.com/collections/terraform/aws-get-started" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; is installed&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt; is installed&lt;/li&gt;
&lt;li&gt;AWS Account and credentials that has access to create AWS resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I previously wrote about  the setup steps of these 3 prerequisites &lt;a href="https://dev.to/aws-builders/basics-of-hosting-a-static-website-in-aws-3ko0"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basics of Terraform
&lt;/h2&gt;

&lt;p&gt;Terraform is a tool for creating Infrastructure as Code (IaC). IaC as a concept helps manage infrastructure with configuration files instead of using the AWS dashboard. The benefits of using IaC in managing your infrastructure are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistent infrastructure across environments&lt;/li&gt;
&lt;li&gt;Versioning of changes&lt;/li&gt;
&lt;li&gt;Reusable and shareable Infrastructure modules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A comprehensive getting-started guide for using Terraform with AWS can be found &lt;a href="https://developer.hashicorp.com/terraform/tutorials/aws-get-started/infrastructure-as-code?in=terraform%2Faws-get-started" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform Commands
&lt;/h2&gt;

&lt;p&gt;In using Terraform, the four basic commands to keep in mind are the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initialize - will install plugins that Terraform needs to manage the infrastructure code.&lt;/li&gt;
&lt;li&gt;Plan - previews the changes that Terraform will make to match your configuration.&lt;/li&gt;
&lt;li&gt;Apply - make the planned changes.&lt;/li&gt;
&lt;li&gt;Destroy - destroy all infrastructure defined in code.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Building the Terraform Code, and Getting Familiar with Terraform Commands
&lt;/h2&gt;

&lt;p&gt;First, create a &lt;code&gt;main.tf&lt;/code&gt; file with the following contents:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;

&lt;span class="k"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_region&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;backend&lt;/span&gt; &lt;span class="s2"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bitscollective"&lt;/span&gt;
        &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
        &lt;span class="nx"&gt;key&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"awsEC2.tfstate"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;From above code, we are defining &lt;code&gt;aws&lt;/code&gt; as the provider and defining a terraform state file named &lt;code&gt;awsEC2.tfstate&lt;/code&gt; that will be stored in the s3 bucket &lt;code&gt;bitscollective&lt;/code&gt;.&lt;br&gt;
Then create a &lt;code&gt;vars.tf&lt;/code&gt; file with the following contents.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"aws_region"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
    &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This simply creates a variable "aws_region" that can be referenced from this context. Now let's initialize the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terraform Init&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

kayea@JARVIS MINGW64 ~/workspace/aws-terrraform-ec2app &lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;terraform init

Initializing the backend...

Successfully configured the backend &lt;span class="s2"&gt;"s3"&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v5.12.0...
- Installed hashicorp/aws v5.12.0 &lt;span class="o"&gt;(&lt;/span&gt;signed by HashiCorp&lt;span class="o"&gt;)&lt;/span&gt;

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file &lt;span class="k"&gt;in &lt;/span&gt;your version control repository
so that Terraform can guarantee to make the same selections by default when
you run &lt;span class="s2"&gt;"terraform init"&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running &lt;span class="s2"&gt;"terraform plan"&lt;/span&gt; to see
any changes that are required &lt;span class="k"&gt;for &lt;/span&gt;your infrastructure. All Terraform commands
should now work.

If you ever &lt;span class="nb"&gt;set &lt;/span&gt;or change modules or backend configuration &lt;span class="k"&gt;for &lt;/span&gt;Terraform,
rerun this &lt;span class="nb"&gt;command &lt;/span&gt;to reinitialize your working directory. If you forget, other
commands will detect it and remind you to &lt;span class="k"&gt;do &lt;/span&gt;so &lt;span class="k"&gt;if &lt;/span&gt;necessary.



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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Terraform Plan&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From here, you'll notice that a .terraform directory is created with a terraform.tfstate file. A providers folder with a terraform executable is also downloaded to the folder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F9vk3crx62hjmpzueugoa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F9vk3crx62hjmpzueugoa.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's add more code to the main.tf file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"app_server"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-830c94e3"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ExampleAppServerInstance"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Then from the command line, run &lt;code&gt;terraform plan&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

kayea@JARVIS MINGW64 ~/workspace/aws-terrraform-ec2app &lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;terraform plan

Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  &lt;span class="c"&gt;# aws_instance.app_server will be created&lt;/span&gt;
  + resource &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"app_server"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      + ami                                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-830c94e3"&lt;/span&gt;
      + arn                                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + associate_public_ip_address          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + availability_zone                    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + cpu_core_count                       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + cpu_threads_per_core                 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + disable_api_stop                     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + disable_api_termination              &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + ebs_optimized                        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + get_password_data                    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
      + host_id                              &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + host_resource_group_arn              &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + iam_instance_profile                 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + &lt;span class="nb"&gt;id&lt;/span&gt;                                   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + instance_initiated_shutdown_behavior &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + instance_lifecycle                   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + instance_state                       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + instance_type                        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;
      + ipv6_address_count                   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + ipv6_addresses                       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + key_name                             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + monitoring                           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + outpost_arn                          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + password_data                        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + placement_group                      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + placement_partition_number           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + primary_network_interface_id         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + private_dns                          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + private_ip                           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + public_dns                           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + public_ip                            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + secondary_private_ips                &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + security_groups                      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + source_dest_check                    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
      + spot_instance_request_id             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + subnet_id                            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + tags                                 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          + &lt;span class="s2"&gt;"Name"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ExampleAppServerInstance"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      + tags_all                             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          + &lt;span class="s2"&gt;"Name"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ExampleAppServerInstance"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      + tenancy                              &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + user_data                            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + user_data_base64                     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + user_data_replace_on_change          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
      + vpc_security_group_ids               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

Plan: 1 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────────────

Note: You didn&lt;span class="s1"&gt;'t use the -out option to save this plan, so Terraform can'&lt;/span&gt;t
guarantee to take exactly these actions &lt;span class="k"&gt;if &lt;/span&gt;you run &lt;span class="s2"&gt;"terraform apply"&lt;/span&gt; now.


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Terraform Apply&lt;/strong&gt;&lt;br&gt;
This will show that the code is attempting to add a new resource. Now, run &lt;code&gt;terraform apply&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value:


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

&lt;/div&gt;

&lt;p&gt;Enter a value of &lt;code&gt;yes&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

aws_instance.app_server: Creating...
aws_instance.app_server: Still creating... [10s elapsed]
aws_instance.app_server: Still creating... [20s elapsed]
aws_instance.app_server: Still creating... [30s elapsed]
aws_instance.app_server: Creation complete after 36s [id=i-0a5d2d786793f8176]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.


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

&lt;/div&gt;

&lt;p&gt;Go to EC2 in the AWS dashboard, and the created instance should now show up here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fj65fcdo2hg5bp8exr090.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fj65fcdo2hg5bp8exr090.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In S3, you will see that the state file have been created. This file will keep track of any changes done to the code. Keeping this file in a remote location such as S3 ensures that any remote server will follow a single source of truth for any updates to the infrastructure code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fuurumehgu1arltbb3gzp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fuurumehgu1arltbb3gzp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terraform Destroy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To destroy all created resources, you can run &lt;code&gt;terraform destroy&lt;/code&gt;. Terraform destroy command ensures that all created resources are removed.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;

&lt;span class="nx"&gt;Plan&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;destroy&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;Do&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt; &lt;span class="nx"&gt;really&lt;/span&gt; &lt;span class="nx"&gt;want&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;destroy&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;
  &lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;destroy&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;managed&lt;/span&gt; &lt;span class="nx"&gt;infrastructure&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;shown&lt;/span&gt; &lt;span class="nx"&gt;above&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;
  &lt;span class="nx"&gt;There&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;no&lt;/span&gt; &lt;span class="nx"&gt;undo&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Only&lt;/span&gt; &lt;span class="s1"&gt;'yes'&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;accepted&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;confirm&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Terraform destroy command ensures that all created resources are removed.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

  Enter a value: yes

aws_instance.app_server: Destroying... [id=i-0a5d2d786793f8176]
aws_instance.app_server: Still destroying... [id=i-0a5d2d786793f8176, 10s elapsed]
aws_instance.app_server: Still destroying... [id=i-0a5d2d786793f8176, 20s elapsed]
aws_instance.app_server: Still destroying... [id=i-0a5d2d786793f8176, 30s elapsed]
aws_instance.app_server: Still destroying... [id=i-0a5d2d786793f8176, 40s elapsed]
aws_instance.app_server: Destruction complete after 43s

Destroy complete! Resources: 1 destroyed.


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

&lt;/div&gt;

&lt;p&gt;Note that destroying the infrastructure does not remove the created terraform state file in the s3 bucket.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform Modules
&lt;/h2&gt;

&lt;p&gt;Let's continue with building the rest of the infrastructure with an introduction to Terraform modules. Terraform modules are nothing but putting together infrastructure code into logical reusable groups to allow re-use on other parts of the code.&lt;/p&gt;

&lt;p&gt;Download the rest of the project from &lt;a href="https://github.com/coderkaye/aws-terrraform-ec2app" rel="noopener noreferrer"&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here, you'll see that I grouped the infrastructure code under one folder named ha-application. Ultimately, I wanted to be able to re-use this module when deploying the same infrastructure code across multiple environments (dev, qa, staging, prod).&lt;br&gt;
&lt;a href="https://media.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%2F948prmd6qx5vjv6wcovg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F948prmd6qx5vjv6wcovg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under this folder, there's a vars.tf file that would have default values, but can be overwritten when calling the module so that the values can be updated when deploying across environments.&lt;/p&gt;

&lt;p&gt;Going back to the main code, I'm invoking the module and passing the required variables which is also referenced in the main code's vars.tf file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

module "application" {
   source               = "./modules/ha-application"
   aws_region           = var.aws_region
   imageid              = var.imageid
   availability_zones   = var.availability_zones
   vpc_id               = var.vpc_id
}


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Deploying the code&lt;/strong&gt;&lt;br&gt;
Since the code have significantly changed and would require new plugins, we need to re-run &lt;code&gt;terraform init&lt;/code&gt; again. After this, we can go directly to &lt;code&gt;terraform apply&lt;/code&gt; to check out the resources being created.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;

&lt;span class="nx"&gt;kayea&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;JARVIS&lt;/span&gt; &lt;span class="nx"&gt;MINGW64&lt;/span&gt; &lt;span class="err"&gt;~/&lt;/span&gt;&lt;span class="nx"&gt;Workspace&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;aws-terrraform-ec2app&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="k"&gt;terraform&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

&lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="nx"&gt;used&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt; &lt;span class="nx"&gt;providers&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;generate&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;execution&lt;/span&gt; &lt;span class="nx"&gt;plan&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Resource&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;indicated&lt;/span&gt; &lt;span class="nx"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;symbols&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;        
  &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;

&lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;perform&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;

  &lt;span class="c1"&gt;# module.application.aws_alb.application-lb will be created&lt;/span&gt;
  &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_alb"&lt;/span&gt; &lt;span class="s2"&gt;"application-lb"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;arn&lt;/span&gt;                                         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;arn_suffix&lt;/span&gt;                                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;desync_mitigation_mode&lt;/span&gt;                      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"defensive"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dns_name&lt;/span&gt;                                    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;drop_invalid_header_fields&lt;/span&gt;                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_deletion_protection&lt;/span&gt;                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_http2&lt;/span&gt;                                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_tls_version_and_cipher_suite_headers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_waf_fail_open&lt;/span&gt;                        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_xff_client_port&lt;/span&gt;                      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;                                          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;idle_timeout&lt;/span&gt;                                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;internal&lt;/span&gt;                                    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ip_address_type&lt;/span&gt;                             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;load_balancer_type&lt;/span&gt;                          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;                                        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application-lb"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;preserve_host_header&lt;/span&gt;                        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;security_groups&lt;/span&gt;                             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"sg-0c9234a6c5f976d95"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"sg-3ab9a217"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;subnets&lt;/span&gt;                                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"subnet-51813e1c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"subnet-d33cd6f2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tags_all&lt;/span&gt;                                    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;vpc_id&lt;/span&gt;                                      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;xff_header_processing_mode&lt;/span&gt;                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"append"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;zone_id&lt;/span&gt;                                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# module.application.aws_alb_listener.http-listener will be created&lt;/span&gt;
  &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_alb_listener"&lt;/span&gt; &lt;span class="s2"&gt;"http-listener"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;arn&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;load_balancer_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;protocol&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ssl_policy&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tags_all&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;default_action&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;target_group_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"forward"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# module.application.aws_alb_target_group.http will be created&lt;/span&gt;
  &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_alb_target_group"&lt;/span&gt; &lt;span class="s2"&gt;"http"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;arn&lt;/span&gt;                                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;arn_suffix&lt;/span&gt;                         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;connection_termination&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;deregistration_delay&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"300"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;                                 &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ip_address_type&lt;/span&gt;                    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;lambda_multi_value_headers_enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;load_balancing_algorithm_type&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;load_balancing_cross_zone_enabled&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;                               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application-tg"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt;                               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;preserve_client_ip&lt;/span&gt;                 &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;protocol&lt;/span&gt;                           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;protocol_version&lt;/span&gt;                   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;proxy_protocol_v2&lt;/span&gt;                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;slow_start&lt;/span&gt;                         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tags_all&lt;/span&gt;                           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;target_type&lt;/span&gt;                        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"instance"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;vpc_id&lt;/span&gt;                             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"vpc-cf89b1b5"&lt;/span&gt;

      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;health_check&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;healthy_threshold&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;matcher&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"200"&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/"&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"80"&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;protocol&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP"&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;unhealthy_threshold&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# module.application.aws_autoscaling_group.application-asg will be created&lt;/span&gt;
  &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_autoscaling_group"&lt;/span&gt; &lt;span class="s2"&gt;"application-asg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;arn&lt;/span&gt;                              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;availability_zones&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;default_cooldown&lt;/span&gt;                 &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;desired_capacity&lt;/span&gt;                 &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;force_delete&lt;/span&gt;                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;force_delete_warm_pool&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;health_check_grace_period&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;health_check_type&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;                               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ignore_failed_scaling_activities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;load_balancers&lt;/span&gt;                   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;max_size&lt;/span&gt;                         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;metrics_granularity&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1Minute"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;min_size&lt;/span&gt;                         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;                             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application-asg"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name_prefix&lt;/span&gt;                      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;predicted_capacity&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;protect_from_scale_in&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;service_linked_role_arn&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;target_group_arns&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;vpc_zone_identifier&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;wait_for_capacity_timeout&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"10m"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;warm_pool_size&lt;/span&gt;                   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;launch_template&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="s2"&gt;Latest"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# module.application.aws_launch_template.application-template will be created&lt;/span&gt;
  &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_launch_template"&lt;/span&gt; &lt;span class="s2"&gt;"application-template"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;arn&lt;/span&gt;                    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;default_version&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;image_id&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-070d7322559e500ee"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;instance_type&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;latest_version&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;                   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application-template"&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name_prefix&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tags_all&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;update_default_version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;vpc_security_group_ids&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"sg-0c9234a6c5f976d95"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Plan&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;destroy&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;Do&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt; &lt;span class="nx"&gt;want&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;perform&lt;/span&gt; &lt;span class="nx"&gt;these&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;
  &lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;perform&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="nx"&gt;described&lt;/span&gt; &lt;span class="nx"&gt;above&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;
  &lt;span class="nx"&gt;Only&lt;/span&gt; &lt;span class="s1"&gt;'yes'&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;accepted&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;approve&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;

  &lt;span class="nx"&gt;Enter&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;yes&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;After this, let's checkout the resources created.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Launch Template contains the EC2 configuration and references the ami we created previously.&lt;br&gt;
&lt;a href="https://media.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%2Faho1qqqy4pxsot2dal3a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Faho1qqqy4pxsot2dal3a.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Target Groups contains a reference to the EC2 instances were traffic will be forwarded to.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fx0qvvmmcyfn6trqmvr0h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fx0qvvmmcyfn6trqmvr0h.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Auto-scaling Group contains the scaling configurations for high-availability&lt;br&gt;
&lt;a href="https://media.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%2F2r9ma8q0xj41g3i5s2pt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F2r9ma8q0xj41g3i5s2pt.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Load Balancer will be forwarding traffic to the target defined.&lt;br&gt;
&lt;a href="https://media.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%2Fkigm54iezziwzt40fv4i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fkigm54iezziwzt40fv4i.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also notice that the application load balancer will have a DNS endpoint which we can now load in the browser (application-lb-1968702359.us-east-1.elb.amazonaws.com)&lt;br&gt;
&lt;a href="https://media.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%2Fvtdw9ys6tomexxtnnmp6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fvtdw9ys6tomexxtnnmp6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A better architecture will use https and have an SSL certificate.&lt;/p&gt;

&lt;p&gt;As always, destroy the infrastructure after testing to ensure you are not being charged unnecessarily. And that's it! Stay tuned for my next update (where I'll be creating a pipeline in Github to run the Terraform commands on a runner instead of my machine)!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ec2</category>
      <category>terraform</category>
      <category>cd</category>
    </item>
    <item>
      <title>Building a Reusable Image Pipeline with AWS Image Builder</title>
      <dc:creator>Kaye Alvarado</dc:creator>
      <pubDate>Sun, 13 Aug 2023 17:17:23 +0000</pubDate>
      <link>https://forem.com/aws-builders/building-a-reusable-image-pipeline-with-aws-image-builder-17eh</link>
      <guid>https://forem.com/aws-builders/building-a-reusable-image-pipeline-with-aws-image-builder-17eh</guid>
      <description>&lt;p&gt;Maintaining a secure, up-to-date AMI (Amazon Machine Image) used to be a tedious, and expensive process of running the latest updates on a running EC2 machine, and creating an image based off of this EC2 machine. If any required step is missed such as stopping any service, the image created will not work as intended and can sometimes waste an engineer's time looking through logs and finding the issue. &lt;/p&gt;

&lt;p&gt;In &lt;a href="https://aws.amazon.com/about-aws/whats-new/2019/12/introducing-ec2-image-builder/" rel="noopener noreferrer"&gt;December 2019&lt;/a&gt;, AWS introduced Image Builder that aims to solve these problems and allow users to create an image pipeline at no cost, except for the underlying resources used by the service.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is EC2 Image Builder?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/imagebuilder/latest/userguide/what-is-image-builder.html" rel="noopener noreferrer"&gt;EC2 Image Builder&lt;/a&gt; is an AWS service that simplifies the building, testing, and deployment of Virtual Machine and container images for use on AWS or on-premises. Image builder has the capability to create an image with customization with pre-built templates available, allow testing on the image, and export the image making it accessible across regions and/or across accounts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F83gsefe5zc08myru78ia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F83gsefe5zc08myru78ia.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a walkthrough on the different steps of building an image pipeline to ultimately produce a secure, working image of an application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fbfscqz935t5rze5og0ur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fbfscqz935t5rze5og0ur.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Image Pipeline
&lt;/h2&gt;

&lt;p&gt;To get started, navigate through the &lt;strong&gt;Image Builder&lt;/strong&gt; service in AWS. On the left pane, click on Image pipelines and click on the &lt;strong&gt;&lt;em&gt;Create image pipeline&lt;/em&gt;&lt;/strong&gt; to start building.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fsxzet0ce6fy6s9h71baa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fsxzet0ce6fy6s9h71baa.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Specify Pipeline Details&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the first step, specify the pipeline details such as Pipeline name, description. Here, you can also specify a Build schedule to instruct image builder to build a new version of the AMI on a regular/cron-based schedule. You can also choose to trigger the pipeline if there is a dependency update on the components that you specify.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fxd9fwjpb23wl5n3kaaeb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fxd9fwjpb23wl5n3kaaeb.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Creating a Recipe&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next step is for the creation of the image recipe. As a recipe contains the ingredients list and steps in creating a final food product, an image recipe is a document defining the components to be applied to the base images to create the desired configuration for the output image. If a recipe needs to be modified, a new version must be created with the updated components&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fdynlrjbmmzsnl2lup0lq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fdynlrjbmmzsnl2lup0lq.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you already created an image recipe prior to building the image pipeline, you can just select it here. If building the recipe for the first time, you can follow along the steps. Image type can either be an existing AMI or a Docker image. Also add a name and description to easily identify this recipe. Note that you can update the working directory at this stage. I've updated mine to &lt;code&gt;/var/tmp&lt;/code&gt; to test this out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fqrnonpxjfswwektyzpzu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fqrnonpxjfswwektyzpzu.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Going back to the image recipe, I'm selecting an Amazon-managed AMI using the latest OS version of Amazon Linux 2 x86. As part of the recipe, you can also add &lt;strong&gt;user data&lt;/strong&gt;. User data are commands run on a Linux instance at launch time. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build Components&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a section on the recipe that I'd like to focus on. As defined, components are software scripts allowing for custom configuration of the image. The components can either be Amazon-managed, owned by me, shared with me, or third party managed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fxj0os11pq9z9b0g4hu61.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fxj0os11pq9z9b0g4hu61.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let us ensure that we are updating to the latest linux version. This can be done by adding the &lt;strong&gt;Amazon-managed update-linux&lt;/strong&gt; component. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fp5od17uwestg58tw6v6a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fp5od17uwestg58tw6v6a.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let us also create a custom component to be added, by clicking on the &lt;strong&gt;Create build component&lt;/strong&gt; button on the upper right side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Ffu34iubkps6buy3or6q6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ffu34iubkps6buy3or6q6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating a Custom Component&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Select the component type as &lt;strong&gt;Build&lt;/strong&gt;. This component will run the configuration script to run the script to install Apache, and create and run the Apache application, so I'm naming this as apache-application and setting the version as 1.0.0.&lt;/p&gt;

&lt;p&gt;For the content, copy and modify the script below:&lt;/p&gt;

&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;imagebuilder-applicationcomponent&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;This&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;component&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;will&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;download&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;apache&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;script,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;deploy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;sample&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;application'&lt;/span&gt;
&lt;span class="na"&gt;schemaVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.0&lt;/span&gt;
&lt;span class="na"&gt;phases&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;build&lt;/span&gt;
      &lt;span class="na"&gt;steps&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;DownloadInstallScript&lt;/span&gt;
          &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S3Download&lt;/span&gt;
          &lt;span class="na"&gt;onFailure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Abort&lt;/span&gt;
          &lt;span class="na"&gt;maxAttempts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
          &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&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="s"&gt;s3://bitscollective/install-apache.sh&lt;/span&gt;
              &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/tmp/install-apache.sh&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;RunScript&lt;/span&gt;
          &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ExecuteBash&lt;/span&gt;
          &lt;span class="na"&gt;onFailure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Abort&lt;/span&gt;
          &lt;span class="na"&gt;maxAttempts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
          &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;commands&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;chmod&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;755&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;build.DownloadInstallScript.inputs[0].destination&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&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;bash&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;build.DownloadInstallScript.inputs[0].destination&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&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;SampleApplication&lt;/span&gt;
          &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S3Download&lt;/span&gt;
          &lt;span class="na"&gt;onFailure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Abort&lt;/span&gt;
          &lt;span class="na"&gt;maxAttempts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
          &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&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="s"&gt;s3://bitscollective/index.html&lt;/span&gt;
              &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/www/html/index.html&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;CleanupInstallFiles&lt;/span&gt;
          &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ExecuteBash&lt;/span&gt;
          &lt;span class="na"&gt;onFailure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Abort&lt;/span&gt;
          &lt;span class="na"&gt;maxAttempts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
          &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;commands&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;rm&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;build.DownloadInstallScript.inputs[0].destination&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;


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

&lt;p&gt;This will allow us to add this custom component in the recipe.&lt;br&gt;
&lt;a href="https://media.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%2Ff9snww0wnr7fhb67edxy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ff9snww0wnr7fhb67edxy.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the s3 files that will be accessed by this component, create the following files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;index.html
```html
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;br&gt;
&lt;br&gt;
    &lt;br&gt;
        &lt;/p&gt;
&lt;h1&gt;Sample Application&lt;/h1&gt;
&lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
        &lt;p&gt;hello!&lt;/p&gt;
&lt;br&gt;
    &lt;br&gt;




&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- install-apache.sh
```bash


#!/bin/bash

# Install Apache
sudo yum install -y httpd
sudo systemctl start httpd
sudo systemctl enable httpd


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

&lt;p&gt;&lt;strong&gt;Adding a Test Component&lt;/strong&gt;&lt;br&gt;
Another great feature of the image builder is the capability to add tests to the instance after image creation, to ensure that the image is working as you expect. There are a few basic AWS-managed test components available for use, and you can create any custom test component yourself to be added to the pipeline.&lt;br&gt;
&lt;a href="https://media.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%2Fbh4l9mzi7ge5zo7wblyi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fbh4l9mzi7ge5zo7wblyi.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Defining Infrastructure Configuration (Optional)&lt;/strong&gt;&lt;br&gt;
Infrastructure configuration determines the EC2 instances created when customizing the images and running validation tests. The default setting will also create an IAM role with the required policy to execute commands and customize the image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fwj92kkga7k76sirqdog4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fwj92kkga7k76sirqdog4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Defining Distribution Settings (Optional)&lt;/strong&gt;&lt;br&gt;
Distribution settings will allow customizations on allowed regions, encryption, launch permissions, allowed accounts that can launch the output AMI, and license configurations.&lt;/p&gt;

&lt;p&gt;Continue to the last step, and create the pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the Image Builder Pipeline
&lt;/h2&gt;

&lt;p&gt;To start testing the image, first let's run the pipeline to create an image with all the customizations we defined. Go to image pipelines, select the pipeline created, then click on Actions &amp;gt; Run pipeline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fgsye9621hpkzxgwhch2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fgsye9621hpkzxgwhch2m.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the message that pops up, click on View details. This will allow navigation to the pipeline workflow where we can drill down to the steps and identify any issues if any.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F6f2y4t6ayght0w8frvns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F6f2y4t6ayght0w8frvns.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based from the logs, there is a 403 encountered because the role assumed by the EC2 image builder does not have permissions to get files from the S3 bucket. To find out the role, go back to the pipeline and get the IAM role that has been set up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F5bi3gsf0y43909b8g7o1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F5bi3gsf0y43909b8g7o1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, go the the S3 bucket and add the required bucket policy to allow access to Image builder. &lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

#Replace &amp;lt;accountid&amp;gt; with the aws account id
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ImageBuilder",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::&amp;lt;accountid&amp;gt;:role/EC2InstanceProfileForImageBuilder"
            },
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::bitscollective/*",
                "arn:aws:s3:::bitscollective"
            ]
        }
    ]
}


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

&lt;p&gt;Re-run the pipeline, and the issue should be resolved now&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fryqimu80kyfd9ssie505.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fryqimu80kyfd9ssie505.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once complete, the image should appear under the output resources and can now be used for EC2s.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fz5f6qsdy8uy7m30jsgkw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fz5f6qsdy8uy7m30jsgkw.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing and Using the Created AMI
&lt;/h2&gt;

&lt;p&gt;To quickly test if the image works as expected, go to the EC2 service, and on the left pane, select AMI. Select the AMI created and click on &lt;em&gt;Launch instance from AMI&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fbtab0ewnkmgk1v69sa0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fbtab0ewnkmgk1v69sa0w.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a name to the EC2 host, let other details remain as default and click on &lt;em&gt;Launch instance&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Once the instance is created, get the public IP and attempt to load this in a web browser. If the page doesn't load for some reason, one possibility is that http traffic is not allowed on the EC2 instance. To update this, go to the instance's security tab and click on the security group link. Edit the inbound rules and add an allow all for http traffic (port 80). Save the rule.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fnqn5dol8oq7bkyacjgx6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fnqn5dol8oq7bkyacjgx6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reload the public IP again from the browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fx70mjkiun27j5v6uofvp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fx70mjkiun27j5v6uofvp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you verified that the image works, you can terminate the EC2 resource created to ensure you are not being charged with anything.&lt;/p&gt;

&lt;p&gt;This is the first of a three-part series about &lt;strong&gt;Infrastructure as Code&lt;/strong&gt;. Stay tuned for the next article!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>imagebuilder</category>
      <category>ec2</category>
      <category>pipeline</category>
    </item>
  </channel>
</rss>
