<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gabriel</title>
    <description>The latest articles on DEV Community by Gabriel (@gabbyti).</description>
    <link>https://dev.to/gabbyti</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1272262%2F1673030d-ffbb-4145-a2f1-0f8d7eb58dc2.jpeg</url>
      <title>DEV Community: Gabriel</title>
      <link>https://dev.to/gabbyti</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gabbyti"/>
    <language>en</language>
    <item>
      <title>Deploying a 3-Tier Full-Stack App on AWS with Terraform, GitHub Actions, and Amplify (Node.js + React)</title>
      <dc:creator>Gabriel</dc:creator>
      <pubDate>Wed, 16 Jul 2025 14:01:37 +0000</pubDate>
      <link>https://dev.to/gabbyti/deploying-a-3-tier-full-stack-app-on-aws-with-terraform-github-actions-and-amplify-1f97</link>
      <guid>https://dev.to/gabbyti/deploying-a-3-tier-full-stack-app-on-aws-with-terraform-github-actions-and-amplify-1f97</guid>
      <description>&lt;p&gt;In this post, I walk you through how I built and deployed a 3-tier full-stack application using AWS services. The project combines Infrastructure as Code with Terraform, CI/CD with GitHub Actions, and frontend hosting with AWS Amplify.&lt;/p&gt;

&lt;p&gt;This guide is ideal for DevOps engineers, cloud practitioners, and developers looking to bridge the gap between application code and scalable infrastructure.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is a 3-Tier App?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;3-tier architecture&lt;/strong&gt; is a classic design pattern that divides an application into three distinct layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Presentation Layer (Frontend)&lt;/strong&gt;&lt;br&gt;
The user interface users interact with.&lt;br&gt;
👉 In this project: a &lt;strong&gt;React.js app&lt;/strong&gt; hosted on &lt;strong&gt;AWS Amplify&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Application Layer (Backend)&lt;/strong&gt;&lt;br&gt;
Handles business logic and API processing.&lt;br&gt;
👉 Here: a &lt;strong&gt;Node.js API&lt;/strong&gt; deployed on an &lt;strong&gt;EC2 instance behind a Load Balancer&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Layer (Database)&lt;/strong&gt;&lt;br&gt;
Responsible for storing and retrieving data.&lt;br&gt;
👉 In this case: a &lt;strong&gt;PostgreSQL database&lt;/strong&gt; deployed in a &lt;strong&gt;private subnet&lt;/strong&gt; on AWS.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why Use 3 Tiers?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Separation of concerns&lt;/strong&gt; – Each tier is independently scalable and maintainable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; – Sensitive data stays isolated in the private network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt; – Easily grow or debug specific components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This architecture is widely adopted in real-world production systems and aligns perfectly with modern DevOps workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;This deployment setup uses two open-source apps to showcase DevOps automation workflows and infrastructure practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Backend API&lt;/strong&gt;&lt;br&gt;
A Node.js + TypeScript app using &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt; and &lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma ORM&lt;/a&gt;, connected to PostgreSQL.&lt;br&gt;
🔗 Repo: &lt;a href="https://github.com/gabbyTI/nodejs-simple-api-with-db" rel="noopener noreferrer"&gt;gabbyTI/nodejs-simple-api-with-db&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Frontend&lt;/strong&gt;&lt;br&gt;
A minimal React app that communicates with the backend via API requests.&lt;br&gt;
🔗 Repo: &lt;a href="https://github.com/gabbyTI/react-simpleapi-frontend" rel="noopener noreferrer"&gt;gabbyTI/react-simpleapi-frontend&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The focus isn’t on complex application logic — it’s on demonstrating how to &lt;strong&gt;deploy and manage full-stack apps on AWS&lt;/strong&gt; using Terraform, CI/CD, and AWS-native services.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture Diagram
&lt;/h2&gt;

&lt;p&gt;Here’s the high-level infrastructure design:&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Components Breakdown
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;VPC&lt;/strong&gt; with public and private subnets across two Availability Zones&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Load Balancer (ALB)&lt;/strong&gt; routes traffic to the backend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EC2 instance&lt;/strong&gt; hosts the Node.js app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt; deployed in a private subnet (via RDS or manually)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Amplify&lt;/strong&gt; hosts and deploys the frontend from GitHub&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IAM roles, security groups, and routing&lt;/strong&gt; are defined via Terraform&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Infrastructure as Code with Terraform
&lt;/h2&gt;

&lt;p&gt;All infrastructure lives in the &lt;code&gt;infrastructure/&lt;/code&gt; folder of the backend repo. Using Terraform ensures the setup is reproducible, modular, and version-controlled.&lt;/p&gt;

&lt;p&gt;🔗 Infra Code: &lt;a href="https://github.com/gabbyTI/nodejs-simple-api-with-db/tree/main/infrastructure" rel="noopener noreferrer"&gt;infrastructure/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Key AWS Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;aws_vpc&lt;/code&gt;, subnets, route tables, internet/NAT gateways&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aws_security_group&lt;/code&gt; for EC2 and RDS&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aws_alb&lt;/code&gt;, listeners, and target groups&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aws_instance&lt;/code&gt; for the backend app&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aws_db_instance&lt;/code&gt; for PostgreSQL&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Each resource is modularized for reusability. The infrastructure README includes setup instructions.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Backend CI/CD with GitHub Actions
&lt;/h2&gt;

&lt;p&gt;The backend API is deployed to an EC2 instance via a GitHub Actions pipeline triggered on pushes to the &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  CI/CD Workflow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-version Node Testing&lt;/strong&gt;&lt;br&gt;
The code is tested against Node.js versions 22, 23, and 24.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Artifact Packaging&lt;/strong&gt;&lt;br&gt;
After testing, an artifact containing the compiled app and environment files is prepared.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deployment to EC2&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Artifact is securely copied via &lt;code&gt;scp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the EC2 instance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Old files are cleared&lt;/li&gt;
&lt;li&gt;Dependencies are installed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.env&lt;/code&gt; is generated using GitHub Secrets&lt;/li&gt;
&lt;li&gt;TypeScript is compiled&lt;/li&gt;
&lt;li&gt;Prisma migrations are applied&lt;/li&gt;
&lt;li&gt;Dev dependencies are pruned&lt;/li&gt;
&lt;li&gt;App is restarted using &lt;code&gt;pm2&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;All secrets (e.g., DB URLs, SSH keys) are securely managed via GitHub Secrets and Encrypted Variables.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  GitHub Actions Workflow (Simplified)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to EC2&lt;/span&gt;

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

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;22&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;23&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;24&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci &amp;amp;&amp;amp; npm test&lt;/span&gt;

  &lt;span class="na"&gt;upload-artifact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;upload app files as artifact&lt;/span&gt;

  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;upload-artifact&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;download artifact&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;scp files to EC2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run: ssh to EC2 and&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;set up .env&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;install dependencies&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;run build &amp;amp; migrations&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;prune dev deps&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;reload app with pm2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Frontend Hosting with AWS Amplify
&lt;/h2&gt;

