<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Wangoi Mwangi on Medium]]></title>
        <description><![CDATA[Stories by Wangoi Mwangi on Medium]]></description>
        <link>https://medium.com/@wangoi-mwangi?source=rss-25b8a3b45b96------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*MhhHkHGJFABGowGAjlGVOg.jpeg</url>
            <title>Stories by Wangoi Mwangi on Medium</title>
            <link>https://medium.com/@wangoi-mwangi?source=rss-25b8a3b45b96------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 06:27:09 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@wangoi-mwangi/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[CI/CD Pipeline with Azure DevOps, ArgoCD, & Kubernetes]]></title>
            <link>https://blog.devops.dev/ci-cd-pipeline-automation-with-azure-devops-argocd-kubernetes-e0be5e613d32?source=rss-25b8a3b45b96------2</link>
            <guid isPermaLink="false">https://medium.com/p/e0be5e613d32</guid>
            <category><![CDATA[azure]]></category>
            <category><![CDATA[azure-devops]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[devops]]></category>
            <dc:creator><![CDATA[Wangoi Mwangi]]></dc:creator>
            <pubDate>Wed, 06 Nov 2024 09:31:30 GMT</pubDate>
            <atom:updated>2024-11-12T09:14:42.802Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/875/1*dk9SfAWxBytGg2FgKwuUaw.png" /><figcaption>Project Architect</figcaption></figure><h3>Introduction</h3><p>In this project, we’ll build a CI/CD pipeline for a voting application deployed through microservices. Each microservice is written in a different language — Python, Node.js, and .NET — creating a polyglot environment. The application uses Redis for caching and Postgres as its primary database. Our goal is to streamline development and deployment workflows using Azure DevOps and Kubernetes.</p><h3><strong>Overview of Azure DevOps vs. Azure Portal</strong></h3><blockquote>Azure DevOps is a comprehensive suite of tools that supports the entire software lifecycle, from code repositories and CI/CD pipelines to project tracking and testing.In this project, we’ll use Azure DevOps for managing our code, building CI/CD pipelines, and automating deployments.</blockquote><blockquote>Meanwhile, Azure Portal is the central management hub for Azure cloud resources, where we’ll manage services like Azure Kubernetes Service (AKS) and Azure Container Registry (ACR) used in our deployments.</blockquote><h3>Tools and Technologies Used</h3><p>To achieve this, we’ll utilize several key tools and platforms:</p><ul><li><strong>Azure DevOps Repos</strong>: Centralized source control for code.</li><li><strong>Azure DevOps Pipelines</strong>: Automates build, test, and deployment stages.</li><li><strong>SonarQube</strong>: Static code analysis to maintain quality and detect vulnerabilities.</li><li><strong>Trivy &amp; OWASP Dependency-Check</strong>: Security scanners for container images and dependencies.</li><li><strong>Docker</strong>: Containerizes microservices for consistent deployment.</li><li><strong>Azure Container Registry (ACR)</strong>: Stores Docker images for seamless Azure integration.</li><li><strong>Kubernetes</strong>: Orchestrates and scales microservices in a clustered environment.</li><li><strong>Argo CD</strong>: GitOps tool for managing and deploying Kubernetes resources.</li></ul><p>By the end of this project, you’ll have a solid understanding of how to build a robust CI/CD pipeline for microservices, incorporating best practices for version control, testing, security, and deployment.</p><p><strong><em>Feel free to connect with me on </em></strong><a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> to discuss this post, or ask any questions.</em></strong></p><h3>Setting Up Azure DevOps and Azure Portal Accounts</h3><p>Before starting with the project setup, you’ll need accounts on both Azure DevOps and Azure Portal. Here’s how to get started on each platform:</p><h4>Step 1: Create an Azure DevOps Account</h4><ul><li>Go to <a href="https://dev.azure.com/"><strong><em>Azure DevOps</em></strong></a><strong> </strong>and click<strong> </strong><em>Sign in.</em></li><li>If you have a Microsoft account, sign in.</li><li>If not, click <strong><em>Create one!</em> </strong>and follow the prompts.</li><li>After signing in, you’ll be prompted to create an <strong><em>organization.</em></strong> Enter a name and select a region. Click<strong> <em>Continue.</em></strong></li><li>Click <strong><em>New Project, </em></strong>enter a project name, select public or private, and click <strong><em>Create.</em></strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I2UwDUB_ojE7mysZX3ENxw.png" /><figcaption>Azure Devops Project Creation</figcaption></figure><h4>Step 2: Create an Azure Portal Account</h4><ul><li>Go to <a href="https://portal.azure.com/"><strong><em>Azure Portal</em></strong></a> and click <strong><em>Sign in.</em></strong></li><li>Use your existing Microsoft account or click <strong><em>Create one!</em></strong> to set up a new account.</li><li>New users can activate a <a href="https://azure.microsoft.com/free/"><strong><em>free trial</em></strong></a><strong> </strong>that includes credits for various Azure services.</li><li>Once signed in, explore the dashboard, where you’ll manage services like<em> Azure Kubernetes Service (AKS)</em> and <em>Azure Container Registry (ACR)</em> for this project.</li></ul><p><em>With these accounts set up, you’ll have access to both Azure DevOps and Azure Portal, and you’ll be ready to proceed with the project configuration.</em></p><h3>Importing the GitHub Repository into Azure Repos</h3><p>Now that you have set up your Azure DevOps account, we can import our existing GitHub repository into Azure Repos. Follow these steps:</p><p><strong>Step 1: Copy the GitHub Repository URL</strong></p><ul><li>Navigate to my <a href="https://github.com/wangoimwangi"><strong><em>GitHub repository </em></strong></a>and find the<strong><em> </em></strong><a href="https://github.com/wangoimwangi/example-voting-app"><strong><em>source code here</em></strong></a></li><li>On the repository page, click on the green <em>Code</em> button.</li><li>Copy the URL displayed (use HTTPS or SSH format as preferred)</li></ul><h4>Step 2: Import the Repository into Azure Repos</h4><ul><li>Go back to your Azure DevOps project and click on <strong><em>Repos</em> </strong>in the left sidebar.</li><li>Click on the <strong><em>Import a Repository</em></strong> option.</li><li>In the <strong><em>Clone </em></strong><em>URL</em> field, paste the copied GitHub repository URL.</li><li>Choose a name for your new Azure Repo and adjust any other settings if necessary.</li><li>Click the<em> </em><strong><em>Import </em></strong>button. Azure DevOps will start importing the repository, including its history and contents.</li><li>Once the import is complete, you’ll see your repository listed under <em>Repos</em> in Azure DevOps.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CstDcPEgjGCUrZ3ZF8UOOA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*g_cs_ucDcPtHzu8Qea8Y0Q.png" /><figcaption>Importing Git Repo to Azure Devops</figcaption></figure><h3>Setting Up Azure Container Registry (ACR)</h3><p>Now that you’ve imported our GitHub repository into Azure Repos, the next step is to create an Azure Container Registry (ACR) to store and manage your Docker images. Follow these steps:</p><h4><strong>Step 1: Access Azure Portal</strong></h4><p>Open your web browser and navigate to Azure Portal.<br>Enter your Microsoft account credentials to sign in.</p><h4>Step 2: Create a New Container Registry</h4><p><strong>1.</strong> <strong>Navigate to Container Registries</strong><br>In the Azure Portal, click on <strong><em>Create a resource</em> </strong>in the top left corner. In the search bar, type <strong><em>Container Registry</em> </strong>and select Container Registry from the dropdown.</p><p><strong>2. Click on Create</strong><br>Click the<strong> <em>Create</em> </strong>button to start the registry creation process.</p><p><strong>3. Fill in the Required Information</strong></p><ul><li><strong>Subscription</strong>: Select your Azure subscription.</li><li><strong>Resource Group</strong>: Choose an existing resource group or create a new one.</li><li><strong>Registry Name</strong>: Enter a unique name for your registry (e.g., my-voting-app-acr).</li><li><strong>Location</strong>: Choose the Azure region where you want your registry to be hosted.</li><li><strong>SKU</strong>: Select the pricing tier (Basic, Standard, or Premium) based on your needs. The Basic tier is sufficient for small projects.</li></ul><p><strong>4. Configure Networking Options (Optional)</strong><br>You can configure networking options, but for most cases, the default settings will suffice.<br><strong>5. Review and Create</strong><br>Click on the <strong><em>Review + create</em></strong><em> </em>button. After validating the details, click <strong><em>Create</em></strong> to provision your ACR instance.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/937/1*8zm8m7W30GmBgrW9UxH-mg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/972/1*9RcKyyfJYHqAsNJm9y5v4Q.png" /><figcaption>ACR Creation</figcaption></figure><h4>Step 3: Access Your New ACR</h4><p><strong>1. Go to Resource</strong><br>After the deployment is complete, click on <em>Go to resource</em> to access your new Azure Container Registry.</p><p><strong>2. Explore the ACR Interface</strong><br>Here, you can manage your container images, configure access policies, and set up webhooks.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tumFMghTncSr8f3Lk_a-Hw.png" /><figcaption>ACR Creation</figcaption></figure><h3>Note on Azure Kubernetes Service (AKS) Costs</h3><blockquote>To manage costs effectively, we’ll first set up the CI/CD pipeline before configuring the Azure Kubernetes Service (AKS). This approach allows us to validate our deployment process without incurring significant expenses. We will return to set up AKS later in the project.</blockquote><h3>Setting Up CI/CD Pipelines in Azure DevOps</h3><p>Now that we have our repository and ACR set up, we can proceed to create CI/CD pipelines in Azure DevOps. This will automate the building, testing, and deployment of our voting application.</p><h4>Step 1: Navigate to Pipelines</h4><ol><li><strong>Access Azure DevOps</strong><br>Open your Azure DevOps project and select <em>Pipelines</em> from the left sidebar.</li><li><strong>Create a New Pipeline</strong><br>Click on the <em>New pipeline</em> button to begin the setup.</li></ol><h4>Step 2: Select Your Source</h4><ol><li><strong>Choose Your Repository</strong></li></ol><ul><li>Select <em>Azure Repos Git</em> as the source for your pipeline.</li><li>Choose the repository you previously imported containing your voting application code.</li></ul><h4>Step 3: Configure the Pipeline</h4><ol><li><strong>Select a Pipeline Template</strong><br>Choose <strong><em>Docker build and push </em></strong>as your starter template. This template is optimized for building Docker images and pushing them to a container registry.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*N_PAyOzAVTnHUX8GctPL2g.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-14N4Twjv5y2QIUegtJidg.png" /><figcaption>CI/CD Pipeline Setup</figcaption></figure><p><strong>2. Edit the Pipeline YAML</strong><br>We will be editing the pipeline YAML to add more stages beyond just building and pushing the Docker images.</p><p>Each of our microservices will have its own pipeline, but the core steps will remain consistent.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/597/1*wRy5yAMcoADdy3xSI6agEA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*X6FE4BbmjHOlu5S001pMOA.png" /><figcaption>CI/CD Pipeline Setup</figcaption></figure><h3>Configuring Triggers</h3><p>In Azure DevOps, triggers determine when a pipeline runs automatically based on changes to your code repository.</p><p>For our voting application, which consists of three microservices <strong>—<em> vote, worker, and result </em>— </strong>we will set up 3 different triggers for each microservice. For example, if you are setting up the pipeline for the <strong><em>result</em> </strong>microservice, you will use the following trigger configuration in your YAML:</p><pre>trigger:<br> paths:<br>  include:<br>    - result/*</pre><p>This configuration means that the pipeline will automatically run whenever there are changes made to any files in the result directory.</p><p>You will need to replace the default trigger with the relevant value for the microservice you are configuring: <strong><em>- result/*, — vote/* or — worker/*</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/872/1*2VvvEX9ZxoAZrm0I87xgvg.png" /><figcaption>Trigger Setup</figcaption></figure><h3><strong>Agent Pool Creation</strong></h3><p>To run CI/CD tasks, Azure DevOps needs an agent — a machine that performs the actual build and deployment processes. Users with an Azure DevOps subscription can use the default <strong><em>Azure Pipelines</em></strong> agent pool, so they can skip this step.</p><p>However, if you’re using the free version of Azure DevOps, you’ll need to set up and maintain your own agent by creating a VM and adding it to an agent pool in Azure DevOps.</p><h4>Step 1: Create a VM for the Agent</h4><p><strong>1: Go to the Azure Portal</strong>: Sign in to the <a href="https://portal.azure.com/"><strong><em>Azure Portal</em></strong></a><strong><em>.</em></strong></p><p><strong>2. Create a Virtual Machine</strong>:</p><ul><li>In the Azure Portal, navigate to <strong><em>Virtual Machines</em></strong> and click on<em> </em><strong><em>Create</em></strong><em>.</em></li><li>Select the required options, such as the <strong>Region</strong>, <strong>Resource Group</strong>, <strong>VM <em>Name</em></strong><em>,</em> and <strong><em>Size</em></strong><em>. </em>For DevOps purposes, a standard DS1_v2 size VM should be sufficient.</li><li>Choose an operating system (typically <strong><em>Ubuntu</em></strong> or <strong><em>Windows Server</em></strong><em>,</em> depending on your preference and needs).</li><li>Configure <strong><em>Administrator Account</em></strong> settings for SSH or password-based access.</li></ul><p><strong>3. Configure Networking and Storage</strong>:</p><ul><li>Under <strong><em>Networking</em></strong><em>,</em> ensure your VM has a public IP (or configure it for private access if you’re connecting through a VPN).</li><li>You may keep the default settings for storage unless you have specific requirements.</li></ul><p><strong>4. Review and Create the VM</strong>:</p><ul><li>After configuring, review your settings and click <strong><em>Create</em></strong> to start the VM deployment.</li><li>Once the VM is created, make a note of its IP address for later access.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kbju-znldClISCBYPhT5WQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5y3PNa9sW9z-8K6b5XKmqA.png" /><figcaption>VM Creation</figcaption></figure><h4>Step 2: Generate a Personal Access Token (PAT) for Agent Authentication</h4><p>To allow your agent to connect to Azure DevOps, you need a Personal Access Token <strong><em>(PAT).</em></strong></p><p>1: In Azure DevOps, click on your profile icon and select <strong><em>Personal Access Tokens</em></strong><em>.</em></p><p>2. Click <strong>+</strong> New Token:</p><ul><li>Set a<em> </em><strong><em>name</em></strong> (e.g., “Agent Token”).</li><li>Choose <strong><em>Organization</em></strong> for the scope.</li><li>Under <strong><em>Permissions</em></strong><em>,</em> select <strong><em>Full Access</em></strong> (or at minimum Agent Pools and Pipelines).</li><li>Set an expiration date.</li></ul><p>3. Click <strong><em>Create</em></strong><em>, </em>and <strong><em>copy the token</em></strong><em>. </em>You’ll use it during the agent configuration.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*za-NCRU_I4wFIG-uD9nrHw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/791/1*SI33-aUGgc4vf3UmOwpctw.png" /><figcaption>Generating a PAT</figcaption></figure><h4>Step 3: Add the VM Agent to Your Azure DevOps Project</h4><p><strong>1: Open Azure DevOps Project Settings</strong>: In Azure DevOps, go to <strong><em>Project Settings</em></strong><em> </em>by selecting the gear icon in the bottom left.</p><p><strong>2: Create an Agent Pool</strong>:</p><ul><li>Under <strong><em>Pipelines</em></strong><em>,</em> select <strong><em>Agent Pools</em></strong><em>.</em></li><li>Click on <strong><em>Add pool</em></strong><em>,</em> provide a name (e.g., Custom Agent Pool), and click <strong><em>Create</em></strong><em>.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rmQvckrP_MboVBKOTT39jA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UGXgI5ONrlaLBm8tNDjfrQ.png" /><figcaption>Adding Self Hosted Agent Pool to Azure Devops</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/610/1*fBRskBnrX58rdCPDNMzBxw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/937/1*MBA4LOayns9Iw0MdvFpuyQ.png" /><figcaption>Adding Self Hosted Agent Pool to Azure Devops</figcaption></figure><p><strong>3: Download and Configure the Agent</strong>:</p><ul><li>In the <strong><em>Agent Pools</em></strong><em> </em>section, select the new pool you created and click <strong><em>New agent</em></strong><em>.</em></li><li>Choose the operating system of your VM and follow the instructions to download the agent.</li><li>When prompted for authentication, <strong><em>paste your PAT</em></strong> from <strong><em>Step 2.</em></strong></li><li>After downloading, connect to your VM, install the agent, and configure it using the setup commands provided by Azure DevOps.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TpRPU1dgRSUeq5YPOTBUcQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1015/1*gYA2Q7rPQMJ4qRQV2i1Kkg.png" /><figcaption>Downloading and Configuring the Agent</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wgvo2CAvP-jRF0pQEzwDxQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oTeuTHeHTgPd-9IwLJssvw.png" /><figcaption>Downloading and Configuring the Agent</figcaption></figure><p><strong>4: Run and Verify the Agent</strong></p><ul><li>Once installed, start the agent on your VM.</li><li>Back in Azure DevOps, you should see the agent listed as <strong><em>Online</em></strong> in the agent pool.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/657/1*XuLPAfU7CmgtpntSAWIHiQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s76t7wjnRIqyB4mjDj_0Jg.png" /></figure><p>Now your agent is ready and can be referenced in your pipeline configuration for running CI/CD tasks!</p><p>Make sure you update your pipeline with the new created agentpool.</p><pre> # Agent VM image name<br>pool:<br> name: &#39;azureagent&#39;</pre><p><strong>Note: </strong><em>Always make sure the agent is running before executing any CI/CD pipelines in Azure DevOps. If the agent is stopped or offline, your pipelines won’t be able to run. If you set up the agent as a service, it should automatically restart with the VM. Otherwise, if you’re using </em><em>./run.sh, remember to keep the terminal session open, or restart it as needed.</em></p><h3>Tools to Install on the Self-Hosted Agent VM</h3><ol><li><strong>Docker</strong>: Required for containerizing applications.</li><li><strong>Security and Quality Scanning Tools</strong>: <strong><em>Trivy</em></strong> and <strong><em>SonarQube Scanner</em></strong>: These are needed if you’re integrating security scans in our pipeline. Install them on the agent to allow direct scanning as part of CI/CD.</li></ol><pre># Docker (if not already installed)<br>sudo apt-get update &amp;&amp; sudo apt-get install -y docker.io<br># Pull the SonarQube Docker image<br>docker pull sonarqube<br># Run SonarQube in a Docker container<br>docker run -d --name sonarqube -p 9000:9000 sonarqube<br># Download and install Trivy<br>wget https://github.com/aquasecurity/trivy/releases/latest/download/trivy_0.39.1_Linux-64bit.deb<br>sudo dpkg -i trivy_0.39.1_Linux-64bit.deb</pre><h4>Final Note</h4><p>After installing these tools, you might also need to add the agent user to the docker group to allow Docker commands without <strong><em>sudo</em></strong></p><pre>sudo usermod -aG docker $(whoami)</pre><p>Replace <strong><em>$(whoami)</em></strong> with the actual username of the agent on your VM. Remember to restart the agent or log out and log back in for this change to take effect.</p><p><strong>Note</strong>: <em>We’ll use </em><strong><em>Azure DevOps task templates</em></strong><em> for some of our pipeline steps. These templates provide a ready-to-use setup, saving time by filling in common fields and configurations automatically. Once the templates are in place, we’ll customize the specific settings.</em></p><p>Now let’s go back to our pipeline and configure the different stages.</p><h3>Pipeline Variables Section</h3><p>In this section, we’ll define the variables that our pipeline will use. These variables are essential for maintaining consistency and flexibility in the CI/CD process. Here’s an example of how you might configure your variables:</p><pre>variables:<br>  # Container registry service connection established during pipeline creation<br>  dockerRegistryServiceConnection: &#39;31a607b0-f8ba-466b-a965-c66a0b69044f&#39;<br>  imageRepository: &#39;workerapp&#39;<br>  containerRegistry: &#39;mariaazurecicd.azurecr.io&#39;<br>  dockerfilePath: &#39;$(Build.SourcesDirectory)/result/Dockerfile&#39;<br>  tag: &#39;$(Build.BuildId)&#39;</pre><h3>Continuous integration (CI)</h3><h3>Code Quality Analysis &amp; Dependency Scanning</h3><p>We will be using <strong><em>SonarQube</em></strong> for our code analysis and <strong><em>OWASP Dependency-Check</em></strong> to scan for vulnerable dependencies.</p><p>SonarQube can be storage-intensive, especially with larger projects or multiple microservices. Here are key recommendations:</p><ul><li><strong>Upgrade Storage on the Current Agent</strong>: If SonarQube runs on the same server as your Azure DevOps agent, consider adding extra storage to prevent memory issues.</li><li><strong>Set Up a Dedicated SonarQube Server</strong>: For improved performance and isolation, set up SonarQube on a separate VM with sufficient storage.</li></ul><h4>Access SonarQube UI</h4><p>To access the SonarQube UI, ensure that port <strong><em>9000</em></strong> is open on your firewall. You can access the SonarQube interface by navigating to http://&lt;your-server-ip&gt;:9000 in your web browser after starting the SonarQube container. The default login credentials are:</p><ul><li><strong>Username</strong>: admin</li><li><strong>Password</strong>: admin (you should change this after the first login).</li></ul><h3>Creating a Service Connection for SonarQube</h3><p><strong>1: Navigate to Project Settings</strong>: Go to your Azure DevOps project and click on the <strong><em>Project Settings</em></strong> gear icon at the bottom left.</p><p><strong>2. Select Service connections</strong>: Under the <strong><em>Pipelines</em></strong> section, click on <strong><em>Service connections</em></strong><em>.</em></p><p><strong>3. Add a New Service Connection</strong>:</p><ul><li>Click on <strong><em>New service connection</em></strong><em>.</em></li><li>Select<em> </em><strong><em>SonarQube</em></strong> from the list and click <strong><em>Next</em></strong><em>.</em></li></ul><p><strong>4. Enter Connection Details</strong>:</p><ul><li><strong>Server URL</strong>: Enter the URL of your SonarQube server (e.g., http://&lt;your-server-ip&gt;:9000).</li><li><strong>Authentication</strong>: You can use either a token or username/password for authentication. If you opt for a token, you need to create one in SonarQube (under <strong><em>My Account </em>&gt; <em>Security</em></strong>) and enter it here.</li></ul><p><strong>5. Name the Connection</strong>: Give your service connection a recognizable name (e.g., sonar-svc).</p><p><strong>6. Verify and Save</strong>: Click <strong><em>Verify</em></strong> to check the connection, then click<em> </em><strong><em>Save</em></strong> to finalize.</p><h3>Using Azure DevOps Tasks:</h3><p><strong>1: Navigate to Pipeline Tasks</strong>:</p><ul><li>Open the pipeline editor in Azure DevOps.</li><li>Click on the <strong><em>Tasks</em></strong><em> </em>tab to add pre-configured tasks.</li></ul><p><strong>2. Adding SonarQube Tasks</strong>:</p><p><strong>Prepare Analysis Configuration</strong>:</p><ul><li>In the search bar under <strong><em>Tasks</em></strong><em>, </em>search for <strong><em>“SonarQube.”</em></strong></li><li>Select <strong><em>SonarQubePrepare</em></strong> (version 7 or latest).</li><li>Set the <strong><em>SonarQube Service Connection</em></strong> to <em>&#39;sonar-svc&#39;</em> (or the name you configured for your SonarQube server in Azure DevOps).</li><li>Set <strong><em>Project Key</em></strong> and <strong><em>Project Name</em></strong> to match your application, e.g., voteapp.</li><li>For <strong><em>Source Files</em></strong><em>, </em>use the value . to specify the root directory</li></ul><p><strong>Run Code Analysis</strong>:</p><ul><li>Add another task, <strong><em>SonarQubeAnalyze</em></strong><em>.</em></li><li>Specify the <strong><em>Java version</em></strong> if needed by selecting JAVA_HOME_17_X64 under the<em> </em><strong><em>jdkversion</em></strong> field, particularly if your project includes Java components.</li></ul><p><strong>3. Add OWASP Dependency-Check Task</strong>:</p><ul><li>For the dependency check, there isn’t a built-in Azure DevOps task, so you’ll use a<em> </em><strong><em>Script</em></strong> task.</li><li>Search for and add a <strong><em>Script</em></strong> task, then enter the following script:</li></ul><pre># Step to run Dependency-Check<br>    - script: |<br>        echo &quot;Running Dependency-Check...&quot;<br>        dependency-check.sh --project &quot;voteapp&quot; --scan . --outdir ./dependency-check-report --format ALL<br>      displayName: &#39;Run OWASP Dependency-Check&#39;</pre><p>Here is the full yaml pipeline for this stage remember to replace with your actual values.</p><pre>stages:<br>  # Code Quality and Dependency Scanning Stage<br>  - stage: SonarAnalysis<br>    displayName: SonarAnalysis<br>    jobs:<br>      - job: SonarAnalysis<br>        displayName: SonarAnalysis<br>        steps:<br>          # Pull the latest code from the repository<br>          - checkout: self<br>            fetchDepth: 0  # Fetch full commit history for detailed analysis<br>            <br>          # Prepare SonarQube analysis<br>          - task: SonarQubePrepare@7<br>            inputs:<br>              SonarQube: &#39;sonar-svc&#39;  # Replace &#39;sonar-svc&#39; with your SonarQube service connection name<br>              scannerMode: &#39;cli&#39;<br>              configMode: &#39;manual&#39;<br>              cliProjectKey: &#39;voteapp&#39;  # Unique key for the project in SonarQube<br>              cliProjectName: &#39;voteapp&#39;<br>              cliSources: &#39;.&#39;  # Set the root directory for SonarQube to analyze<br>              extraProperties: &#39;sonar.java.binaries=.&#39;  # Specify binaries location if needed for Java analysis<br><br>          # Run the SonarQube analysis<br>          - task: SonarQubeAnalyze@7<br>            inputs:<br>              jdkversion: &#39;JAVA_HOME_17_X64&#39;  # Specify Java version if your project includes Java files<br><br>          # Run OWASP Dependency-Check for vulnerabilities<br>          - script: |<br>              echo &quot;Running Dependency-Check...&quot;<br>              dependency-check.sh --project &quot;voteapp&quot; --scan . --outdir ./dependency-check-report --format ALL<br>            displayName: &#39;Run OWASP Dependency-Check&#39;</pre><h3>Building Docker Image</h3><p>In this stage, we’ll build our Docker image using the <strong><em>Azure DevOps Docker task. (I’m assuming you are all familiar with using Azure DevOps tasks from our previous SonarQube configuration, so I’ll keep the remaining steps brief.)</em></strong></p><p>The following YAML configuration outlines the build process:</p><pre># BUILD STAGE (Docker)<br>- stage: Build<br>  displayName: Build<br>  jobs:<br>  - job: Build<br>    displayName: Build<br>    steps:<br>    - task: Docker@2<br>      displayName: Build<br>      inputs:<br>        containerRegistry: &#39;$(dockerRegistryServiceConnection)&#39;<br>        repository: &#39;$(imageRepository)&#39;<br>        command: &#39;build&#39;<br>        Dockerfile: &#39;worker/Dockerfile&#39;<br>        tags: &#39;$(tag)&#39;</pre><h4>Configuration Notes:</h4><ul><li><strong>containerRegistry</strong>: Ensure that this variable points to the service connection created for your Azure Container Registry.<em>(Make sure you have configured this service connection).</em></li><li><strong>repository</strong>: This should match the name of the image repository where the Docker image will be stored.</li><li><strong>Dockerfile</strong>: Update the path to the Dockerfile if your Dockerfile is located in a different directory.</li><li><strong>tags</strong>: The tag will default to the build ID; however, you can customize it if needed.</li></ul><h3>Docker Image Scanning with Trivy</h3><p>In this stage, we will scan the built Docker image for vulnerabilities using <strong><em>Trivy. </em></strong>The following YAML configuration outlines the scanning process:</p><pre># SCAN IMAGE STAGE (Trivy)<br>- stage: TrivyScan<br>  displayName: Trivy Scan<br>  jobs:<br>  - job: TrivyScan<br>    displayName: Trivy Image Scan<br>    steps:<br>    - script: |<br>        echo &quot;Scanning Docker image with Trivy...&quot;<br>        trivy image --exit-code 1 --severity HIGH,CRITICAL $(containerRegistry)/$(imageRepository):$(tag) || true<br>      displayName: &#39;Run Trivy Scan&#39;<br>      env:<br>        TRIVY_SEVERITY: &#39;HIGH,CRITICAL&#39;<br>        TRIVY_SKIP_UPDATE: &#39;true&#39; # Skip the database update to speed up scans</pre><h4>Explanation:</h4><ul><li><strong>trivy image</strong>: This command scans the specified Docker image for vulnerabilities.</li><li><strong>— exit-code 1</strong>: The scan will return a non-zero exit code if vulnerabilities are found, allowing for further action in the pipeline.</li><li><strong>— severity HIGH,CRITICAL</strong>: This limits the scan to only report high and critical severity vulnerabilities, which helps focus on the most significant risks.</li><li><strong>TRIVY_SKIP_UPDATE</strong>: This environment variable is set to <strong><em>true </em></strong>to skip the database update, which speeds up the scanning process.</li></ul><h3><strong>Docker Image Push</strong></h3><p>Using the <strong><em>Azure DevOps Docker task </em></strong>we will push the built Docker image to our container registry<strong><em>.</em></strong></p><p>The following YAML configuration outlines the pushing process:</p><pre># PUSH STAGE (Docker)<br>- stage: Push<br>  displayName: Push<br>  jobs:<br>  - job: Push<br>    displayName: Push<br>    steps:<br>    - task: Docker@2<br>      displayName: Push<br>      inputs:<br>        containerRegistry: &#39;$(dockerRegistryServiceConnection)&#39;<br>        repository: &#39;$(imageRepository)&#39;<br>        command: &#39;push&#39;<br>        tags: &#39;$(tag)&#39;</pre><h4>Explanation:</h4><ul><li><strong>Docker@2 task</strong>: This task is used to push the Docker image to the specified container registry.</li><li><strong>containerRegistry</strong>: This input specifies the service connection for the Azure Container Registry that was established during the pipeline setup.</li><li><strong>repository</strong>: This input defines the name of the image repository where the image will be pushed.</li><li><strong>command</strong>: The command is set to <strong><em>push</em></strong>, indicating that we want to push the image to the container registry.</li><li><strong>tags</strong>: This input defines the tag for the image being pushed, typically using the build ID or version number for identification.</li></ul><h3>Update Script (Kubernetes Manifest Files)</h3><p>In this stage, we will update our existing Kubernetes manifests files and ensure that ArgoCD can detect and deploy the latest Docker image. The following YAML configuration outlines the update process:</p><pre># UPDATE SCRIPT STAGE<br>- stage: Update<br>  displayName: Update <br>  jobs:<br>    - job: Update<br>      displayName: Update<br>      steps:<br>        - script: sudo apt-get update<br>          displayName: Update package list<br><br>        - script: sudo apt-get install -y dos2unix<br>          displayName: Install dos2unix<br><br>        - script: dos2unix scripts/updateK8sManifests.sh<br>          displayName: Convert script to Unix format<br><br>        - task: ShellScript@2<br>          displayName: Run Update Script<br>          inputs:<br>            scriptPath: &#39;scripts/updateK8sManifests.sh&#39;<br>            args: &#39;vote $(imageRepository) $(tag)&#39;</pre><h4>Explanation:</h4><ul><li><strong>Updating Package List</strong>: Ensures the system has the latest package information.</li><li><strong>Installing </strong><strong>dos2unix</strong>: Converts Windows line endings to Unix format for script compatibility <em>(For the Windows users).</em></li><li><strong>Converting Script to Unix Format</strong>: Applies <strong><em>dos2unix</em></strong> to <strong><em>updateK8sManifests.sh</em></strong> for correct line endings.</li><li><strong>Running the Update Script</strong>: Executes <strong><em>updateK8sManifests.sh</em></strong> with the specified microservice, repository, and tag, allowing ArgoCD to track changes and deploy the updated image.</li></ul><h3>Run the Pipeline</h3><p><strong>1: Trigger the Pipeline</strong>:</p><ul><li>Once the pipeline is configured and ready, navigate to Azure DevOps.</li><li>Under your project, go to <strong><em>Pipelines</em></strong><em> </em>and select the pipeline you want.</li><li>Click on<em> </em><strong><em>Validate and save</em></strong><em> &gt; </em><strong><em>Run Pipeline</em></strong> to manually trigger it.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Pv3sVzR9GNmPBXdN-4Kj6A.png" /></figure><p><strong>2. Monitor the Pipeline Execution</strong>:</p><ul><li>After triggering, monitor the pipeline’s progress in the Azure DevOps UI.</li><li>You can view logs and check each stage to ensure everything is running smoothly.</li></ul><p><strong>3. Check for Success or Failure</strong>:</p><ul><li>The pipeline will provide a success or failure status after execution.</li><li>If it fails, review the logs to identify and resolve any issues before re-running.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7VAd5rhNCHTByXqCyCwDsQ.png" /><figcaption>Vote Pipeline</figcaption></figure><p><strong>4. Confirm Deployment</strong>:</p><ul><li>Once the pipeline completes successfully, confirm the application deployment by checking ArgoCD or the relevant Kubernetes cluster to ensure the updated application is deployed.<em> (Which we will do at the end of this project don’t worry about this part for now)</em></li></ul><p>5. Repeat the steps for all the remaining microservices.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rUsgKcZb-BzVpdrLAqJ32Q.png" /><figcaption>Complete Pipelines</figcaption></figure><h3>Continuous Deployment</h3><h3>AKS Cluster Set Up</h3><p>Since our CI/CD pipeline will ultimately deploy to an Azure Kubernetes Service (AKS) cluster, the next step is to set up the AKS cluster.</p><p>Here, we’ll create the cluster through the Azure Portal UI, which simplifies the process and provides flexibility in configuring resources.</p><p><strong>1: Log in to Azure Portal</strong><br>Go to<strong><em> </em></strong><a href="https://portal.azure.com/"><strong><em>Azure Portal</em></strong></a><strong><em> </em></strong>and log in to your account.</p><p><strong>2. Navigate to AKS Service</strong><br>In the search bar, type <strong><em>Azure Kubernetes Service</em></strong> and select it.</p><p><strong>3. Create a New Cluster</strong></p><ul><li>Click <strong><em>+ Create</em></strong> and select <strong><em>Kubernetes cluster</em></strong><em>.</em></li><li>Choose your <strong><em>Subscription</em></strong><em> </em>and <strong><em>Resource Group</em></strong><em> </em>( you can use the resource grp we created at the beginning or create a new one if necessary).</li><li>Enter a <strong><em>Cluster name</em></strong> and select your preferred <strong><em>Region</em></strong><em>.</em></li></ul><p><strong>4. Configure Node Pools</strong></p><ul><li>Set the <strong><em>Node size</em></strong> and <strong><em>Node count</em></strong><em> </em>according to your application’s needs. For example, you might start with 3 nodes of type Standard_DS2_v2.</li><li>Choose options like auto-scaling if you expect variable loads.</li></ul><p><strong>5. Authentication</strong></p><ul><li>Choose your authentication method (e.g., <strong><em>System-assigned managed identity</em></strong><em> </em>for access control).</li><li>Enable <strong><em>RBAC</em></strong><em> </em>(Role-Based Access Control) if you want more granular permissions.</li></ul><p><strong>6. Networking and Integration Options</strong></p><ul><li>Configure your <strong><em>Network</em></strong> settings based on your requirements (you can use default settings for simplicity or define specific VNet and Subnet).</li><li>Decide on <strong><em>integration</em></strong><em> </em>options like <strong><em>Container Insights</em></strong> for monitoring.</li></ul><p><strong>7. Review + Create</strong></p><ul><li>Click on <strong><em>Review + create</em></strong><em> </em>to review your configurations.</li><li>Once confirmed, click <strong><em>Create</em></strong> to deploy the cluster.</li></ul><p><strong>8. Get Cluster Credentials</strong><br>After deployment, retrieve the cluster credentials:</p><ul><li>Go to your AKS resource, and in the left menu, select <strong><em>Connect</em></strong><em>.</em></li><li>Follow the instructions to set up kubectl access if needed. Azure will provide a command you can run locally if your machine is already configured with the Azure CLI and kubectl.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DnmaZFbMfJR9J4-pLrD2bQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Lid4l6ovrzyscV7QgBZ3GQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rz06B-5fMeTO9lulx4_wHg.png" /><figcaption>AKS Setup</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/926/1*ZrabulYh-B8dWEE6VXmddw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*k62K3e2Y-hM5prHpzkd-TA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YxuQg_e7dBZ9jYmhqCvp4g.png" /><figcaption>AKS Setup</figcaption></figure><h3>Argo CD Setup</h3><p><strong><em>ArgoCD</em></strong> is a declarative <strong><em>GitOps tool </em></strong>for Kubernetes that automates application deployments by syncing configurations from a Git repository to your cluster.</p><p>It continuously monitors for changes, ensuring the cluster state matches the desired state defined in Git, enabling automated, version-controlled, and reliable deployments.</p><p>Here’s how to set up ArgoCD in your Kubernetes environment:</p><h4>Step 1: Install ArgoCD</h4><p><strong><em>a) Create a Namespace for ArgoCD</em></strong></p><pre>kubectl create namespace argocd</pre><p><strong><em>b) Apply the ArgoCD Manifests</em></strong></p><pre>kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml</pre><h4>Step 2: Expose the ArgoCD UI</h4><p><strong>a) Change the Service Type to LoadBalancer</strong></p><p>For Linux/MacOS:</p><pre>kubectl patch svc argocd-server -n argocd -p &#39;{&quot;spec&quot;: {&quot;type&quot;: &quot;LoadBalancer&quot;}}&#39;</pre><p>For Windows:</p><pre>kubectl patch svc argocd-server -n argocd -p &#39;{\&quot;spec\&quot;: {\&quot;type\&quot;: \&quot;LoadBalancer\&quot;}}&#39;</pre><p><strong>b) Retrieve the Load Balancer IP</strong></p><pre>kubectl get svc argocd-server -n argocd</pre><p>This command will provide you with the external IP address of the ArgoCD server.</p><h4>Step 3: Access the ArgoCD UI</h4><p>Open your web browser and navigate to the Load Balancer IP address obtained from the previous step. You can access the ArgoCD UI from there. Make sure you have opened the inbound port of the argocd server.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/842/0*RUWEvxkqbZa_QWBZ.png" /><figcaption>ArgoCD UI</figcaption></figure><h4>Step 4: Retrieve ArgoCD Admin Password</h4><p><strong><em>Get the Initial Admin Password</em></strong></p><p>Retrieve the password using the following command</p><pre>kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath=&quot;{.data.password}&quot; | base64 -d</pre><p>This command will output the initial admin password required to log into the ArgoCD UI.</p><h3>Add Update Script to Git Repository</h3><p>To ensure that ArgoCD tracks updates for automatic deployment, add the updateK8sManifests.sh script to your Git repository.</p><p>This allows ArgoCD to continuously monitor the repository for changes and trigger deployments when necessary.</p><p><strong>Steps:</strong></p><ol><li>Add the <strong><em>updateK8sManifests.sh</em></strong> script to your Git repository, ideally in a <strong><em>scripts</em></strong> folder or similar directory.</li><li>Ensure the script contains logic to update the Kubernetes manifests with the new Docker image information.</li><li>Commit and push the changes to the repository so that ArgoCD can detect them.</li></ol><p><strong><em>Note:</em></strong><em> ArgoCD will automatically sync and deploy the changes when it detects updates to the repository, following GitOps principles.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*H7YBl_ak4-ARZNKAlMIhWA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6fvOGEbNZ4m-xloLq-x4Ew.png" /><figcaption>Updating Script To Git Repo</figcaption></figure><h3>Connecting ArgoCD to Azure DevOps using Personal Access Token (PAT)</h3><p><strong>1: Generate a Personal Access Token (PAT) in Azure DevOps</strong>:</p><ul><li>Go to <strong><em>Azure DevOps &gt; Your Profile &gt; Personal Access Tokens.</em></strong></li><li>Click <strong><em>New Token</em></strong><em>,</em> give it a name, select the required scopes (at least <strong><em>“Code”</em></strong> or<strong> <em>“Read &amp; Write”</em></strong> for accessing repositories), and click <strong><em>Create</em></strong><em>.</em></li><li>Copy the generated token as you will need it to connect ArgoCD.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kx0zl2NBI_g5pbXVSIu6nw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BoS927UILBdtkUE7ihQJDw.png" /><figcaption>Generating a PAT</figcaption></figure><p><strong>2. Add the Azure DevOps Repository in ArgoCD</strong>:</p><ul><li>Log into your ArgoCD UI.</li><li>Go to <strong><em>Settings</em></strong><em> &gt; </em><strong><em>Repositories</em></strong><em> </em>and click <strong><em>+ New Repository</em></strong><em>.</em></li><li>Select<em> </em><strong><em>Git</em></strong><em> </em>as the repository type and enter the URL of your Azure DevOps repository (e.g., <a href="https://dev.azure.com/%7Borganization%7D/%7Bproject%7D/_git/%7Brepository%7D).">https://dev.azure.com/{organization}/{project}/_git/{repository}).</a></li><li>Choose <strong><em>Username/Password</em></strong> as the authentication method.</li><li>For the <strong><em>Username</em></strong>, you can use your Azure DevOps username (or devops).</li><li>For the <strong><em>Password</em></strong><em>,</em> paste the <strong><em>PAT</em></strong><em> </em>you generated.</li><li>Click <strong><em>Save</em></strong> to add the repository.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*b-qJOi4z5BHASgywoHUswQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2KY_vcY8tnc71911_1w_hg.png" /><figcaption>Adding Azure Repo in ArgoCD</figcaption></figure><h3>Adjusting the Timeout Reconciliation Time for ArgoCD (Optional)</h3><p>In ArgoCD, the reconciliation process is responsible for ensuring that the state of your Kubernetes cluster matches the desired state defined in the Git repository.</p><p>The default reconciliation timeout in ArgoCD is<em> </em><strong><em>5 minutes (300 seconds)</em></strong><em>.</em></p><p>If you want to adjust this to a shorter value<strong><em> (e.g., 10 seconds),</em></strong> you can update the <strong><em>timeout.reconciliation</em></strong> setting in the <strong>argocd-cm</strong> ConfigMap.</p><p><strong>1. Access ArgoCD ConfigMap</strong></p><p>ArgoCD stores configuration settings in a ConfigMap, which you need to modify.</p><p>Run the following command to open the ConfigMap in an editor.</p><pre>kubectl edit configmap argocd-cm -n argocd</pre><p><strong>2. Modify the Reconciliation Timeout</strong></p><p>In the opened ConfigMap, you’ll need to add or modify the <strong><em>timeout.reconciliation</em></strong> setting under the <strong><em>data</em></strong> section. Set the value to <strong><em>10s </em></strong>for 10 seconds.</p><pre>data:<br>  timeout.reconciliation: &quot;10s&quot;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/977/1*KtNSXm_mj3PqwNRGxUQKpQ.png" /><figcaption>Adjusting Timeout Reconciliation Time For ArgoCD</figcaption></figure><p><strong>3. Save the Changes</strong></p><p>Once you’ve updated the value, save the changes and exit the editor.</p><p><strong>4. Apply the Changes</strong></p><p>The changes should take effect automatically. If needed, restart the ArgoCD server to apply the changes:</p><pre>kubectl rollout restart deployment/argocd-server -n argocd</pre><p><strong>5. Verify the Changes</strong></p><p>You can verify that the new reconciliation timeout is applied by checking the ArgoCD logs to see if the reconciliation interval reflects updated value.</p><pre>kubectl logs deployment/argocd-server -n argocd</pre><h3>Deploy Your Application via ArgoCD</h3><p><strong><em>a) Login to the ArgoCD UI</em></strong></p><ul><li>Use the default username is <em>‘admin’ </em>and the retrieved admin password to log in to the ArgoCD UI.</li></ul><p><strong><em>b) Add Your Application</em></strong></p><ul><li>In the ArgoCD UI, click on<em> </em><strong><em>New App</em></strong><em> </em>to create a new application.</li><li>Provide the necessary details, including the Git repository URL where your Helm chart or Kubernetes manifests are stored, and configure the application settings.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bxufXABzJkVmDr2Jk76VOg.png" /><figcaption>Application Creation in ArgoCD</figcaption></figure><p><strong><em>c) Sync Your Application</em></strong></p><ul><li>After adding the application, click <strong><em>Sync</em></strong> to deploy the application to your Kubernetes cluster.</li><li>Monitor the deployment status and logs directly from the ArgoCD UI.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_2CbbhFpjb7s_Tf6vjGEhQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hs_8wiGMjvdNEYqb7eNYAg.png" /><figcaption>Deployment via ArgoCD</figcaption></figure><h3>Troubleshooting ImagePullBackOff Error</h3><p><strong>Issue:</strong> The <strong><em>ImagePullBackOff</em></strong> error occurs because Kubernetes is unable to authenticate with the container registry when trying to pull the image.</p><p><strong>Cause:</strong> Kubernetes cannot access the image repository because it does not have the necessary credentials to authenticate with the container registry.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/897/1*jm_nIk_-8m3f7HNkYXqCcA.png" /><figcaption>ImagePullBackOff Error</figcaption></figure><p><strong>Solution:</strong></p><p><strong>1: Verify Registry Credentials:</strong></p><p>Ensure that your K8 cluster has the correct credentials to pull from the container registry.</p><p>This can be done by creating a Kubernetes secret for the registry credentials and linking it to your deployment.</p><p>For ACR, you can create a secret that stores the login credentials for ACR.</p><pre>kubectl create secret docker-registry acr-secret \<br>  --docker-server=&lt;your_acr_name&gt;.azurecr.io \<br>  --docker-username=&lt;your_service_principal_id&gt; \<br>  --docker-password=&lt;your_service_principal_password&gt; \<br>  --docker-email=&lt;your_email&gt;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EWLeIwenmnfP12U2NquHhw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/933/1*RgoFVBgQgVPdek0beh3mNw.png" /><figcaption>ACR Secret Creation</figcaption></figure><p><strong>2. Update Deployment with ImagePullSecrets:</strong></p><p>Once the secret is created, update your Kubernetes deployment YAML to reference this secret under <strong><em>imagePullSecrets.</em></strong></p><p>Here’s an example of how to reference the secret in your Kubernetes deployment manifest:</p><pre>apiVersion: apps/v1<br>kind: Deployment<br>metadata:<br>  labels:<br>    app: vote<br>  name: vote<br>spec:<br>  replicas: 1<br>  selector:<br>    matchLabels:<br>      app: vote<br>  template:<br>    metadata:<br>      labels:<br>        app: vote<br>    spec:<br>      containers:<br>      - image: mariaazurecicd.azurecr.io/voteapp:57<br>        name: vote<br>        ports:<br>        - containerPort: 80<br>          name: vote<br>      imagePullSecrets:<br>       - name: acr-secret</pre><p><strong>3. Ensure the Service Principal Has Correct Permissions:</strong></p><p>If you are using a service principal for authentication, make sure it has the correct permissions to pull images from your Azure Container Registry. The service principal needs the<em> </em><strong><em>AcrPull</em></strong> role assigned.</p><p>To assign this role, run the following command:</p><pre>az role assignment create --assignee &lt;your_service_principal_id&gt; --role AcrPull --scope /subscriptions/&lt;subscription_id&gt;/resourceGroups/&lt;resource_group&gt;/providers/Microsoft.ContainerRegistry/registries/&lt;acr_name&gt;</pre><p><strong>4. Check for Role Propagation Delays:</strong></p><p>After assigning the correct permissions, there might be a delay in propagating the permissions. You can verify the permissions with:</p><pre>az role assignment list --assignee &lt;your_service_principal_id&gt;</pre><p>If the permissions are not showing up or there is still an issue, it might be necessary to wait a few minutes and retry.</p><p><strong>5. Verify Deployment:</strong></p><p>Once the pipeline completes successfully, confirm the application deployment by checking ArgoCD to ensure the updated application is deployed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/702/1*Xz52JxtfctR0lweWof4e0g.png" /><figcaption>Confirming all pods are in Running State</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BRf0JxShkMpDQUq35riDkA.png" /><figcaption>Suceessfull Continous Deployment</figcaption></figure><h3>Cleaning Up Resources</h3><p>Here’s a brief list of resources to delete after completing your project.</p><p><strong>1: Azure Kubernetes Service (AKS) Cluster</strong></p><p>If the AKS cluster is no longer needed, delete it to stop any associated costs.</p><pre>az aks delete --name &lt;aks_cluster_name&gt; --resource-group &lt;resource_group&gt; --yes --no-wait</pre><p>2. <strong>Azure Container Registry (ACR)</strong></p><p>If you used Azure Container Registry (ACR) for storing your container images, delete it manually:</p><pre>az acr delete --name &lt;acr_name&gt; --resource-group &lt;resource_group&gt;</pre><p>3. <strong>Persistent Volumes (PVs)</strong></p><p>Any persistent volumes (e.g., Azure Disks or Azure Files) created for your AKS applications need to be manually deleted:</p><pre>kubectl delete pv &lt;pv_name&gt;</pre><p>4. <strong>Virtual Network (VNet) and Subnets</strong></p><p>If you created a custom <strong><em>Virtual Network (VNet)</em></strong> for the AKS cluster, delete it manually:</p><pre>az network vnet delete --name &lt;vnet_name&gt; --resource-group &lt;resource_group&gt;</pre><p><strong>5. Service Principal</strong></p><p>If you created a service principal for the AKS cluster’s managed identity, it will not be automatically deleted. Remove it manually:</p><pre>az ad sp delete --id &lt;service_principal_id&gt;</pre><p><strong>6. Kubernetes Resources (Optional)</strong></p><p>Any Kubernetes resources (e.g., secrets, configmaps, deployments) you created in the AKS cluster will persist. You can delete them using kubectl:</p><pre>kubectl delete all --all</pre><p>Ensure that any <strong><em>network security groups (NSGs)</em></strong><em>, </em><strong><em>public IP addresses</em></strong><em>,</em> and other associated resources are also cleaned up if not needed.</p><h3>Conclusion</h3><p>In this project, we set up a comprehensive CI/CD pipeline with<strong><em> Azure DevOps </em></strong>and integrated it with Kubernetes using <strong><em>ArgoCD</em></strong> for GitOps.</p><p>We utilized <strong><em>SonarQube</em></strong> for code quality analysis, <strong><em>OWASP</em></strong> <strong><em>Dependency-Check </em></strong>for scanning dependencies for known vulnerabilities, <strong><em>docker</em></strong> for building and pushing images, and <strong><em>Trivy</em></strong> for scanning Docker images.</p><p>The pipeline handled the complete flow from building, scanning, to deploying Docker images in <strong><em>AKS,</em> </strong>with updates managed by ArgoCD.</p><p>We also addressed troubleshooting common issues like <strong><em>ImagePullBackOff.</em></strong> Finally, we outlined the steps for cleaning up resources, including AKS, ACR, and custom VMs.</p><p>This workflow ensures automated deployment, monitoring, and security in a Kubernetes environment.</p><p><strong><em>Acknowledgment</em></strong></p><p>This project was significantly inspired by <strong><em>Abhishek Veeramalla</em></strong>, known for his excellent DevOps content. His content provided a solid foundation for my enhancement.</p><h3>Connect with me</h3><p>For more insights and future projects, feel free to connect with me on <a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> , </em></strong><a href="https://github.com/wangoimwangi"><strong><em>GitHub</em></strong></a><strong><em> , </em></strong><a href="https://mary-wangoi.medium.com/"><strong><em>Medium</em></strong></a><strong><em> and </em></strong><a href="https://linktr.ee/wangoimwangi"><strong><em>LinkTree</em></strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e0be5e613d32" width="1" height="1" alt=""><hr><p><a href="https://blog.devops.dev/ci-cd-pipeline-automation-with-azure-devops-argocd-kubernetes-e0be5e613d32">CI/CD Pipeline with Azure DevOps, ArgoCD, &amp; Kubernetes</a> was originally published in <a href="https://blog.devops.dev/">DevOps.dev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Containerizing a MERN stack Application and Deploying using Docker Compose]]></title>
            <link>https://blog.devops.dev/containerizing-a-mern-stack-application-and-deploying-using-docker-compose-46b85106039f?source=rss-25b8a3b45b96------2</link>
            <guid isPermaLink="false">https://medium.com/p/46b85106039f</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[docker-compose]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[docker]]></category>
            <dc:creator><![CDATA[Wangoi Mwangi]]></dc:creator>
            <pubDate>Wed, 02 Oct 2024 19:14:38 GMT</pubDate>
            <atom:updated>2024-10-04T16:07:42.271Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/493/1*V6qkyqo73mfxmYHX6tSRIA.png" /></figure><h3>Introduction</h3><p>The MERN stack, comprising MongoDB for the database, Express.js as the backend framework, React as the frontend library, and Node.js to run the backend server, is a popular choice for building modern web applications.</p><p>However, setting up and managing the different components of a MERN application can sometimes be cumbersome, especially when transitioning between development and production environments.</p><p>Containerization simplifies this process by packaging each component of the application into lightweight, standalone containers. Docker, one of the most widely used containerization platforms, allows developers to encapsulate their applications along with all dependencies, ensuring consistency across various environments.</p><p>In this article, I’ll walk through how to containerize a MERN stack application using Docker and deploy it seamlessly with Docker Compose. By the end, you’ll have a fully containerized MERN application running smoothly with minimal configuration effort, ready for scaling and deployment in any environment.</p><p><em>Feel free to connect with me on </em><a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> </em></strong><em>to discuss this post, or ask any questions.</em></p><h3>Cloning the Application from GitHub</h3><p><strong>1: Install Git</strong>: Ensure that Git is installed on your local machine. If it’s not installed, download and install it from <a href="https://git-scm.com/downloads">Git’s official website</a>.</p><p><strong>2: Open Terminal/Command Prompt</strong>: Open your terminal or command prompt where you will run Git commands.</p><p><strong>3: Clone the Repository</strong>: Use the git clone command followed by the URL of the repository you want to clone. You can find the <a href="https://github.com/wangoimwangi/MERN-docker-compose"><em>Source Code</em></a> here.</p><p>You can get this URL from the GitHub repository page (usually found under the <em>“Code”</em> button).</p><pre>git clone https://github.com/wangoimwangi/MERN-docker-compose.git</pre><p><strong>4: Navigate into the Cloned Directory</strong>: Once the cloning process is complete, navigate to the project folder.</p><pre>cd your-repository-name</pre><p>At this point, you should have a local copy of the MERN stack application, ready for containerization.</p><h3>Creating the Dockerfiles</h3><p>To containerize your MERN stack application, you’ll need to create two separate Dockerfiles: one for the frontend (React) and another for the backend (Node.js and Express). Each Dockerfile specifies how to build the respective Docker image for your application.</p><h4>Frontend Dockerfile</h4><p>Here’s the Dockerfile for the frontend:</p><pre># Use the official image as a parent image<br># Description: Dockerfile for the client side of the MERN stack application<br>FROM node:18.9.1<br><br># Set the working directory<br>WORKDIR /app<br><br># Copy the package.json file from your host to your current location in the container<br>COPY package.json ./<br><br># Install the dependencies defined in package.json<br>RUN npm install<br><br># Inform Docker that the container is listening on port 5173 at runtime<br>EXPOSE 5173<br><br># Copy the rest of your app&#39;s source code from your host to your image filesystem<br>COPY . .<br><br># Run the specified command within the container to start the application<br>CMD [&quot;npm&quot;, &quot;run&quot;, &quot;dev&quot;]</pre><p><strong>Explanation</strong>:</p><ol><li><strong>Base Image</strong>: We start with the official Node.js image (node:18.9.1), which provides the necessary environment to run a Node.js application.</li><li><strong>Working Directory</strong>: The WORKDIR /app command sets the working directory inside the container to /app, where all subsequent commands will be run.</li><li><strong>Copying package.json</strong>: The COPY package.json ./ command copies the package.json file from your local machine into the container, allowing us to install the necessary dependencies.</li><li><strong>Installing Dependencies</strong>: The RUN npm install command installs the application dependencies specified in package.json.</li><li><strong>Port Exposure</strong>: The EXPOSE 5173 command informs Docker that the container will listen on port 5173 at runtime.</li><li><strong>Copying Source Code</strong>: The COPY . . command copies the rest of the application source code into the container.</li><li><strong>Starting the Application</strong>: Finally, the CMD [&quot;npm&quot;, &quot;run&quot;, &quot;dev&quot;] command runs the application in development mode when the container starts.</li></ol><h4>Backend Dockerfile</h4><p>Here’s the Dockerfile for the backend:</p><pre>FROM node:18.9.1<br><br># Set the working directory<br>WORKDIR /app<br><br># Copy the package.json file from your host to your current location in the container<br>COPY package.json ./<br><br># Install the dependencies defined in package.json<br>RUN npm install<br><br># Copy the rest of your app&#39;s source code from your host to your image filesystem<br>COPY . .<br><br># Inform Docker that the container is listening on port 5050 at runtime<br>EXPOSE 5050<br><br># Run the specified command within the container to start the application<br>CMD [&quot;npm&quot;, &quot;start&quot;]</pre><p><strong>Explanation</strong>:</p><ol><li><strong>Base Image</strong>: Similar to the frontend, this Dockerfile also uses the official Node.js image.</li><li><strong>Working Directory</strong>: The working directory is set to /app.</li><li><strong>Copying package.json</strong>: The package.json file is copied into the container to install dependencies.</li><li><strong>Installing Dependencies</strong>: Dependencies are installed using RUN npm install.</li><li><strong>Copying Source Code</strong>: The COPY . . command brings the rest of the backend source code into the container.</li><li><strong>Port Exposure</strong>: The EXPOSE 5050 command indicates that the backend service will run on port 5050.</li><li><strong>Starting the Application</strong>: The CMD [&quot;npm&quot;, &quot;start&quot;] command starts the backend server when the container is launched.</li></ol><h4>Database</h4><p>In our MERN stack, we will be using <strong>MongoDB</strong> as the database to store and manage application data. For our Docker setup, we will use the official MongoDB image, which provides a lightweight and consistent environment for running MongoDB.</p><p>By creating these Dockerfiles, you’ve defined how to build the frontend and backend containers for your MERN stack application. Each Dockerfile encapsulates all necessary configurations, ensuring that your application can run consistently across different environments.</p><h3>Setting Up Docker Compose</h3><p>Docker Compose allows you to define and run multi-container Docker applications. In a MERN stack application, we typically have separate containers for the frontend, backend, and database (MongoDB). Setting up Docker Compose makes it easy to manage these containers as a single application.</p><h4>Creating the docker compose File</h4><ol><li>In the root directory of your MERN stack application, create a new file named docker-compose.yml.</li><li>Open the docker-compose.yml file in your preferred code editor and add the following configuration:</li></ol><pre>services:<br>  backend:<br>    build: ./mern/backend<br>    ports:<br>      - &quot;5050:5050&quot; <br>    networks:<br>      - mern_network<br>    environment:<br>      MONGO_URI: mongodb://mongo:27017/mydatabase  <br>    depends_on:<br>      - mongodb<br><br>  frontend:<br>    build: ./mern/frontend<br>    ports:<br>      - &quot;5173:5173&quot;  <br>    networks:<br>      - mern_network<br>    environment:<br>      REACT_APP_API_URL: http://backend:5050 <br><br>  mongodb:<br>    image: mongo:latest  <br>    ports:<br>      - &quot;27017:27017&quot;  <br>    networks:<br>      - mern_network<br>    volumes:<br>      - mongo-data:/data/db  <br><br>networks:<br>  mern_network:<br>    driver: bridge <br><br>volumes:<br>  mongo-data:<br>    driver: local  # Persist MongoDB data locally</pre><p><strong>Configuration Breakdown</strong>:</p><p><strong>Backend Service</strong>:</p><ul><li><strong>Build Context</strong>: The backend is built from the Dockerfile located in the ./mern/backend directory.</li><li><strong>Ports</strong>: Exposes port <strong>5050</strong> on the host, allowing access to the backend API.</li><li><strong>Network</strong>: Connected to mern_network for inter-service communication.</li><li><strong>Environment Variables</strong>: MONGO_URI is set to connect to the MongoDB service using the hostname mongo and the specified database (mydatabase).</li><li><strong>Dependency</strong>: The backend service depends on the MongoDB service, ensuring it starts only after the database is up.</li></ul><p><strong>Frontend Service</strong>:</p><ul><li><strong>Build Context</strong>: The frontend is built from the Dockerfile located in the ./mern/frontend directory.</li><li><strong>Ports</strong>: Exposes port <strong>5173</strong> for the frontend application.</li><li><strong>Network</strong>: Also connected to mern_network.</li><li><strong>Environment Variables</strong>: REACT_APP_API_URL is set to point to the backend service for API calls.</li></ul><p><strong>MongoDB Service</strong>:</p><ul><li><strong>Image</strong>: Uses the latest official MongoDB image.</li><li><strong>Ports</strong>: Exposes port <strong>27017</strong> for database connections.</li><li><strong>Network</strong>: Connected to mern_network.</li><li><strong>Volumes</strong>: mongo-data is mounted to persist MongoDB data across container restarts.</li></ul><p><strong>Networks</strong>: A custom network named mern_network is created to allow seamless communication between the services.</p><p><strong>Volumes</strong>: The mongo-data volume is defined to ensure that MongoDB data is stored persistently on the local system, safeguarding against data loss.</p><p>This configuration ensures that all components of the MERN stack are well-integrated and can communicate effectively, providing a solid foundation for development and deployment.</p><h4>Running the Application</h4><p>With your docker-compose.yml file set up, you can now build and run your MERN stack application using Docker Compose.</p><ol><li>Open your terminal in the root directory of your project (where the docker-compose.yml file is located).</li><li>Run the following command to start the application:</li></ol><pre>docker-compose up --build</pre><p>The --build flag ensures that Docker Compose builds the images as specified in your Dockerfiles.</p><p>This command will:</p><ul><li>Build the Docker images for the frontend and backend.</li><li>Start the MongoDB service and initialize it with the specified volume for persistent data storage.</li><li>Start the backend and frontend services, making them accessible on the configured ports.</li></ul><p>3. Once the services are up and running, you can access your frontend at http://localhost:5173 and your backend at <a href="http://localhost:5050.">http://localhost:5050</a></p><p>4. When you’re finished testing or using the application, you can stop the running services by pressing CTRL + C in the terminal where Docker Compose is running.</p><p>To remove the containers and associated networks, run:</p><pre>docker-compose down</pre><h3><strong>Conclusion</strong></h3><p>By following these steps, you’ve successfully containerized a MERN stack application and deployed it using Docker Compose. This setup not only simplifies development but also ensures that your application is consistent across various environments. You can now focus on building features and scaling your application, confident in the robust infrastructure you’ve established.</p><h3>Connect with me</h3><p>For more insights and future projects, feel free to connect with me on <a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> , </em></strong><a href="https://github.com/wangoimwangi"><strong><em>GitHub</em></strong></a><strong><em> </em></strong>and<strong> </strong><a href="https://mary-wangoi.medium.com/"><strong><em>Medium.</em></strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=46b85106039f" width="1" height="1" alt=""><hr><p><a href="https://blog.devops.dev/containerizing-a-mern-stack-application-and-deploying-using-docker-compose-46b85106039f">Containerizing a MERN stack Application and Deploying using Docker Compose</a> was originally published in <a href="https://blog.devops.dev/">DevOps.dev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Comprehensive DevOps Implementation]]></title>
            <link>https://blog.devops.dev/comprehensive-devops-implementation-project-b5ae52c2bbfa?source=rss-25b8a3b45b96------2</link>
            <guid isPermaLink="false">https://medium.com/p/b5ae52c2bbfa</guid>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[docker]]></category>
            <dc:creator><![CDATA[Wangoi Mwangi]]></dc:creator>
            <pubDate>Mon, 05 Aug 2024 08:40:04 GMT</pubDate>
            <atom:updated>2024-09-13T10:20:01.609Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/796/1*hF4GExYEVQ5QKbxZaw5QQw.png" /></figure><h3>Introduction</h3><p>This project focuses on deploying a Go application using modern DevOps practices. The goal is to build and run the application locally, then containerize it and deploy it to a Kubernetes environment. Key components of this project include:</p><ul><li><strong>Local Development</strong>: Building and running the Go application on a local machine.</li><li><strong>Dockerfile Creation</strong>: Creating a multistage Dockerfile for efficient containerization.</li><li><strong>Containerization</strong>: Using Docker to package the application into containers.</li><li><strong>AWS EKS Cluster</strong>: Setting up and configuring an Amazon EKS (Elastic Kubernetes Service) cluster.</li><li><strong>Kubernetes Manifests</strong>: Writing Kubernetes manifests for deployment and management.</li><li><strong>Ingress Controller</strong>: Installing and configuring an Ingress Controller for managing external access to the application.</li><li><strong>Local DNS Mapping</strong>: Configure Local DNS mapping to access the application via a custom domain.</li><li><strong>Helm</strong>: Using Helm to simplify and manage Kubernetes deployments.</li><li><strong>Continuous Integration</strong>: Implementing Continuous Integration (CI) with GitHub Actions for automated testing and building.</li><li><strong>Continuous Deployment</strong>: Using Argo CD for automated deployment of changes to the Kubernetes cluster, ensuring seamless updates and rollouts.</li></ul><p>This project demonstrates a comprehensive approach to building, deploying, and managing containerized applications in a Kubernetes environment, leveraging CI/CD best practices for efficient and reliable software delivery.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mtGTxTdYxTUBY1k-bupGjQ.png" /></figure><p><em>Feel free to connect with me on </em><a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> </em></strong><em>to discuss this post, or ask any questions.</em></p><h3>Cloning the Application from GitHub</h3><p><strong>1: Install Git</strong>: Ensure that Git is installed on your local machine. If it’s not installed, download and install it from <a href="https://git-scm.com/downloads">Git’s official website</a>.</p><p><strong>2: Open Terminal/Command Prompt</strong>: Open your terminal or command prompt where you will run Git commands.</p><p><strong>3: Navigate to the Desired Directory</strong>: Change to the directory where you want to clone the repository. Use the cd command to navigate:</p><pre>cd /path/to/your/directory</pre><p><strong>4: Clone the Repository</strong>: Use the git clone command followed by the URL of the repository you want to clone. You can find the <a href="https://github.com/wangoimwangi/go-web-app-devops"><em>Source Code</em></a> here.</p><p>You can get this URL from the GitHub repository page (usually found under the <em>“Code”</em> button).</p><pre>git clone https://github.com/wangoimwangi/go-web-app-devops.git</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sdNLLTyDcxooxOPzhS-rXA.png" /></figure><p><strong>5: Navigate into the Cloned Directory</strong>: Change to the directory of the cloned repository:</p><pre>cd your-repository</pre><p><strong>6: Verify the Clone</strong>: List the files in the directory to ensure that the repository has been cloned correctly:</p><pre>ls</pre><p>You now have the source code of the application on your local machine and can start working on it.</p><h3>Build and Run the Go Application Locally</h3><p>Before you containerize the Go application, it’s important to understand its functionality by building and running it locally.</p><p>This will help you verify that the application works as expected and give you a clear understanding of its behavior.</p><p><strong>1: Ensure Go is Installed</strong>: Make sure that Go is installed on your local machine. If it’s not installed, download and install it from <a href="https://golang.org/dl/"><em>Go’s official website</em></a><em>.</em></p><p><strong>2:Navigate to the Application Directory</strong>: Open your terminal and change to the directory where your Go application’s source code is located. Use the cd command.</p><p><strong>3: Build the Application</strong>: Run go build: This command compiles the Go source code into an executable binary. Execute the following command in the terminal:</p><pre>go build -o main .</pre><p>This will create an executable file named myapp (you can name it anything you like).</p><p><strong>4: Run the Application</strong>: Run the compiled binary to start the application</p><pre>go run main.go</pre><p><strong>5: Access the Application</strong>: Open your browser and navigate to <a href="http://localhost:8080/courses">http://localhost:8080/courses</a> to interact with the application.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XbzttanVN9xDPxjwjdsYHg.png" /></figure><p><strong>6: Observe Output</strong>: Check the application’s output and behavior to understand how it works.</p><h3>Creating a Multistage Dockerfile</h3><p>To containerize the Go application efficiently, we use a multistage Dockerfile. This approach helps in minimizing the final image size and ensuring a clean, production-ready environment.</p><p>Below is the Dockerfile used for this purpose:</p><pre># Containerize the go application that we have created<br># This is the Dockerfile that we will use to build the image<br># and run the container</pre><pre># Start with a base image<br>FROM golang:1.21 as base</pre><pre># Set the working directory inside the container<br>WORKDIR /app</pre><pre># Copy the go.mod and go.sum files to the working directory<br>COPY go.mod ./</pre><pre># Download all the dependencies<br>RUN go mod download</pre><pre># Copy the source code to the working directory<br>COPY . .</pre><pre># Build the application<br>RUN go build -o main .</pre><pre>#######################################################<br># Reduce the image size using multi-stage builds<br># We will use a distroless image to run the application<br>FROM gcr.io/distroless/base</pre><pre># Copy the binary from the previous stage<br>COPY --from=base /app/main .</pre><pre># Copy the static files from the previous stage<br>COPY --from=base /app/static ./static</pre><pre># Expose the port on which the application will run<br>EXPOSE 8080</pre><pre># Command to run the application<br>CMD [&quot;./main&quot;]</pre><p><strong>Explanation:</strong></p><ol><li><strong>Base Image</strong>: The Dockerfile starts with the golang:1.21 image, which contains the Go runtime and tools necessary for building the application.</li><li><strong>Setup Working Directory</strong>: Sets /app as the working directory inside the container.</li><li><strong>Dependency Management</strong>: Copies go.mod and go.sum and runs go mod download to fetch dependencies.</li><li><strong>Application Code</strong>: Copies the application source code into the container and builds the Go application.</li><li><strong>Multistage Build</strong>: Switches to a distroless image to run the application, reducing the final image size by including only the runtime environment and the compiled binary.</li><li><strong>Copy Binaries and Static Files</strong>: Copies the built binary and any static files from the previous stage.</li><li><strong>Expose Port</strong>: Exposes port 8080 for accessing the application.</li><li><strong>Run Command</strong>: Specifies the command to run the application when the container starts.</li></ol><p>This Dockerfile ensures that the final image is lightweight and secure, focusing solely on running the application with minimal overhead.</p><h3>Containerization</h3><p>Containerization packages your application and its dependencies into a container, which can be consistently run on any container platform.</p><p>Here’s how to containerize your Go web application using Docker:</p><p><strong>Prerequisites:</strong></p><p><strong>1: Install Docker</strong>: Download and install Docker from Docker’s official website if it’s not already installed.</p><p><strong>2: Install Docker Desktop</strong>:</p><ul><li><strong>Windows/Mac Users</strong>: Download and install Docker Desktop from Docker’s official website. Docker Desktop is necessary for managing Docker containers and provides a graphical user interface.</li><li><strong>Linux Users</strong>: Install Docker Engine by following the instructions on Docker’s official website. Docker Desktop is not available for Linux, but Docker Engine will allow you to run Docker containers.</li></ul><p><strong>3: Sign Up for a DockerHub Account</strong>: If you don’t have a DockerHub account, sign up at DockerHub to create one. DockerHub is a cloud-based registry service for Docker images and doesn’t require installation.</p><p><strong>4: Ensure Docker Daemon is Running</strong>:</p><ul><li><strong>Windows/Mac Users</strong>: Ensure Docker Desktop is running.</li><li><strong>Linux Users</strong>: Verify that the Docker service is running with:</li></ul><pre>sudo systemctl start docker</pre><ul><li>You can check its status with:</li></ul><pre>sudo systemctl status docker</pre><p>With these prerequisites in place, you’re ready to start containerizing your application.</p><h4>Commands to Build, Run, and Push the Docker Container:</h4><p><strong><em>Build the Docker Image:</em></strong></p><pre>docker build -t &lt;your-docker-username&gt;/go-web-app .</pre><p>Replace &lt;your-docker-username&gt; with your DockerHub username. This tags the image for uploading to DockerHub.</p><p><strong><em>Log In to DockerHub</em></strong><em>:</em></p><p>Enter your DockerHub credentials to authenticate your Docker client.</p><pre>docker login</pre><p><strong><em>Run the Docker Container</em></strong><em>:</em></p><p>This command maps port 8080 on your host to port 8080 in the container.</p><pre>docker run -p 8080:8080 -d &lt;your-docker-username&gt;/go-web-app</pre><p><strong><em>Push the Docker Image to DockerHub</em></strong><em>:</em></p><p>This uploads the image to DockerHub, making it accessible from anywhere.</p><pre>docker push &lt;your-docker-username&gt;/go-web-app</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aCu5BqwGaP2286-s7El8sg.png" /></figure><p><strong><em>Verify the Image on DockerHub</em></strong><em>:</em></p><p>Log in to your DockerHub account at DockerHub.</p><p>Navigate to your repository and ensure the pushed image appears under the tags section. This confirms that your image was successfully uploaded.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*x6SckXMCoNZam35O1cngCg.png" /></figure><p><strong><em>Access the Application</em></strong><em>:</em></p><p>Open your browser and navigate to <a href="http://localhost:8080/courses">http://localhost:8080/courses</a> to interact with the running application.</p><h3>AWS EKS Cluster Setup</h3><p>Setting up an AWS EKS (Elastic Kubernetes Service) cluster involves several key steps. Follow this guide to get your EKS cluster up and running.</p><h4>Prerequisites</h4><p>Before you begin, ensure you have the following tools installed and configured:</p><ul><li><strong>kubectl</strong>: A command-line tool for working with Kubernetes clusters. For more information on installing or updating kubectl, see the <a href="https://kubernetes.io/docs/tasks/tools/">official documentation.</a></li><li><strong>eksctl</strong>: A command-line tool for working with EKS clusters that automates many tasks. For more information on installing or updating eksctl, see the <a href="https://github.com/eksctl-io/eksctl#installation">eksctl documentation.</a></li><li><strong>AWS CLI</strong>: A command-line tool for working with AWS services, including Amazon EKS. For more information on installing, updating, and uninstalling the AWS CLI, see the <a href="https://aws.amazon.com/cli/">AWS CLI User Guide.</a></li></ul><p>After installing the AWS CLI, configure it with:</p><pre>aws configure</pre><p>Verify all the tools are installed successfully by checking their versions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/842/1*n50otg3ly9rS0RzZDUlEyg.png" /></figure><h4>Install and Configure EKS</h4><p>Use eksctl to create the cluster:</p><pre>eksctl create cluster --name demo-cluster --region us-east-1</pre><p><strong>Note:</strong> <em>The EKS cluster creation process can take several minutes to complete. Please be patient during this step. Be aware that creating an EKS cluster will incur charges. If cost is a concern, consider deploying your application on Minikube as an alternative.</em></p><p>Update kubectl to use the new EKS cluster</p><pre>aws eks --region us-east-1 update-kubeconfig --name demo-cluster</pre><p>Verify via the AWS Console manager that the EKS Cluster is created.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Mujn6oAoRHSxa2_8FNqWXw.png" /></figure><p>Check the status of your nodes to ensure they are running:</p><pre>kubectl get nodes</pre><h4>Set Up Networking and IAM Roles</h4><ul><li><strong>Configure Networking</strong>: Ensure your VPC, subnets, and security groups are properly configured to allow traffic to and from your EKS cluster.</li><li><strong>Set Up IAM Roles</strong>: Verify that IAM roles for EKS and worker nodes are correctly configured with the necessary permissions.</li></ul><h3>Kubernetes Manifest Creation</h3><p>To deploy your containerized Go application to a Kubernetes cluster, you need to create several Kubernetes manifests.</p><p>These manifests define how your application is deployed, exposed, and accessed.</p><p>Create a folder calledK8s then inside the K8s folder, create another folder named manifests. Inside the manifests folder, create the following files: deployment.yaml, service.yaml, ingress.yaml</p><p><strong>1: Create </strong><strong>deployment.yaml</strong>: This manifest defines how your application is deployed, including the number of replicas and the Docker image to use.</p><p>Replace &lt;docker-user-name&gt; with your DockerHub username.</p><pre># This is a sample deployment manifest file for a simple web application.<br>apiVersion: apps/v1<br>kind: Deployment<br>metadata:<br>  name: go-web-app<br>  labels:<br>    app: go-web-app<br>spec:<br>  replicas: 1<br>  selector:<br>    matchLabels:<br>      app: go-web-app<br>  template:<br>    metadata:<br>      labels:<br>        app: go-web-app<br>    spec:<br>      containers:<br>      - name: go-web-app<br>        image: &lt;docker-user-name&gt;/go-web-app<br>        ports:<br>        - containerPort: 8080</pre><p><strong>2. Create </strong><strong>service.yaml</strong>: This manifest defines how your application is exposed within the Kubernetes cluster. It creates a Service that routes traffic to your application pods.</p><pre># Service for the application<br>apiVersion: v1<br>kind: Service<br>metadata:<br>  name: go-web-app<br>  labels:<br>    app: go-web-app<br>spec:<br>  ports:<br>  - port: 80<br>    targetPort: 8080<br>    protocol: TCP<br>  selector:<br>    app: go-web-app<br>  type: ClusterIP</pre><p><strong>3: Create </strong><strong>ingress.yaml</strong>: This manifest defines how your application is exposed to the outside world. It creates an Ingress resource that manages external access to the application.</p><p>Replace go-web-app.local with your actual domain or IP address if needed.</p><pre># Ingress resource for the application<br>apiVersion: networking.k8s.io/v1<br>kind: Ingress<br>metadata:<br>  name: go-web-app<br>  annotations:<br>    nginx.ingress.kubernetes.io/rewrite-target: /<br>spec:<br>  ingressClassName: nginx<br>  rules:<br>  - host: go-web-app.local<br>    http:<br>      paths: <br>      - path: /<br>        pathType: Prefix<br>        backend:<br>          service:<br>            name: go-web-app<br>            port:<br>              number: 80</pre><p><strong>4. Apply the Manifests</strong>: Use kubectl to apply these manifests to your EKS cluster:</p><pre>kubectl apply -f K8s/manifests/deployment.yaml</pre><pre>kubectl apply -f K8s/manifests/service.yaml</pre><pre>kubectl apply -f K8s/manifests/ingress.yaml</pre><p><strong>5. Verify Deployment</strong>: Ensure your pods, services, and ingress are running correctly.</p><pre>kubectl get pods</pre><pre>kubectl get services</pre><pre>kubectl get ingress</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/947/1*OpJW8hQHIhdcyCgwmywr1A.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*R4-AZhkpMS56HlPbwpJAUA.png" /></figure><h3>Ingress Controller Setup</h3><p>An <strong>Ingress Controller</strong> manages and routes external traffic to services within your Kubernetes cluster. It listens for changes to <strong>Ingress Resources</strong>, which define how external HTTP and HTTPS requests are directed to your services.</p><p>The Ingress Controller configures the underlying load balancer or proxy (e.g., NGINX) based on the rules specified in the Ingress Resources, handling routing, SSL termination, and other traffic management tasks.</p><p>To manage external access to your services running on an AWS EKS cluster, you’ll need to set up an NGINX Ingress Controller.</p><ol><li><strong>Deploy NGINX Ingress Controller</strong></li></ol><p><strong>Apply the NGINX Ingress Controller Manifest</strong>:</p><ul><li>Run the following kubectl command to deploy the NGINX Ingress Controller:</li></ul><pre>kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.1/deploy/static/provider/aws/deploy.yaml</pre><ul><li>This manifest sets up the NGINX Ingress Controller, which will handle routing external requests to the appropriate services within your cluster.</li></ul><p><strong>2. Verify the Installation</strong></p><p><strong>Check the Status of the Ingress Controller Pods</strong>:</p><ul><li>Ensure that the NGINX Ingress Controller pods are running</li></ul><pre>kubectl get pods -n ingress-nginx</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ICKicWo86-PzqNGNHdXBIg.png" /></figure><p><strong>Check the Service</strong>:</p><ul><li>Verify that the NGINX Ingress Controller service is properly set up and accessible:</li></ul><pre>kubectl get services -n ingress-nginx</pre><p><strong>Verify the Load Balancer</strong></p><ul><li>Check if the Load Balancer is created in the AWS Management Console.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1hBRPjqfqY34BuDJMy4AGA.png" /></figure><p><strong>Check the Ingress Controller Logs</strong>:</p><ul><li>To troubleshoot or verify that the controller is working correctly, you can check the logs of the Ingress Controller pods:</li></ul><pre>kubectl logs -n ingress-nginx &lt;nginx-ingress-controller-pod-name&gt;</pre><p>By following these steps, you will have the NGINX Ingress Controller set up and ready to manage inbound traffic to your applications deployed on AWS EKS.</p><h3>Setting Up Local DNS Mapping</h3><p>To access your application using a custom domain like go-web-app.local, as specified in our ingress rules in <em>ingress.yaml file</em> you&#39;ll need to set up a local DNS mapping.</p><p>This will allow you to use the domain name specified in the Ingress Resource (go-web-app.local) instead of relying on the IP address provided by the Load Balancer. Here’s how to do it:</p><p><strong>Steps to Set Up Local DNS Mapping</strong></p><p><strong>1: Obtain the Load Balancer IP Address</strong></p><ul><li>Navigate to the <strong><em>EC2 Dashboard</em></strong> in the AWS Management Console.</li><li>Select <strong><em>Load Balancers</em></strong> from the left-hand menu.</li><li>Locate the Load Balancer associated with the NGINX Ingress Controller.</li><li>Copy the <strong><em>DNS Name</em></strong> of the Load Balancer (e.g., abc123.elb.amazonaws.com).</li><li>Use the DNS Name to find the Load Balancer’s public IP address or resolve the DNS name to an IP address using a command like:</li></ul><pre>nslookup &lt;Load-Balancer-DNS-Name&gt;</pre><p><strong>2: Edit the Hosts File</strong></p><ul><li><strong><em>For Windows:</em></strong></li></ul><p>a) Open Notepad or your preferred text editor as an administrator (right-click and select <em>“Run as administrator”</em>).</p><p>b) Open the file located at C:\Windows\System32\drivers\etc\hosts.</p><p>c) Add a new entry mapping the Load Balancer’s IP address to the domain name:</p><pre>&lt;Load-Balancer-IP&gt; go-web-app.local</pre><p>d) Save the changes to the hosts file.</p><ul><li><strong><em>For macOS and Linux:</em></strong></li></ul><p>a) Open a terminal.</p><p>b) Use a text editor with sudo to open the file located at /etc/hosts</p><pre>sudo nano /etc/hosts</pre><p>c) Add a new entry mapping the Load Balancer’s IP address to the domain name:</p><pre>&lt;Load-Balancer-IP&gt; go-web-app.local</pre><p>d) Save and exit the editor (e.g., press Ctrl+X, then Y to confirm in nano).</p><p><strong>3: Verify the Local DNS Mapping</strong></p><ul><li>Open your web browser and navigate to <a href="http://go-web-app.local/courses.">http://go-web-app.local/courses</a></li><li>Ensure that the application loads correctly and that you can access it via the specified domain.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/930/1*INUAhtxkVDooV-ZwUyFPxg.png" /></figure><p>By setting up this local DNS mapping, you ensure that requests to go-web-app.local are directed to your application&#39;s Load Balancer, matching the domain name specified in your Ingress Resource.</p><h3>Helm Chart Configuration</h3><p>Helm is a package manager for Kubernetes that helps manage Kubernetes applications using Helm charts.</p><p>Helm simplifies the deployment and management of applications on Kubernetes by packaging all necessary configurations into a single chart.</p><p><strong>Helm Chart Structure</strong></p><p>A Helm chart consists of several key components that define how your application is deployed and managed in Kubernetes:</p><p><strong><em>a) Chart.yaml</em></strong></p><p>This file contains metadata about the Helm chart, including its name, version, and description.</p><p><strong><em>b) values.yaml</em></strong></p><p>This is the default configuration file for the chart. It defines values that can be customized to modify the behavior of the chart without changing the underlying templates.</p><p>Users can override these values when deploying the chart.</p><p><strong><em>c) templates/</em></strong></p><p>This directory contains Kubernetes manifest templates that define the resources for your application, such as deployments, services, and ingresses.</p><p>Helm renders these templates into Kubernetes manifests using the values specified in values.yaml.</p><p><strong><em>d) charts/</em></strong></p><p>This directory can contain any sub-charts that your chart depends on. These are other Helm charts packaged as dependencies.</p><p><strong><em>e) README.md</em></strong></p><p><em>(Optional)</em> This file provides documentation about the chart, including how to use and configure it.</p><p><strong>Steps to Configure and Deploy Using Helm</strong></p><p><strong><em>a) Install Helm</em></strong></p><ul><li>Follow the official Helm installation guide to install Helm on your local machine.</li></ul><p><strong><em>b) Create a Helm Chart</em></strong></p><ul><li>Create a new Helm chart for your application:</li></ul><pre>helm create go-web-app-chart</pre><p>This command creates a directory named go-web-app-chart with a default chart structure.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/702/1*IXAbc6N_siSlBV4s8zF53w.png" /></figure><p><em>c) </em><strong><em>Customize the Helm Chart</em></strong></p><ul><li>Navigate to the go-web-app-chart directory</li></ul><pre>cd go-web-app-chart</pre><ul><li>Modify the templates/deployment.yaml, templates/service.yaml, and templates/ingress.yaml if necessary to suit your application’s specific needs. Use the manifest files we created before.</li></ul><p>templates/deployment.yaml</p><pre># This is a sample deployment manifest file for a simple web application.<br>apiVersion: apps/v1<br>kind: Deployment<br>metadata:<br>  name: go-web-app<br>  labels:<br>    app: go-web-app<br>spec:<br>  replicas: 1<br>  selector:<br>    matchLabels:<br>      app: go-web-app<br>  template:<br>    metadata:<br>      labels:<br>        app: go-web-app<br>    spec:<br>      containers:<br>      - name: go-web-app<br>        image: abhishekf5/go-web-app:{{ .Values.image.tag }}<br>        ports:<br>        - containerPort: 8080</pre><p>templates/service.yaml</p><pre># Service for the application<br>apiVersion: v1<br>kind: Service<br>metadata:<br>  name: go-web-app<br>  labels:<br>    app: go-web-app<br>spec:<br>  ports:<br>  - port: 80<br>    targetPort: 8080<br>    protocol: TCP<br>  selector:<br>    app: go-web-app<br>  type: ClusterIP</pre><p>templates/ingress.yaml</p><pre># Ingress resource for the application<br>apiVersion: networking.k8s.io/v1<br>kind: Ingress<br>metadata:<br>  name: go-web-app<br>  annotations:<br>    nginx.ingress.kubernetes.io/rewrite-target: /<br>spec:<br>  rules:<br>  - host: go-web-app.local<br>    http:<br>      paths: <br>      - path: /<br>        pathType: Prefix<br>        backend:<br>          service:<br>            name: go-web-app<br>            port:<br>              number: 80</pre><ul><li>Customize the default values.yaml file to match your application’s configuration:</li></ul><pre># Default values for go-web-app-chart.<br># This is a YAML-formatted file.<br># Declare variables to be passed into your templates.</pre><pre>replicaCount: 1</pre><pre>image:<br>  repository: abhishekf5/go-web-app<br>  pullPolicy: IfNotPresent<br>  # Overrides the image tag whose default is the chart appVersion.<br>  tag: &quot;10016307834&quot;</pre><pre>ingress:<br>  enabled: false<br>  className: &quot;&quot;<br>  annotations: {}<br>    # kubernetes.io/ingress.class: nginx<br>    # kubernetes.io/tls-acme: &quot;true&quot;<br>  hosts:<br>    - host: chart-example.local<br>      paths:<br>        - path: /<br>          pathType: ImplementationSpecific</pre><p><em>d) </em><strong><em>Package and Deploy the Helm Chart</em></strong></p><ul><li>Package the Helm chart:</li></ul><pre>helm package go-web-app-chart</pre><ul><li>Deploy the Helm chart to your Kubernetes cluster:</li></ul><pre>helm install go-web-app-chart ./go-web-app-chart-&lt;version&gt;.tgz</pre><p>Replace &lt;version&gt; with the actual version number of the chart, such as 1.0.0, for example, go-web-app-1.0.0.tgz.</p><p><em>e) </em><strong><em>Verify the Deployment</em></strong></p><ul><li>Check the status of the deployed application:</li></ul><pre>kubectl get all -l app=go-web-app</pre><p>Ensure that the application is running as expected and that the Ingress rules are applied correctly.</p><p>By following these steps, you’ll configure and deploy your application using Helm, allowing for simplified management and updates of your Kubernetes resources.</p><h3>Continuous Integration with GitHub Actions</h3><p>Continuous Integration (CI) is a key part of the DevOps pipeline that automates the process of integrating code changes into a shared repository frequently.</p><p>GitHub Actions allows you to create workflows that build, test, and deploy your application automatically.</p><p><strong>Steps to Configure CI with GitHub Actions</strong></p><p><strong><em>a) Create a GitHub Actions Workflow File</em></strong></p><ul><li>In your GitHub repository, navigate to the .github/workflows directory. If it doesn’t exist, create it.</li><li>Create a new YAML file for your workflow, such as ci.yml.</li></ul><p><strong><em>b) Define the Workflow</em></strong></p><ul><li>Open ci.yml and define the workflow using the following template:</li></ul><pre># CICD using GitHub actions</pre><pre>name: CI/CD</pre><pre># Exclude the workflow to run on changes to the helm chart<br>on:<br>  push:<br>    branches:<br>      - main<br>    paths-ignore:<br>      - &#39;helm/**&#39;<br>      - &#39;k8s/**&#39;<br>      - &#39;README.md&#39;</pre><pre>jobs:</pre><pre>build:<br>    runs-on: ubuntu-latest</pre><pre>steps:<br>    - name: Checkout repository<br>      uses: actions/checkout@v4</pre><pre>- name: Set up Go 1.22<br>      uses: actions/setup-go@v2<br>      with:<br>        go-version: 1.22</pre><pre>- name: Build<br>      run: go build -o go-web-app</pre><pre>- name: Test<br>      run: go test ./...<br>  <br>  code-quality:<br>    runs-on: ubuntu-latest</pre><pre>steps:<br>    - name: Checkout repository<br>      uses: actions/checkout@v4</pre><pre>- name: Run golangci-lint<br>      uses: golangci/golangci-lint-action@v6<br>      with:<br>        version: v1.56.2<br>  <br>  push:<br>    runs-on: ubuntu-latest</pre><pre>needs: build</pre><pre>steps:<br>    - name: Checkout repository<br>      uses: actions/checkout@v4</pre><pre>- name: Set up Docker Buildx<br>      uses: docker/setup-buildx-action@v1</pre><pre>- name: Login to DockerHub<br>      uses: docker/login-action@v3<br>      with:<br>        username: ${{ secrets.DOCKERHUB_USERNAME }}<br>        password: ${{ secrets.DOCKERHUB_TOKEN }}</pre><pre>- name: Build and Push action<br>      uses: docker/build-push-action@v6<br>      with:<br>        context: .<br>        file: ./Dockerfile<br>        push: true<br>        tags: ${{ secrets.DOCKERHUB_USERNAME }}/go-web-app:${{github.run_id}}</pre><pre>update-newtag-in-helm-chart:<br>    runs-on: ubuntu-latest</pre><pre>needs: push</pre><pre>steps:<br>    - name: Checkout repository<br>      uses: actions/checkout@v4<br>      with:<br>        token: ${{ secrets.TOKEN }}</pre><pre>- name: Update tag in Helm chart<br>      run: |<br>        sed -i &#39;s/tag: .*/tag: &quot;${{github.run_id}}&quot;/&#39; helm/go-web-app-chart/values.yaml</pre><pre>- name: Commit and push changes<br>      run: |<br>        git config --global user.email &quot;&lt;your-git-email-address&gt;&quot;<br>        git config --global user.name &quot;&lt;your-git-username&gt;&quot;<br>        git add helm/go-web-app-chart/values.yaml<br>        git commit -m &quot;Update tag in Helm chart&quot;<br>        git push</pre><p><em>Replace values &lt;your-git-email-address&gt; and &lt;your-git-username&gt;</em> <em>with your actual values.</em></p><p>If you are not sure of the syntax of action to put on your workflow google search <em>“githubactions market place”</em></p><h4>Workflow Breakdown:</h4><p><strong><em>a) Trigger</em></strong></p><ul><li><strong>on: push</strong>: Runs the workflow on pushes to the main branch, excluding changes in specified paths like Helm charts and Kubernetes manifests.</li></ul><p><strong><em>b) Jobs</em></strong></p><p><strong><em>build</em></strong>:</p><ul><li><strong>Checkout repository</strong>: Checks out the repository code.</li><li><strong>Set up Go</strong>: Configures the Go environment.</li><li><strong>Build</strong>: Compiles the Go application.</li><li><strong>Test</strong>: Runs tests for the application.</li></ul><p><strong><em>code-quality</em></strong>:</p><ul><li><strong>Checkout repository</strong>: Checks out the repository code.</li><li><strong>Run golangci-lint</strong>: Executes golangci-lint to perform linting and check for code quality issues.</li></ul><p><strong>push</strong>:</p><ul><li><strong>Checkout repository</strong>: Checks out the repository code.</li><li><strong>Set up Docker Buildx</strong>: Configures Docker Buildx for building multi-platform images.</li><li><strong>Login to DockerHub</strong>: Authenticates to Docker Hub using secrets.</li><li><strong>Build and Push Docker Image</strong>: Builds and pushes the Docker image to Docker Hub with a tag based on the GitHub run ID.</li></ul><p><strong><em>update-newtag-in-helm-chart</em></strong>:</p><ul><li><strong>Checkout repository</strong>: Checks out the repository code.</li><li><strong>Update tag in Helm chart</strong>: Updates the image tag in the Helm chart values file.</li><li><strong>Commit and push changes</strong>: Commits and pushes the updated Helm chart to the repository.</li></ul><p><strong><em>c) Set Up DockerHub Credentials</em></strong></p><ul><li><strong><em>Log in to GitHub</em></strong><em>:</em> Navigate to your repository.</li><li><strong><em>Go to Settings</em></strong><em>: </em>Click on the “<em>Settings”</em> tab.</li><li><strong><em>Select Secrets and Variables</em></strong><em>:</em> Choose <em>“Secrets and Variables”</em> and then <em>“Actions”</em>.</li><li><strong><em>Add New Repository Secret</em></strong><em>:</em> Add the necessary secrets for DockerHub credentials:</li></ul><p><strong>DOCKERHUB_USERNAME</strong>: Your DockerHub username.</p><p><strong>DOCKERHUB_TOKEN</strong>: A personal access token or password for DockerHub.</p><p>Ensure that your CI workflow (GitHub Actions YAML file) uses these secrets to authenticate with DockerHub.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/943/1*H4INc3_adoTSGbIBrACNvA.png" /></figure><p><strong><em>d) Push the Workflow File</em></strong></p><ul><li>Commit and push the ci.yml file to your GitHub repository</li></ul><pre>git add .github/workflows/ci.yml<br>git commit -m &quot;Add GitHub Actions CI workflow&quot;<br>git push</pre><p><strong><em>e) Monitor CI Runs</em></strong></p><ul><li>Go to the <strong><em>Actions</em></strong> tab in your GitHub repository to view the progress and results of your CI runs.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AqwpvkxHtm3QkvRJDILlLQ.png" /></figure><p>By following this setup, you ensure that code changes trigger automated builds, tests, and deployments, integrating seamlessly into your development workflow.</p><h3>Continuous Delivery with ArgoCD</h3><p><strong>ArgoCD</strong> is a declarative, GitOps continuous delivery tool for Kubernetes. It enables you to manage and automate your application deployments directly from Git repositories.</p><p>Here’s how to set up ArgoCD in your Kubernetes environment:</p><h4>Step 1: Install ArgoCD</h4><p><strong><em>a) Create a Namespace for ArgoCD</em></strong></p><pre>kubectl create namespace argocd</pre><p><strong><em>b) Apply the ArgoCD Manifests</em></strong></p><pre>kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml</pre><h4>Step 2: Expose the ArgoCD UI</h4><p><strong>a) Change the Service Type to LoadBalancer</strong></p><p>For Linux/MacOS:</p><pre>kubectl patch svc argocd-server -n argocd -p &#39;{&quot;spec&quot;: {&quot;type&quot;: &quot;LoadBalancer&quot;}}&#39;</pre><p>For Windows:</p><pre>kubectl patch svc argocd-server -n argocd -p &#39;{\&quot;spec\&quot;: {\&quot;type\&quot;: \&quot;LoadBalancer\&quot;}}&#39;</pre><p><strong>b) Retrieve the Load Balancer IP</strong></p><pre>kubectl get svc argocd-server -n argocd</pre><p>This command will provide you with the external IP address of the ArgoCD server.</p><h4>Step 3: Access the ArgoCD UI</h4><p>Open your web browser and navigate to the Load Balancer IP address obtained from the previous step. You can access the ArgoCD UI from there.</p><p>However, Instead of using the Load Balancer IP address directly, you can set up a local DNS entry or update your DNS settings to map a domain name <em>(go-web-app.local)</em> to the Load Balancer IP for the ArgoCD UI just like we did in the ingress section of this project.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/842/1*PAaZhZNzH88nGVtoKk7vFw.png" /></figure><h4>Step 4: Retrieve ArgoCD Admin Password</h4><p><strong><em>Get the Initial Admin Password</em></strong></p><p>Retrieve the password using the following command</p><pre>kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath=&quot;{.data.password}&quot; | base64 -d</pre><p>This command will output the initial admin password required to log into the ArgoCD UI.</p><h4>Step 5: Deploy Your Application via ArgoCD</h4><p><strong><em>a) Login to the ArgoCD UI</em></strong></p><ul><li>Use the default username is <em>‘admin’ </em>and the retrieved admin password to log in to the ArgoCD UI at <a href="http://argocd.local./">http://argocd.local</a></li></ul><p><strong><em>b) Add Your Application</em></strong></p><ul><li>In the ArgoCD UI, click on <strong><em>New App</em></strong> to create a new application.</li><li>Provide the necessary details, including the Git repository URL where your Helm chart or Kubernetes manifests are stored, and configure the application settings.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/847/1*nBR6cdqDf_FTVEMpzi3ANw.png" /></figure><p><strong><em>c) Sync Your Application</em></strong></p><ul><li>After adding the application, click <strong><em>Sync</em></strong> to deploy the application to your Kubernetes cluster.</li><li>Monitor the deployment status and logs directly from the ArgoCD UI.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1003/1*FRttUtAZqVJCQ08wclifaw.png" /></figure><p>This guide provides a comprehensive setup for integrating <em>ArgoCD </em>into your CI/CD pipeline, enabling automated deployments and efficient management of your applications.</p><h3>Cleaning Up Resources</h3><p>After completing your DevOps implementation, it is important to clean up all resources used in this project to avoid incurring any additional costs. Below are the steps to remove the resources you created during this project:</p><p><strong><em>a) Delete Kubernetes Resources:</em> </strong>To delete the Kubernetes resources (Deployment, Service, Ingress) that were created, use the following commands:</p><pre>kubectl delete -f K8s/manifests/deployment.yaml<br>kubectl delete -f K8s/manifests/service.yaml<br>kubectl delete -f K8s/manifests/ingress.yaml</pre><p><strong><em>b) Remove Helm Releases:</em> </strong>If you used Helm for deployment, you can delete the Helm release with:</p><pre>helm uninstall go-web-app-chart</pre><p><strong><em>c) Delete AWS EKS Cluster: </em></strong>To delete the EKS cluster, use the eksctl command:</p><pre>eksctl delete cluster --name demo-cluster --region us-east-1</pre><p>Make sure to also manually verify and clean up any associated resources in the AWS Management Console if necessary.</p><p><strong><em>d) Remove Docker Images from DockerHub:</em> </strong>If you pushed Docker images to DockerHub, you can remove them using the following commands:</p><pre>docker rmi &lt;your-docker-username&gt;/go-web-app</pre><p>Log in to DockerHub and delete the repository or individual tags through the DockerHub web interface if required.</p><p><strong><em>e) Clean Up Local DNS Mappings: </em></strong>Remove the local DNS mapping entry from your hosts file:</p><ul><li>For Windows: Edit C:\Windows\System32\drivers\etc\hosts and remove the line mapping the IP address to go-web-app.local.</li><li>For macOS/Linux: Edit /etc/hosts and remove the corresponding line.</li></ul><p>By following these steps, you will ensure that no unnecessary resources are left running, thus avoiding additional costs associated with cloud and container services.</p><h3>Conclusion</h3><p>This project successfully demonstrates the process of deploying a Go application using contemporary DevOps practices.</p><p>By building and running the application locally, creating a multistage Dockerfile for efficient containerization, and deploying the application to an Amazon EKS cluster, we’ve showcased a robust workflow for modern software delivery.</p><p><strong><em>Acknowledgment</em></strong></p><p>This project was significantly inspired by <strong><em>Abhishek Veeramalla</em></strong>, known for his excellent DevOps content.</p><p>His content provided a solid foundation for my enhancement. Check out his content <a href="https://www.youtube.com/@AbhishekVeeramalla"><strong>here</strong></a><strong>.</strong></p><h3>Connect with me</h3><p>For more insights and future projects, feel free to connect with me on <a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> , </em></strong><a href="https://github.com/wangoimwangi"><strong><em>GitHub</em></strong></a><strong><em> </em></strong>and<strong> </strong><a href="https://mary-wangoi.medium.com/"><strong><em>Medium.</em></strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b5ae52c2bbfa" width="1" height="1" alt=""><hr><p><a href="https://blog.devops.dev/comprehensive-devops-implementation-project-b5ae52c2bbfa">Comprehensive DevOps Implementation</a> was originally published in <a href="https://blog.devops.dev/">DevOps.dev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Ansible Automation for AWS EC2: Provisioning and Security]]></title>
            <link>https://towardsaws.com/ansible-automation-for-aws-ec2-provisioning-authentication-and-conditional-operations-edf1ce7aed6e?source=rss-25b8a3b45b96------2</link>
            <guid isPermaLink="false">https://medium.com/p/edf1ce7aed6e</guid>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[ansible]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[devops]]></category>
            <dc:creator><![CDATA[Wangoi Mwangi]]></dc:creator>
            <pubDate>Tue, 23 Jul 2024 15:17:05 GMT</pubDate>
            <atom:updated>2024-10-07T10:01:32.315Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/877/1*UFW4GXrEPkhcAnHH6RDtNA.png" /></figure><h3>Introduction</h3><p><strong>What is Ansible?</strong></p><p>Ansible is an open-source IT automation tool used for provisioning, configuration management, application deployment, and orchestration.</p><p><strong>How Ansible Works</strong></p><p>Ansible is agentless, meaning no software needs to be installed on managed nodes.</p><p>It connects via SSH (or other methods for non-SSH environments) and pushes small programs called Ansible modules to achieve the desired system state.</p><p>These modules are idempotent, ensuring changes are made only when necessary.</p><h3>Project Overview</h3><p>This Ansible Realtime Project aims to demonstrate the automation capabilities of Ansible in managing AWS EC2 instances.</p><p>This project involves creating EC2 instances with different Linux distributions, configuring password less SSH authentication, and automating instance shutdown operations.</p><h3>Objectives</h3><ul><li><strong>Provisioning EC2 Instances</strong>:</li></ul><p>Utilize Ansible loops to automate the creation of three EC2 instances — two running Ubuntu and one running Amazon Linux.</p><p>This step showcases how Ansible can efficiently manage multiple instances with different configurations.</p><ul><li><strong>Passwordless Authentication Setup</strong>:</li></ul><p>Implement passwordless SSH authentication between the Ansible control node and the newly created instances.</p><p>This step demonstrates the automation of security configurations, facilitating seamless management of the instances.</p><ul><li><strong>Conditional Instance Management</strong>:</li></ul><p>Automate the shutdown process for the Ubuntu instances using Ansible conditionals.</p><p>This task highlights the use of Ansible’s powerful conditional statements to perform operations based on specific criteria.</p><h3>Prerequisites</h3><p><strong>1: Ansible Installation</strong></p><p>Install Ansible on your control node. Use apt, yum, or pip.</p><p><strong>For Linux/macOS</strong>:</p><pre># Debian/Ubuntu<br>sudo apt update<br>sudo apt install ansible<br><br># RedHat/CentOS<br>sudo yum install ansible<br><br># Using pip<br>pip install ansible</pre><p><strong>For Windows</strong>:</p><p>It’s recommended to use Windows Subsystem for Linux (WSL) for running Ansible.</p><pre>wsl --install</pre><p>First, install WSL and then follow the Linux/macOS instructions above within your WSL environment to install Ansible.</p><p><strong>2: AWS Account &amp; Credentials</strong></p><p>Ensure you have an AWS account and configure AWS credentials using aws configure</p><p>Configure IAM user with permissions to manage EC2 instances.</p><ul><li><strong>Log in</strong> to the AWS Management Console.</li><li><strong>Navigate</strong> to the IAM service.</li><li><strong>Click</strong> on <em>“Users”</em> in the sidebar and then <em>“Add user.”</em></li><li><strong>Enter</strong> a user name (e.g., ansible-user).</li><li><strong>Select</strong> <em>“Programmatic access”</em> to enable API access.</li><li><strong>Click</strong> “Next: Permissions.”</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Fs4s1RDWy_5aQEXsyVa-uQ.png" /></figure><p><strong>Set Permissions:</strong></p><ol><li><strong>Click</strong> on <em>“Attach policies directly”</em></li><li><strong>Search</strong> for <em>“EC2FullAccess”</em> and <strong>check</strong> the box next to it.</li><li><strong>Click</strong> <em>“Next: Tags”</em> (optional) and then<em> “Next: Review”</em></li><li><strong>Click</strong><em> “Create user”</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/905/1*PBuEiLws1pMy80BgDo_VMg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mse1nnXujuA64Ak_s4HflQ.png" /></figure><p><strong>3: SSH Key Pair</strong></p><p>Generate an SSH key pair for passwordless authentication</p><pre>ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa</pre><p><strong>4: Install Required Packages</strong></p><p><strong>‘boto3’ </strong>: For AWS API interactions.</p><pre>pip install boto3</pre><p><strong>AWS Collection</strong>: Install Ansible AWS collection.</p><pre>ansible-galaxy collection install amazon.aws</pre><p><strong>5: Basic Ansible Knowledge</strong></p><p>Understand basic concepts like playbooks and inventory files.</p><p><strong>6: Network &amp; Security Group</strong></p><p>Ensure security groups allow SSH access and the network setup is correct.</p><p>By completing these steps, you’ll be ready to start the Ansible Realtime Project.</p><p><strong>7: AWS EC2 AMI IDs</strong></p><p>Obtain the AMI IDs for the Ubuntu and Amazon Linux distributions you plan to use. These IDs are required for launching EC2 instances.</p><ul><li>Go to the <a href="https://aws.amazon.com/console/"><em>AWS Management Console</em></a> and log in.</li><li>Search for <em>“EC2” </em>and select it from the services list.</li><li>Click on <strong><em>Launch Instance</em></strong><em>.</em></li><li>In the <strong><em>Choose an Amazon Machine Image (AMI)</em></strong> section, enter <em>“Ubuntu”</em> or <em>“Amazon Linux”</em> in the search bar.</li><li>Find the desired AMI and copy its AMI ID directly from this page. Do not launch the instance.</li><li>Replace placeholder AMI IDs in your playbook with the copied AMI IDs.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/893/1*wpS9ru_PGykx9Mf05dTICg.png" /></figure><h3><strong>Setting up Vault</strong></h3><p>Ansible Vault is a feature that allows you to keep sensitive data such as passwords or keys in encrypted files.</p><p>Here’s how to set up Vault for securely storing your AWS credentials</p><blockquote><strong>Create Vault Password</strong>:</blockquote><p>Generate a strong password to use with Ansible Vault</p><pre>openssl rand -base64 2048 &gt; vault.pass</pre><p>This command creates a file named vault.pass containing a 2048-bit random base64 string, which will serve as the password for encrypting and decrypting your Vault files.</p><blockquote><strong>Add AWS Credentials to Vault</strong>:</blockquote><p>Use Ansible Vault to create an encrypted file for storing your AWS credentials.</p><pre>ansible-vault create group_vars/all/pass.yml --vault-password-file vault.pass</pre><p>This command opens a new file in your default text editor.</p><p>To enter your AWS credentials:</p><ul><li>Press i to enter insert mode.</li><li>Enter your AWS credentials in the following format, replacing YOUR_ACCESS_KEY and YOUR_SECRET_KEY with your actual AWS access key and secret key.</li></ul><pre>ec2:<br>  access_key: YOUR_ACCESS_KEY<br>  secret_key: YOUR_SECRET_KEY</pre><ul><li>After entering the credentials, press Esc to exit insert mode.</li><li>Type :wq and press Enter to save and exit the editor.</li></ul><p>Your AWS credentials are now stored securely in group_vars/all/pass.yml and can be accessed in your playbooks while remaining encrypted.</p><p><strong>Usage Note</strong>:</p><p>Whenever you run an Ansible playbook that requires these credentials, which we will cover later on you will need to specify the Vault password file to decrypt them:</p><pre>ansible-playbook YOUR_PLAYBOOK.yml --vault-password-file vault.pass</pre><p><em>Replace </em><em>YOUR_PLAYBOOK.yml with the actual name of your playbook file</em></p><p>In your Ansible playbook or role, you can reference these credentials.</p><p>By setting up Ansible Vault, you ensure that sensitive information is protected and can be securely accessed during your automation processes.</p><h3><strong>Provisioning EC2 Instances</strong></h3><p>The first task in this project is to provision three EC2 instances using Ansible.</p><p>Two instances will run Ubuntu, and one instance will run Amazon Linux.</p><p>This task demonstrates how Ansible can efficiently manage multiple instances with different configurations.</p><h4>Concept of Idempotence</h4><p><strong>Idempotence</strong> is a key principle in Ansible, ensuring that running a task multiple times has the same effect as running it once.</p><p>In other words, idempotent tasks will only make changes if necessary, maintaining the desired state without performing redundant actions.</p><p>This guarantees that the system’s state remains consistent and predictable, regardless of how many times the playbook is executed.</p><h4>Steps to Provision EC2 Instances:</h4><p><strong>1: Install Ansible AWS Collection</strong>:</p><p>Ensure you have the necessary Ansible collection for AWS installed.</p><pre>ansible-galaxy collection install amazon.aws</pre><p><strong>2: Create Ansible Playbook</strong>:</p><p>Write a playbook to provision the EC2 instances (e.g., ec2_create.yaml).</p><p>Ensure that you update the AMI IDs according to your account.</p><pre>---<br>- hosts: localhost<br>  connection: local<br><br>  tasks:<br>  - name: Create EC2 instances<br>    amazon.aws.ec2_instance:<br>      name: &quot;{{ item.name }}&quot;<br>      key_name: &quot;server-Jenkins&quot;<br>      instance_type: t2.micro<br>      security_group: default<br>      region: ap-southeast-2<br>      aws_access_key: &quot;{{ec2.access_key}}&quot;  # From vault as defined<br>      aws_secret_key: &quot;{{ec2.secret_key}}&quot;  # From vault as defined      <br>      network:<br>        assign_public_ip: true<br>      image_id: &quot;{{ item.image }}&quot;<br>      tags:<br>        environment: &quot;{{ item.name }}&quot;<br>    loop:<br>      - { image: &quot;ami-09f5ddaab17f5ff43&quot;, name: &quot;manage-node-1&quot; } # Update AMI ID according <br>      - { image: &quot;ami-03f0544597f43a91d&quot;, name: &quot;manage-node-2&quot; } # to your account<br>      - { image: &quot;ami-03f0544597f43a91d&quot;, name: &quot;manage-node-3&quot; }</pre><p><strong>Explanation of the Playbook</strong><br>The provided playbook uses Ansible loops to provision three EC2 instances, avoiding task repetition and demonstrating efficient management of multiple instances with different configurations.</p><p>Here’s a breakdown of the playbook:</p><p><strong><em>Hosts and Connection</em></strong><em>:</em></p><ul><li>hosts: localhost: The playbook runs on the local machine, which is the Ansible control node.</li><li>connection: local: Specifies a local connection to execute tasks on the control node itself.</li></ul><p><strong><em>Tasks</em></strong><em>:</em></p><p><strong><em>Create EC2 instances</em></strong><em>:</em></p><ul><li>amazon.aws.ec2_instance: An Ansible module for managing EC2 instances.</li><li>name: &quot;{{ item.name }}&quot;: Sets the name for each instance using the item.name variable.</li><li>key_name: &quot;server-Jenkins&quot;: Specifies the SSH key pair name for the instances. Replace this with our actual key pair name.</li><li>instance_type: t2.micro: Defines the instance type.</li><li>security_group: default: Assigns the default security group.</li><li>region: ap-southeast-2: Specifies the AWS region.</li><li>aws_access_key and aws_secret_key: Retrieves AWS credentials from the Ansible vault.</li><li>network.assign_public_ip: true: Assigns a public IP to each instance.</li><li>image_id: &quot;{{ item.image }}&quot;: Sets the AMI ID for each instance using the item.image variable.</li><li>tags.environment: &quot;{{ item.name }}&quot;: Tags each instance with its name for easy identification.</li><li>loop: Iterates over a list of dictionaries, each containing an image and name for the instances.</li></ul><p><strong>By using a <em>loop,</em> </strong>the playbook avoids repetitive tasks, making it more concise and easier to manage.</p><p>Each iteration creates an EC2 instance with the specified AMI and name.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MQf5N_8bTNeyJM9HX0muig.png" /></figure><p><strong>3: Run the Playbook</strong>:</p><p>To execute the playbook and provision the EC2 instances, use the following command:</p><pre>ansible-playbook ec2_create.yaml --vault-password-file vault.pass</pre><p><em>Replace </em><em>ec2_create.yaml with the actual name of your playbook file.</em></p><p>This task highlights Ansible’s capability to efficiently manage cloud infrastructure consistently and predictably, leveraging the concept of idempotence to ensure reliable provisioning of EC2 instances.</p><p>Go to your console management and ensure that all the 3 instances are created successfully</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NEr4t_xYaNggjAzB_HA6Iw.png" /></figure><h3><strong>Passwordless Authentication Setup</strong></h3><p>The second task in the project involves setting up passwordless SSH authentication between the Ansible control node and the EC2 instances.</p><p>This ensures secure and seamless management of the instances without needing to manually enter passwords.</p><p><strong><em>Methods Available:</em></strong></p><p>When setting up passwordless authentication for your EC2 instances, you have two primary methods: using public key authentication or enabling password authentication.</p><p>Here’s a brief overview of each approach:</p><p><strong>Method 1: Using Public Key Authentication</strong></p><ol><li><strong><em>Generate SSH Key Pair:</em></strong></li></ol><p>Create a new SSH key pair on the Ansible control node. This key pair will be used to authenticate with the EC2 instances.</p><pre>ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa</pre><ul><li>-t rsa: Specifies the RSA algorithm for the key.</li><li>-b 2048: Sets the key length to 2048 bits.</li><li>-f ~/.ssh/id_rsa: Defines the file path to save the private key.</li></ul><p>This command generates two files:</p><ul><li>~/.ssh/id_rsa: The private key (keep this secure).</li><li>~/.ssh/id_rsa.pub: The public key (to be shared with EC2 instances).</li></ul><p><strong><em>2: Copy Public Key to EC2 Instances:</em></strong></p><p>The public key needs to be copied to the ~/.ssh/authorized_keys file on each EC2 instance to allow passwordless SSH access.</p><p>Use ssh-copy-id to automate this process.</p><pre>ssh-copy-id -f &quot;-o IdentityFile &lt;PATH TO PEM FILE&gt;&quot; ubuntu@&lt;INSTANCE-PUBLIC-IP&gt;</pre><ul><li>-f: Forces copying of keys (overwrites existing keys).</li><li>&quot;-o IdentityFile &quot;: Specifies the path to your private key file.</li><li>ubuntu@: Username and IP address of the EC2 instance you are accessing.</li></ul><p><strong>Note:</strong> <em>For instances created via automation tools like Ansible, public key authentication is typically handled by configuring the instance’s key pair during provisioning, so you generally do not need to manually use </em><em>ssh-copy-id.</em></p><p><strong>Method 2: Using Password Authentication</strong></p><p>While less secure than public key authentication, enabling password authentication allows access using a password instead of a key.</p><p>This method is generally used when key-based access is not feasible.</p><p><strong><em>1: Update SSH Configuration</em></strong></p><p>Edit the SSH configuration file on your EC2 instance to allow password authentication.</p><pre>sudo nano /etc/ssh/sshd_config.d/60-cloudimg-settings.conf</pre><p>Change the PasswordAuthentication line to yes</p><pre>PasswordAuthentication yes</pre><p><strong><em>2: Restart SSH Service</em></strong></p><p>Apply the changes by restarting the SSH service.</p><pre>sudo systemctl restart ssh</pre><h4>Summary</h4><ul><li><strong>Public Key Authentication:</strong> Preferred method for secure, passwordless access. Use ssh-copy-id for manual setups, or configure keys through automation tools like Ansible.</li><li><strong>Password Authentication:</strong> Enables access using a password, less secure but sometimes necessary. Update SSH configuration and restart the service to apply changes.</li></ul><h3><strong>Conditional Instance Management</strong></h3><p>The goal of this task is to automate the shutdown of EC2 instances running Ubuntu using Ansible conditionals.</p><p>Ansible’s conditional statements allow you to execute tasks only if certain conditions are met.</p><p>You will use Ansible’s when condition to ensure that only instances with Ubuntu OS are shut down.</p><p><strong>Concept:</strong></p><p>Ansible’s when condition allows you to execute tasks based on the results of gathered facts or other conditions.</p><p>This ensures that the playbook performs actions only if certain criteria are met, which in this case means shutting down only Ubuntu instances.</p><p><strong>Steps to Implement Conditional Instance Management:</strong></p><p><strong><em>1: Inventory File:</em></strong></p><p>An inventory file is used by Ansible to specify the hosts that playbooks will manage.</p><p>Below is the inventory file (inventory.ini) for this project:</p><pre>[all]<br>ec2_user@3.25.73.73<br>ubuntu@3.27.140.245<br>ubuntu@3.27.185.253</pre><ul><li><strong>Replace</strong> the example IP addresses with the actual public IP addresses of your EC2 instances.</li><li>Save this configuration in a file named inventory.ini.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/631/1*NqjxRvToWXLcj8OKvk3-6A.png" /></figure><p><strong><em>2: Define Conditions:</em></strong></p><p>You need to set up conditions that determine when an instance should be managed (e.g., shut down).</p><p>These conditions might be based on tags, instance names, or other instance attributes.</p><p><strong><em>3: Create an Ansible Playbook:</em></strong></p><p>Write a playbook that includes tasks to manage the EC2 instances conditionally.</p><pre>---<br>- hosts: all<br>  become: true<br><br>  tasks:<br>    - name: Shutdown ubuntu instances only<br>      ansible.builtin.command: /sbin/shutdown -t now<br>      when:<br>        ansible_facts[&#39;os_family&#39;] == &quot;Debian&quot;</pre><p><strong>Explanation of the Playbook:</strong></p><p><strong>1: <em>Hosts and Privilege Escalation:</em></strong></p><ul><li><strong>hosts: all</strong>: Specifies that the playbook will run on all hosts in the inventory.</li><li><strong>become: true</strong>: Runs tasks with elevated privileges (e.g., sudo) to allow the shutdown command to be executed.</li></ul><p><strong>2: <em>Shutdown Ubuntu Instances Only:</em></strong></p><ul><li><strong>name</strong>: Describes the task, which is to shut down Ubuntu instances.</li><li><strong>ansible.builtin.command</strong>: Uses the command module to execute the shutdown command.</li><li><strong>/sbin/shutdown -h now</strong>: Issues the shutdown command to halt the system immediately. (-h is used for halt instead of -t, which is not a valid option for shutdown).</li><li><strong>when</strong>: The condition that controls when this task should run:</li><li><strong>ansible_facts[‘os_family’] == “Debian”</strong>: Ensures the task runs only if the operating system family of the instance is Debian.</li></ul><p><strong>Steps to Implement</strong></p><p><strong><em>1: Run the Playbook:</em></strong></p><p>To execute the playbook and shut down Ubuntu instances, use the following command:</p><pre>ansible-playbook ec2_shutdown.yaml</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dqT92Yo532edKbYskIQ1pw.png" /></figure><p><strong><em>2: Verify Instance Shutdown:</em></strong></p><p>Check your EC2 instances in the AWS Management Console to confirm that only Ubuntu instances have been shut down as specified.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vN747DlN_1GBPGUNL-Iy9Q.png" /></figure><p><strong>Summary</strong></p><p>By using Ansible’s when condition, you can efficiently manage EC2 instances based on their operating system.</p><p>This playbook demonstrates how to automate the shutdown of Ubuntu instances while ensuring other instances are not affected. This conditional approach provides flexibility and control in managing cloud infrastructure.</p><h3>Conclusion</h3><p>In this project, we used Ansible to:</p><ol><li><strong>Provision EC2 Instances:</strong> We automated the creation of EC2 instances with different configurations, using loops to manage multiple instances efficiently.</li><li><strong>Set Up Passwordless Authentication:</strong> We configured secure, passwordless SSH access to EC2 instances, making management easier and more secure.</li><li><strong>Manage Instances Conditionally:</strong> We automated the shutdown of Ubuntu instances using Ansible conditionals to perform actions based on specific criteria.</li></ol><p><strong>In summary</strong>, this project demonstrated how Ansible can simplify and automate cloud infrastructure tasks, ensuring efficient, reliable, and secure management of EC2 instances.</p><h3>Connect with me</h3><p>For more insights and future projects, feel free to connect with me on <a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> , </em></strong><a href="https://github.com/wangoimwangi"><strong><em>GitHub</em></strong></a><strong><em> </em></strong>and<strong> </strong><a href="https://mary-wangoi.medium.com/"><strong><em>Medium.</em></strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=edf1ce7aed6e" width="1" height="1" alt=""><hr><p><a href="https://towardsaws.com/ansible-automation-for-aws-ec2-provisioning-authentication-and-conditional-operations-edf1ce7aed6e">Ansible Automation for AWS EC2: Provisioning and Security</a> was originally published in <a href="https://towardsaws.com/">Towards AWS</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Terraform-Based Automation for AWS EKS Cluster and VPC Deployment]]></title>
            <link>https://wangoi-mwangi.medium.com/aws-eks-cluster-vpc-creation-using-terraform-35b82bcc9af6?source=rss-25b8a3b45b96------2</link>
            <guid isPermaLink="false">https://medium.com/p/35b82bcc9af6</guid>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[terraform]]></category>
            <category><![CDATA[infrastructure-as-code]]></category>
            <dc:creator><![CDATA[Wangoi Mwangi]]></dc:creator>
            <pubDate>Thu, 20 Jun 2024 17:12:25 GMT</pubDate>
            <atom:updated>2024-09-13T10:21:26.006Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/847/1*U1DjiQHjK4r3t3dkl3nNVQ.png" /></figure><h3>Introduction</h3><p>As cloud-native applications become increasingly complex, managing infrastructure manually can be a daunting task.</p><p>Automation tools like Terraform offer a powerful solution, enabling us to define and provision our infrastructure as code.</p><p>In this project, I’ll walk you through the process of setting up an Amazon Elastic Kubernetes Service (EKS) cluster with autoscaling self-managed nodes and a custom Virtual Private Cloud (VPC) using Terraform.</p><p>We’ll cover:</p><ol><li>Creating a VPC tailored for our EKS cluster.</li><li>Configuring security groups to control network traffic.</li><li>Setting up the EKS cluster for container orchestration.</li><li>Implementing autoscaling for worker nodes to handle varying workloads.</li></ol><p>By the end of this guide, you’ll have a scalable, secure Kubernetes environment on AWS, ready to deploy your applications. Let’s dive in!</p><p><em>Feel free to connect with me on </em><a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> </em></strong><em>to discuss this post, or ask any questions.</em></p><h3>Prerequisites</h3><p>Before diving into setting up your EKS cluster with Terraform, ensure you have the following prerequisites in place:</p><ol><li><strong>AWS Account</strong>: An active AWS account is essential. If you don’t have one, you can sign up at <a href="https://aws.amazon.com/"><strong><em>aws.amazon.com</em></strong></a><strong><em>.</em></strong></li><li><strong>AWS CLI</strong>: The AWS Command Line Interface (CLI) should be installed and configured on your local machine. You can follow the installation guide <a href="https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html"><strong><em>here</em></strong></a><strong><em>. </em></strong>Ensure you’ve run aws configure to set up your credentials.</li><li><strong>Terraform</strong>: Install Terraform on your local machine. The installation instructions can be found <a href="https://learn.hashicorp.com/tutorials/terraform/install-cli"><strong><em>here.</em></strong></a></li><li><strong>kubectl</strong>: The Kubernetes command-line tool, kubectl, is required to interact with your EKS cluster. Install it following the instructions here.</li><li><strong>Basic Knowledge of Kubernetes and Terraform</strong>: Familiarity with Kubernetes concepts and Terraform’s configuration syntax will help you follow along with the steps in this guide.</li></ol><p>Once you have all these prerequisites set up, you’re ready to start creating your infrastructure.</p><p>Let’s move on to setting up the project structure.</p><h3>Project Setup</h3><p>Let’s set up the project structure and create the necessary Terraform files. Follow these steps to organize your project directory:</p><p><strong>1: Create Project Directory</strong>: Start by creating a new directory for your Terraform project.</p><pre>mkdir eks-terraform<br>cd eks-terraform</pre><p><strong>2: Create Terraform Files</strong>: Inside the eks-terraform directory, create the following files:</p><ul><li>eks-cluster.tf</li></ul><p>Define the EKS cluster and node group resources.</p><ul><li>outputs.tf</li></ul><p>Define the outputs to display important information after deployment.</p><ul><li>security-group.tf</li></ul><p>Define the security groups for the EKS control plane and worker nodes.</p><ul><li>variables.tf</li></ul><p>Define the variables used in your Terraform configuration.</p><ul><li>vpc.tf</li></ul><p>Define the VPC and subnet resources.</p><ul><li>version.tf</li></ul><p>This file specifies the required Terraform version and provider details.</p><ul><li>.ignore</li></ul><p>Specify files and directories to ignore in version control.</p><p><strong>Summary</strong></p><p>Your project directory should now look like this:</p><pre>eks-terraform/<br>├── eks-cluster.tf<br>├── outputs.tf<br>├── security-group.tf<br>├── variables.tf<br>├── vpc.tf<br>├── version.tf<br>└── .gitignore</pre><h3>EKS Cluster Creation</h3><p>In this section, we’ll use Terraform to create the EKS cluster.</p><p>We will be leveraging a pre-built Terraform module from the Terraform Registry to simplify the process.</p><p>Terraform modules are self-contained packages of Terraform configuration files that are managed together.</p><p>They allow you to encapsulate and reuse resource configurations across different parts of your infrastructure.</p><p>Using modules has several advantages such as reusability, maintainability, consistency, and abstraction.</p><p>Inside the eks-cluster.tf file, paste this code:</p><pre>module &quot;eks&quot; {<br>  source          = &quot;terraform-aws-modules/eks/aws&quot;<br>  version         = &quot;20.8.4&quot;<br>  cluster_name    = local.cluster_name<br>  cluster_version = var.kubernetes_version<br>  subnet_ids      = module.vpc.private_subnets<br><br>  enable_irsa = true<br><br>  tags = {<br>    cluster = &quot;demo&quot;<br>  }<br><br>  vpc_id = module.vpc.vpc_id<br><br>  eks_managed_node_group_defaults = {<br>    ami_type               = &quot;AL2_x86_64&quot;<br>    instance_types         = [&quot;t3.medium&quot;]<br>    vpc_security_group_ids = [aws_security_group.all_worker_mgmt.id]<br>  }<br><br>  eks_managed_node_groups = {<br>    node_group = {<br>      min_size     = 2<br>      max_size     = 6<br>      desired_size = 2<br>    }<br>  }<br>}</pre><p><strong>Explanation of the Code:</strong></p><p><strong>1: Module Source and Version</strong>:</p><pre>source = &quot;terraform-aws-modules/eks/aws&quot;<br>version = &quot;20.8.4&quot;</pre><p>This specifies the source of the module and the version to use.</p><p>The terraform-aws-modules/eks/aws module from the Terraform Registry simplifies the creation of EKS clusters.</p><p>Version 20.8.4 is specified to ensure compatibility and stability.</p><p><strong>2: Cluster Name and Version</strong>:</p><pre>cluster_name    = local.cluster_name<br>cluster_version = var.kubernetes_version</pre><ul><li>local.cluster_name: This local variable holds the name of the EKS cluster.</li><li>var.kubernetes_version: This variable specifies the Kubernetes version to be used in the EKS cluster.</li></ul><p><strong>3: Subnets and VPC ID</strong>:</p><pre>subnet_ids = module.vpc.private_subnets<br>vpc_id = module.vpc.vpc_id</pre><ul><li>module.vpc.private_subnets: This references the private subnets created in the VPC module.</li><li>module.vpc.vpc_id: This references the VPC ID created in the VPC module.</li></ul><p><strong>4: IRSA (IAM Roles for Service Accounts)</strong>:</p><pre>enable_irsa = true</pre><p>This enables IAM Roles for Service Accounts (IRSA), which allows for fine-grained access control on AWS resources for applications running on EKS.</p><p><strong>5: Tags</strong>:</p><pre>tags = {<br>  cluster = &quot;demo&quot;<br>}</pre><ul><li>This adds tags to the EKS cluster for identification and management.</li></ul><p><strong>6: Managed Node Group Defaults</strong>:</p><pre>eks_managed_node_group_defaults = {<br>  ami_type               = &quot;AL2_x86_64&quot;<br>  instance_types         = [&quot;t3.medium&quot;]<br>  vpc_security_group_ids = [aws_security_group.all_worker_mgmt.id]<br>}</pre><p>This block sets default configurations for EKS managed node groups:</p><ul><li>ami_type: Specifies the Amazon Linux 2 AMI for the nodes.</li><li>instance_types: Specifies the instance type for the nodes (e.g., t3.medium).</li><li>vpc_security_group_ids: Associates the worker nodes with the specified security group.</li></ul><p><strong>7: Managed Node Groups</strong>:</p><pre>eks_managed_node_groups = {<br>  node_group = {<br>    min_size     = 2<br>    max_size     = 6<br>    desired_size = 2<br>  }<br>}</pre><p>This block defines the managed node group configuration:</p><ul><li>min_size: Minimum number of nodes in the node group.</li><li>max_size: Maximum number of nodes in the node group.</li><li>desired_size: Desired number of nodes in the node group.</li></ul><h3><strong>VPC Creation</strong></h3><p>A <strong><em>Virtual Private Cloud (VPC)</em></strong> is a virtual network environment within a cloud provider like AWS that allows you to logically isolate and manage your resources securely.</p><p>It provides a customizable network configuration, including IP address ranges, subnets, route tables, and security settings, enabling you to create a virtual network infrastructure that closely resembles a traditional data center.</p><p>In this step, we create a VPC using Terraform. The VPC is essential for isolating and controlling network resources for your Amazon EKS cluster.</p><p>Here’s the provided code for vpc.tf, followed by a detailed explanation of each part:</p><pre>provider &quot;aws&quot; {<br>  region = var.aws_region<br>}<br><br>data &quot;aws_availability_zones&quot; &quot;available&quot; {}<br><br>locals {<br>  cluster_name = &quot;abhi-eks-${random_string.suffix.result}&quot;<br>}<br><br>resource &quot;random_string&quot; &quot;suffix&quot; {<br>  length  = 8<br>  special = false<br>}<br><br>module &quot;vpc&quot; {<br>  source  = &quot;terraform-aws-modules/vpc/aws&quot;<br>  version = &quot;5.7.0&quot;<br><br>  name                 = &quot;abhi-eks-vpc&quot;<br>  cidr                 = var.vpc_cidr<br>  azs                  = data.aws_availability_zones.available.names<br>  private_subnets      = [&quot;10.0.1.0/24&quot;, &quot;10.0.2.0/24&quot;]<br>  public_subnets       = [&quot;10.0.4.0/24&quot;, &quot;10.0.5.0/24&quot;]<br>  enable_nat_gateway   = true<br>  single_nat_gateway   = true<br>  enable_dns_hostnames = true<br>  enable_dns_support   = true<br><br>  tags = {<br>    &quot;kubernetes.io/cluster/${local.cluster_name}&quot; = &quot;shared&quot;<br>  }<br><br>  public_subnet_tags = {<br>    &quot;kubernetes.io/cluster/${local.cluster_name}&quot; = &quot;shared&quot;<br>    &quot;kubernetes.io/role/elb&quot;                      = &quot;1&quot;<br>  }<br><br>  private_subnet_tags = {<br>    &quot;kubernetes.io/cluster/${local.cluster_name}&quot; = &quot;shared&quot;<br>    &quot;kubernetes.io/role/internal-elb&quot;             = &quot;1&quot;<br>  }<br>}</pre><p><strong>Explanation of the code:</strong></p><p><strong>1: AWS Provider:</strong></p><pre>provider &quot;aws&quot; {<br>  region = var.aws_region<br>}</pre><p><strong><em>provider “aws”</em></strong><em>:</em> Specifies that we are using the AWS provider and sets the region using a variable var.aws_region.</p><p><strong>2: Data Source for Availability Zones:</strong></p><pre>data &quot;aws_availability_zones&quot; &quot;available&quot; {}</pre><p><strong><em>data “aws_availability_zones” “available”</em></strong><em>:</em> Fetches the available AWS availability zones in the specified region.</p><p><strong>3: Local Values</strong></p><pre>locals {<br>  cluster_name = &quot;abhi-eks-${random_string.suffix.result}&quot;<br>}</pre><p><strong><em>locals</em></strong><em>:</em> Defines local values. Here, it creates a unique cluster_name by appending a random string suffix.</p><p><strong>4: Random String Resource</strong></p><pre>resource &quot;random_string&quot; &quot;suffix&quot; {<br>  length  = 8<br>  special = false<br>}</pre><p><strong><em>resource “random_string” “suffix”</em></strong><em>:</em> Generates a random string of 8 characters, excluding special characters, used to ensure unique resource names.</p><p><strong>5: VPC Module</strong></p><pre>module &quot;vpc&quot; {<br>  source  = &quot;terraform-aws-modules/vpc/aws&quot;<br>  version = &quot;5.7.0&quot;</pre><ul><li><strong>source</strong>: Specifies the source of the module terraform-aws-modules/vpc/aws, which is located in the Terraform Registry.</li><li><strong>version</strong>: Specifies the version of the module to use (5.7.0). This ensures consistency and compatibility with the module&#39;s features and functionality.</li></ul><pre>  name                 = &quot;abhi-eks-vpc&quot;<br>  cidr                 = var.vpc_cidr<br>  azs                  = data.aws_availability_zones.available.names</pre><ul><li><strong><em>name</em></strong>: Sets the name of the VPC to &quot;abhi-eks-vpc&quot;.</li><li><strong><em>cidr</em></strong>: Specifies the CIDR block for the VPC, retrieved from the var.vpc_cidr variable. This defines the IP address range for the VPC.</li><li><strong><em>azs</em></strong>: Specifies the availability zones (AZs) where subnets will be created. This data is fetched using data.aws_availability_zones.available.names, which lists all available AZs in the specified region.</li></ul><pre>  private_subnets      = [&quot;10.0.1.0/24&quot;, &quot;10.0.2.0/24&quot;]<br>  public_subnets       = [&quot;10.0.4.0/24&quot;, &quot;10.0.5.0/24&quot;]</pre><ul><li><strong><em>private_subnets</em></strong>: Defines the CIDR blocks for private subnets within the VPC. Private subnets are typically used for resources that do not need direct access to the internet.</li><li><strong><em>public_subnets</em></strong>: Defines the CIDR blocks for public subnets within the VPC. Public subnets are used for resources that require internet access, such as load balancers or web servers.</li></ul><pre>  enable_nat_gateway   = true<br>  single_nat_gateway   = true</pre><p><strong><em>enable_nat_gateway</em> </strong>: Enables a NAT gateway for outbound internet traffic from private subnets.</p><p><strong><em>single_nat_gateway</em></strong> : Ensures that all private subnets share a single NAT gateway to minimize costs.</p><pre>  enable_dns_hostnames = true<br>  enable_dns_support   = true</pre><p><strong><em>enable_dns_hostnames </em></strong>and<strong><em> </em></strong><strong><em>enable_dns_support</em></strong>: Enable DNS hostnames and DNS resolution within the VPC, allowing instances in the VPC to resolve public DNS hostnames and receive DNS requests from the VPC itself.</p><p><strong>6: Tags</strong></p><pre>tags = {<br>    &quot;kubernetes.io/cluster/${local.cluster_name}&quot; = &quot;shared&quot;<br>  }</pre><p><strong><em>tags</em></strong>: Tags are metadata assigned to AWS resources for organization and identification purposes. Here, tags are applied to the VPC itself, indicating it belongs to the Kubernetes cluster named ${local.cluster_name}.</p><pre>public_subnet_tags = {<br>    &quot;kubernetes.io/cluster/${local.cluster_name}&quot; = &quot;shared&quot;<br>    &quot;kubernetes.io/role/elb&quot;                      = &quot;1&quot;<br>  }<br><br>  private_subnet_tags = {<br>    &quot;kubernetes.io/cluster/${local.cluster_name}&quot; = &quot;shared&quot;<br>    &quot;kubernetes.io/role/internal-elb&quot;             = &quot;1&quot;<br>  }<br>}</pre><p><strong><em>public_subnet_tags</em> </strong>and<strong> </strong><strong><em>private_subnet_tags</em></strong>: Tags applied specifically to public and private subnets, respectively. These tags help in identifying subnet roles within the Kubernetes cluster environment.</p><h3>Security Group Creation</h3><p><strong><em>Security groups</em></strong> are virtual firewalls that control inbound and outbound traffic for instances. They act as a fundamental component of network security, providing traffic control, stateful filtering, instance-level protection and flexibility &amp; scalability.</p><ul><li><strong><em>Ingress Rule</em></strong><em>:</em> Allows inbound traffic from the specified CIDR blocks, which are private IP address ranges commonly used within networks.</li><li><strong><em>Egress Rule</em></strong><em>: </em>Permits outbound traffic to any destination (0.0.0.0/0), allowing instances associated with the security group to communicate freely with the internet and other resources.</li></ul><p>Here’s the Terraform code from security-groups.tf that creates an AWS security group and associated rules:</p><pre>resource &quot;aws_security_group&quot; &quot;all_worker_mgmt&quot; {<br>  name_prefix = &quot;all_worker_management&quot;<br>  vpc_id      = module.vpc.vpc_id<br>}<br><br>resource &quot;aws_security_group_rule&quot; &quot;all_worker_mgmt_ingress&quot; {<br>  description       = &quot;allow inbound traffic from eks&quot;<br>  from_port         = 0<br>  protocol          = &quot;-1&quot;<br>  to_port           = 0<br>  security_group_id = aws_security_group.all_worker_mgmt.id<br>  type              = &quot;ingress&quot;<br>  cidr_blocks       = [<br>    &quot;10.0.0.0/8&quot;,<br>    &quot;172.16.0.0/12&quot;,<br>    &quot;192.168.0.0/16&quot;,<br>  ]<br>}<br><br>resource &quot;aws_security_group_rule&quot; &quot;all_worker_mgmt_egress&quot; {<br>  description       = &quot;allow outbound traffic to anywhere&quot;<br>  from_port         = 0<br>  protocol          = &quot;-1&quot;<br>  security_group_id = aws_security_group.all_worker_mgmt.id<br>  to_port           = 0<br>  type              = &quot;egress&quot;<br>  cidr_blocks       = [&quot;0.0.0.0/0&quot;]<br>}</pre><p><strong>Explanation of the Code</strong></p><p><strong>1: </strong><strong>aws_security_group Resource</strong></p><p><strong><em>aws_security_group.all_worker_mgmt</em>: </strong>Defines an AWS security group named all_worker_management within the VPC specified by module.vpc.vpc_id. This security group will govern inbound and outbound traffic rules for associated instances.</p><p><strong>2: </strong><strong>aws_security_group_rule Resources</strong></p><ul><li><strong><em>aws_security_group_rule.all_worker_mgmt_ingress</em></strong>: Specifies an ingress (inbound) rule for the all_worker_mgmt security group. It allows traffic from specified CIDR blocks (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) on any protocol (-1) and port (0).</li><li><strong><em>aws_security_group_rule.all_worker_mgmt_egress</em></strong>: Defines an egress (outbound) rule for the all_worker_mgmt security group. It permits all outbound traffic (0.0.0.0/0) on any protocol (-1) and port (0).</li></ul><p>These security group rules ensure that instances within the associated VPC can communicate securely based on specified network traffic requirements.</p><h3>Configure variables.tf</h3><p>The variables.tf file defines the input variables that can be used to customize the Terraform configuration.</p><p>Here’s the provided code with a brief explanation of each variable:</p><pre>variable &quot;kubernetes_version&quot; {<br>  default     = 1.27<br>  description = &quot;Kubernetes version&quot;<br>}<br><br>variable &quot;vpc_cidr&quot; {<br>  default     = &quot;10.0.0.0/16&quot;<br>  description = &quot;Default CIDR range of the VPC&quot;<br>}<br><br>variable &quot;aws_region&quot; {<br>  default     = &quot;us-west-1&quot;<br>  description = &quot;AWS region&quot;<br>}</pre><p><strong>Explanation of the Variables:</strong></p><p><strong>1:</strong><strong>kubernetes_version</strong></p><ul><li><strong>Purpose</strong>: Specifies the version of Kubernetes to use for the EKS cluster.</li><li><strong>Default Value</strong>: 1.27</li><li><strong>Description</strong>: This variable allows you to specify which version of Kubernetes will be deployed in the EKS cluster. Keeping Kubernetes versions up-to-date ensures compatibility with the latest features and security patches.</li></ul><p><strong>2: </strong><strong>vpc_cidr</strong></p><ul><li><strong>Purpose</strong>: Defines the CIDR (Classless Inter-Domain Routing) block for the VPC.</li><li><strong>Default Value</strong>: 10.0.0.0/16</li><li><strong>Description</strong>: This variable sets the IP address range for the VPC. The 10.0.0.0/16 range provides 65,536 IP addresses, which is typically sufficient for most use cases. This range can be adjusted based on your network requirements</li></ul><p><strong>3: </strong><strong>aws_region</strong></p><ul><li><strong>Purpose</strong>: Specifies the AWS region where the infrastructure will be deployed.</li><li><strong>Default Value</strong>: us-west-1</li><li><strong>Description</strong>: This variable determines the AWS region for deploying your resources. Regions are geographic locations that allow you to place resources closer to your users or meet specific legal and regulatory requirements.</li></ul><p>By defining these variables, you can easily modify your configuration without changing the actual Terraform code, promoting reusability and flexibility.</p><h3>Configure outputs.tf</h3><p>The outputs.tf file defines the outputs of your Terraform configuration, which are useful for obtaining information about the created resources. Here&#39;s the provided code with a brief explanation of each output:</p><pre>output &quot;cluster_id&quot; {<br>  description = &quot;EKS cluster ID.&quot;<br>  value       = module.eks.cluster_id<br>}<br><br>output &quot;cluster_endpoint&quot; {<br>  description = &quot;Endpoint for EKS control plane.&quot;<br>  value       = module.eks.cluster_endpoint<br>}<br><br>output &quot;cluster_security_group_id&quot; {<br>  description = &quot;Security group ids attached to the cluster control plane.&quot;<br>  value       = module.eks.cluster_security_group_id<br>}<br><br>output &quot;region&quot; {<br>  description = &quot;AWS region&quot;<br>  value       = var.aws_region<br>}<br><br>output &quot;oidc_provider_arn&quot; {<br>  value = module.eks.oidc_provider_arn<br>}<br><br>output &quot;zz_update_kubeconfig_command&quot; {<br>  value = &quot;aws eks update-kubeconfig --name &quot; + module.eks.cluster_id<br>  value = format(&quot;%s %s %s %s&quot;, &quot;aws eks update-kubeconfig --name&quot;, module.eks.cluster_id, &quot;--region&quot;, var.aws_region)<br>}</pre><h4>Explanation of Outputs</h4><ol><li><strong>cluster_id</strong></li></ol><ul><li><strong><em>Description</em></strong>: The ID of the EKS cluster.</li><li><strong><em>Value</em></strong>: Retrieved from module.eks.cluster_id.</li><li><strong><em>Purpose</em></strong>: This output provides the unique identifier for the EKS cluster, which is essential for managing and referencing the cluster.</li></ul><p><strong>2:</strong><strong>cluster_endpoint</strong></p><ul><li><strong><em>Description</em></strong>: The endpoint for the EKS control plane.</li><li><strong><em>Value</em></strong>: Retrieved from module.eks.cluster_endpoint.</li><li><strong><em>Purpose</em></strong>: This output provides the URL endpoint to interact with the EKS control plane. It’s necessary for configuring kubectl and other Kubernetes tools to communicate with the cluster.</li></ul><p><strong>3: </strong><strong>cluster_security_group_id</strong></p><ul><li><strong><em>Description</em></strong>: The security group IDs attached to the cluster control plane.</li><li><strong><em>Value</em></strong>: Retrieved from module.eks.cluster_security_group_id.</li><li><strong><em>Purpose</em></strong>: This output provides the security group IDs, which are crucial for managing network access to the EKS control plane.</li></ul><p><strong>4:</strong> <strong>region</strong></p><ul><li><strong><em>Description</em></strong>: The AWS region where the infrastructure is deployed.</li><li><strong><em>Value</em></strong>: Retrieved from var.aws_region.</li><li><strong><em>Purpose</em></strong>: This output confirms the AWS region used for the deployment, which can be useful for cross-referencing and managing resources in a multi-region setup.</li></ul><p><strong>5: </strong><strong>oidc_provider_arn</strong></p><ul><li><strong><em>Description</em></strong>: The ARN of the OIDC provider associated with the EKS cluster.</li><li><strong><em>Value</em></strong>: Retrieved from module.eks.oidc_provider_arn.</li><li><strong><em>Purpose</em></strong>: This output provides the Amazon Resource Name (ARN) for the OIDC provider, used for integrating IAM roles with Kubernetes service accounts for fine-grained access control.</li></ul><p><strong>6: </strong><strong>zz_update_kubeconfig_command</strong></p><ul><li><strong><em>Description</em></strong>: A command to update the kubeconfig file with the EKS cluster configuration.</li><li><strong><em>Value</em></strong>: Constructs the command using the cluster ID and AWS region.</li><li><strong><em>Purpose</em></strong>: Although commented out, this output provides a ready-to-use command for updating the local kubeconfig file to interact with the EKS cluster. Uncomment and use it for convenience.</li></ul><p>By defining these outputs, you make it easier to access and utilize key details of your infrastructure, facilitating management and integration with other tools and services.</p><h3>Configure versions.tf</h3><p>The versions.tf file sets the required versions for Terraform and the necessary providers.</p><p>This ensures compatibility and stability across your Terraform project. Here’s a breakdown of the provided code:</p><pre>terraform {<br>  required_version = &quot;&gt;= 0.12&quot;<br>  required_providers {<br>    random = {<br>      source  = &quot;hashicorp/random&quot;<br>      version = &quot;~&gt; 3.1.0&quot;<br>    }<br>    kubernetes = {<br>      source  = &quot;hashicorp/kubernetes&quot;<br>      version = &quot;&gt;=2.7.1&quot;<br>    }<br>    aws = {<br>      source  = &quot;hashicorp/aws&quot;<br>      version = &quot;&gt;= 3.68.0&quot;<br>    }<br>    local = {<br>      source  = &quot;hashicorp/local&quot;<br>      version = &quot;~&gt; 2.1.0&quot;<br>    }<br>    null = {<br>      source  = &quot;hashicorp/null&quot;<br>      version = &quot;~&gt; 3.1.0&quot;<br>    }<br>    cloudinit = {<br>      source  = &quot;hashicorp/cloudinit&quot;<br>      version = &quot;~&gt; 2.2.0&quot;<br>    }<br>  }<br>}</pre><p><strong>Explanation of the version.tf</strong></p><p><strong>1: </strong><strong>required_version</strong></p><ul><li><strong><em>Purpose</em></strong>: Specify the minimum version of Terraform required to run the configuration.</li><li><strong><em>Value</em></strong>: &gt;= 0.12 ensures compatibility with Terraform version 0.12 and newer. Terraform 0.12 introduced many new features and improvements, so this ensures those features are available.</li></ul><p><strong>2: </strong><strong>required_providers</strong></p><ul><li><strong><em>Purpose</em></strong>: Defines the required providers and their versions for the configuration.</li></ul><p><strong>Providers</strong>:</p><p><strong>random</strong>:</p><ul><li><strong><em>Source</em></strong>: hashicorp/random</li><li><strong><em>Version</em></strong>: ~&gt; 3.1.0 (compatible with 3.x versions, starting from 3.1.0)</li></ul><p><strong>kubernetes</strong>:</p><ul><li><strong><em>Source</em></strong>: hashicorp/kubernetes</li><li><strong><em>Version</em></strong>: &gt;= 2.7.1 (version 2.7.1 or newer)</li></ul><p><strong>aws</strong>:</p><ul><li><strong><em>Source</em></strong>: hashicorp/aws</li><li><strong><em>Version</em></strong>: &gt;= 3.68.0 (version 3.68.0 or newer)</li></ul><p><strong>local</strong>:</p><ul><li><strong><em>Source</em></strong>: hashicorp/local</li><li><strong><em>Version</em></strong>: ~&gt; 2.1.0 (compatible with 2.x versions, starting from 2.1.0)</li></ul><p><strong>null</strong>:</p><ul><li><strong><em>Source</em></strong>: hashicorp/null</li><li><strong><em>Version</em></strong>: ~&gt; 3.1.0 (compatible with 3.x versions, starting from 3.1.0)</li></ul><p><strong>cloudinit</strong>:</p><ul><li><strong><em>Source</em></strong>: hashicorp/cloudinit</li><li><strong><em>Version</em></strong>: ~&gt; 2.2.0 (compatible with 2.x versions, starting from 2.2.0)</li></ul><h3><strong>Backend Configuration (Optional)</strong></h3><p>If you are using a remote backend (e.g., S3 for state files), you should configure it in a backend.tf file.</p><p>A remote backend in Terraform is a way to store the Terraform state file remotely, rather than locally on your machine.</p><p>This approach has several advantages, especially when working in a team or when managing large-scale infrastructure.</p><p><strong>Benefits of Using a Remote Backend</strong></p><p><strong>State Management:</strong></p><ul><li><strong>Centralized State</strong>: Keeps the Terraform state file in a central location, enabling multiple team members to work on the same infrastructure without conflicts.</li><li><strong>State Locking</strong>: Prevents simultaneous updates to the state file, reducing the risk of corruption. Supports features like AWS S3 with DynamoDB for state locking.</li></ul><p><strong>Collaboration:</strong></p><ul><li><strong>Team Collaboration</strong>: Allows team members to share and manage infrastructure state efficiently, with everyone accessing the latest state.</li><li><strong>Versioning and History</strong>: Maintains a history of state changes, allowing rollbacks to previous states if needed.</li></ul><p><strong>Security:</strong></p><ul><li><strong>Secure Storage</strong>: Stores state files securely in solutions like AWS S3, with encryption and access controls.</li><li><strong>Backup</strong>: Provides reliable backup for your state files.</li></ul><p><strong>Scalability:</strong></p><ul><li><strong>Scalable Management</strong>: Makes it easier to manage larger and more complex infrastructures by ensuring state consistency and reliability.</li></ul><p>Inside the backend.tf file paste this code:</p><pre>terraform {<br>  backend &quot;s3&quot; {<br>    bucket         = &quot;my-terraform-state-bucket&quot;<br>    key            = &quot;path/to/my/key&quot;<br>    region         = &quot;us-west-1&quot;<br>    dynamodb_table = &quot;my-lock-table&quot;<br>    encrypt        = true<br>  }<br>}</pre><ul><li><strong><em>bucket</em></strong>: The name of the S3 bucket where the state file will be stored.</li><li><strong><em>key</em></strong>: The path within the bucket to the state file.</li><li><strong><em>region</em></strong>: The AWS region where the S3 bucket is located.</li><li><strong><em>dynamodb_table</em></strong>: The DynamoDB table used for state locking.</li><li><strong><em>encrypt</em></strong>: Ensures that the state file is encrypted in S3.</li></ul><h3>DynamoDB Table Configuration (Only if you have implemented Backend Configuration).</h3><p>Amazon DynamoDB is a fully managed NoSQL database service provided by AWS, designed to deliver low-latency performance at any scale.</p><p>In addition to its typical use cases, a DynamoDB table is often utilized in AWS environments as part of Terraform’s remote backend configuration.</p><p>Specifically, it plays a critical role in state locking, ensuring that only one Terraform process can modify the state file at any given time.</p><p>This mechanism prevents concurrent modifications and maintains the integrity of infrastructure deployments managed by Terraform.</p><p>Paste this code inside the <strong><em>dynamodb.tf</em></strong> file:</p><pre>resource &quot;aws_dynamodb_table&quot; &quot;terraform_lock&quot; {<br>  name         = &quot;my-lock-table&quot;  // Match the name used in backend.tf<br>  billing_mode = &quot;PAY_PER_REQUEST&quot;<br>  hash_key     = &quot;LockID&quot;<br><br>  attribute {<br>    name = &quot;LockID&quot;<br>    type = &quot;S&quot;<br>  }<br><br>  tags = {<br>    Name = &quot;my-lock-table&quot;  // Tag the DynamoDB table for identification<br>  }<br>}</pre><p><strong>Explanation of the DynamoDB Table</strong></p><ul><li><strong><em>name = &quot;my-lock-table&quot;</em></strong>: Specifies the name of the DynamoDB table as &quot;my-lock-table&quot;, matching the name used in backend.tf for dynamodb_table.</li><li><strong><em>billing_mode = &quot;PAY_PER_REQUEST&quot;</em></strong>: Sets the billing mode to &quot;PAY_PER_REQUEST&quot;, which is suitable for on-demand usage.</li><li><strong><em>hash_key = &quot;LockID&quot;</em></strong>: Defines &quot;LockID&quot; as the hash key attribute for the DynamoDB table.</li><li><strong><em>attribute {}</em></strong>: Defines the attribute &quot;LockID&quot; as a string (&quot;S&quot; type) to be used as the hash key.</li><li><strong><em>tags = { Name = &quot;my-lock-table&quot; }</em></strong>: Tags the DynamoDB table with a name for identification purposes, ensuring clarity in your AWS resources.</li></ul><h3><strong>Default State Management in Terraform</strong></h3><p>When using Terraform, managing state files is crucial for tracking the state of your infrastructure resources and ensuring consistency across deployments. Terraform offers flexibility in how state files are managed:</p><h4>Remote Backend and DynamoDB Configuration</h4><p>If you configure a remote backend, such as AWS S3 with DynamoDB for state locking:</p><ul><li><strong><em>State Locking</em></strong><em>:</em> Ensures that only one Terraform process can modify the state file at a time, preventing concurrent modifications and maintaining infrastructure integrity.</li><li><strong><em>High Availability</em></strong><em>: </em>Provides a centralized location for storing state files, accessible to team members for collaborative infrastructure management.</li></ul><h4>Default State Management</h4><p>If you do not configure a remote backend and DynamoDB table:</p><ul><li><strong><em>Local State Files</em></strong>: Terraform automatically manages state files locally in a file named terraform.tfstate.</li><li><strong><em>Single User Operations</em></strong>: Suitable for individual use or small teams where concurrent modifications are not a concern.</li><li><strong><em>Limitations</em></strong>: May lead to conflicts and state file corruption in collaborative environments or complex infrastructure setups.</li></ul><h3>Initialize and Validate Configuration</h3><p>Before applying your Terraform configuration to provision or modify infrastructure, it’s essential to initialize and validate your Terraform configuration files.</p><p>This step ensures that your environment is properly set up and that the configuration is syntactically correct and ready for deployment.</p><ol><li><strong>Initialize Terraform</strong></li></ol><p>To initialize Terraform, you run the following command in your Terraform project directory:</p><pre>terraform init</pre><p><strong>Explanation</strong>:</p><ul><li><strong><em>Initialization</em></strong>: Downloads the necessary providers and modules specified in your configuration files (provider.tf, versions.tf), setting up your environment for Terraform operations.</li><li><strong><em>Backend Configuration</em></strong>: If using a remote backend (backend.tf), initializes connection settings like AWS S3 bucket and DynamoDB table for state storage and locking.</li></ul><p><strong>2. Validate Configuration</strong></p><p>After initialization, validate your Terraform configuration files using:</p><pre>terraform validate</pre><p><strong>Explanation</strong>:</p><ul><li><strong><em>Validation</em></strong>: Checks the syntax and structure of your Terraform configuration files (*.tf files) to ensure they are correctly formatted and compliant with Terraform&#39;s expected syntax.</li><li><strong><em>Errors and Warnings</em></strong>: Identifies any errors or warnings in your configuration that could prevent successful deployment.</li></ul><h3>Finalize Configuration</h3><p>After initializing and validating your Terraform configuration, the typical next steps involve planning, applying changes, and managing your infrastructure.</p><p><strong>1: Plan Changes</strong></p><pre>terraform plan</pre><ul><li><strong><em>Purpose</em></strong>: Generates an execution plan showing what Terraform will do when you apply your configuration.</li><li><strong><em>Review</em></strong>: Review the plan to understand the actions Terraform will take, such as creating, modifying, or deleting resources.</li><li><strong><em>Validation</em></strong>: Ensures your configuration is correct and aligns with your intentions before making changes to your infrastructure.</li></ul><p><strong>2: Apply Changes</strong></p><pre>terraform apply</pre><ul><li><strong><em>Execution</em></strong>: Applies the changes defined in your configuration to your infrastructure.</li><li><strong><em>Interactive</em></strong>: Confirms changes before applying unless automated with -auto-approve.</li><li><strong><em>State Management</em></strong>: Updates the Terraform state file (terraform.tfstate or remote backend) to reflect the current state of deployed resources.</li></ul><p><strong>3: Review Outputs</strong></p><pre>terraform output</pre><ul><li><strong>Outputs</strong>: Displays any outputs defined in output.tf, such as resource IDs, endpoints, or other relevant information.</li><li><strong>Verification</strong>: Use outputs to verify successful deployment and gather necessary information for further operations or integrations.</li></ul><p><strong>4: Manage State</strong></p><pre>terraform state</pre><ul><li><strong>State Management</strong>: Provides commands to manage Terraform state, such as listing resources, moving states, or deleting resources from the state.</li><li><strong>Maintenance</strong>: Useful for troubleshooting, state file maintenance, or recovering from errors.</li></ul><h3>Managing Terraform Configurations with .gitignore</h3><p>When using Terraform to manage infrastructure as code, it’s essential to properly manage your project’s version control.</p><p>One critical aspect of this is the .gitignore file, which helps ensure that sensitive or unnecessary files are not included in your Git repository.</p><h4>Importance of .gitignore</h4><ul><li><strong><em>Sensitive Information</em></strong>: Excludes sensitive data such as credentials, API keys, and state files (terraform.tfstate or .terraform/) from being tracked by version control.</li><li><strong><em>Temporary Files</em></strong>: Ignores temporary files, logs, and artifacts generated during Terraform operations, reducing repository clutter.</li><li><strong><em>Enhanced Security</em></strong>: Protects sensitive information from being exposed inadvertently in version control history or during collaboration.</li></ul><p>Paste this code inside the<strong><em> .gitignore</em></strong> file:</p><pre># Local .terraform directories<br>**/.terraform/*<br><br># .tfstate files<br>*.tfstate<br>*.tfstate.*<br><br># Crash log files<br>crash.log<br>crash.*.log<br><br># Exclude all .tfvars files, which are likely to contain sensitive data, such as<br># password, private keys, and other secrets. These should not be part of version <br># control as they are data points which are potentially sensitive and subject <br># to change depending on the environment.<br>*.tfvars<br>*.tfvars.json<br><br># Ignore override files as they are usually used to override resources locally and so<br># are not checked in<br>override.tf<br>override.tf.json<br>*_override.tf<br>*_override.tf.json<br><br># Include override files you do wish to add to version control using negated pattern<br># !example_override.tf<br><br># Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan<br># example: *tfplan*<br><br># Ignore CLI configuration files<br>.terraformrc<br>terraform.rc</pre><p><strong>Explanation of .gitignore:</strong></p><p><strong>1: Local .terraform directories</strong></p><pre>**/.terraform/*</pre><p>Excludes any .terraform directories and their contents from being committed to Git. These directories contain local Terraform plugins and modules.</p><p><strong>2: .tfstate files</strong></p><pre>*.tfstate<br>*.tfstate.*</pre><p>Ignores Terraform state files (*.tfstate) and any backup or temporary state files (*.tfstate.*) that may be generated during Terraform operations.</p><p><strong>3: Crash log files</strong></p><pre>crash.log<br>crash.*.log</pre><p>Excludes crash log files (crash.log and crash.*.log) from being tracked. These files are generated in case of Terraform command crashes or errors.</p><p><strong>4: .tfvars files</strong></p><pre>*.tfvars<br>*.tfvars.json</pre><p>Ignores Terraform variable files (*.tfvars and *.tfvars.json) which may contain sensitive data such as passwords, API keys, or other secrets.</p><p><strong>5: Override files</strong></p><pre>override.tf<br>override.tf.json<br>*_override.tf<br>*_override.tf.json</pre><p>Excludes override files (override.tf, override.tf.json, *_override.tf, *_override.tf.json) typically used to locally override Terraform configurations.</p><p><strong>6: Include override files in version control</strong></p><pre># Include override files you do wish to add to version control using negated pattern<br># !example_override.tf</pre><p>Provides a comment showing how to include specific override files (!example_override.tf) in version control if needed.</p><p><strong>7: Include tfplan files</strong></p><pre># Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan<br># example: *tfplan*</pre><p>Comments suggesting to include tfplan files if you want to ignore the plan output generated by terraform plan -out=tfplan.</p><p><strong>8: CLI configuration files</strong></p><pre>.terraformrc<br>terraform.rc</pre><p>Ignores CLI configuration files (.terraformrc and terraform.rc) which may contain local or user-specific Terraform configurations.</p><h3>Validate the resources creation via AWS Management Console (UI)</h3><h4>1. Login to AWS Console</h4><ul><li>Open your web browser and navigate to the <a href="https://aws.amazon.com/console/"><strong><em>AWS Management Console</em></strong></a><strong><em>.</em></strong></li><li>Sign in using your AWS account credentials.</li></ul><h4>2. Navigate to Each Resource Type</h4><p>EC2 Instances:</p><ul><li><strong><em>Services</em></strong>: Click on <strong><em>“Services”</em></strong> in the top-left corner.</li><li><strong><em>Compute</em></strong>: Select <strong><em>“EC2”</em></strong> under the Compute section.</li><li><strong><em>Instances</em></strong>: Verify that EC2 instances created by Terraform are listed under <strong><em>“Instances”</em></strong><em>.</em></li><li><strong><em>Details</em></strong><em>:</em> Click on an instance to view its details, including instance type, status, security groups, and tags.</li></ul><p>VPC (Virtual Private Cloud):</p><ul><li><strong><em>Networking &amp; Content Delivery</em></strong>: Click on <strong><em>“Services”</em></strong> and then <strong><em>“VPC”</em></strong><em>.</em></li><li><strong><em>Your VPCs</em></strong><em>: </em>Ensure that the VPC created by Terraform is listed under <strong><em>“Your VPCs”</em></strong><em>.</em></li><li><strong><em>Subnets</em></strong><em>:</em> Verify that the subnets (public and private) associated with your VPC are correctly configured.</li></ul><p>Security Groups:</p><ul><li><strong><em>Networking &amp; Content Delivery</em></strong><em>:</em> Click on <strong><em>“Services”</em></strong><em> </em>and then <strong><em>“EC2”</em></strong><em>.</em></li><li><strong><em>Security Groups</em></strong>: Navigate to <strong><em>“Security Groups”</em></strong><em> </em>under the <strong><em>“Network &amp; Security”</em></strong><em> </em>section.</li><li><strong>Verify</strong>: Check that the security groups created by Terraform are listed and configured with the expected inbound and outbound rules.</li></ul><p>EKS Cluster:</p><ul><li><strong><em>Compute</em></strong><em>:</em> Select <strong><em>“Elastic Kubernetes Service”</em></strong><em> </em>under Compute.</li><li><strong><em>Clusters</em></strong>: Ensure that the EKS cluster created by Terraform is listed under <strong><em>“Clusters”</em></strong><em>.</em></li><li><strong><em>Details</em></strong>: Click on the cluster name to review its details, including Kubernetes version, endpoint, node groups, and associated resources.</li></ul><p>IAM Roles and Policies:</p><ul><li><strong><em>Security, Identity, &amp; Compliance</em></strong>: Click on<em> </em><strong><em>“Services”</em></strong> and then<em> </em><strong><em>“IAM”</em></strong><em>.</em></li><li><strong><em>Roles/Policies</em></strong>: Verify that IAM roles and policies created by Terraform are present under <strong><em>“Roles”</em></strong> and <strong><em>“Policies”</em></strong><em> </em>respectively.</li><li><strong><em>Details</em></strong>: Click on a role or policy to inspect its permissions, trust relationships, and usage.</li></ul><h4>3. Review and Confirm Configuration</h4><ul><li><strong><em>Settings</em></strong>: For each resource type, review its configuration settings to ensure they match what you defined in your Terraform scripts (*.tf files).</li><li><strong><em>Tags</em></strong>: Check that tags applied to resources are correctly assigned and labeled.</li></ul><h4>4. Functional Testing (Optional)</h4><ul><li><strong><em>Interact</em></strong>: If applicable, interact with deployed resources to validate functionality, such as accessing EC2 instances via SSH, accessing Kubernetes cluster via kubectl, or testing network connectivity.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/887/1*CwU6VlpIQEeRyEbstfi_ww.png" /></figure><h3>Clean Up Resources</h3><p><strong>1: Identify Resources</strong></p><ul><li>List all resources provisioned by Terraform, including EC2 instances, VPCs, EKS clusters, IAM roles, and any other resources managed through your Terraform scripts.</li></ul><p><strong>2: Terminate EC2 Instances</strong></p><ul><li><strong><em>AWS Management Console</em></strong>: Navigate to <strong><em>“Services”</em></strong><em> </em>&gt; <strong><em>“EC2”</em></strong><em> </em>&gt; <strong><em>“Instances”</em></strong><em>.</em></li><li>Select instances created by Terraform, verify their IDs, and terminate them.</li><li><strong><em>CLI</em></strong><em>:</em> Use aws ec2 terminate-instances --instance-ids &lt;instance-id&gt; to terminate instances via the AWS CLI if preferred.</li></ul><p><strong>3: Delete EKS Cluster</strong></p><ul><li><strong><em>AWS Management Console</em></strong><em>:</em> Navigate to <strong><em>“Services”</em></strong> &gt; <strong><em>“Elastic Kubernetes Service”</em></strong><em>.</em></li><li>Select the EKS cluster created by Terraform, and choose <strong>“Delete”</strong> to remove it.</li><li>Ensure to delete associated resources such as node groups and any add-ons if applicable.</li></ul><p><strong>4: Remove VPC and Subnets</strong></p><ul><li><strong><em>AWS Management Console</em></strong><em>: </em>Navigate to <strong><em>“Services”</em></strong> &gt; <strong><em>“VPC”</em></strong><em>.</em></li><li>Delete the VPC and associated subnets created by Terraform.</li><li>Remove any remaining resources like route tables, internet gateways, or NAT gateways associated with the VPC.</li></ul><p><strong>5: Delete IAM Roles and Policies</strong></p><ul><li><strong><em>AWS Management Console</em></strong><em>:</em> Navigate to<em> </em><strong><em>“Services”</em></strong> &gt; <strong><em>“IAM”</em></strong><em>.</em></li><li>Remove IAM roles and policies created by Terraform that are no longer needed.</li><li>Ensure to detach policies from roles before deletion if they are attached.</li></ul><p><strong>6: Clean Up Security Groups</strong></p><ul><li><strong><em>AWS Management Console</em></strong><em>:</em> Navigate to <strong><em>“Services”</em></strong> &gt; <strong><em>“EC2”</em></strong> &gt; <strong><em>“Security Groups”</em></strong><em>.</em></li><li>Delete any security groups created by Terraform that are no longer in use.</li></ul><p><strong>7: Verify Deletion</strong></p><ul><li>Double-check the AWS Management Console to ensure all resources have been deleted successfully.</li><li>Use the AWS CLI or SDKs to automate resource deletion if handling a large number of resources.</li></ul><p><strong>8: State File Management</strong></p><ul><li>Remove local Terraform state files (terraform.tfstate and terraform.tfstate.backup) if you&#39;re not using a remote backend for state management.</li></ul><p><strong>9: Review Billing</strong></p><ul><li>Monitor your AWS billing dashboard to ensure that resources have been successfully terminated and to verify that no unexpected charges occur.</li></ul><h3>Conclusion</h3><p>This project showcased the effective use of Terraform for automating AWS infrastructure deployments.</p><p>By leveraging infrastructure as code principles, we achieved scalability, reliability, and cost efficiency.</p><p>Through automated provisioning of resources like EKS clusters, VPCs, and security groups, we ensured consistent deployments while maintaining robust security practices.</p><p>Moving forward, Terraform remains pivotal in enabling agile and efficient management of cloud infrastructure, supporting our goal of streamlined operations and optimized resource utilization.</p><h3>Connect with me</h3><p>For more insights and future projects, feel free to connect with me on <a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> , </em></strong><a href="https://github.com/wangoimwangi"><strong><em>GitHub</em></strong></a><strong><em> </em></strong>and<strong> </strong><a href="https://mary-wangoi.medium.com/"><strong><em>Medium.</em></strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=35b82bcc9af6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Robust AWS VPC Design for High Availability and Security]]></title>
            <link>https://wangoi-mwangi.medium.com/creating-a-robust-aws-vpc-architecture-7602b20d3ac8?source=rss-25b8a3b45b96------2</link>
            <guid isPermaLink="false">https://medium.com/p/7602b20d3ac8</guid>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[vpc]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[Wangoi Mwangi]]></dc:creator>
            <pubDate>Wed, 19 Jun 2024 20:10:43 GMT</pubDate>
            <atom:updated>2024-09-13T10:19:34.687Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/762/1*cTnA9qFAIveeZa4LafFTsA.png" /></figure><h3>Introduction</h3><p>In today’s cloud-centric world, a secure and scalable network infrastructure is essential. Amazon Web Services (AWS) offers Virtual Private Cloud (VPC), enabling users to create isolated networks tailored to their needs.</p><p>This project will guide you through setting up a comprehensive VPC environment on AWS, covering key components such as subnets, gateways, load balancers, and security measures.</p><p>By the end of this tutorial, you’ll learn to build and manage a robust VPC architecture, ensuring your cloud resources are secure and highly available.</p><p><em>Feel free to connect with me on </em><a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> </em></strong><em>to discuss this post, or ask any questions.</em></p><h3>Project Overview</h3><p>This project demonstrates how to create a <strong><em>Virtual Private Cloud (VPC)</em></strong> suitable for hosting servers in a production environment.</p><p>To enhance resilience, servers are deployed across two <strong><em>Availability Zones</em></strong> using an <strong><em>Auto Scaling Group</em></strong> and an <strong><em>Application Load Balancer.</em></strong></p><p>For additional security measures, servers are placed in <strong><em>private subnets,</em> </strong>while a <strong><em>public subnet</em></strong><em> </em>allows inbound traffic through the Application Load Balancer.</p><p>Servers can access the internet via a<em> </em><strong><em>NAT Gateway,</em></strong> which is deployed in both Availability Zones for improved resilience.</p><p>An <strong><em>Internet Gateway</em></strong><em> </em>facilitates outbound Internet access for resources within the VPC.</p><p>A <strong><em>bastion host</em></strong> is used alongside <strong><em>Security Groups</em></strong>, <strong><em>EC2 instances</em></strong>, and <strong><em>Target Groups</em></strong><em> </em>to securely manage access to resources within the VPC.</p><p><strong>NOTE: </strong><em>Most of these step can also be automated using </em><strong><em>Terraform,</em></strong><em> but for the sake of simplicity, we will do it manually here.</em></p><h3>Tools and Technologies Used</h3><p>In this project, we leverage several key tools and technologies to build a robust Virtual Private Cloud (VPC) environment on AWS:</p><p><strong>1: Amazon VPC (Virtual Private Cloud)</strong>: Provides a logically isolated network to deploy AWS resources.</p><p><strong>2: Availability Zones</strong>: Geographic regions with independent infrastructure to enhance fault tolerance and stability.</p><p><strong>3: Subnets</strong>:</p><ul><li><strong>Public Subnet</strong>: Allows resources to be accessible from the internet.</li><li><strong>Private Subnet</strong>: Provides enhanced security by isolating resources from direct internet access.</li></ul><p><strong>4: NAT Gateway</strong>: Enables instances in private subnets to access the internet while maintaining security.</p><p><strong>5: Internet Gateway</strong>: Facilitates outbound internet access for resources within the VPC.</p><p><strong>6: Application Load Balancer (ALB)</strong>: Distributes incoming traffic across multiple targets such as EC2 instances, enhancing fault tolerance and scalability.</p><p><strong>7: Security Groups</strong>: Acts as virtual firewalls to control inbound and outbound traffic at the instance level.</p><p><strong>8: EC2 Instances</strong>: Virtual servers running in the AWS cloud that provide compute capacity.</p><p><strong>9: Auto Scaling Group</strong>: Ensures the availability and scalability of EC2 instances by automatically adjusting capacity based on traffic demands.</p><p><strong>10: Bastion Host</strong>: Acts as a secure gateway to access and manage instances in private subnets.</p><p><strong>11: Target Groups</strong>: Directs Application Load Balancer traffic to registered targets, such as EC2 instances.</p><p>These tools and technologies collectively enable the creation of a resilient, scalable, and secure VPC environment suitable for hosting production applications on AWS.</p><h3>Creating VPC</h3><p>Creating a Virtual Private Cloud (VPC) is the first step in setting up a secure and isolated network environment within AWS.</p><p>A VPC allows you to launch AWS resources, such as EC2 instances, in a logically isolated virtual network that you define.</p><p>This section will walk through the process of creating a VPC, which will serve as the foundation for our entire infrastructure.</p><p>This VPC will include public and private subnets across multiple availability zones to ensure high availability and security for our applications.</p><p><strong><em>Note:</em></strong><em> This step can also be automated using </em><strong><em>Terraform,</em></strong><em> but for the sake of simplicity, we will do it manually here.</em></p><p><strong>1: Sign in to AWS Console</strong>:</p><ul><li>Go to <a href="https://aws.amazon.com/console/"><strong><em>AWS Management Console</em></strong></a> and sign in using your credentials.</li><li>After signing in, you’ll land on the AWS Management Console dashboard.</li></ul><p><strong>2: Navigate to VPC Dashboard</strong>:</p><ul><li>Search for <em>“VPC” </em>in the search bar and select it from the results.</li></ul><p><strong>3: Start VPC Wizard</strong>:</p><ul><li>In the VPC dashboard, click on the <em>“Create VPC”</em> button to start the VPC creation process.</li></ul><p><strong>4: Choose a VPC Configuration</strong>:</p><ul><li>AWS provides several VPC configuration options. Let’s choose the <em>“VPC and more”</em> option.</li><li>Add a name tag to identify your VPC.</li></ul><p><strong>5: Configure VPC Details</strong>:</p><ul><li>Enter the IPv4 CIDR block for your VPC. This defines the range of IP addresses that can be used within your VPC.</li><li>Optionally, you can also specify an IPv6 CIDR block for your VPC.</li><li>Leave other settings as default or configure as needed based on your requirements.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/588/1*hX5WI2W-wlSueGwDpo38hA.png" /></figure><p><strong>6: Configure Subnets</strong>:</p><ul><li>For Number of <strong><em>Availability Zones,</em></strong> choose 2, so that you can launch instances in multiple Availability Zones to improve resiliency.</li><li>For the Number of <strong><em>public subnets, </em></strong>choose 2.</li><li>For the Number of <strong><em>private subnets,</em></strong> choose<strong> </strong>2.</li><li>For <strong><em>NAT gateways,</em></strong> choose 1 per AZ to improve resiliency.</li><li>For <strong><em>VPC endpoints,</em></strong> if your instances must access an S3 bucket, keep the <strong><em>S3 Gateway</em></strong> default. Otherwise, instances in your private subnet can’t access Amazon S3. There is no cost for this option, so you can keep the default if you might use an S3 bucket in the future. If you choose <strong><em>None</em></strong><em>,</em> you can always add a gateway VPC endpoint later on.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/546/1*R0rwBTTRnpgn-YL5PwY52Q.png" /></figure><ul><li>The wizard will automatically create route tables for your subnets.</li><li>Ensure that routes are correctly configured, such as routing internet-bound traffic through an Internet Gateway for public subnets.</li><li>For <strong><em>DNS options</em></strong><em>,</em> clear Enable DNS hostnames.</li></ul><p><strong>7: Review and Create</strong>:</p><ul><li>Review your configurations details you’ve chosen for your VPC.</li><li>Choose <em>“Create VPC”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vY_mcbx1iMQb2vQw4AcOAA.png" /></figure><ul><li>AWS will now create your VPC based on the configuration you’ve specified.</li><li>This process usually completes within a few minutes please be patient.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/911/1*JB4-QIB9vxjVQDK7mRQWkw.png" /></figure><p><strong>8: Verification:</strong></p><ul><li>After the VPC is created, verify its details in the VPC dashboard.</li><li>Ensure all components (VPC, subnets, route tables) are correctly configured according to your requirements.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*l9rTVVU-II3NfxXJ9aOXaw.png" /></figure><h3>Creating Auto Scaling Group</h3><p>Auto Scaling in AWS empowers applications to automatically adjust compute capacity based on demand, optimizing performance and costs.</p><p>This guide explores the straightforward steps to create an Auto Scaling group using the AWS Management Console.</p><p>By setting up Auto Scaling, you can ensure your infrastructure scales efficiently to meet fluctuating workload requirements, enhancing the resilience and cost-effectiveness of your AWS deployments.</p><p><strong>1: Sign in to AWS Console</strong>:</p><ul><li>Go to <a href="https://aws.amazon.com/console/"><strong><em>AWS Management Console</em></strong></a> and sign in using your credentials.</li></ul><p><strong>2: Navigate to Auto Scaling</strong>:</p><ul><li>Search for <em>“Auto Scaling”</em> in the search bar and select it from the results.</li></ul><p><strong>3: Create an Auto Scaling Group</strong>:</p><ul><li>Click on the <em>“Create Auto Scaling group”</em> button to start creating a new Auto Scaling group.</li></ul><p><strong>4: Choose Launch Template or Launch Configuration</strong>:</p><ul><li>Click on <em>“Create Launch Template” </em>if you don’t have an existing one, or choose an existing Launch Template from the dropdown.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/998/1*sLnTT6-FzIbc8MaXQPDCNQ.png" /></figure><p><strong>5: Create a Launch Template</strong> (if applicable):</p><p>If creating a new Launch Template, provide the following details:</p><ul><li><strong>Template name</strong>: Enter a name and description for your Template.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/942/1*Nd2JbxWEQYuMR3E6yXeFoQ.png" /></figure><ul><li><strong>AMI (Amazon Machine Image)</strong>: Select an AMI for your EC2 instances.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/881/1*eXC1jJt9bGDzk2Od50Z-Dg.png" /></figure><ul><li><strong>Instance type</strong>: Choose the instance type for your EC2 instances (e.g., t2.micro).</li><li><strong>Key pair (if needed)</strong>: Specify a key pair for SSH access to instances.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/897/1*0OsNZHt32PL7CjBrjpuSVA.png" /></figure><ul><li>Configure other instance details such as networking, as per your requirements.</li><li>Ensure you select the previously created VPC, we will be using this throughout the project.</li></ul><p><strong>5: Configure Security Group</strong></p><ul><li>Create a Security Group.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/937/1*BscwMQZxe5WTW_YKrAEJDQ.png" /></figure><ul><li>Ensure that the security group allows SSH access and custom TCP port 8000.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/874/1*EI1OziEwxOlS5Xi-Imapaw.png" /></figure><ul><li>Configure other instance details such as storage as per your requirements.</li><li>Click on <em>“Create launch template” </em>once all details are configured.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*F-PrOndpXeZ1Ko4UzIMNmw.png" /></figure><ul><li>Verify that the Launch template was created successfully.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sN33vCe1rG4qBoX88hxP4g.png" /></figure><p><strong>6: Configure Auto Scaling Group</strong>:</p><p>After selecting or creating a Launch Template, configure the Auto Scaling group settings:</p><ul><li><strong>Group name</strong>: Provide a name for your Auto Scaling group.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/920/1*WG4dCXc6yFtJq0XgiluTDw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/926/1*X1SCwt973fZ1y4vskjwuaQ.png" /></figure><ul><li><strong>Network</strong>: Choose the VPC and subnet where instances will be launched. Select the two private subnets and for the VPC select the one we created previously.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/916/1*_OMa1-JrTg6E8bnJVzg13w.png" /></figure><ul><li><strong>Group size</strong>: Define the initial number of instances (2).</li><li><strong>Scaling Limits:</strong> Choose the minimum(1) and maximum(4) desired capacity.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/902/1*QUxHrdHQSnQuzn-R6mWE-w.png" /></figure><p><strong>7: Configure Scaling Policies</strong> (if applicable):</p><ul><li>Configure scaling policies (optional).</li><li>Click<em> “Next”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/972/1*KYzMUJJiBYttS2AzM3EIOw.png" /></figure><ul><li>Add Notifications (optional).</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/963/1*ss-Asi6LBmJ6IYMqXywTcQ.png" /></figure><p><strong>8: Review and Create</strong>:</p><ul><li>Review all the configuration details you’ve chosen for your Auto Scaling group.</li><li>Double-check the Launch Template, scaling policies, networking settings, and any other configurations.</li><li>Click on <em>“Create Auto Scaling group”</em> to initiate the creation process.</li></ul><p><strong>9: Wait for Auto Scaling Group Creation</strong>:</p><ul><li>AWS will now create your Auto Scaling group based on the configuration you’ve specified.</li><li>This process may take a few moments to complete please be patient.</li></ul><p><strong>10: Verification</strong>:</p><ul><li>After the Auto Scaling group is created, verify its details in the Auto Scaling dashboard.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-Szk0KQWGQGu8yHrbDDFag.png" /></figure><ul><li>Go to the EC2 dashboard and ensure instances are launched according to scaling policies ( 2 instances in our case) and that they are integrated in two availability zones.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*P2fbBdLPHIBKEQhQeN65jw.png" /></figure><h3>Creating Bastion Host</h3><p>In AWS environments, maintaining secure access to private instances within a Virtual Private Cloud (VPC) is crucial for effective management and troubleshooting.</p><p>A bastion host, or jump server, serves as a secure gateway allowing authorized users to securely connect to instances in private subnets.</p><ul><li>Go to <a href="https://aws.amazon.com/console/"><strong><em>AWS Management Console</em></strong></a> and sign in using your credentials.</li><li>In the AWS Management Console, search for <em>“EC2”</em> in the search bar.</li><li>Click on <em>“Launch Instance”</em> to start the instance creation process.</li><li>Select an appropriate AMI for your bastion host.</li><li>Select an instance type that meets your performance and capacity requirements. A <em>t2.micro</em> instance type is often sufficient for a bastion host.</li><li>Select an existing key pair or create a new key pair to securely access your instance.</li><li>Download the key pair file (.pem) and keep it safe. You cannot download it again after it is created. It will be required to connect to your bastion host via SSH.</li><li>Choose the VPC you created earlier for your project.</li><li>Select a public subnet within your VPC to ensure the bastion host has a public IP address and internet access.</li><li><strong><em>Auto-assign Public IP:</em></strong> Enable this option to assign a public IP address to the bastion host.</li><li>Configure storage settings as needed. The default settings are typically sufficient for a bastion host.</li><li>Add tags to the instance for easy identification and organization. For example, you can add a tag with Key<em> “Name” </em>and Value <em>“Bastion Host”.</em></li><li>Create a new security group or use an existing one that allows inbound SSH (port 22) access from your IP address (or IP range) for secure SSH connections.</li><li>Optionally, configure additional rules for any other necessary access (e.g., HTTPS for web-based management).</li><li>Review all the instance details you’ve configured.</li><li>Click on <em>“Launch Instances” </em>to start the bastion host instance.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MYBpMjTz7HdUhT2ngFZ-yA.png" /></figure><h3><strong>Access the Bastion Host</strong></h3><ul><li>Once the instance state changes to <em>“running”,</em> note down the public IP address of the bastion host.</li><li>Use SSH and the key pair file (.pem) to securely connect to the bastion host from your local machine or terminal:</li></ul><pre>ssh -i /path/to/your-key.pem ec2-user@bastion-host-public-ip</pre><ul><li>Replace /path/to/your-key.pem with the path to your downloaded key pair file, and bastion-host-public-ip with the actual public IP address of your bastion host.</li><li>Verify that you can successfully connect to the bastion host using SSH.</li></ul><p>Alternatively for Windows users if you have <strong><em>MobaXterm</em></strong> you have use it to ssh into the bastion host like we have been doing with ec2 instances on our other project demos.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1012/1*ELMqU5HEzD7D_Sc1h8aV2Q.png" /></figure><h3>Securely Copying PEM File to Bastion Host</h3><p>To securely access EC2 instances via SSH through a bastion host, you first need to transfer your SSH key (.pem file) to the bastion host.</p><p>This is particularly crucial when the EC2 instance resides in a private subnet without direct internet access.</p><p>In such cases, the bastion host serves as a secure gateway, allowing controlled SSH access from your local machine to the private instances within the AWS Virtual Private Cloud (VPC).</p><p>Below are the steps for securely copying your SSH key using the scp command.</p><ul><li>Ensure you have the .pem file (your private key) that you downloaded when you created the EC2 instance.</li><li>Before transferring the file, make sure its permissions are set correctly to prevent unauthorized access:</li></ul><pre>chmod 400 /path/to/your-key.pem</pre><ul><li>Open a terminal or command prompt on your local machine.</li><li>Use the scp command to securely copy the .pem file to the bastion host.</li></ul><pre>scp -i /path/to/your-key.pem /path/to/your-key.pem ec2-user@bastion-host-public-ip:/home/ec2-user/</pre><ul><li>Replace /path/to/your-key.pem with the actual path to your .pem file, and bastion-host-public-ip with the public IP address of your bastion host.</li><li>Use /home/ubuntu/ instead of /home/ec2-user/ if you choose an Ubuntu AMI.</li></ul><p>Example Sample:</p><pre>scp -i ~/.ssh/my-key.pem ~/.ssh/my-key.pem ec2-user@123.456.789.0:/home/ec2-user/</pre><ul><li>This command securely copies the .pem file to the home directory (/home/ec2-user/) of the ec2-user on the bastion host.</li><li>If you’re prompted to enter a password, use the password associated with the SSH key pair for authentication.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tsegK8ojsKaYCifuDEaFNA.png" /></figure><ul><li>After the transfer completes, verify that the .pem file is in the correct directory on the bastion host:</li></ul><pre>ls /home/ec2-user/</pre><ul><li>If you used an Ubuntu AMI, use:</li></ul><pre>ls /home/ubuntu/</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/548/1*8hfa63DV3Q_PVixiLMiQtg.png" /></figure><h3>SSH into EC2 Instance via Bastion Host</h3><p>Once the .pem file is securely copied to the bastion host, you can proceed to SSH into your EC2 instance using the bastion host as a gateway:</p><p><strong>1: SSH into Bastion Host</strong>:</p><p>We had done this in the above steps</p><pre>ssh -i /path/to/your-key.pem ec2-user@bastion-host-public-ip</pre><p><strong>2: SSH into EC2 Instance from Bastion Host</strong>:</p><p>Once connected to the bastion host, SSH into the desired EC2 instance within your VPC using its private IP address and the .pem file:</p><pre>ssh -i /home/ec2-user/your-key.pem ec2-user@private-ip-of-ec2-instance</pre><p>Example for Ubuntu:</p><pre>ssh -i /home/ubuntu/your-key.pem ubuntu@private-ip-of-ec2-instance</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/606/1*rxVkY70ih8f_HxN1WbiSuA.png" /></figure><h3>Creating a Simple HTML Application</h3><p>After connecting to the EC2 instance via the Bastion host, if you don’t have an application to deploy, you can create a simple HTML application for demonstration purposes.</p><ul><li>On your EC2 instance, use vim to create and edit an HTML file:</li></ul><pre>vim index.html</pre><ul><li>Press i to enter insert mode in vim.</li><li>Paste the following HTML content:</li></ul><pre>&lt;!DOCTYPE html&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>&lt;title&gt;Page Title&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br><br>&lt;h1&gt;My First AWS Project to demonstrate apps in private subnet&lt;/h1&gt;<br><br>&lt;/body&gt;<br>&lt;/html&gt;</pre><ul><li>Press Esc to exit insert mode.</li><li>Type :wq and press Enter to save the file and exit vim.</li><li>You can list the directory contents to confirm that index.html is created:</li></ul><pre>ls</pre><p><strong>Note: </strong><em>We intentionally deployed the application on only one instance to check if the load balancer will distribute 50% of the traffic to one instance, which will receive a response, and 50% to another instance, which will not receive a response.</em></p><p><em>This concept will be explained in the next part where we will create an Application Load Balancer.</em></p><h3>Viewing Your HTML Application</h3><p>To view your HTML application, you need to serve it through a web server. For simplicity, you can use Python’s built-in HTTP server.</p><p><strong>1: Install Python (if not already installed)</strong>:</p><pre>sudo yum install python3 -y</pre><p>For Ubuntu, use:</p><pre>sudo apt-get install python3 -y</pre><p><strong>2: Start the HTTP Server</strong>:</p><pre>python3 -m http.server 8000</pre><h3>Creating an Application Load Balancer</h3><p>An Application Load Balancer (ALB) in AWS distributes incoming application traffic across multiple targets, such as EC2 instances, in different availability zones.</p><p>This ensures high availability and fault tolerance for your applications.</p><p><strong>1: Sign in to AWS Console</strong>:</p><ul><li>Go to the <a href="https://aws.amazon.com/console/"><em>AWS Management Console</em></a> and sign in using your credentials.</li></ul><p><strong>2: Navigate to the EC2 Dashboard</strong>:</p><ul><li>In the AWS Management Console, search for <em>“EC2”</em> in the search bar.</li></ul><p><strong>3: Access Load Balancers</strong>:</p><ul><li>In the left-hand menu, under <em>“Load Balancing,”</em> click on <em>“Load Balancers.”</em></li></ul><p><strong>4: Create Load Balancer</strong>:</p><ul><li>Click on the <em>“Create Load Balancer” </em>button.</li><li>Choose <em>“Application Load Balancer”</em> and click on <em>“Create.”</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/785/1*0kJhSrvz9JjsI8lqWEzJ8A.png" /></figure><p><strong>5: Configure Load Balancer Basics</strong>:</p><ul><li>Enter a name for your load balancer.</li><li>Choose <em>“internet-facing”</em> to make the load balancer accessible over the internet.</li><li>Choose <em>“ipv4”.</em></li></ul><p><strong>6: Configure Network and Listeners</strong>:</p><ul><li>Select the VPC you created earlier.</li><li>Select at least two availability zones and their corresponding public subnets.</li><li>By default, a listener on port 80 (HTTP) is created. You can add more listeners if needed.</li></ul><p><strong>7: Configure Security Groups</strong>:</p><ul><li>Choose an existing security group or create a new one that allows inbound HTTP traffic (port 80).</li><li>Ensure this security group also allows any other required inbound traffic.</li></ul><p><strong>8: Configure Routing</strong>:</p><ul><li>Create a new target group.</li><li>Enter a name for your target group.</li><li>Choose <em>“Instance”</em> to register EC2 instances.</li><li>Select “HTTP” enter port 80</li><li>Configure the health check settings (default settings are usually sufficient).</li></ul><p><strong>9: Register Targets</strong>:</p><ul><li>Select the EC2 instances you want to include in this target group.</li><li>Click <em>“Include as pending below”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*p_Llb0_OLXZYrRhRx1FWig.png" /></figure><ul><li>Click <em>“Create target group”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LJGymzeSthOLwUoZkz5DvQ.png" /></figure><p><strong>10: Review and Create</strong>:</p><ul><li>Review all your settings for the Application Load Balancer.</li><li>Click <em>“Create”</em> to launch the load balancer.</li></ul><p><strong>11: Verify Load Balancer</strong>:</p><ul><li>After the ALB is created, you will see it listed in the Load Balancers section.</li><li>Note the DNS name of the ALB. This is the endpoint you will use to access your application.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5eEUbyqrrCPEvcxStdvXSw.png" /></figure><h3>Verification</h3><p><strong>1: Access the Load Balancer DNS</strong>:</p><ul><li>Open a web browser and navigate to the DNS name of the load balancer.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DQ8FF1lQmTY5Rrs3SgSg9A.png" /></figure><ul><li>You should see your application, verifying that the ALB is correctly distributing traffic.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZiVhzHMaiQvaOnzSlzS9kQ.png" /></figure><p><strong>2: Check Traffic Distribution</strong>:</p><ul><li>As noted earlier, only one instance has the application deployed.</li><li>Access the ALB DNS multiple times to observe if 50% of the requests go to the instance with the application (receiving a response) and 50% go to the instance without the application (not receiving a response).</li></ul><h3>Clean up Resources</h3><p>After completing your AWS VPC architecture project, it’s essential to clean up resources to prevent incurring unnecessary charges.</p><p>AWS bills for resources such as EC2 instances, NAT Gateways, and Load Balancers, even if they are not actively used.</p><p>Follow these steps to delete resources effectively:</p><p><strong>1: Terminate EC2 Instances:</strong></p><ul><li>Navigate to the EC2 Dashboard.</li><li>Select the instances you created for the project.</li><li>Click on <em>“Instance State” </em>and choose <em>“Terminate.”</em></li><li>Confirm the termination.</li></ul><p><strong>2: Delete Auto Scaling Groups:</strong></p><ul><li>Go to the Auto Scaling Dashboard.</li><li>Select the Auto Scaling group you created.</li><li>Click on <em>“Actions”</em> and choose <em>“Delete.”</em></li><li>Confirm the deletion.</li></ul><p><strong>3: Remove Load Balancers:</strong></p><ul><li>In the EC2 Dashboard, click on <em>“Load Balancers.”</em></li><li>Select the Application Load Balancer you created.</li><li>Click on <em>“Actions”</em> and choose <em>“Delete.”</em></li><li>Confirm the deletion.</li></ul><p><strong>4: Delete NAT Gateways:</strong></p><ul><li>Navigate to the VPC Dashboard.</li><li>Click on <em>“NAT Gateways.”</em></li><li>Select the NAT Gateway you created.</li><li>Click on<em> “Actions”</em> and choose <em>“Delete NAT Gateway.”</em></li><li>Confirm the deletion.</li><li>Ensure to release the Elastic IP associated with the NAT Gateway to avoid charges.</li></ul><p><strong>5: Remove Security Groups:</strong></p><ul><li>Go to the VPC Dashboard.</li><li>Click on <em>“Security Groups.”</em></li><li>Select the security groups created for the project.</li><li>Ensure no instances are using them, then delete the security groups.</li></ul><p><strong>6: Delete Subnets and VPC:</strong></p><ul><li>In the VPC Dashboard, click on<em> “Subnets.”</em></li><li>Select each subnet created and delete them.</li><li>After deleting all subnets, go back to the VPC Dashboard.</li><li>Select the VPC you created and delete it.</li></ul><p><strong>7: Remove Internet Gateways:</strong></p><ul><li>Navigate to the VPC Dashboard.</li><li>Click on<em> “Internet Gateways.”</em></li><li>Detach the Internet Gateway from your VPC.</li><li>Once detached, delete the Internet Gateway.</li></ul><p><strong>8: Release Elastic IP Addresses:</strong></p><ul><li>Go to the EC2 Dashboard.</li><li>Click on <em>“Elastic IPs.”</em></li><li>Select the Elastic IPs you allocated.</li><li>Click on <em>“Actions”</em> and choose <em>“Release Elastic IP Addresses.”</em></li></ul><p><strong>9: Delete Key Pairs:</strong></p><ul><li>In the EC2 Dashboard, click on <em>“Key Pairs.”</em></li><li>Select the key pairs created for the project.</li><li>Delete the key pairs.</li></ul><h3>Conclusion</h3><p>In this project, we successfully created a robust Virtual Private Cloud (VPC) infrastructure suitable for a production environment.</p><p>By deploying resources across multiple availability zones, we ensured high availability and resiliency. Key components included public and private subnets, a bastion host for secure access, an auto scaling group for automated scaling of EC2 instances, and an Application Load Balancer to distribute incoming traffic efficiently.</p><p>This setup not only enhances security through the use of private subnets and security groups but also ensures that applications remain highly available and scalable.</p><p>This foundational architecture is critical for building resilient, secure, and scalable cloud applications.</p><h3>Connect with me</h3><p>For more insights and future projects, feel free to connect with me on <a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> , </em></strong><a href="https://github.com/wangoimwangi"><strong><em>GitHub</em></strong></a><strong><em> </em></strong>and<strong> </strong><a href="https://mary-wangoi.medium.com/"><strong><em>Medium.</em></strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7602b20d3ac8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Automated Continuous Deployment with AWS Code Deploy and Code Pipeline]]></title>
            <link>https://wangoi-mwangi.medium.com/implementing-continuous-deployment-cd-with-aws-codedeploy-and-aws-code-pipeline-17b387dc7f17?source=rss-25b8a3b45b96------2</link>
            <guid isPermaLink="false">https://medium.com/p/17b387dc7f17</guid>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[ci-cd-pipeline]]></category>
            <category><![CDATA[aws-codedeploy]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[Wangoi Mwangi]]></dc:creator>
            <pubDate>Tue, 18 Jun 2024 19:56:00 GMT</pubDate>
            <atom:updated>2024-09-13T10:24:30.970Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/788/1*fMHSNvTRZzq7xSR7F9My7Q.png" /></figure><h3><strong>Introduction</strong></h3><p>In this guide, we’ll dive into setting up continuous deployment (CD) using AWS CodeDeploy, a powerful managed service for automating application deployments.</p><p>Before implementing this project, it’s crucial to complete the continuous integration (CI) phase using AWS services like CodeCommit, CodeBuild, and CodePipeline.</p><p>I’ve already covered this essential step in a previous Medium article, which you can find <a href="https://mary-wangoi.medium.com/implementing-continuous-integration-ci-with-aws-codebuild-and-aws-code-pipeline-4f8451a3c79d"><strong>here.</strong></a></p><p>Let’s streamline our deployment process with AWS CodeDeploy and ensure a smooth transition from CI to CD.</p><p><em>Feel free to connect with me on </em><a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> </em></strong><em>to discuss this post, or ask any questions.</em></p><h3>Tools and Technologies Used</h3><ul><li><strong>AWS CodePipeline</strong>: Continuous integration and continuous delivery service that orchestrates your release process.</li><li><strong>AWS CodeDeploy</strong>: Managed deployment service that automates software deployments to a variety of computing services such as Amazon EC2 instances, AWS Lambda functions, or on-premises servers.</li><li><strong>Amazon EC2</strong>: Scalable virtual servers in the cloud used as deployment targets by AWS CodeDeploy.</li></ul><p>These tools enable efficient deployment automation and scalability, ensuring reliable and consistent application releases without the need to manage underlying infrastructure.</p><h3><strong>Prerequisites</strong></h3><p>Detailed steps for setting up each prerequisite will be provided in the documentation.</p><ol><li><strong>AWS Account</strong>:</li></ol><p>You need an AWS account to access and use AWS services, including AWS CodeDeploy.</p><p><strong>2. GitHub Repository:</strong></p><p>Have a GitHub repository where your application source code is stored. This repository will trigger automated deployments in AWS CodeDeploy upon code commits.</p><p><strong>3. CodeDeploy IAM Role</strong>:</p><p>Create an IAM role with permissions for AWS CodeDeploy to access your deployment resources.</p><p><strong>4. Deployment Target</strong>:</p><p>Prepare your deployment target, which could be:</p><ul><li><strong>Amazon EC2 instances</strong>: Ensure your instances are configured with the necessary IAM roles and permissions. Steps for setting this up will be covered.</li><li><strong>AWS Fargate</strong>: Set up your Fargate profiles if deploying to serverless containers.</li></ul><p>5.<strong> Deployment Package</strong>:</p><p>Prepare your application code packaged for deployment, typically stored in Amazon S3 or another accessible repository.</p><p>6.<strong> Deployment Configuration</strong>:</p><p>Define your deployment configuration in AWS CodeDeploy, including deployment groups and deployment settings.</p><h3>Setting Up Git Repository</h3><ul><li><strong>Fork the GitHub Repository</strong>: Fork the GitHub repository I’ve prepared for this demo. You can find it <a href="https://github.com/wangoimwangi/aws-devops-zero-to-hero"><strong>here</strong></a><strong>.</strong></li></ul><h3>Create an EC2 Instance</h3><p>Note that this step can also be automated using <strong><em>Terraform</em>,</strong> but for the sake of simplicity, we will do it manually here.</p><p>Here is a detailed step-by-step guide to creating an EC2 instance:</p><ol><li><strong>Log into AWS Management Console</strong>:</li></ol><ul><li>Navigate to the <a href="https://aws.amazon.com/console/"><strong><em>AWS Management Console</em></strong></a><strong><em>.</em></strong></li><li>Sign in with your AWS credentials.</li></ul><p><strong>2. Open the EC2 Dashboard</strong>:</p><ul><li>In the AWS Management Console, search for <em>“EC2”</em> in the search bar.</li><li>Select <em>“EC2”</em> from the list of services.</li></ul><p><strong>3. Launch Instance</strong>:</p><ul><li>Click the <em>“Launch Instance”</em> button on the EC2 Dashboard.</li></ul><p><strong>4. Add Tags</strong>:</p><ul><li><em>(Optional)</em> Add tags to your instance for easier identification.</li></ul><p><strong>5. Choose an Amazon Machine Image (AMI)</strong>:</p><ul><li>Select an appropriate AMI for your needs. For this example, you can choose <em>“Ubuntu”.</em></li></ul><p><strong>6. Choose an Instance Type</strong>:</p><ul><li>Select an instance type. For most use cases, the <em>“t2.micro”</em> instance type is sufficient and is free tier eligible.</li></ul><p><strong>7. Select a Key Pair</strong>:</p><ul><li>Select an existing key pair or create a new key pair to securely access your instance.</li><li>Download the key pair file (.pem) and keep it safe. You cannot download it again after it is created.</li></ul><p><strong>8</strong>.<strong><em> </em>Configure Instance Details:</strong></p><ul><li>Optionally, configure instance details such as network settings, subnets, IAM role, etc. You can leave these settings as default for now.</li></ul><p><strong>9. Configure Security Group</strong>:</p><ul><li>Create a new security group or select an existing one.</li><li>Ensure that you have rules allowing SSH access (port 22) from your IP address.</li></ul><p><strong>10. Add Storage</strong>:</p><ul><li>The default storage settings should be sufficient.</li><li>You can adjust the size if needed.</li></ul><p><strong>11. Review and Launch</strong>:</p><ul><li>Review your instance configuration.</li><li>Click “Launch” to proceed.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kKGrZ6_KS0ph37bIuhVFSA.png" /></figure><h3>Access Your Instance</h3><p>Once the instance is launched, it will take a few minutes to initialize.</p><p>You can then connect to your instance using SSH with the downloaded .pem file.</p><p>We are using Mobaxterm to SSH to the EC2 Instance ( For Windows machines).</p><ul><li>Get <a href="https://mobaxterm.mobatek.net/"><strong>MobaXterm</strong></a> and install it.</li><li>Open MobaXterm from your desktop or the Start menu.</li><li>Click the <em>“Session”</em> button, then select <em>“SSH”.</em></li><li>Enter the IP address or hostname of the server and specify username.</li><li>Click on <em>“Advanced SSH settings”</em> tick the <em>“Use private key”</em> box and select the private key pair you used in your instance.</li><li>Click <em>“OK” </em>to connect.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*J7Y7QGWdp-GiR8aK7Fq7zg.png" /></figure><h3>Installing AWS CodeDeploy Agent</h3><p><strong>1: Install the AWS CodeDeploy Agent</strong>:</p><p>The AWS CodeDeploy agent is required on your EC2 instance to facilitate communication with the AWS CodeDeploy service.</p><p>This agent manages deployments and ensures that your application updates are orchestrated correctly according to your deployment configurations.</p><p>For detailed installation instructions, refer to the AWS documentation <a href="https://docs.aws.amazon.com/codedeploy/latest/userguide/codedeploy-agent-operations-install-ubuntu.html"><strong>here</strong></a><strong>.</strong></p><p>Ensure you select the documentation relevant to the operating system used on your EC2 instance.</p><p><strong>2: Verify the Installation</strong>:</p><p>After installing the AWS CodeDeploy agent, verify its installation by running the following command on your EC2 instance:</p><pre>sudo service codedeploy-agent status</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qyQLdT-G8IRPz_tD6m427A.png" /></figure><p><strong>Install Docker</strong></p><p>Ensure Docker is installed to use Docker commands later in the project.</p><pre>sudo apt install docker -y</pre><h3><strong>Creating IAM Role and Granting Permissions</strong></h3><p>An IAM role in AWS defines the permissions and access controls for services like AWS CodeDeploy.</p><p>It enables secure management and deployment of applications by granting necessary permissions to EC2 instances, ensuring seamless interaction with AWS services.</p><p><strong>1; Create an IAM Role</strong>:</p><ul><li>Navigate to the AWS Management Console and go to the IAM service.</li><li>Click on <em>“Roles”</em> in the left-hand menu and then <em>“Create role”</em>.</li><li>Choose the service that will use this role (EC2 in this case) and click <em>“Next: Permissions”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JvM4hL3g33huP5KbYT4HJw.png" /></figure><ul><li>In the <em>“Filter policies”</em> search box, type <em>“AWSCodeDeployRole”</em> and select the policy named AWSCodeDeployRole (for AWS managed policies).</li><li>Alternatively, create a custom policy allowing the necessary permissions for AWS CodeDeploy. Click <em>“Next”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6b5HbvKmk3Ax76wXNA3RLA.png" /></figure><ul><li>Optionally, add tags to your role for better organization and click <em>“Next: Review”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BbVWBSvxzBs6SRbsp2pgcg.png" /></figure><ul><li>Provide a name and description for the role and click <em>“Create role”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5xoyoknbURLQa_9stc1TyA.png" /></figure><p><strong>2; Attach IAM Role to EC2 Instance</strong>:</p><ul><li>Once the role is created, navigate to the <em>EC2 </em>service in the AWS Management Console.</li><li>Select your EC2 instance, click <em>“Actions”,</em> navigate to <em>“Security”,</em> and then <em>“Modify IAM Role”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qZ935VFQO35LFqEBUycA8w.png" /></figure><ul><li>Choose the IAM role created in the previous step and click <em>“Update IAM Role”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5YkCXjnEfxtaIJl-Wq92qQ.png" /></figure><p>Go to your terminal and restart your code deploy agent service.</p><pre>sudo service codedeploy-agent restart</pre><p>Then run the status again to verify it has started.</p><pre>sudo service codedeploy-agent status</pre><p><strong>3: Grant Additional Permissions</strong></p><ul><li>Navigate to the above created IAM Role.</li><li>Click on the <em>“Permissions”</em> tab, then click “<em>Add permissions</em>” and then <em>“Attach Policies”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*m7AYvwvY3W7KzH2ekIo2Ng.png" /></figure><ul><li>In the search box, type<em> “AmazonEC2FullAccess”</em> and select the policy.</li><li>Review the policy and click <em>“Add permissions”</em> to attach it to the role.</li><li>Verify the role’s permissions include both <em>AWSCodeDeployRole</em> and <em>AmazonEC2FullAccess.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*f3gRZTdtJ3Odd5mil8_m9w.png" /></figure><h3>Configure AWS Code Deploy Application</h3><p>Configure AWS CodeDeploy to orchestrate and automate application deployments across your AWS infrastructure.</p><p>Follow these steps to set up deployment groups, define deployment settings, and integrate with other AWS services seamlessly.</p><ul><li>Go to the AWS Management Console and select the <em>AWS CodeDeploy service.</em></li><li>Click on <em>“Create Application” </em>button.</li><li>Provide a name for your application.</li><li>Select the compute platform where your application will be deployed <em>(EC2/On-premises or AWS Lambda).</em></li><li>Click on <em>“Create application” </em>to finalize and create the application.</li><li>Once created, you will see the new application listed in your CodeDeploy dashboard.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OxbvTVIjxRReWal34YmwKA.png" /></figure><h3>Create Deployment Group in AWS CodeDeploy</h3><p>Set up a deployment group in AWS CodeDeploy to define where and how your application will be deployed across your AWS infrastructure.</p><p>Follow these steps to configure deployment settings, choose deployment targets, and finalize the setup for seamless application deployments.</p><ul><li>Navigate to AWS CodeDeploy Console</li><li>In the CodeDeploy dashboard, click on the name of the application you previously created.</li><li>Click on the <em>“Create deployment group”</em> button.</li><li>Provide a name for your deployment group.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*g-19IR0UQmQ1iKTzjINRvA.png" /></figure><ul><li>Configure deployment settings like service role.</li><li>Choose the deployment type <em>(In-place or Blue/green).</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/946/1*Dd3Fl5orh1kOSDrRx8yqsQ.png" /></figure><ul><li>Select the environment configuration <em>(EC2/On-premises or AWS Lambda).</em></li><li>Mention the key and value of this. (It will be matched with an Instance)</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/974/1*52JSSdRCu0vLDfjKE2y0kw.png" /></figure><ul><li>You can configure advanced settings such as triggers, alarms, and notifications.</li><li>Click on<em> “Create deployment group” </em>to finalize and create the deployment group.</li><li>Once created, the new deployment group will be listed under your application in the CodeDeploy dashboard.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*m3f4VNnmwgrNBB19zrD0fg.png" /></figure><h3>Create a Deployment in AWS CodeDeploy</h3><ul><li>Navigate to AWS CodeDeploy Console</li><li>In the CodeDeploy dashboard, click on the name of the application you previously created.</li><li>Click on <em>“Create deployment”.</em></li><li>Select the deployment group you created earlier.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/946/1*4Kx5pFmt-yuOmMfRKG1yFg.png" /></figure><ul><li>Choose the source of your application code. Options include:</li></ul><p><strong>S3</strong>: Specify the S3 bucket name and object key.</p><p><strong>GitHub</strong>: Provide the repository name and commit ID.</p><p><strong>Bitbucket</strong>: Provide the repository name and commit ID.</p><p><strong>Local file</strong>: Upload a local file as the revision.</p><ul><li>Optionally, provide a description for the deployment.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/911/1*aypU_IQwGz1ikZmTgrBbnA.png" /></figure><ul><li>Configure additional options (optional).</li><li>Click on <em>“Create deployment”</em> to start the deployment process.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-Pp2t0BjWaaszhlEcnZuGQ.png" /></figure><ul><li>Monitor the status of your deployment in the CodeDeploy dashboard to ensure it completes successfully.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fMinwGN3nDC9eNVCrmu09g.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NCmMMMbkxW4EEUx9EK5_jQ.png" /></figure><h3>Integrate AWS CodeDeploy with AWS CodePipeline</h3><p>Integrating AWS CodeDeploy with AWS CodePipeline automates your deployment process, enabling continuous delivery (CD).</p><p>This integration ensures that every change in your source code repository triggers a new deployment, streamlining your workflow and improving deployment efficiency.</p><p>Here are the steps to set up this integration:</p><ul><li>Log in to the AWS Management Console.</li><li>Go to the AWS CodePipeline service.</li><li>Find and select the pipeline we set up in the previous project while working on the CI part of this project.</li><li>Find the steps of creating the pipeline <a href="https://mary-wangoi.medium.com/implementing-continuous-integration-ci-with-aws-codebuild-and-aws-code-pipeline-4f8451a3c79d"><strong>here.</strong></a></li><li>Click on <em>“Edit”</em> in the top-right corner of the pipeline details page.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/832/1*zJ8-25_aGuRQAeo5rPUeBQ.png" /></figure><ul><li>Click on <em>“Add stage” </em>at the appropriate point in your pipeline where you want the deployment to occur (typically after the build stage).</li><li>Name the stage<em> (e.g., “Deploy”) </em>then click <em>“Add Stage”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/498/1*qAtxOhFxBl_uvRYFDFW2Bw.png" /></figure><ul><li>Provide a name for this action <em>(e.g., “DeployAction”).</em></li><li>Select <em>“AWS CodeDeploy”.</em></li><li>Select the region where your CodeDeploy application is located.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1023/1*Td1KEGpB1cVt8FDKk3L_gg.png" /></figure><ul><li>Select the output artifact from the previous build stage.</li><li>Choose the CodeDeploy application you created.</li><li>Choose the CodeDeploy deployment group you created.</li><li>Click on “Done”.</li><li>Review the changes to ensure that the new deploy stage and action are correctly configured.</li><li>Click on “Save pipeline changes”.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/939/1*zM-9R8WunNGsgJKyJo_2Lw.png" /></figure><ul><li>Trigger the pipeline manually by clicking <em>“Release change”</em> or wait for an automated trigger from a new code commit.</li><li>Monitor the progress of the pipeline in the CodePipeline console. Each stage (Source, Build, Deploy) will show its status.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/823/1*-Fz6lN24IyV-xIMr8pnAWw.png" /></figure><h3>Clean Up Resources</h3><p>After completing the deployment, it’s important to clean up resources to avoid unnecessary charges. Ensure you:</p><ol><li><strong>Terminate EC2 Instances</strong>: Stop and terminate the EC2 instances used for deployment.</li><li><strong>Delete the CodeDeploy Application</strong>: Remove the CodeDeploy application and deployment groups.</li><li><strong>Remove IAM Roles and Policies</strong>: Delete any IAM roles and policies created specifically for this project.</li><li><strong>Clean Up the CodePipeline</strong>: If no longer needed, delete the CodePipeline to prevent further triggers and resource usage.</li></ol><p>By cleaning up, you maintain a tidy AWS environment and avoid incurring unexpected costs.</p><h3><strong>Conclusion</strong></h3><p>In this project, we extended our existing CI pipeline by integrating AWS CodeDeploy to automate the deployment process.</p><p>By following the outlined steps, we successfully set up a seamless CI/CD pipeline using AWS services.</p><p>This setup ensures efficient, automated deployments, enhancing our workflow and reducing manual intervention.</p><p>Feel free to refer to this guide for setting up similar projects, and explore the benefits of continuous delivery using AWS CodeDeploy.</p><p>For further information on the CI part of this project, you can refer<a href="https://mary-wangoi.medium.com/implementing-continuous-integration-ci-with-aws-codebuild-and-aws-code-pipeline-4f8451a3c79d"> <strong>here.</strong></a></p><h3>Connect with me</h3><p>For more insights and future projects, feel free to connect with me on <a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> , </em></strong><a href="https://github.com/wangoimwangi"><strong><em>GitHub</em></strong></a><strong><em> </em></strong>and<strong> </strong><a href="https://mary-wangoi.medium.com/"><strong><em>Medium.</em></strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=17b387dc7f17" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Streamlined Continuous Integration Using AWS Code Build and Code Pipeline]]></title>
            <link>https://wangoi-mwangi.medium.com/implementing-continuous-integration-ci-with-aws-codebuild-and-aws-code-pipeline-4f8451a3c79d?source=rss-25b8a3b45b96------2</link>
            <guid isPermaLink="false">https://medium.com/p/4f8451a3c79d</guid>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[ci-cd-pipeline]]></category>
            <category><![CDATA[aws-codepipeline]]></category>
            <dc:creator><![CDATA[Wangoi Mwangi]]></dc:creator>
            <pubDate>Tue, 18 Jun 2024 19:48:04 GMT</pubDate>
            <atom:updated>2024-09-13T10:25:27.626Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/788/1*fMHSNvTRZzq7xSR7F9My7Q.png" /></figure><h3>Introduction</h3><p>In modern software development, Continuous Integration (CI) plays a crucial role in automating build and test processes, ensuring efficient code integration and quality assurance.</p><p>This project explores CI practices using AWS CodeBuild and AWS CodePipeline to automate the build, test, and validation of code changes.</p><p>This article focuses exclusively on the CI aspect. For Continuous Deployment (CD), please refer to the documentation <a href="https://mary-wangoi.medium.com/implementing-continuous-deployment-cd-with-aws-codedeploy-and-aws-code-pipeline-17b387dc7f17"><strong>here.</strong></a></p><p><em>Feel free to connect with me on </em><a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> </em></strong><em>to discuss this post, or ask any questions.</em></p><h3><strong>Tools and Technologies Used</strong></h3><p>This project utilizes a range of tools and technologies to streamline Continuous Integration (CI) with AWS CodeBuild and AWS CodePipeline:</p><ul><li><strong>AWS CodeBuild:</strong> AWS’s fully managed build service for compiling source code, running tests, and producing software packages.</li><li><strong>AWS CodePipeline:</strong> A continuous integration and continuous delivery service that orchestrates workflows for building, testing, and deploying code changes.</li><li><strong>GitHub:</strong> A version control repository to store and manage source code, triggering automated builds in AWS CodeBuild upon code commits.</li><li><strong>Docker:</strong> A platform for developing, shipping, and running applications inside containers, providing consistency across development, testing, and deployment environments.</li><li><strong>Docker Hub:</strong> A cloud-based repository for Docker container images used in the application.</li><li><strong>AWS Systems Manager:</strong> Facilitates secure storage and management of Docker Hub credentials using Parameter Store, ensuring sensitive information is stored centrally and accessed securely.</li></ul><p>These tools and technologies together automate build and test processes, ensure efficient integration of code changes, and enhance overall development productivity.</p><h3>Prerequisites</h3><p>Detailed steps for setting up each prerequisite will be provided in the documentation.</p><ul><li><strong>AWS Account:</strong></li></ul><p>Sign up for an AWS account to access AWS CodeBuild, AWS CodePipeline, and other AWS services.</p><ul><li><strong>GitHub Repository:</strong></li></ul><p>Have a GitHub repository where your application source code is stored. This repository will trigger automated builds in AWS CodeBuild upon code commits.</p><ul><li><strong>AWS IAM Role:</strong></li></ul><p>Create an IAM role with necessary permissions to allow AWS CodePipeline and AWS CodeBuild to access AWS resources securely.</p><ul><li><strong>AWS CLI:</strong></li></ul><p>Install and configure the AWS Command Line Interface (CLI) to interact with AWS services from your terminal.</p><ul><li><strong>Docker Hub Account (Optional):</strong></li></ul><p>If using Docker containers, have a Docker Hub account to store and manage Docker images used in your application.</p><ul><li><strong>Access to AWS Systems Manager (Optional):</strong></li></ul><p>Ensure access to AWS Systems Manager Parameter Store if storing sensitive credentials like Docker Hub credentials securely.</p><h3>Setting Up Git Repository</h3><ul><li><strong>Fork the GitHub Repository</strong>: Fork the GitHub repository I’ve prepared for this demo. You can find it <a href="https://github.com/wangoimwangi/aws-devops-zero-to-hero"><strong>here</strong></a><strong>.</strong></li></ul><h3>Create IAM Role and Add Permissions</h3><ul><li>Navigate to the <a href="https://console.aws.amazon.com/iam/"><strong>AWS IAM Console</strong></a><strong>.</strong></li><li>In the left-hand menu, click on <em>“Roles” </em>under<em> “Access management”.</em></li><li>Click on the <em>“Create role”</em> button.</li><li>Select the service that will use this role, choose<em> “AWS service”</em> .</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GAFhn8rGDn6LTzNpzUg0jA.png" /></figure><ul><li>Select <em>“CodeBuild”</em> for the service.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ro-w_YfUfymJ3161G5l6XQ.png" /></figure><ul><li>Search for and select the following policies to attach to the role: <em>AmazonEC2FullAccess and AmazonSSMFullAccess.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4JaPFqrBVgqs3v-WXY24dg.png" /></figure><ul><li>Provide a name and description for the role, then click <em>“Create role”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qeGpIIua32kW8A5DgU9VGw.png" /></figure><ul><li>Optionally, add tags to your IAM role for better organization and management.</li><li>Review everything then click <em>“Create role”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MjGunlUI5GSjEqjxe7Y7Vw.png" /></figure><h3><strong>Configure AWS Systems Manager Parameter Store</strong></h3><p>To securely manage and access Docker credentials such as username, password, and Docker registry URL within AWS environments, the AWS Systems Manager Parameter Store provides a robust solution.</p><p>By storing these sensitive values as SecureString parameters, AWS ensures encryption using AWS Key Management Service (KMS), maintaining the confidentiality and integrity of your credentials.</p><p>This setup is crucial for integrating Docker-based workflows with AWS services like AWS CodeBuild and AWS CodePipeline, enabling seamless and secure CI/CD pipelines.</p><ul><li>Navigate to the <a href="https://console.aws.amazon.com/systems-manager/"><strong>AWS Systems Manager Console</strong></a><strong>.</strong></li><li>Click on <em>“Parameter Store” </em>in the left-hand menu</li><li>Click on the <em>“Create parameter” </em>button.</li><li>Enter parameter details: Enter a name for your parameter, such as /docker/username, /docker/password, and /docker/registry-url.</li><li>Optionally, provide a description to document the purpose of the parameter.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KN5daZA88kiO8GL2BprMmQ.png" /></figure><ul><li>Choose <em>“SecureString”</em> as the parameter type. This encrypts the parameter value with an AWS Key Management Service (KMS) key, ensuring secure storage.</li><li>Optionally, you can choose a specific AWS KMS key to encrypt the parameter value. AWS manages the default KMS key if none is specified.</li><li>Create the value</li><li>Click on <em>“Create parameter” </em>to save.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WXh5O0Dza28Y9t3mbFterw.png" /></figure><p>The Docker credentials are securely stored in the AWS Systems Manager Parameter Store.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-24nLr0TRCw-hPYIhV-nRA.png" /></figure><h3>AWS CodeBuild</h3><ul><li>Navigate to the <a href="https://console.aws.amazon.com/codesuite/codebuild/home"><strong>AWS CodeBuild Console</strong></a><strong>.</strong></li><li>Click on<em> “Create build project” </em>button.</li><li>Enter a name for your CodeBuild project.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/961/1*aC1sHnb9jC2hOkb4UIqLiA.png" /></figure><ul><li>Choose the source provider where your build will fetch the code. This could be AWS CodeCommit, GitHub, Bitbucket, or Amazon S3.</li><li>Specify the branch, tag, or revision ID for the source code version.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/923/1*Ze6_EVntqQ8NIe-l2AMIFA.png" /></figure><ul><li>Define the build environment with details such as operating system, runtime version, and Docker configuration if applicable.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/971/1*e1ffXUqu5ifTMCNMK24u-A.png" /></figure><ul><li>Choose<em> </em>an<em> “existing service role.”</em></li><li>From the dropdown menu, select the IAM role you created in the previous steps. This role should have the necessary permissions, such as SSM Full Access, to access the Docker credentials stored in AWS Systems Manager and any other required resources.</li><li>Ensure you enable the privileged box.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/978/1*azbJH9tiDdFtT6qxPy40gg.png" /></figure><ul><li>Choose between using a <em>buildspec file </em>stored in your source code repository or providing a<em> buildspec </em>directly in the console.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/934/1*Xwz2UtZLujlKIlyZPLbRzw.png" /></figure><p><strong>Buildspec file</strong></p><ul><li>Copy and paste this buildspec file.</li></ul><pre>version: 0.2<br><br>env:<br>  parameter-store:<br>    DOCKER_REGISTRY_USERNAME: /myapp/docker-credentials/username<br>    DOCKER_REGISTRY_PASSWORD: /myapp/docker-credentials/password<br>    DOCKER_REGISTRY_URL: /myapp/docker-registry/url<br>phases:<br>  install:<br>    runtime-versions:<br>      python: 3.11<br>  pre_build:<br>    commands:<br>      - echo &quot;Installing dependencies...&quot;<br>      - pip install -r day-14/simple-python-app/requirements.txt<br>  build:<br>    commands:<br>      - echo &quot;Running tests...&quot;<br>      - cd day-14/simple-python-app/<br>      - echo &quot;Building Docker image...&quot;<br>      - echo &quot;$DOCKER_REGISTRY_PASSWORD&quot; | docker login -u &quot;$DOCKER_REGISTRY_USERNAME&quot; --password-stdin &quot;$DOCKER_REGISTRY_URL&quot;<br>      - docker build -t &quot;$DOCKER_REGISTRY_URL/$DOCKER_REGISTRY_USERNAME/simple-python-flask-app:latest&quot; .<br>      - docker push &quot;$DOCKER_REGISTRY_URL/$DOCKER_REGISTRY_USERNAME/simple-python-flask-app:latest&quot;<br>  post_build:<br>    commands:<br>      - echo &quot;Build completed successfully!&quot;<br>artifacts:<br>  files:<br>    - &#39;**/*&#39;<br>  base-directory: ../simple-python-app</pre><ul><li>Configure where build logs should be stored for monitoring and troubleshooting.</li><li>Specify the build artifacts to be generated and where they should be stored (e.g., S3 bucket).</li><li>Review the configuration details to ensure accuracy.</li><li>Click on <em>“Create build project”</em> to create the CodeBuild project.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1006/1*kJPC-D_l53cReOZxGkZH8g.png" /></figure><ul><li>The CodeBuild project is now created and ready to execute builds based on the specified configuration.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*E3vfhyZ69guZwQLySvNpUw.png" /></figure><ul><li>Click <em>“Start Build”.</em></li><li>Use<em> “Build Details” </em>to see the status of the build.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*H_0LPgL8XJJ9Rp_pZEDu_Q.png" /></figure><p>By following these steps, you can create an AWS CodeBuild project that integrates with your source code repository and is configured to build Docker images or execute other build tasks as per your project requirements.</p><h3><strong>Verify the Image Was Pushed to Docker Hub</strong></h3><ul><li>Log in to your Docker Hub account.</li><li>Navigate to the repository where you expected the image to be pushed.</li><li>Verify that the image is present with the correct tag and was pushed recently.</li></ul><p>By following these steps, you can confirm that your Docker image was successfully pushed to Docker Hub, ensuring the build process was completed correctly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9N-GGG93aq5fuwEi1jsGQw.png" /></figure><h3>AWS Code Pipeline</h3><p>In this step, we will set up an AWS CodePipeline to automate the continuous integration (CI) process.</p><p>CodePipeline is a fully managed continuous delivery service that helps you automate your release pipelines for fast and reliable application and infrastructure updates.</p><p>By integrating with your source repository and CodeBuild project, CodePipeline will automatically detect changes in your code and trigger the build process.</p><p>For this article, we’ll focus on the CI part, ensuring that every code change is automatically built and tested.</p><p>The deployment (CD) part is covered in another documentation, which you can find <a href="https://mary-wangoi.medium.com/implementing-continuous-deployment-cd-with-aws-codedeploy-and-aws-code-pipeline-17b387dc7f17"><strong>here.</strong></a></p><ul><li>Open the AWS Management Console.</li><li>Navigate to the AWS CodePipeline service.</li><li>Click on <em>“Create pipeline” </em>to start the pipeline creation wizard.</li><li>Enter a name for your pipeline.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*v_gdKMj7jCE3HlCdnyrkiw.png" /></figure><ul><li>Select <em>“New service role” </em>to let AWS create a role for the pipeline or <em>“Existing service role” </em>if you have a preconfigured IAM role.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/902/1*VDodBM6zmNooY3YDes74Ug.png" /></figure><ul><li>Select the source provider for your code repository <em>(e.g., AWS CodeCommit, GitHub, Bitbucket).</em></li><li>Enter the name of your repository.</li><li>Specify the branch to use (e.g., main or master).</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/917/1*1QIkl9h1wDPzOJVZCSuglQ.png" /></figure><ul><li>Choose AWS CodeBuild.</li><li>Select the region where your CodeBuild project is located.</li><li>Select the CodeBuild project you created earlier.</li><li>Add any necessary environment variables required for the build process.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/952/1*Hz140gxpIHThAPrSuwY80w.png" /></figure><ul><li>Skip code deploy, since this guide focuses on CI, you might not need a deploy stage here.</li><li>Review all the stages and configurations.</li><li>Click on <em>“Create pipeline” </em>to finalize and create your CodePipeline.</li><li>Trigger the pipeline manually by clicking <em>“Release change”</em> or wait for an automated trigger from a new code commit.</li><li>Monitor the progress of the pipeline in the CodePipeline console. Each stage (Source, Build) will show its status.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/831/1*rbfFBMAD7BPeRnWZZ74rnQ.png" /></figure><h3>Clean Up Resources</h3><p>After completing the deployment, it’s important to clean up resources to avoid unnecessary charges. Ensure you:</p><p><strong>1: Delete the CodePipeline: </strong>Select the pipeline you created and delete it.</p><p>2: <strong>Delete the CodeBuild Project: </strong>Select the build used in the pipeline and delete it.</p><p>3: <strong>Remove Secrets from AWS Systems Manager: </strong>Select and delete the parameters used to store Docker credentials.</p><p>4: <strong>Clean Up IAM Roles: </strong>Find the roles created for this project (e.g., CodePipeline and CodeBuild roles). Detach any policies attached to these roles and then delete the roles.</p><p><strong>Verify Deletion</strong>:</p><p>Double-check that all resources have been deleted from the AWS Management Console to ensure there are no lingering resources that could incur charges.</p><h3>Conclusion</h3><p>In this project, we successfully set up a Continuous Integration (CI) pipeline using AWS CodePipeline and AWS CodeBuild, complemented by AWS Systems Manager for securely managing Docker credentials.</p><p>This setup ensures that every code change is automatically built and tested, streamlining our development workflow and maintaining code quality.</p><p>By leveraging these AWS services, we’ve created a scalable and efficient CI pipeline that supports rapid development and deployment.</p><p>For further information on the CD part of this project, you can refer <a href="https://mary-wangoi.medium.com/implementing-continuous-deployment-cd-with-aws-codedeploy-and-aws-code-pipeline-17b387dc7f17"><strong>here.</strong></a></p><h3>Connect with me</h3><p>For more insights and future projects, feel free to connect with me on <a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> , </em></strong><a href="https://github.com/wangoimwangi"><strong><em>GitHub</em></strong></a><strong><em> </em></strong>and<strong> </strong><a href="https://mary-wangoi.medium.com/"><strong><em>Medium.</em></strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4f8451a3c79d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Serverless Application Deployment with AWS EKS and Fargate]]></title>
            <link>https://blog.devops.dev/streamlined-deployment-leveraging-aws-eks-and-fargate-e3d046263f4a?source=rss-25b8a3b45b96------2</link>
            <guid isPermaLink="false">https://medium.com/p/e3d046263f4a</guid>
            <category><![CDATA[ingress]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[aws-eks]]></category>
            <category><![CDATA[devops]]></category>
            <dc:creator><![CDATA[Wangoi Mwangi]]></dc:creator>
            <pubDate>Wed, 12 Jun 2024 15:20:32 GMT</pubDate>
            <atom:updated>2024-09-13T10:17:26.591Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/910/1*ymDNYCdoqKkAJgvxUJhC0Q.png" /></figure><h3><strong>Introduction</strong></h3><p>In today’s fast-paced development environment, deploying applications in a scalable, reliable, and efficient manner is crucial.</p><p>This guide will walk you through deploying a containerized application using Amazon Web Services (AWS) Elastic Kubernetes Service (EKS) and AWS Fargate.</p><p>By the end, you’ll understand how to leverage these tools to streamline your deployment process for various architectures, including 2-tier (web server and database) and 3-tier (web server, application server, and database) applications.</p><p><em>Feel free to connect with me on </em><a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> </em></strong><em>to discuss this post, or ask any questions.</em></p><h3><strong>Project Overview</strong></h3><p>In this project, we aim to deploy an application on AWS, utilizing <strong>EKS</strong> for orchestrating the Kubernetes control plane and <strong>Fargate</strong> to manage serverless compute resources for the worker nodes.</p><p>This setup ensures our application benefits from Kubernetes’ orchestration capabilities and Fargate’s scalability and simplicity.</p><p>Additionally, we will configure <strong>Ingress </strong>to manage external access to the services within our cluster, providing load balancing and SSL termination.</p><h3><strong>Tools and Technologies Used</strong></h3><p>We will be utilizing a variety of technologies and tools in this guide, including:</p><ul><li><strong>Amazon EKS:</strong> Managed Kubernetes service simplifying control plane and node operations.</li><li><strong>AWS Fargate:</strong> Serverless compute engine for containers, eliminating the need for infrastructure management.</li><li><strong>Kubernetes:</strong> An open-source system for automating deployment, scaling, and management of containerized applications.</li><li><strong>Docker:</strong> A Platform for developing, shipping, and running applications inside containers.</li><li><strong>kubectl:</strong> Command-line tool for interacting with Kubernetes clusters.</li><li><strong>eksctl:</strong> Command-line tool for creating and managing EKS clusters.</li><li><strong>AWS CLI:</strong> Tool to manage AWS services from the command line.</li><li><strong>Ingress:</strong> Kubernetes resource managing external access to services, providing load balancing and SSL termination.</li></ul><h3><strong>Prerequisites</strong></h3><p>Before we dive into the deployment process, ensure you have the following:</p><ol><li><strong>AWS Account</strong>: Sign up for an <a href="https://aws.amazon.com/free/">AWS account</a> to create and manage resources like EKS clusters and Fargate profiles.</li><li><strong>AWS CLI</strong>: Install and configure the AWS Command Line Interface (CLI) to manage AWS services. Follow the instructions <a href="https://aws.amazon.com/cli/">here</a>.</li><li><strong>kubectl</strong>: Install the kubectl command-line tool for interacting with Kubernetes clusters. Follow the instructions <a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/">here.</a></li><li><strong>eksctl</strong>: Install eksctl, a command-line utility for creating and managing EKS clusters. Follow the instructions <a href="https://github.com/weaveworks/eksctl#installation">here</a>.</li></ol><p>Ensure all prerequisites are met before proceeding with the deployment steps.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5_jsLdTsoBlHen1Ybxbq0g.png" /></figure><h3><strong>Setting Up the EKS Cluster and Worker Nodes</strong></h3><p><strong>Create an EKS Cluster</strong>:</p><ul><li>The first step is to create an EKS cluster. You can do this using the eksctl command-line tool, which simplifies cluster creation.</li><li>Specify configuration options such as region, version, and node instance type.</li><li>Run the command to create the cluster.</li></ul><pre>eksctl create cluster --name &lt;cluster-name&gt; --region &lt;region-name&gt; --fargate</pre><p>Replace &lt;cluster-name&gt; with your desired cluster name and &lt;region-name&gt; with the region for deployment.</p><p><strong>Note:</strong> <em>The EKS cluster creation process can take several minutes to complete. Please be patient during this step.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/945/1*cObK9vk3Aky-XbR36I8wIQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/987/1*aaUeCLtDKcr1FmIHMampug.png" /></figure><p><strong>Configure Fargate Profiles:</strong></p><ul><li>Define Fargate profiles to specify which Kubernetes namespaces should use Fargate for running pods.</li><li>Create Fargate profiles for the necessary namespaces using eksctl or the AWS Management Console.</li></ul><pre>eksctl create fargateprofile --cluster &lt;cluster-name&gt; --region &lt;region-name&gt; --name &lt;fargate-profile-name&gt; --namespace &lt;namespace-name&gt;</pre><p>Ensure that you replace &lt;cluster-name&gt;, &lt;region-name&gt;, &lt;fargate-profile-name&gt;, and &lt;namespace-name&gt; with the appropriate values for your setup.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1FUzquWp4AsSBvtw-j8PdQ.png" /></figure><p><strong>Note:</strong><em> With EKS, you have the flexibility to choose between EC2 instances, which are self-managed, and Fargate, which is managed by AWS, for your worker nodes.</em></p><p><strong>Verify Setup</strong>:</p><ul><li>Access the AWS Management Console and navigate to the <em>“Amazon EKS” </em>service.</li><li>Choose the EKS cluster you recently created and review its details, including its name, status, and configuration.</li><li>In the selected cluster, find the <em>“Fargate Profiles”</em> tab on the cluster details page and confirm the successful creation of Fargate profiles.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_svCzxrs6_affVboi_1Qig.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QQsHyGEt_dRHnqbgmDj2WA.png" /></figure><h3>Update kubeconfig</h3><p>After creating the EKS cluster, you need to update your<strong> kubeconfig file</strong> to interact with the cluster using kubectl. Follow these steps:</p><ul><li>Use the AWS CLI to update the kubeconfig file with your new cluster’s details:</li></ul><pre>aws eks update-kubeconfig --name &lt;cluster-name&gt; --region &lt;region-name&gt;</pre><p>Replace &lt;cluster-name&gt; with the name of your EKS cluster and &lt;region-name&gt; with the AWS region where your cluster is deployed.</p><ul><li>Confirm that the kubeconfig file has been updated correctly by running the following command:</li></ul><pre>kubectl config get-contexts</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OTVaxsmwrx3fQMMr0BdZKg.png" /></figure><h3>Configure IAM OIDC Provider</h3><p>To enable IAM roles for service accounts and allow your EKS cluster to access AWS services securely, you need to configure an IAM OpenID Connect (OIDC) provider. Follow these steps:</p><ol><li><strong>Create the OIDC Identity Provider</strong>:</li></ol><ul><li>Use the eksctl command to associate the <strong>IAM OIDC provider</strong> with your EKS cluster.</li></ul><pre>eksctl utils associate-iam-oidc-provider --cluster &lt;cluster-name&gt; --region &lt;region-name&gt; --approve</pre><p>Replace &lt;cluster-name&gt; with the name of your EKS cluster and &lt;region-name&gt; with the AWS region where your cluster is deployed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/993/1*uR7DXrJ8QPUtMjvWYlTaRg.png" /></figure><p><strong>2. Verify the OIDC Provider Configuration</strong>:</p><ul><li>Go to the AWS Management Console.</li><li>Navigate to the<em> “IAM”</em> service.</li><li>In the left-hand menu, select <em>“Identity providers.”</em></li><li>You should see an entry for the OIDC provider associated with your EKS cluster.</li></ul><h3><strong>Setup AWS Load Balancer (ALB) Add-On</strong></h3><ol><li><strong>Download IAM Policy:</strong></li></ol><p>Download the IAM policy for the AWS Load Balancer Controller:</p><pre>curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.5.4/docs/install/iam_policy.json</pre><p><strong>2. Create IAM Policy:</strong></p><p>Create an IAM policy using the downloaded JSON file:</p><pre>aws iam create-policy \<br>    --policy-name AWSLoadBalancerControllerIAMPolicy \<br>    --policy-document file://iam_policy.json</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1017/1*DryzsTzN7RXQ0Ld6uWTIwg.png" /></figure><p><strong>3. Create IAM Role:</strong></p><p>Create an IAM role and attach the IAM policy to the service account in your EKS cluster:</p><pre>eksctl create iamserviceaccount \<br>  --cluster=&lt;your-cluster-name&gt; \<br>  --namespace=kube-system \<br>  --name=aws-load-balancer-controller \<br>  --role-name AmazonEKSLoadBalancerControllerRole \<br>  --attach-policy-arn=arn:aws:iam::&lt;your-aws-account-id&gt;:policy/AWSLoadBalancerControllerIAMPolicy \<br>  --approve</pre><p>Replace &lt;your-cluster-name&gt; with the name of your EKS cluster and &lt;your-aws-account-id&gt; with your AWS account ID.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/995/1*y4c5sw3_L31KfYo5zWuURw.png" /></figure><p><strong>Note: </strong><em>Configuring the IAM OIDC provider and associating IAM roles with service accounts enhances the security and flexibility of your EKS cluster by allowing fine-grained access control to AWS resources.</em></p><h3>Deploy ALB Controller</h3><p><strong>a. Add Helm Repo:</strong> Add the EKS Helm repository.</p><pre>helm repo add eks https://aws.github.io/eks-charts</pre><p><strong>b. Update the Repo:</strong> Update the Helm repository.</p><pre>helm repo update eks</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/947/1*8nC8r8OmsnRhXdJT5_gfwA.png" /></figure><p><strong>c. Install the ALB Controller:</strong> Install the AWS Load Balancer Controller using Helm:</p><pre>helm install aws-load-balancer-controller eks/aws-load-balancer-controller \            <br>  -n kube-system \<br>  --set clusterName=&lt;your-cluster-name&gt; \<br>  --set serviceAccount.create=false \<br>  --set serviceAccount.name=aws-load-balancer-controller \<br>  --set region=&lt;region&gt; \<br>  --set vpcId=&lt;your-vpc-id&gt;</pre><p>Replace &lt;your-cluster-name&gt;, &lt;region&gt;, and &lt;your-vpc-id&gt; with your specific values.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*TJRIKTpswNiXHhkKndaohA.png" /></figure><p><strong>d. Verify Deployment:</strong> Ensure that the AWS Load Balancer Controller deployment is running.</p><pre>kubectl get deployment -n kube-system aws-load-balancer-controller</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/991/1*fA7ICF2NkS0Sjb7T4Z3Jzw.png" /></figure><h3>Deploying the Application</h3><p>To deploy your application on AWS EKS, you will need to create and apply the necessary Kubernetes resource files: deployment.yaml, service.yaml, and ingress.yaml.</p><p>Below are the steps to apply each file individually.</p><h4>1. Deployment</h4><p><strong>What is a Deployment?</strong></p><p>A Deployment in Kubernetes is used to manage a set of identical pods, ensuring the desired number of replicas are running at any given time.</p><p>It allows for easy updates, rollbacks, and scaling of applications.</p><p>First, create the namespace and deployment for your application.</p><p><strong>deployment.yaml:</strong></p><pre>---<br>apiVersion: v1<br>kind: Namespace<br>metadata:<br>  name: game-2048<br>---<br>apiVersion: apps/v1<br>kind: Deployment<br>metadata:<br>  namespace: game-2048<br>  name: deployment-2048<br>spec:<br>  selector:<br>    matchLabels:<br>      app.kubernetes.io/name: app-2048<br>  replicas: 5<br>  template:<br>    metadata:<br>      labels:<br>        app.kubernetes.io/name: app-2048<br>    spec:<br>      containers:<br>      - image: public.ecr.aws/l6m2t8p7/docker-2048:latest<br>        imagePullPolicy: Always<br>        name: app-2048<br>        ports:<br>        - containerPort: 80</pre><p>Apply the deployment:</p><pre>kubectl apply -f deployment.yaml</pre><h4>2. Service</h4><p><strong>What is a Service?</strong></p><p>A Service in Kubernetes is an abstraction that defines a logical set of pods and a policy by which to access them.</p><p>Services enable network access to a set of pods, typically through a single IP address and a set of ports.</p><p>Next, create a service to expose your application.</p><p><strong>service.yaml:</strong></p><pre>---<br>apiVersion: v1<br>kind: Service<br>metadata:<br>  namespace: game-2048<br>  name: service-2048<br>spec:<br>  ports:<br>    - port: 80<br>      targetPort: 80<br>      protocol: TCP<br>  type: NodePort<br>  selector:<br>    app.kubernetes.io/name: app-2048</pre><p>Apply the service:</p><pre>kubectl apply -f service.yaml</pre><h4>3. Ingress</h4><p><strong>What is an Ingress?</strong></p><p>An Ingress in Kubernetes manages external access to the services in a cluster, typically HTTP and HTTPS.</p><p>It provides load balancing, SSL termination, and name-based virtual hosting.</p><p>Finally, create an ingress resource to manage external access to your application.</p><p><strong>ingress.yaml:</strong></p><pre>---<br>apiVersion: networking.k8s.io/v1<br>kind: Ingress<br>metadata:<br>  namespace: game-2048<br>  name: ingress-2048<br>  annotations:<br>    alb.ingress.kubernetes.io/scheme: internet-facing<br>    alb.ingress.kubernetes.io/target-type: ip<br>spec:<br>  ingressClassName: alb<br>  rules:<br>    - http:<br>        paths:<br>        - path: /<br>          pathType: Prefix<br>          backend:<br>            service:<br>              name: service-2048<br>              port:<br>                number: 80</pre><p>Apply the ingress:</p><pre>kubectl apply -f ingress.yaml</pre><h3>Verify the Deployment</h3><p>After applying all the configurations, verify that your resources are running correctly:</p><p><strong>Check the deployment:</strong></p><pre>kubectl get deployments -n game-2048</pre><p><strong>Check the service:</strong></p><pre>kubectl get services -n game-2048</pre><p><strong>Check the ingress:</strong></p><pre>kubectl get ingress -n game-2048</pre><p>Ensure that the status of the resources indicates successful deployment and that the ingress has an address assigned by the ALB.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1016/1*9c8csXQ1slc5VG9PCXBVWg.png" /></figure><h3><strong>Accessing the Application via Ingress</strong></h3><p>Once the Ingress resource is set up, you can access your application through the ALB (Application Load Balancer) created by the Ingress controller.</p><p>Follow these steps to access your application:</p><ol><li><strong>Find the ALB DNS Name</strong>:</li></ol><ul><li>The ALB DNS name is provided by the Ingress controller and can be found by describing the Ingress resource.</li></ul><pre>kubectl get ingress -n game-2048</pre><p>This output as seen previously will give you an address.</p><p>The ADDRESS column contains the ALB DNS name.</p><p><strong>2. Access the Application</strong>:</p><ul><li>Open your web browser and navigate to the ALB DNS name. You should see your application running.</li><li>If your application was correctly deployed and the Ingress rules are properly configured, the application’s home page should be displayed.</li></ul><p><strong>3. Troubleshooting</strong>:</p><ul><li>If you cannot access the application, ensure that the Ingress controller is correctly installed and the ALB is in an Active state.</li><li>Verify the Ingress resource configuration to ensure the paths and backend services are correctly specified.</li><li>Check the status of the Ingress resource for any errors or warnings:</li></ul><pre>kubectl describe ingress ingress-2048 -n game-2048</pre><p>This command provides detailed information about the Ingress resource, including any events or error messages.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/685/1*Ky65369f-ldhL_6Gbl7ofw.png" /></figure><h3>Summary</h3><p>By following these steps, you should be able to access your deployed application via the Ingress resource.</p><p>The Ingress controller uses the ALB to route external traffic to your Kubernetes services, providing a scalable and reliable access point for your application.</p><h3>Deleting the EKS Cluster and Associated Resources</h3><p>To avoid incurring unnecessary charges, it’s important to delete your EKS cluster and associated resources when they are no longer needed.</p><p>Follow these steps to clean up your environment:</p><ol><li><strong>Delete the EKS Cluster using eksctl</strong>:</li></ol><ul><li>The easiest way to delete the EKS cluster is by using the eksctl command-line tool.</li><li>This command will delete the cluster and all associated resources, such as worker nodes and networking components.</li></ul><pre>eksctl delete cluster --name &lt;cluster-name&gt; --region &lt;region-name&gt;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uhMK55rlN4pWtA_zEorKdw.png" /></figure><p><strong>2. Verify Cluster Deletion</strong>:</p><ul><li>After running the delete command, verify that the cluster has been deleted by checking the status in the AWS Management Console or by using the AWS CLI:</li></ul><pre>aws eks describe-cluster --name &lt;cluster-name&gt; --region &lt;region-name&gt;</pre><ul><li>If the cluster has been successfully deleted, this command will return a <em>“ResourceNotFoundException”.</em></li></ul><p><strong>3. Delete Associated Resources Manually</strong>:</p><p>Although eksctl typically cleans up all resources, you should manually verify that there are no lingering resources that could incur charges.</p><p>Check and delete the following resources if necessary:</p><ul><li><strong>Load Balancers</strong>: In the EC2 console, check for any load balancers created by the Ingress controller.</li><li><strong>EBS Volumes</strong>: In the EC2 console, check for any Elastic Block Store (EBS) volumes that were attached to your nodes.</li><li><strong>Elastic IPs</strong>: In the EC2 console, check for any Elastic IP addresses.</li><li><strong>Security Groups</strong>: In the VPC console, check for any security groups associated with your cluster.</li></ul><p><strong>4. Delete IAM Roles and Policies</strong>:</p><ul><li>If you created any IAM roles or policies for your cluster (e.g., for the AWS Load Balancer Controller), delete them to avoid unnecessary charges:</li></ul><pre>aws iam delete-role --role-name &lt;role-name&gt;<br>aws iam delete-policy --policy-arn arn:aws:iam::&lt;your-aws-account-id&gt;:policy/&lt;policy-name&gt;</pre><p>Replace &lt;role-name&gt; with the name of the IAM role and &lt;policy-name&gt; with the name of the IAM policy.</p><p>By following these steps, you ensure that all components associated with your EKS cluster are deleted, preventing any additional charges from accruing.</p><h3>Conclusion</h3><p>Deploying an application on AWS EKS can be straightforward with the right tools and configuration.</p><p>By following these steps, you can leverage the power of Kubernetes while benefiting from AWS’s managed services.</p><p>If you have any questions or run into issues, feel free to leave a comment below!</p><p>Happy deploying!</p><h3>Connect with me</h3><p>For more insights and future projects, feel free to connect with me on <a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> , </em></strong><a href="https://github.com/wangoimwangi"><strong><em>GitHub</em></strong></a><strong><em> </em></strong>and<strong> </strong><a href="https://mary-wangoi.medium.com/"><strong><em>Medium.</em></strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e3d046263f4a" width="1" height="1" alt=""><hr><p><a href="https://blog.devops.dev/streamlined-deployment-leveraging-aws-eks-and-fargate-e3d046263f4a">Serverless Application Deployment with AWS EKS and Fargate</a> was originally published in <a href="https://blog.devops.dev/">DevOps.dev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Automated Cost Optimization for AWS EBS Snapshot Using Lambda]]></title>
            <link>https://medium.com/pythons-gurus/aws-cost-optimization-using-lambda-1f03fa91a00a?source=rss-25b8a3b45b96------2</link>
            <guid isPermaLink="false">https://medium.com/p/1f03fa91a00a</guid>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[aws-lambda]]></category>
            <dc:creator><![CDATA[Wangoi Mwangi]]></dc:creator>
            <pubDate>Wed, 05 Jun 2024 01:34:10 GMT</pubDate>
            <atom:updated>2024-09-13T10:18:43.629Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GooinRCuS2Ci3-6Cb_Ykuw.png" /></figure><h3>Introduction</h3><p>Managing cloud costs effectively is essential for any organization using AWS (Amazon Web Services). One way to optimize costs is by identifying and removing unused resources.</p><p>In this blog post, I’ll show you how to save on storage costs by detecting and deleting stale EBS (Elastic Block Store) snapshots.</p><p>EBS snapshots are backups of your EBS volumes, but they can become orphaned when instances are terminated or volumes are deleted. These unused snapshots take up space and incur unnecessary costs.</p><p>We’ll create a Lambda function that automatically finds and deletes these stale snapshots, helping you manage your AWS expenses more efficiently.</p><p>Whether you’re new to AWS or an experienced user, this guide will help you automate cost-saving measures in your cloud environment.</p><h3><strong>Prerequisites</strong></h3><p>Before you start with the project, ensure you have the following prerequisites in place:</p><ul><li><strong>AWS Account</strong>: With permissions to manage Lambda, EBS snapshots, and EC2 instances.</li><li><strong>AWS CLI</strong>: Installed and configured on your machine.</li><li><strong>Basic IAM Understanding: </strong>To create roles and custom policies.</li><li><strong>Basic AWS Lambda Knowledge</strong>: To create and deploy the function.</li><li><strong>Python Knowledge</strong>: Since the Lambda function will be in Python.</li><li><strong>Boto3 Library</strong>: Familiarity, as it will be used for AWS service interactions.</li></ul><p>Ensure these prerequisites are met to follow along effectively.</p><p><em>Feel free to connect with me on </em><a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> </em></strong><em>to discuss this post or ask any questions.</em></p><h3>Create an EC2 Instance</h3><p>This instance will serve as a resource to interact with during the setup of our Lambda function.</p><p>Note that this step can also be automated using <em>Terraform</em>, but for the sake of simplicity, we will do it manually here.</p><p>Here is a detailed step-by-step guide to creating an EC2 instance:</p><ol><li><strong>Log into AWS Management Console</strong>:</li></ol><ul><li>Navigate to the <a href="https://aws.amazon.com/console/"><em>AWS Management Console</em></a><em>.</em></li><li>Sign in with your AWS credentials.</li></ul><p><strong>2. Open the EC2 Dashboard</strong>:</p><ul><li>In the AWS Management Console, search for <em>“EC2”</em> in the search bar.</li><li>Select <em>“EC2”</em> from the list of services.</li></ul><p><strong>3. Launch Instance</strong>:</p><ul><li>Click the <em>“Launch Instance”</em> button on the EC2 Dashboard.</li></ul><p><strong>4. Add Tags</strong>:</p><ul><li><em>(Optional)</em> Add tags to your instance for easier identification.</li></ul><p><strong>5. Choose an Amazon Machine Image (AMI)</strong>:</p><ul><li>Select an appropriate AMI for your needs. For this example, you can choose <em>“Ubuntu”.</em></li></ul><p><strong>6. Choose an Instance Type</strong>:</p><ul><li>Select an instance type. For most use cases, the <em>“t2.micro”</em> instance type is sufficient and is free tier eligible.</li></ul><p><strong>7. Select a Key Pair</strong>:</p><ul><li>Select an existing key pair or create a new key pair to securely access your instance.</li><li>Download the key pair file (.pem) and keep it safe. You cannot download it again after it is created.</li></ul><p><strong>8</strong>.<strong><em> </em>Configure Instance Details:</strong></p><ul><li>Optionally, configure instance details such as network settings, subnets, IAM role, etc. You can leave these settings as default for now.</li></ul><p><strong>9. Configure Security Group</strong>:</p><ul><li>Create a new security group or select an existing one.</li><li>Ensure that you have rules allowing SSH access (port 22) from your IP address.</li></ul><p><strong>10. Add Storage</strong>:</p><ul><li>The default storage settings should be sufficient.</li><li>You can adjust the size if needed.</li></ul><p><strong>11. Review and Launch</strong>:</p><ul><li>Review your instance configuration.</li><li>Click “Launch” to proceed.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4h19Mt79ntFXj1PqxcMvaA.png" /></figure><h3><strong>Verify the Volume</strong></h3><ul><li>Navigate to the created EC2 Instance under the <em>“storage”</em> section.</li><li>This will open the details page for the volume, where you can see information like size, state, and type.</li><li>Notice that this volume was automatically created during the instance setup process and is used as the root volume for your EC2 instance.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6WpJS25J3Hip7ispAgmP_A.png" /></figure><h3>Creating Snapshots of the Volume</h3><p>Currently we don’t have any snapshots available for our instance.</p><p>To confirm this navigate to the <em>EC2 Dashboard </em>by searching for <em>“EC2”</em> in the services menu.</p><p>Find the <em>“Snapshots” </em>section in the left-hand menu and click on it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*n7XgLYOjZ8v3kb77ZC8uuQ.png" /></figure><ul><li>To create a snapshot of the instance click on the <em>“Create Snapshot”</em> button.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*baCVMb20fNlS43vaDUgqQA.png" /></figure><ul><li>Choose the EBS volume for which you want to create a snapshot from the dropdown menu.</li><li>Optionally, add a description for the snapshot to provide more context.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ShEe-H7ldezqOwwiDYj0wg.png" /></figure><ul><li>Double-check the details you’ve entered to ensure accuracy.</li><li>Once you’re satisfied, click on the <em>“Create Snapshot”</em> button to initiate the snapshot creation process.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*p2nRYsXxscVY6Ta9-ZUyiQ.png" /></figure><h3>AWS Lambda</h3><p>Creating an AWS Lambda function allows you to execute code in response to events without provisioning or managing servers.</p><p>In our project, we aim to automate the identification and deletion of stale EBS snapshots using an AWS Lambda function.</p><p>Here’s how you can create this Lambda function using the AWS Management Console:</p><ol><li><strong>Log into AWS Management Console</strong>:</li></ol><ul><li>Navigate to the <a href="https://aws.amazon.com/console/">AWS Management Console</a>.</li><li>Sign in with your AWS credentials.</li></ul><p><strong>2. Open the Lambda Dashboard</strong>:</p><ul><li>In the AWS Management Console, search for <em>“Lambda” </em>in the services.</li><li>Select <em>“Lambda”</em> from the list of services.</li></ul><p><strong>3. Click on “Create function”</strong>:</p><ul><li>On the Lambda Dashboard, click on the orange<em> “Create function”</em> button.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8btECKFaBCbLHS4sOr-d1g.png" /></figure><p><strong>4. Choose Authoring Method</strong>:</p><ul><li>Select<em> “Author from scratch”</em> to create a new Lambda function from scratch.</li></ul><p><strong>5. Configure Basic Information</strong>:</p><ul><li>Provide a meaningful name for your Lambda function.</li><li>Select the runtime environment. Since we’re using Python, choose <em>“Python 3.12”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1012/1*5cI23uHtvtGvVSTKAw6cLA.png" /></figure><ul><li>Click on <em>“Create function”</em> to proceed.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iYpbXETo9u7AaTy7I9kMUw.png" /></figure><p><strong>Edit Configuration</strong></p><ul><li>Navigate to the <em>“configuration tab”</em> of the created Lambda function and click “Edit”.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GNE48nV7DBalQcZ0vOm7Tg.png" /></figure><ul><li>Look for the section where you can adjust the function timeout.</li><li>By default, the timeout is set to <em>“3 seconds”. </em>Change this to <em>“10 seconds”.</em></li><li>This value represents the maximum amount of time (in seconds) that Lambda will allow the function to run before terminating it.</li><li>It is good practice to keep the execution time as small as possible since AWS will charge you using this as one of the parameters.</li><li>Click <em>“Save”</em> to apply the changes.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/953/1*Epky3ZvmununMldaVb-UlQ.png" /></figure><h3>IAM Role</h3><p>In our project, the Lambda function is central to optimizing AWS costs by identifying and deleting stale EBS snapshots.</p><p>To accomplish this, it requires specific permissions. These include the ability to describe and delete snapshots, as well as to describe volumes and instances.</p><p>Roles are used to delegate access to AWS resources securely, without the need to share long-term credentials like access keys.</p><p>To achieve this follow these step by step guide below:</p><ul><li>In the Lambda function details page, click on the <em>“Configuration”</em> tab.</li><li>Scroll down to the <em>“Permissions”</em> section to expand it.</li><li>Click on the execution role link to open the IAM role configuration in a new tab.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*J7LKLuCOfVEYOt90VcrdAA.png" /></figure><ul><li>In the new tab that opens, you’ll be directed to the IAM Console with the details of the IAM role associated with your Lambda function.</li><li>Scroll down to the <em>“Permissions” </em>section of the IAM role details page.</li><li>Click on the <em>“Add inline policy”</em> button to create a new inline policy.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XCTw0Jb2gv42u0CHnaAmJw.png" /></figure><ul><li>Choose services as EC2 filter permissions.</li><li>Search <em>“Snapshot” </em>and add these options <em>“DescribeSnapshots”</em>, <em>“Delete Snapshots”.</em></li><li>Also add these permissions as well <em>“Describe Volume”</em>, and <em>“Describe Instances”.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5FHxXpWyN93kwSnCTfRt2g.png" /></figure><ul><li>Under the Resources section select <em>“All”.</em></li><li>Click the <em>“Next” </em>button.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tNVHULeIxfGFhD0qfBcAIQ.png" /></figure><ul><li>Give the name of the policy then click the <em>“Create Policy”</em> button.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Doupl4d2gg7zdXPCCxn68g.png" /></figure><ul><li>Make sure that the created policy is attached to the existing role.</li></ul><h3>Writing the Lambda Function</h3><p>Our Lambda function, powered by Boto3, automates the identification and deletion of stale EBS snapshots. Key features include:</p><ol><li><strong>Snapshot Retrieval</strong>: Fetching owned EBS snapshots and active EC2 instances.</li><li><strong>Stale Snapshot Detection</strong>: Identifying unattached snapshots and checking volume-attachment status.</li><li><strong>Exception Handling</strong>: Ensuring robustness with error management.</li><li><strong>Cost Optimization</strong>: Efficiently managing resources to minimize storage costs.</li></ol><pre>import boto3<br><br>def lambda_handler(event, context):<br>    ec2 = boto3.client(&#39;ec2&#39;)<br><br>    # Get all EBS snapshots<br>    response = ec2.describe_snapshots(OwnerIds=[&#39;self&#39;])<br><br>    # Get all active EC2 instance IDs<br>    instances_response = ec2.describe_instances(Filters=[{&#39;Name&#39;: &#39;instance-state-name&#39;, &#39;Values&#39;: [&#39;running&#39;]}])<br>    active_instance_ids = set()<br><br>    for reservation in instances_response[&#39;Reservations&#39;]:<br>        for instance in reservation[&#39;Instances&#39;]:<br>            active_instance_ids.add(instance[&#39;InstanceId&#39;])<br><br>    # Iterate through each snapshot and delete if it&#39;s not attached to any volume or the volume is not attached to a running instance<br>    for snapshot in response[&#39;Snapshots&#39;]:<br>        snapshot_id = snapshot[&#39;SnapshotId&#39;]<br>        volume_id = snapshot.get(&#39;VolumeId&#39;)<br><br>        if not volume_id:<br>            # Delete the snapshot if it&#39;s not attached to any volume<br>            ec2.delete_snapshot(SnapshotId=snapshot_id)<br>            print(f&quot;Deleted EBS snapshot {snapshot_id} as it was not attached to any volume.&quot;)<br>        else:<br>            # Check if the volume still exists<br>            try:<br>                volume_response = ec2.describe_volumes(VolumeIds=[volume_id])<br>                if not volume_response[&#39;Volumes&#39;][0][&#39;Attachments&#39;]:<br>                    ec2.delete_snapshot(SnapshotId=snapshot_id)<br>                    print(f&quot;Deleted EBS snapshot {snapshot_id} as it was taken from a volume not attached to any running instance.&quot;)<br>            except ec2.exceptions.ClientError as e:<br>                if e.response[&#39;Error&#39;][&#39;Code&#39;] == &#39;InvalidVolume.NotFound&#39;:<br>                    # The volume associated with the snapshot is not found (it might have been deleted)<br>                    ec2.delete_snapshot(SnapshotId=snapshot_id)<br>                    print(f&quot;Deleted EBS snapshot {snapshot_id} as its associated volume was not found.&quot;)</pre><p>This script is pivotal in our AWS cost optimization strategy, showcasing the effectiveness of serverless computing for streamlining operations.</p><h3>Testing the Lambda Function</h3><p>To simulate a real-world scenario, delete the existing EC2 instance.</p><p>When an EC2 instance is deleted, AWS automatically removes the attached EBS volume as shown below.</p><p>However, any EBS snapshots associated with that volume remain in storage, even though they are no longer needed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kA3M0584bni9RD_nYfom8A.png" /></figure><p>These snapshots, termed <em>‘stale,’</em> incur additional storage costs without serving any purpose.</p><p>Therefore, it’s crucial to regularly identify and remove such stale snapshots to optimize AWS storage costs effectively.</p><p>Once the Instance is deleted we can observe whether our Lambda function successfully identifies and removes any associated snapshots.</p><p>Follow the below steps:</p><ul><li>Navigate to the created EC2 instance and terminate it.</li><li>Navigate to the created Lambda Function.</li><li>Under the<em> “Code”</em> section in <em>“lambda_function” </em>paste the above Python code for your Lambda function.</li><li>Ensure that your code includes necessary imports (e.g., import boto3) and the lambda_handler function.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iZwaL_H2g9FLGQQKJDmqaQ.png" /></figure><ul><li>Save your Lambda Function to test it click on the <em>“Test”</em> Button.</li><li>After running the test, review the output and logs to ensure that your function executed as expected.</li><li>Debug any errors or issues that may arise during testing.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GifyK9iTKswN-DidXDqR3A.png" /></figure><ul><li>Once your function passes testing, you can deploy it by clicking on the <em>“Deploy”</em> button.</li></ul><p>The Lambda function automatically finds and deletes these stale snapshots, helping you manage your AWS expenses more efficiently.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7qMmJBiycPsrUkuczRkdAg.png" /></figure><ul><li>After deployment, monitor the execution of your Lambda function in the AWS Lambda console.</li><li>Use CloudWatch Logs to view detailed logs and metrics for your function.</li></ul><h3>Conclusion</h3><p>In this project, we’ve implemented a solution to automate the identification and deletion of stale EBS snapshots, leveraging AWS Lambda and Boto3.</p><p>By optimizing storage usage, we’ve reduced costs and improved resource efficiency.</p><p>This project demonstrates the effectiveness of automation in driving cost optimization within AWS, setting the stage for continued success in cloud management endeavors.</p><h3>Connect with me</h3><p>For more insights and future projects, feel free to connect with me on <a href="https://www.linkedin.com/in/mary-wangoi-39951826b/"><strong><em>LinkedIn</em></strong></a><strong><em> , </em></strong><a href="https://github.com/wangoimwangi"><strong><em>GitHub</em></strong></a><strong><em> </em></strong>and<strong> </strong><a href="https://mary-wangoi.medium.com/"><strong><em>Medium.</em></strong></a></p><h3>Python’s Gurus🚀</h3><p><em>Thank you for being a part of the </em><a href="https://medium.com/pythons-gurus"><strong><em>Python’s Gurus community</em></strong></a><strong><em>!</em></strong></p><p><em>Before you go:</em></p><ul><li>Be sure to <strong>clap x50 time </strong>and <strong>follow</strong> the writer ️👏<strong>️️</strong></li><li>Follow us: <a href="https://medium.com/pythons-gurus/newsletters/gurus-advisor"><strong>Newsletter</strong></a></li><li>Do you aspire to become a Guru too? <strong><em>Submit your best article or draft</em></strong> to reach our audience.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1f03fa91a00a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/pythons-gurus/aws-cost-optimization-using-lambda-1f03fa91a00a">Automated Cost Optimization for AWS EBS Snapshot Using Lambda</a> was originally published in <a href="https://medium.com/pythons-gurus">Python’s Gurus</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>