&lt;p&gt;The frontend is hosted using &lt;a href="https://aws.amazon.com/amplify/" rel="noopener noreferrer"&gt;AWS Amplify&lt;/a&gt;, which automatically builds and deploys on every GitHub push.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Amplify?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Built-in CI/CD and GitHub integration&lt;/li&gt;
&lt;li&gt;Free SSL and custom domain support&lt;/li&gt;
&lt;li&gt;Quick to set up and deploy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I connected the frontend repo, set the build output to &lt;code&gt;build/&lt;/code&gt;, and Amplify took care of the rest.&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Done
&lt;/h2&gt;

&lt;p&gt;✅ Full-stack app (Node.js + React) complete&lt;br&gt;
✅ Infrastructure provisioned manually with Terraform&lt;br&gt;
✅ CI/CD pipeline for backend using GitHub Actions&lt;br&gt;
✅ Automatic frontend deployment with AWS Amplify&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Next
&lt;/h2&gt;

&lt;p&gt;🔄 Add infrastructure CI/CD (&lt;code&gt;terraform plan&lt;/code&gt; + &lt;code&gt;apply&lt;/code&gt; via GitHub Actions)&lt;br&gt;
📊 Integrate CloudWatch for logs and observability&lt;br&gt;
📉 Set up alarms and billing alerts for cost control&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You don’t need Kubernetes to follow solid DevOps practices.&lt;/li&gt;
&lt;li&gt;Declarative IaC with Terraform boosts reproducibility and confidence.&lt;/li&gt;
&lt;li&gt;CI/CD pipelines can be simple yet powerful.&lt;/li&gt;
&lt;li&gt;AWS Amplify is perfect for fast and secure frontend deployments.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Let’s Connect
&lt;/h2&gt;

&lt;p&gt;If you found this guide helpful, follow me or connect on &lt;a href="https://www.linkedin.com/in/gabbyti" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to ⭐ the repo or fork it for your own DevOps experiments:&lt;br&gt;
🔗 &lt;a href="https://github.com/gabbyTI/nodejs-simple-api-with-db" rel="noopener noreferrer"&gt;https://github.com/gabbyTI/nodejs-simple-api-with-db&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>terraform</category>
      <category>node</category>
    </item>
    <item>
      <title>Quick Setup: Jenkins on AWS with Terraform &amp; Bash</title>
      <dc:creator>Gabriel</dc:creator>
      <pubDate>Sat, 16 Mar 2024 02:18:54 +0000</pubDate>
      <link>https://dev.to/gabbyti/quick-setup-jenkins-on-aws-with-terraform-bash-1mj8</link>
      <guid>https://dev.to/gabbyti/quick-setup-jenkins-on-aws-with-terraform-bash-1mj8</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;
The Bash Script

&lt;ul&gt;
&lt;li&gt;docker-setup.sh&lt;/li&gt;
&lt;li&gt;jenkins-slave-setup.sh&lt;/li&gt;
&lt;li&gt;jenkins-setup.sh&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Terraform IaC Scripts

&lt;ul&gt;
&lt;li&gt;main.tf&lt;/li&gt;
&lt;li&gt;output.tf&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hey there! Welcome to the world of automation where we make tedious tasks disappear with the magic of scripts and infrastructure as code. Today, I'm going to share with you a practical solution for automating the setup of a Jenkins server and a slave node on AWS using Terraform and Bash scripts.&lt;/p&gt;

&lt;p&gt;Forget about manual configurations and hours of tinkering. With the scripts I've crafted, you'll breeze through the process of provisioning an AWS EC2 instance and configuring Jenkins, all in a few simple steps.&lt;/p&gt;

&lt;p&gt;No lengthy theoretical discussions here—just pure, hands-on automation goodness. So, let's dive straight into the action and see how Terraform and Bash can revolutionize your CI/CD pipeline setup.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The Bash Scripts
&lt;/h2&gt;

&lt;p&gt;We have three bash scripts that will be used in this setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Script to setup up Jenkins&lt;/li&gt;
&lt;li&gt;Script to install Docker&lt;/li&gt;
&lt;li&gt;Script to setup Jenkins slave server&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  docker-setup.sh
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Automate Installation of Docker&lt;/span&gt;
&lt;span class="c"&gt;# Author: Gabriel Ibenye&lt;/span&gt;

&lt;span class="c"&gt;# Update the apt package index and install packages to allow apt to use a repository over HTTPS&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; apt-transport-https ca-certificates curl software-properties-common

&lt;span class="c"&gt;# Add Docker’s official GPG key&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://download.docker.com/linux/ubuntu/gpg | &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-key add -

&lt;span class="c"&gt;# Set up the stable repository for your architecture (amd64)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;add-apt-repository &lt;span class="s2"&gt;"deb [arch=amd64] https://download.docker.com/linux/ubuntu &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;lsb_release &lt;span class="nt"&gt;-cs&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; stable"&lt;/span&gt;

&lt;span class="c"&gt;# Update the apt package index again and install the latest version of Docker Engine and containerd&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; docker-ce docker-ce-cli containerd.io

&lt;span class="c"&gt;# Verify that Docker Engine is installed correctly&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;docker &lt;span class="nt"&gt;--version&lt;/span&gt;

&lt;span class="c"&gt;# Add your user to the docker group to run Docker commands without sudo&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"User added to the docker group. Logging out and back in to apply changes..."&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Docker setup completed."&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  jenkins-slave-setup.sh
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Automate Jenkins Slave Node Setup&lt;/span&gt;
&lt;span class="c"&gt;# Author: Gabriel Ibenye&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
&lt;span class="c"&gt;# Print a message in a given color.&lt;/span&gt;
&lt;span class="c"&gt;# Arguments:&lt;/span&gt;
&lt;span class="c"&gt;#   Color. eg: green, red&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;print_color&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0m'&lt;/span&gt; &lt;span class="c"&gt;# No Color&lt;/span&gt;

  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
  &lt;span class="s2"&gt;"green"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;COLOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;32m'&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="s2"&gt;"red"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;COLOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;31m'&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;COLOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0m'&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="k"&gt;esac&lt;/span&gt;

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;COLOR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"---------------- JENKINS SLAVE NODE SETUP ------------------"&lt;/span&gt;

print_color &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="s2"&gt;"Update apt repository. "&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update

print_color &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="s2"&gt;"Installing Java(openjdk-17-jre)"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;openjdk-17-jre &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"---------------- SETUP COMPLETE ------------------"&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  jenkins-setup.sh
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Automate Installation of Jenkins&lt;/span&gt;
&lt;span class="c"&gt;# Author: Gabriel Ibenye&lt;/span&gt;

&lt;span class="c"&gt;#######################################&lt;/span&gt;
&lt;span class="c"&gt;# Print a message in a given color.&lt;/span&gt;
&lt;span class="c"&gt;# Arguments:&lt;/span&gt;
&lt;span class="c"&gt;#   Color. eg: green, red&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;print_color&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0m'&lt;/span&gt; &lt;span class="c"&gt;# No Color&lt;/span&gt;

  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
  &lt;span class="s2"&gt;"green"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;COLOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;32m'&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="s2"&gt;"red"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;COLOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;31m'&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;COLOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0m'&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="k"&gt;esac&lt;/span&gt;

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;COLOR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;#######################################&lt;/span&gt;
&lt;span class="c"&gt;# Check the status of a given service. If not active exit script&lt;/span&gt;
&lt;span class="c"&gt;# Arguments:&lt;/span&gt;
&lt;span class="c"&gt;#   Service Name. eg: firewalld, mariadb&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;check_service_status&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;service_is_active&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl is-active &lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$service_is_active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"active"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt; is active and running"&lt;/span&gt;
  &lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt; is not active/running"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;#######################################&lt;/span&gt;
&lt;span class="c"&gt;# Check if a given service is enabled to run on boot. If not enabled exit script&lt;/span&gt;
&lt;span class="c"&gt;# Arguments:&lt;/span&gt;
&lt;span class="c"&gt;#   Service Name. eg: jenkins, mariadb&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;check_service_enable&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;service_is_enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl is-enabled &lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$service_is_enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"enabled"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt; is enabled"&lt;/span&gt;
  &lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt; is not enabled"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;#######################################&lt;/span&gt;
&lt;span class="c"&gt;# Check the status of a firewalld rule. If not configured exit.&lt;/span&gt;
&lt;span class="c"&gt;# Arguments:&lt;/span&gt;
&lt;span class="c"&gt;#   Port Number. eg: 3306, 80&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;is_firewalld_rule_configured&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="nv"&gt;firewalld_ports&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--list-all&lt;/span&gt; &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;public | &lt;span class="nb"&gt;grep &lt;/span&gt;ports&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$firewalld_ports&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FirewallD has port &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt; configured"&lt;/span&gt;
  &lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FirewallD port &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt; is not configured"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"---------------- Adding Debian package repository of Jenkins to apt repository ------------------"&lt;/span&gt;

print_color &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="s2"&gt;"Download jenkins debian package repository. "&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;wget &lt;span class="nt"&gt;-O&lt;/span&gt; /usr/share/keyrings/jenkins-keyring.asc &lt;span class="se"&gt;\&lt;/span&gt;
  https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key

print_color &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="s2"&gt;"Adding jenkins debian package to apt repository. "&lt;/span&gt;
&lt;span class="nb"&gt;echo &lt;/span&gt;deb &lt;span class="o"&gt;[&lt;/span&gt;signed-by&lt;span class="o"&gt;=&lt;/span&gt;/usr/share/keyrings/jenkins-keyring.asc] &lt;span class="se"&gt;\&lt;/span&gt;
  https://pkg.jenkins.io/debian-stable binary/ | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  /etc/apt/sources.list.d/jenkins.list &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null

print_color &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="s2"&gt;"Update apt repository. "&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update

print_color &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="s2"&gt;"Installing fontconfig"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;fontconfig &lt;span class="nt"&gt;-y&lt;/span&gt;

print_color &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="s2"&gt;"Installing Java(openjdk-17-jre)"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;openjdk-17-jre &lt;span class="nt"&gt;-y&lt;/span&gt;

print_color &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="s2"&gt;"Installing Jenkins"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;jenkins &lt;span class="nt"&gt;-y&lt;/span&gt;

print_color &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="s2"&gt;"Enable jenkins service to run on boot"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;jenkins

print_color &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="s2"&gt;"Starting jenkins service"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start jenkins

&lt;span class="c"&gt;# check Jenkins is enable&lt;/span&gt;
check_service_enable jenkins

&lt;span class="c"&gt;# check Jenkins is running&lt;/span&gt;
check_service_status jenkins

print_color &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="s2"&gt;"Opening jenkins default port (8080)"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 8080

print_color &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="s2"&gt;"Opening OpenSSH port"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow OpenSSH

print_color &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="s2"&gt;"Enable Firewall"&lt;/span&gt;
&lt;span class="nb"&gt;yes&lt;/span&gt; | &lt;span class="nb"&gt;sudo &lt;/span&gt;ufw &lt;span class="nb"&gt;enable

echo&lt;/span&gt; &lt;span class="s2"&gt;"---------------- SETUP COMPLETE ------------------"&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Terraform IaC Scripts
&lt;/h2&gt;

&lt;p&gt;With the IaC tool terraform, we will be provisioning 2 basic ec2 instances with a security group.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Prerequisite: you should have your ssh private and public keys setup locally. To create these you can run the &lt;code&gt;ssh-keygen&lt;/code&gt; command. Default location of the keys is &lt;code&gt;~/.ssh/&lt;/code&gt; or in windows os &lt;code&gt;c:/users/&amp;lt;user&amp;gt;/.ssh/&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  main.tf
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"primary"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-0e83be366243f524a"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;
  &lt;span class="c1"&gt;#running script&lt;/span&gt;
  &lt;span class="nx"&gt;user_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"path/to/bash/jenkins-setup.sh"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"Name"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Jenkins Server"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;key_name&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_key_pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_security_group_ids&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"slave"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-0e83be366243f524a"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;
  &lt;span class="c1"&gt;#running script&lt;/span&gt;
  &lt;span class="nx"&gt;user_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"path/to/bash/jenkins-slave-setup.sh"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"path/to/bash/docker-setup.sh"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"Name"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Jenkins Slave"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;key_name&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_key_pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_security_group_ids&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;#Enabling ssh access&lt;/span&gt;
&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_key_pair"&lt;/span&gt; &lt;span class="s2"&gt;"web"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;public_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"~/.ssh/id_rsa.pub"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"primary"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"jenkins_sg"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow Jenkins Server Traffic"&lt;/span&gt;

  &lt;span class="c1"&gt;# SSH Port&lt;/span&gt;
  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Jenkins port&lt;/span&gt;
  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Allow all outbound connection over the internet&lt;/span&gt;
  &lt;span class="nx"&gt;egress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-1"&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cm"&gt;/**
* Creating node on jenkins
* First create a credential to login with username and private key
* Create the private key and public key on the jenkins slave (ssh-keygen)
* Use the private key on the jenkins credential you were creating earlier
* Copy and paste the public key into the authorized_keys file (~/.ssh/authorized_keys) of the slave server
* In the jenkins credentials select Non verifying Verification Strategy
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  output.tf
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"jenkins_server_ip"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_ip&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"jenkins_slave_ip"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slave&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_ip&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;In a nutshell, automating Jenkins setup on AWS with Terraform and Bash is a game-changer. Say goodbye to manual headaches and hello to streamlined processes. With just a few commands, you're up and running, saving time and hassle. Keep exploring and tweaking to fit your needs.&lt;br&gt;
Happy automating!&lt;/p&gt;

</description>
      <category>jenkins</category>
      <category>aws</category>
      <category>terraform</category>
      <category>docker</category>
    </item>
    <item>
      <title>How to Setup Jenkins Locally With Oracle VirtualBox VM</title>
      <dc:creator>Gabriel</dc:creator>
      <pubDate>Mon, 26 Feb 2024 03:32:16 +0000</pubDate>
      <link>https://dev.to/gabbyti/how-to-setup-jenkins-locally-with-oracle-virtualbox-vm-3cmi</link>
      <guid>https://dev.to/gabbyti/how-to-setup-jenkins-locally-with-oracle-virtualbox-vm-3cmi</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Creating The Virtual Box VM&lt;/li&gt;
&lt;li&gt;Installing Jenkins on VM&lt;/li&gt;
&lt;li&gt;Opening the firewall&lt;/li&gt;
&lt;li&gt;Setting Up Port Forwarding&lt;/li&gt;
&lt;li&gt;Setting Up Jenkins&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Creating The Virtual Box VM
&lt;/h2&gt;

&lt;p&gt;Download and Install &lt;a href="https://www.virtualbox.org/wiki/Downloads" rel="noopener noreferrer"&gt;Oracle VM Virtual Box&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Download Ubuntu 22.04 VirtualBox(VDI) Image from &lt;a href="https://www.osboxes.org/ubuntu/" rel="noopener noreferrer"&gt;Osboxes.org&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: &lt;strong&gt;Extract the content of the downlod downloaded file&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Open Oracle VM Virtual Box application and create new VM&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Name: vm-jenkins&lt;/li&gt;
&lt;li&gt;Base: Memory 2048&lt;/li&gt;
&lt;li&gt;CPU: 2&lt;/li&gt;
&lt;li&gt;Use Existing Virtual Hard Disk File: Import the VDI file downloaded earlier&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ozt91xghoe9rhc5wygn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ozt91xghoe9rhc5wygn.gif" alt="create vb vm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Start Up the VM and Login&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Username&lt;/strong&gt;: osboxes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Password&lt;/strong&gt;: osboxes.org&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Open Terminal and update system&lt;/p&gt;

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

sudo apt update


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Installing Jenkins on VM
&lt;/h2&gt;

&lt;p&gt;This is the Debian package repository of Jenkins to automate installation and upgrade. To use this repository, first add the key to your system&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \
  https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key


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

&lt;/div&gt;

&lt;p&gt;Then add a Jenkins apt repository entry:&lt;/p&gt;

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

echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
  https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
  /etc/apt/sources.list.d/jenkins.list &amp;gt; /dev/null


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

&lt;/div&gt;

&lt;p&gt;Update your local package index, then finally install Jenkins:&lt;/p&gt;

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

sudo apt update
sudo apt install fontconfig openjdk-17-jre -y
sudo apt install jenkins -y


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

&lt;/div&gt;

&lt;p&gt;Start Jenkins by using systemctl:&lt;/p&gt;

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

sudo systemctl enable jenkins
sudo systemctl start jenkins


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

&lt;/div&gt;

&lt;p&gt;Since systemctl doesn’t display status output, we’ll use the status command to verify that Jenkins started successfully:&lt;/p&gt;

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

sudo systemctl status jenkins


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

&lt;/div&gt;

&lt;p&gt;If everything went well, the beginning of the status output shows that the service is active and configured to start at boot(enabled):&lt;/p&gt;

&lt;p&gt;Output&lt;/p&gt;

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

● jenkins.service - Jenkins Continuous Integration Server
     Loaded: loaded (/lib/systemd/system/jenkins.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2024-02-25 18:55:21 EST; 10min ago
   Main PID: 779 (java)
      Tasks: 46 (limit: 2292)
     Memory: 273.7M
        CPU: 21.993s
     CGroup: /system.slice/jenkins.service
             └─779 /usr/bin/java -Djava.awt.headless=true -jar /usr/share/java/jenkins.war --webroot=/var/cache/jenkins/war --httpP&amp;gt;


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

&lt;/div&gt;

&lt;p&gt;Now that Jenkins is up and running, let’s adjust our firewall rules so that we can reach it from a web browser to complete the initial setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opening the firewall
&lt;/h2&gt;

&lt;p&gt;By default, Jenkins runs on port 8080. We’ll open that port using ufw:&lt;/p&gt;

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

sudo ufw allow 8080


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

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: If the firewall is inactive, the following commands will allow OpenSSH and enable the firewall:&lt;/p&gt;
&lt;/blockquote&gt;

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

sudo ufw allow OpenSSH
sudo ufw enable


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

&lt;/div&gt;

&lt;p&gt;Check ufw’s status to confirm the new rules:&lt;/p&gt;

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

sudo ufw status


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

&lt;/div&gt;

&lt;p&gt;You’ll notice that traffic is allowed to port 8080 from anywhere:&lt;/p&gt;

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

Status: active
To                         Action      From
--                         ------      ----
8080                       ALLOW       Anywhere
OpenSSH                    ALLOW       Anywhere
8080 (v6)                  ALLOW       Anywhere (v6)
OpenSSH (v6)               ALLOW       Anywhere (v6)


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

&lt;/div&gt;

&lt;p&gt;Now we will look at how to reach the jenkins vm on the host machine by setting port forwarding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Port Forwarding
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open VirtualBox VM settings.&lt;/li&gt;
&lt;li&gt;Navigate to the NAT network adapter settings.&lt;/li&gt;
&lt;li&gt;Click Advanced and then Port Forwarding.&lt;/li&gt;
&lt;li&gt;Add a new rule named "jenkins connection".&lt;/li&gt;
&lt;li&gt;Set Protocol to TCP.&lt;/li&gt;
&lt;li&gt;Enter Host IP as 127.0.0.1 and Host Port as 8080.&lt;/li&gt;
&lt;li&gt;Guest Port should also be set to 8080.&lt;/li&gt;
&lt;li&gt;Click OK to save the settings.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg3g8249qsozth6uad5r4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg3g8249qsozth6uad5r4.png" alt="Setting Up Port Forwarding"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Jenkins
&lt;/h2&gt;

&lt;p&gt;Open your browser and go to 127.0.0.1:8080 to access Jenkins, you will land on the getting started jenkins page:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxyppeuvk0m9alzchf4z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxyppeuvk0m9alzchf4z.png" alt="Setting Up Jenkins"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use the terminal in your VM and run&lt;/p&gt;

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

sudo cat /var/lib/jenkins/secrets/initialAdminPassword


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

&lt;/div&gt;

&lt;p&gt;Copy the 32-character alphanumeric password from the terminal and paste it into the Administrator password field on the Jenkins page. Then, click Continue.&lt;br&gt;
Click on &lt;code&gt;Install suggested plugins&lt;/code&gt;&lt;br&gt;
Create your admin user&lt;br&gt;
Set &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt; as the jenkins URL&lt;br&gt;
Click &lt;code&gt;Save and Finish&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;THE END&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>jenkins</category>
      <category>ubuntu</category>
      <category>oracle</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Cloud Safety: How to Establish Azure Point-to-Site VPN Connections</title>
      <dc:creator>Gabriel</dc:creator>
      <pubDate>Fri, 16 Feb 2024 23:38:01 +0000</pubDate>
      <link>https://dev.to/gabbyti/cloud-safety-how-to-establish-azure-point-to-site-vpn-connections-3e</link>
      <guid>https://dev.to/gabbyti/cloud-safety-how-to-establish-azure-point-to-site-vpn-connections-3e</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Table of Contents&lt;/li&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;
Understanding Point-to-Site (P2S) VPN Connection

&lt;ul&gt;
&lt;li&gt;P2S Example Sceneraio&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Setting up P2S VPN Connection in Azure&lt;/li&gt;

&lt;li&gt;

Step by step P2S VPN implementation

&lt;ul&gt;
&lt;li&gt;Create resource group&lt;/li&gt;
&lt;li&gt;Create virtual network&lt;/li&gt;
&lt;li&gt;Create gateway subnet&lt;/li&gt;
&lt;li&gt;Create virtual network gateway&lt;/li&gt;
&lt;li&gt;Point-to-Site Configuration&lt;/li&gt;
&lt;li&gt;Authorize the Azure VPN application&lt;/li&gt;
&lt;li&gt;Download VPN Client Configuration&lt;/li&gt;
&lt;li&gt;Install the Azure VPN client&lt;/li&gt;
&lt;li&gt;Import VPN Client Configuration&lt;/li&gt;
&lt;li&gt;Connect to the VPN&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Create Virtual Machine&lt;/li&gt;

&lt;li&gt;Logging into VM with Private IP&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In a world where remote work has become a norm, ensuring secure and reliable access to company infrastructure has become increasingly important, Cloud solutions like Microsoft Azure offer tools for establishing secure connections between remote users and resources hosted in the cloud. One such tool is the Point-to-Site (P2S) VPN, a mechanism that enables individual devices to securely connect to your azure infrastructure.&lt;/p&gt;

&lt;p&gt;In this guide, we'll walk through the process of setting up a Point-to-Site VPN connection in Azure, providing step-by-step instructions to on how you can establish a secure link between your local device and your Azure infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Point-to-Site (P2S) VPN Connection
&lt;/h2&gt;

&lt;p&gt;Before diving into the setup process, let's briefly explain what a Point-to-Site VPN connection is and how it functions. In a Point-to-Site VPN configuration, individual client devices establish encrypted connections to a virtual network in Azure. This enables remote users to securely access resources such as Azure Virtual Machines, Azure SQL Databases, and other services within the virtual network, as if they were directly connected to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  P2S Example Sceneraio
&lt;/h3&gt;

&lt;p&gt;A company XYZ has an Azure virtual machine (VM) resource that has both a public &amp;amp; private IP address and is secured behind a virtual private network. Usually, logging into the VM is done with the public IP address but this is unsecure because it goes through the internet. So the company decides to get rid of the public IP entirely and requies staff to access the VM with only the private IP.&lt;/p&gt;

&lt;p&gt;When trying to access the VM with private IP, the staff encounter a connection error because that private IP address is not discoverable from outside the Azure virtual network. This means that attempting to access the VM solely via its private IP address from an external network, such as the internet or another corporate network, won't establish a connection due to network isolation.&lt;/p&gt;

&lt;p&gt;To address this problem and make sure the staff can securely reach the VM, Company XYZ opts to set up a Point-to-Site (P2S) VPN connection in Azure. With this setup, our team members can safely connect to the Azure virtual network where the VM is located from anywhere they have internet access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up P2S VPN Connection in Azure
&lt;/h2&gt;

&lt;p&gt;We will go over setting up everything from scratch, including the virtual machine. Here are resources and tools that will be used in this setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resource Group&lt;/li&gt;
&lt;li&gt;Virtual Machine&lt;/li&gt;
&lt;li&gt;Virtual Network (VNet) and Subnets&lt;/li&gt;
&lt;li&gt;Virtual Network Gateway&lt;/li&gt;
&lt;li&gt;Azure VPN Client&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step by step P2S VPN implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create resource group
&lt;/h3&gt;

&lt;p&gt;Create a resource group with name "RGTEST1". This is the resource group that you will create every other resource in.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyd8ts0jwd9w8bm9ajfl6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyd8ts0jwd9w8bm9ajfl6.png" alt="Azure Resource group"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create virtual network
&lt;/h3&gt;

&lt;p&gt;Create a virtual network resource in the RGTEST1 resource group&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;&lt;strong&gt;Name&lt;/strong&gt;: my-secure-vnet&lt;/em&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F04fo672j6fx6c485oiju.gif" alt="Create a virtual network resource"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create gateway subnet
&lt;/h3&gt;

&lt;p&gt;Create a gateway subnet in the "my-secure-vnet" virtual network&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fou5b37qzrayuud9aey8g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fou5b37qzrayuud9aey8g.gif" alt="Create a gateway subnet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create virtual network gateway
&lt;/h3&gt;

&lt;p&gt;Create a virtual network gateway resource with the following details:&lt;br&gt;
&lt;em&gt;&lt;strong&gt;Name&lt;/strong&gt;: secure-vnet-gtw&lt;/em&gt;&lt;br&gt;
&lt;em&gt;&lt;strong&gt;SKU&lt;/strong&gt;: VpnGw1&lt;/em&gt;&lt;br&gt;
&lt;em&gt;&lt;strong&gt;Gateway Type&lt;/strong&gt;: VPN&lt;/em&gt;&lt;br&gt;
&lt;em&gt;&lt;strong&gt;Generation&lt;/strong&gt;: Generation 1&lt;/em&gt;&lt;br&gt;
&lt;em&gt;&lt;strong&gt;Virtual Network&lt;/strong&gt;: my-secure-vnet&lt;/em&gt;&lt;br&gt;
&lt;em&gt;&lt;strong&gt;Public IP address name&lt;/strong&gt;: vnet-gtw-ip&lt;/em&gt;&lt;br&gt;
&lt;em&gt;&lt;strong&gt;Enable active-active mode&lt;/strong&gt;: Disabled&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4v64n73rixhptemxijp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4v64n73rixhptemxijp.png" alt="Create a virtual network gateway"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Price alert&lt;/strong&gt;: virtual network gateway is &lt;strong&gt;NOT&lt;/strong&gt; free. Except the SKU type &lt;strong&gt;VpnGw1&lt;/strong&gt; that is only free for the 1st 12 months of your azure free account subscription.&lt;br&gt;
⚠️ &lt;strong&gt;DELETE ALL RESOURCES AFTER PRACTICE&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Point-to-Site Configuration
&lt;/h3&gt;

&lt;p&gt;In the virtual network gateway resource, navigate to and click &lt;strong&gt;&lt;em&gt;point-to-site-configuration&lt;/em&gt;&lt;/strong&gt; under &lt;strong&gt;&lt;em&gt;settings&lt;/em&gt;&lt;/strong&gt; section in the left menu. Click on &lt;strong&gt;&lt;em&gt;Configure now&lt;/em&gt;&lt;/strong&gt;. You should see something like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx6jbz2hvq8fm25zpxn9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx6jbz2hvq8fm25zpxn9.png" alt="Configure P2S"&gt;&lt;/a&gt;&lt;br&gt;
Use the details below to complete the configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Address pool&lt;/strong&gt; (can be any valid address range of your choice): 10.1.3.0/27&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Tunnel type&lt;/strong&gt;: OpenVPN(SSL)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Authentication type&lt;/strong&gt;: Azure Active Directory&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Tenant ID&lt;/strong&gt;: &lt;a href="https://login.microsoftonline.com/" rel="noopener noreferrer"&gt;https://login.microsoftonline.com/&lt;/a&gt;&amp;lt;&lt;strong&gt;YOUR_TENANT_ID&lt;/strong&gt;&amp;gt;/ (for your tenant id go to &lt;strong&gt;Microsoft Entra ID&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Properties&lt;/strong&gt;)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Audience&lt;/strong&gt; (same for everyone): 41b23e61-6c1e-4545-b367-cd054e0ed4b4&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Issuer&lt;/strong&gt;: &lt;a href="https://sts.windows.net/" rel="noopener noreferrer"&gt;https://sts.windows.net/&lt;/a&gt;&amp;lt;&lt;strong&gt;YOUR_TENANT_ID&lt;/strong&gt;&amp;gt;/&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click Save&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;:&lt;br&gt;
The trailing &lt;strong&gt;" / "&lt;/strong&gt; is required&lt;br&gt;
Saving can take up to 30 minutes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Authorize the Azure VPN application
&lt;/h3&gt;

&lt;p&gt;Make sure you are signed into to your azure portal as a Global administrator.&lt;br&gt;
Copy the link below.&lt;br&gt;
Replace &amp;lt;&lt;strong&gt;YOUR_TENANT_ID&lt;/strong&gt;&amp;gt; with your Azure tenant ID.&lt;/p&gt;

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

https://login.microsoftonline.com/&amp;lt;YOUR_TENANT_ID&amp;gt;/oauth2/authorize?client_id=41b23e61-6c1e-4545-b367-cd054e0ed4b4&amp;amp;response_type=code&amp;amp;redirect_uri=https://portal.azure.com&amp;amp;nonce=1234&amp;amp;prompt=admin_consent


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

&lt;/div&gt;

&lt;p&gt;You will be prompted to sign in again, sign in with the global administrator user. You should then see this&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ebr24215q4oxikowdbd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ebr24215q4oxikowdbd.png" alt="Authorize the Azure VPN application"&gt;&lt;/a&gt;&lt;br&gt;
Click "Accept"&lt;/p&gt;

&lt;h3&gt;
  
  
  Download VPN Client Configuration
&lt;/h3&gt;

&lt;p&gt;When the P2S configuration is done saving, refresh the page and click the Download VPN Client button&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxx9q0mvet27cuugld5t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxx9q0mvet27cuugld5t.png" alt="Download VPN Client"&gt;&lt;/a&gt;&lt;br&gt;
A zipped file is downloaded, Extract the content to a folder. The contents are as shown below&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv8e5sy26tflip5abts4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv8e5sy26tflip5abts4.png" alt="extracted contentent"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the Azure VPN client
&lt;/h3&gt;

&lt;p&gt;Download and install the Azure VPN client from Microsoft Store (for windows PC) and Mac App Store (For Mac)&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd0hf19w11dhr5kvts5ln.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd0hf19w11dhr5kvts5ln.png" alt="az vpn client"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Import VPN Client Configuration
&lt;/h3&gt;

&lt;p&gt;Open the Azure VPN client and click the plus sign on the bottom left&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe78qb8q7f8a5omt6ccl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe78qb8q7f8a5omt6ccl2.png" alt="azure client"&gt;&lt;/a&gt;&lt;br&gt;
Click on Import&lt;br&gt;
Navigate to the Extracted content fronme &lt;strong&gt;step 7&lt;/strong&gt; and select the file &lt;code&gt;AzureVPN/azurevpnconfig.xml&lt;/code&gt;.&lt;br&gt;
After Importing, Click Save.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1isqgc3z2j995t9l1q9d.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1isqgc3z2j995t9l1q9d.gif" alt="Importing azure vpn client"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect to the VPN
&lt;/h3&gt;

&lt;p&gt;When you click the connect button, you will be prompted to login to your azure account for authentication.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnut9i9mrroerjmncprs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnut9i9mrroerjmncprs.png" alt="Connect vpn"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Virtual Machine
&lt;/h2&gt;

&lt;p&gt;Now that we have our network infrasture setup, we can go ahead and create a virtual machine that will be in the virtual network. I will be creating a windows VM, here are the details i used to create the vm:&lt;/p&gt;

&lt;p&gt;Basics Tab&lt;/p&gt;

&lt;p&gt;-** resource group**: RGTEST1&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Name&lt;/em&gt;&lt;/strong&gt;: my-secure-vm&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Image&lt;/em&gt;&lt;/strong&gt;: Windows Server 2019 Datacenter - x64 Gen2&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Size&lt;/em&gt;&lt;/strong&gt;: Standard_B2s - 2 vcpus, 4 GiB memory&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Username&lt;/em&gt;&lt;/strong&gt;: adminUser&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Password&lt;/em&gt;&lt;/strong&gt;: ******************&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Public Inbound Ports&lt;/em&gt;&lt;/strong&gt;: Allow Seleted Ports&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Select Inbound Ports&lt;/em&gt;&lt;/strong&gt;: RDP (3389)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Networking Tab&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Virtual network&lt;/em&gt;&lt;/strong&gt;: my-secure-vnet &lt;em&gt;(the vnet we created ealier)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Public IP&lt;/em&gt;&lt;/strong&gt;: None &lt;em&gt;(We won't be needing a public facing IP address for this vm)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Price Alert: Creating a VM is &lt;strong&gt;NOT&lt;/strong&gt; free&lt;br&gt;
&lt;strong&gt;DELETE ALL RESOURCES AFTER PRACTICE&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Click Create&lt;br&gt;
Go to the newly creted VM resource and get the &lt;strong&gt;Private IP&lt;/strong&gt; address&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2veq98vj7gv5impwxl8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2veq98vj7gv5impwxl8.png" alt="VM Private IP"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging into VM with Private IP
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Connect your virtual network with Azure VPN Client&lt;/li&gt;
&lt;li&gt;Open Remote Desktop Connection&lt;/li&gt;
&lt;li&gt;Input the Private IP&lt;/li&gt;
&lt;li&gt;Input Username and Password that we set when creating the VM
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flzdo5lzmdo3hfhrr1i4m.gif" alt="Logging into VM with Private IP"&gt;
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Throughout this guide, we've navigated the process of setting up a Point-to-Site (P2S) VPN connection in Azure. From understanding the concept of P2S VPNs to configuring the necessary resources in Azure and connecting remote devices securely, we've covered the essentials. By implementing this solution, you can ensure secure access to your Azure infrastructure for your remote workforce, enabling seamless collaboration and productivity from any location.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>networking</category>
      <category>vpn</category>
      <category>cloudcomputing</category>
    </item>
    <item>
      <title>Cloud Resume Challenge - Azure Edition (part 2)</title>
      <dc:creator>Gabriel</dc:creator>
      <pubDate>Wed, 07 Feb 2024 05:11:15 +0000</pubDate>
      <link>https://dev.to/gabbyti/cloud-resume-challenge-azure-edition-part-2-1ke</link>
      <guid>https://dev.to/gabbyti/cloud-resume-challenge-azure-edition-part-2-1ke</guid>
      <description>&lt;h2&gt;
  
  
  Table of Content
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Table of Content&lt;/li&gt;
&lt;li&gt;1. Introduction&lt;/li&gt;
&lt;li&gt;
2. The Deployments

&lt;ul&gt;
&lt;li&gt;2.1. Infrastructure CI/CD pipeline&lt;/li&gt;
&lt;li&gt;2.2. Frontend CI/CD Pipeline&lt;/li&gt;
&lt;li&gt;2.3. Backend CI/CD Pipeline&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;3. What's Next&lt;/li&gt;
&lt;li&gt;4. Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.to/gabbyti/cloud-resume-challenge-azure-edition-part-1-fgb"&gt;part one&lt;/a&gt;, we covered the basics of my Cloud Resume Challenge journey. Now, let's dive into the heart of the challenge: deployment pipelines. These are the backbone of our cloud setup, making deployment smooth and efficient. Join me as we explore how these pipelines work and how they make our deployment process easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Deployments
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1. Infrastructure CI/CD pipeline
&lt;/h3&gt;

&lt;p&gt;To streamline our infrastructure management, I've implemented a pipeline using GitHub Actions. Here's the breakdown of our workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initialization&lt;/strong&gt;: We kick off by initializing Terraform, ensuring all necessary configurations and plugins are set up correctly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Planning&lt;/strong&gt;: Terraform meticulously plans the proposed changes, outlining what will be added, modified, or destroyed in our infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation&lt;/strong&gt;: Once the plan is generated, Terraform validates it against our existing infrastructure, ensuring compatibility and compliance without making any actual modifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Applying Changes&lt;/strong&gt;: With the validated plan, Terraform proceeds to apply the changes, seamlessly updating our infrastructure to reflect the desired state.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the workflow flow file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;read'&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;write'&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ARM_CLIENT_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.AZURE_CLIENT_ID&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
  &lt;span class="na"&gt;ARM_CLIENT_SECRET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.AZURE_CLIENT_SECRET&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
  &lt;span class="na"&gt;ARM_SUBSCRIPTION_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.AZURE_SUBSCRIPTION_ID&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
  &lt;span class="na"&gt;ARM_TENANT_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.AZURE_TENANT_ID&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/setup-terraform@v3&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Initialize terraform configuration&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform init&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Validate terraform configuration&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform validate&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Plan terraform configuration&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform plan -refresh=false&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Apply terraform configuration&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform apply -refresh=false -auto-approve&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: I used a service principal details and environment varaibles to authenticate terraform to azure. Read more about that &lt;a href="https://learn.microsoft.com/en-us/azure/developer/terraform/authenticate-to-azure?tabs=bash#specify-service-principal-credentials-in-environment-variables"&gt;&lt;strong&gt;HERE&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2. Frontend CI/CD Pipeline
&lt;/h3&gt;

&lt;p&gt;For the deployment pipeline for the frontend, i have used github actions workflows. The workflow includes the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Azure Login&lt;/strong&gt;: Authenticates access to the Azure environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delete Previous Content&lt;/strong&gt;: Clears out existing website content to ensure a clean deployment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upload New Content&lt;/strong&gt;: Transfers the updated website content to the Azure platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Purge Azure CDN&lt;/strong&gt;: Refreshes the Azure CDN to reflect the latest changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure Logout&lt;/strong&gt;: Safely terminates the Azure session.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the workflow flow file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cloud Resume Deployment&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure/login@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;creds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AZURE_CREDENTIALS }}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Delete previous content&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure/CLI@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;inlineScript&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;az storage blob delete-batch --account-name ${{ vars.STORAGE_ACCOUNT_NAME }} --auth-mode key --source '$web'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload to blob storage&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure/CLI@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;inlineScript&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;az storage blob upload-batch --account-name ${{ vars.STORAGE_ACCOUNT_NAME }} --auth-mode key -d '$web' -s .&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Purge CDN endpoint&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure/CLI@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;inlineScript&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;az cdn endpoint purge --content-paths  "/*" --profile-name ${{ vars.CDN_PROFILE_NAME }} --name ${{ vars.CDN_ENDPOINT_NAME }} --resource-group ${{ vars.RESOURCE_GROUP }}&lt;/span&gt;
        &lt;span class="c1"&gt;# Azure logout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;logout&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;az logout&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.3. Backend CI/CD Pipeline
&lt;/h3&gt;

&lt;p&gt;I decided to switch it up a bit and used azure DevOps for deploying to the Azure functions. The script steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Installing Dependencies&lt;/strong&gt;: Ensuring all necessary dependencies are set up and ready to go.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publishing Deployment Artifact&lt;/strong&gt;: Packaging everything up neatly for deployment to Azure Functions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the pipeline file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Cloud Resume Deployment
on:
  push:
    branches: [main]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}
      - name: Delete previous content
        uses: azure/CLI@v1
        with:
          inlineScript: |
            az storage blob delete-batch --account-name ${{ vars.STORAGE_ACCOUNT_NAME }} --auth-mode key --source '$web'

      - name: Upload to blob storage
        uses: azure/CLI@v1
        with:
          inlineScript: |
            az storage blob upload-batch --account-name ${{ vars.STORAGE_ACCOUNT_NAME }} --auth-mode key -d '$web' -s .

      - name: Purge CDN endpoint
        uses: azure/CLI@v1
        with:
          inlineScript: |
            az cdn endpoint purge --content-paths  "/*" --profile-name ${{ vars.CDN_PROFILE_NAME }} --name ${{ vars.CDN_ENDPOINT_NAME }} --resource-group ${{ vars.RESOURCE_GROUP }}
        # Azure logout
      - name: logout
        run: |
          az logout
        if: always()

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

&lt;/div&gt;



&lt;p&gt;The remaining steps are configured in Azure DevOps by creating a release pipeline. Here is mine shown below:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  3. What's Next
&lt;/h2&gt;

&lt;p&gt;While the project is mostly complete, there's always room for improvement. Here are some areas I'll be focusing on to enhance my knowledge and experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implementing unit testing for Python code.&lt;/li&gt;
&lt;li&gt;Conducting code scans with SonarQube or Synk for security and quality assurance.&lt;/li&gt;
&lt;li&gt;Modularizing infrastructure to make it more reusable and scalable.&lt;/li&gt;
&lt;li&gt;Privatizing Azure infrastructure behind a VNet (Virtual Network) for enhanced security.&lt;/li&gt;
&lt;li&gt;Setting up a DNS Zone and managing my custom domain for better branding and accessibility.&lt;/li&gt;
&lt;li&gt;Implementing monitoring solutions to ensure system health and performance optimization.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;That wraps up part two of our Cloud Resume Challenge journey! We've dived deep into the deployment pipelines, seeing how they make our cloud setup smooth and efficient. From initializing Terraform to deploying our frontend and backend, each step has been crucial in streamlining our deployment process.&lt;/p&gt;

&lt;p&gt;But our journey doesn't end here. We've outlined some areas for improvement, like implementing unit testing, conducting code scans, and making our infrastructure more modular and secure. These steps will help us further enhance our project and deepen our understanding of cloud technologies.&lt;/p&gt;

</description>
      <category>cloudresumechallenge</category>
      <category>azure</category>
      <category>devops</category>
      <category>cloudcomputing</category>
    </item>
    <item>
      <title>Cloud Resume Challenge - Azure Edition (part 1)</title>
      <dc:creator>Gabriel</dc:creator>
      <pubDate>Wed, 07 Feb 2024 04:34:51 +0000</pubDate>
      <link>https://dev.to/gabbyti/cloud-resume-challenge-azure-edition-part-1-fgb</link>
      <guid>https://dev.to/gabbyti/cloud-resume-challenge-azure-edition-part-1-fgb</guid>
      <description>&lt;h2&gt;
  
  
  Table of Content
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Table of Content&lt;/li&gt;
&lt;li&gt;1. Introduction&lt;/li&gt;
&lt;li&gt;2. The Certification&lt;/li&gt;
&lt;li&gt;3. The HTML, CSS &amp;amp; JavaScript Frontend&lt;/li&gt;
&lt;li&gt;
4. Backend Code: Python Counter API

&lt;ul&gt;
&lt;li&gt;4.1. Prerequisite&lt;/li&gt;
&lt;li&gt;4.2. Setup&lt;/li&gt;
&lt;li&gt;4.3. Running Azure Function Locally&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;5. Terraform IaC&lt;/li&gt;

&lt;li&gt;6. Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;The Cloud Resume Challenge offers a really cool and hands-on way to dive into cloud technologies. I recently took on the Azure-focused version, and it was a fantastic journey through Microsoft's cloud platform. In this blog post, I'll share my experience and the awesome skills I picked up along the way. Here are some useful links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gabriel-cloud-resume.azureedge.net/" rel="noopener noreferrer"&gt;The Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gabbyTI/cloud_resume" rel="noopener noreferrer"&gt;Frontend Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gabbyTI/python-counter-api" rel="noopener noreferrer"&gt;Backend Code: Python API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gabbyTI/cloud-resume-azure-infrastructure" rel="noopener noreferrer"&gt;Terraform IaC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is a diagram of the entire system, showing all tools used in for this challenge and how it was implemented.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  2. The Certification
&lt;/h2&gt;

&lt;p&gt;First requirement for this challenge was to get the fundamental azure certification (AZ900). I studied for this with the &lt;a href="https://learn.microsoft.com/en-us/training/paths/microsoft-azure-fundamentals-describe-cloud-concepts/" rel="noopener noreferrer"&gt;Microsoft learn&lt;/a&gt; website and it was helpful. A quick tip, the exam is a little bit more practical than you would expect, so as you go through the modules, practice on the azure portal (even as little as searching for the azure services).&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The HTML, CSS &amp;amp; JavaScript Frontend
&lt;/h2&gt;

&lt;p&gt;Don't know about you, but i used an existing HTML &amp;amp; CSS template for the website, mostly to speed up my development. You can check out the template right &lt;a href="https://www.themezy.com/free-website-templates/151-ceevee-free-responsive-website-template" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;.&lt;br&gt;
I wrote a JavaScript file where i call my python counter API, here is the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Function to fetch visitor count from the API&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getVisitorCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://&amp;lt;PYTHON_COUNTER_API_BASE_URL&amp;gt;/api/getvisitorcount&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Update the counter on the webpage&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HEREEEE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="c1"&gt;// Call updateVisitorCount with the current count&lt;/span&gt;
      &lt;span class="nf"&gt;updateVisitorCount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error fetching visitor count:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Function to update visitor count on the API&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateVisitorCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://&amp;lt;PYTHON_COUNTER_API_BASE_URL&amp;gt;/api/updatevisitorcount&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({}),&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Visitor count updated successfully:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error updating visitor count:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Fetch the visitor count and update on page load&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getVisitorCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Backend Code: Python Counter API
&lt;/h2&gt;

&lt;p&gt;I had some trouble when trying to write this initially, so much so, i had to rewrite the azure functions in NodeJS(&lt;a href="https://github.com/gabbyTI/node-counter-api" rel="noopener noreferrer"&gt;here&lt;/a&gt;) which worked fine, Then went back to it and discovered it was a python version constraint with the azure-functions-core-tools i had downloaded. Here is a little documentation on my backend&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1. Prerequisite
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Python v10 or higher&lt;/li&gt;
&lt;li&gt;Azure CosmosDB for Table database connection string&lt;/li&gt;
&lt;li&gt;Azure CLI&lt;/li&gt;
&lt;li&gt;Install latest azure-functions-core-tools
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; azure-functions-core-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2. Setup
&lt;/h3&gt;

&lt;p&gt;4.2.1. Clone repository&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/gabbyTI/python-counter-api.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4.2.2. Initialize the azure function to create the&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;python-counter-api
func init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4.2.3. Install dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4.2.4. Add connection string and table name to the local.settings.json file(this is created after the 2nd steps)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"conn_str"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your connection string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"table_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your table name"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.3. Running Azure Function Locally
&lt;/h3&gt;

&lt;p&gt;4.2.1. Login to Azure&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;4.2.2. Start the azure function locally&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;func start &lt;span class="nt"&gt;-p&lt;/span&gt; 7071
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Terraform IaC
&lt;/h2&gt;

&lt;p&gt;Provisioning the infrastructure for this challenge was done entirely with terraform IaC tool. This was the most fun for me during this challenge because of there was much i learnt from this stage. I would say the best is the knowledge of how to use the comprehensive terraform provider documentations. I created the following resources with terraform&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resource Group: containing all resources&lt;/li&gt;
&lt;li&gt;Azure Function&lt;/li&gt;
&lt;li&gt;ComosDB for Table API&lt;/li&gt;
&lt;li&gt;Storage Account &amp;amp; Static Website Container&lt;/li&gt;
&lt;li&gt;CDN Profile &amp;amp; Endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also implemented a remote backend for for my terraform state in a separate storage account and on a different resource group that i created manually. Checkout out my terraform scripts repository &lt;a href="https://github.com/gabbyTI/cloud-resume-azure-infrastructure" rel="noopener noreferrer"&gt;&lt;strong&gt;HERE&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Conclusion
&lt;/h2&gt;

&lt;p&gt;As we come to the end of this part of our journey, I've decided to split it into two parts to make sure we can really dive deep into everything we've experienced. In this first part, we've gone over some of the most exciting moments and things I've learned along the way. From getting my Azure certification to putting together a cool website, it's been quite the ride with its fair share of challenges and triumphs.&lt;/p&gt;

&lt;p&gt;But hold onto your hats because the fun isn't over yet! In the next part, we'll dig even deeper into the deployment pipelines that made all of this possible. We'll take a closer look at how these pipelines were set up and fine-tuned to make our deployment process smoother than ever. So get ready for more insights and behind-the-scenes action as we continue this adventure together!&lt;br&gt;
&lt;a href="https://dev.to/gabbyti/cloud-resume-challenge-azure-edition-part-2-1ke"&gt;&lt;em&gt;Go to part two&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cloudresumechallenge</category>
      <category>azure</category>
      <category>cloudcomputing</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
