<?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: Jones Ndzenyuy</title>
    <description>The latest articles on DEV Community by Jones Ndzenyuy (@ndzenyuy).</description>
    <link>https://dev.to/ndzenyuy</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%2F2232552%2Fa7efa3cc-6626-4cf2-bcd9-d5f483e7246a.jpg</url>
      <title>DEV Community: Jones Ndzenyuy</title>
      <link>https://dev.to/ndzenyuy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ndzenyuy"/>
    <language>en</language>
    <item>
      <title>AWS community day Workshop: Building Your First DevOps Blue/Green Pipeline with ECS</title>
      <dc:creator>Jones Ndzenyuy</dc:creator>
      <pubDate>Fri, 21 Nov 2025 21:49:20 +0000</pubDate>
      <link>https://dev.to/ndzenyuy/aws-community-day-workshop-building-your-first-devops-bluegreen-pipeline-with-ecs-4o67</link>
      <guid>https://dev.to/ndzenyuy/aws-community-day-workshop-building-your-first-devops-bluegreen-pipeline-with-ecs-4o67</guid>
      <description>&lt;p&gt;In this workshop, I will guide you step by step how to build a Blue-Green deployment pipeline with AWS pipeline and deploys on AWS ECS with EC2. This deployment strategy helps teams to first test an app while routing traffic to a non-prod route, when confirmed that the app functions as expected, then the traffic is routed to prod. In case of any failure, a rollback is initiated for the previously working version hence avoiding downtime. &lt;/p&gt;

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

&lt;h3&gt;
  
  
  App Flow
&lt;/h3&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%2F00ic54n0vvkm826uc5p2.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%2F00ic54n0vvkm826uc5p2.png" alt="Application Archichitecture" width="800" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Infrastructure consists of an Application Load Balancer which exposes the app on Port 80, routes traffic to the autoscaling group managed by ECS, a fleet of EC2 instances running in two AZs for High availability. Each of these instances have ECS agent installed and the necessary software for running our Docker containers. These interact with Aurora PostgreSQL database in RDS for data storage. Aurora PostgreSQL database is configured to replicate data in another availability zone for a resilient database configuration. When there is a spike in traffic, ECS will launch other containers in order to accommodate the load.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment Flow
&lt;/h3&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%2Feye9iygsdput5ol4nz50.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%2Feye9iygsdput5ol4nz50.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Provided the developers do changes and want to update the deployed app,  our CI/CD pipeline is configured to automate the deployment. With code stored in GitLab, once there is a push, AWS CodePipeline is triggered via a connection app setup and authenticated to Gitlab, Codebuild builds, containerize and push the image to ECR, next Codedeploy deploys the new app, first will deploy it with port 8080 for tests, if the team is happy with their changes, they can approve for traffic to be switch to the newly deployed container and terminate the former. The former containers can be configured to still run for some time while the newly deployed is tested, if everything is fine, then the last version of the deployed app can be terminated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build it step by step
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;**Note**: _If you face issues putting it up and working, go to the optional stage and deploy with Cloudformation_&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ensure you have a code editor like VScode, you have a Gitlab account, an AWS account will appropriate permissions(full access to RDS, ECS, ECR, IAM), configure awscli on you terminal with access keys  &lt;/p&gt;

&lt;h3&gt;
  
  
  Clone the Code
&lt;/h3&gt;

&lt;p&gt;On your local computer terminal(i use wsl with ubuntu os) run&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://gitlab.com/ndzenyuy/tripmgmt.git
&lt;span class="nb"&gt;cd &lt;/span&gt;tripmgmt
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; .git
git init
code &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will clone the repository that has the application code to your local machine, enter the folder and remove the .git file so as to remove the url for the repository from whence the code was pulled, therefore making it possible to use the code and push to your own repository. &lt;/p&gt;

&lt;p&gt;On the browser, go to GitLab and create an account if you don't have one, in it, create a repository named "tripmgmt", you can make the project public and don't create it with a READme.md file. Now copy the repository http url and go back to your terminal and run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add origin &amp;lt;your repo url&amp;gt;
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit"&lt;/span&gt;
git push &lt;span class="nt"&gt;--set-upstream&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These will push the code to the newly created repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup AWS Resources
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create required AWS IAM Roles
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Task Execution Role&lt;/strong&gt;: Grants the Amazon ECS container and Fargate agents permission to make AWS API calls on your behalf.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create the &lt;em&gt;ecsTaskExecutionRole&lt;/em&gt; IAM role  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the IAM console &lt;/li&gt;
&lt;li&gt;In the navigation pane, choose Roles, Create role.&lt;/li&gt;
&lt;li&gt;In the Trusted entity type, select AWS Service&lt;/li&gt;
&lt;li&gt;Under Use case, select Elastic Container Service and Elastic Container Service Task, then choose Next: Permissions.&lt;/li&gt;
&lt;li&gt;In the Attach permissions policy section, search for &lt;em&gt;AmazonECSTaskExecutionRolePolicy&lt;/em&gt;, select the policy, and then choose Next: Review.&lt;/li&gt;
&lt;li&gt;For Role Name, type &lt;em&gt;ecsTaskExecutionRole&lt;/em&gt; and choose Create role.&lt;/li&gt;
&lt;li&gt;Please save value of the Role ARN in the open text file to use in the later section of the workshop.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ECS Container Instance Role&lt;/strong&gt;: This IAM role is required for the EC2 launch type. The Amazon ECS container agent makes calls to the Amazon ECS API on your behalf. Container instances that run the agent require an IAM policy and role for the service to know that the agent belongs to you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create the &lt;strong&gt;ecsInstanceRole&lt;/strong&gt; IAM role&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the navigation pane, choose Roles, Create role.&lt;/li&gt;
&lt;li&gt;In the Trusted entity type, select AWS Service&lt;/li&gt;
&lt;li&gt;Under Use case, select EC2, then choose Next: Permissions.&lt;/li&gt;
&lt;li&gt;In the Attach permissions policy section, search for &lt;em&gt;AmazonEC2ContainerServiceforEC2Role&lt;/em&gt;, select the policy, and then choose Next: Review.&lt;/li&gt;
&lt;li&gt;For Role Name, type &lt;em&gt;ecsInstanceRole&lt;/em&gt; and choose Create role.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ECS CodeDeploy Role&lt;/strong&gt;: Before you can use the CodeDeploy blue/green deployment type with Amazon ECS, the CodeDeploy service needs permissions to update your Amazon ECS service on your behalf. These permissions are provided by the CodeDeploy IAM role.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create the &lt;em&gt;ecsCodeDeployRole&lt;/em&gt; IAM role  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the navigation pane, choose Roles, Create role.&lt;/li&gt;
&lt;li&gt;In the Trusted entity type, select AWS Service&lt;/li&gt;
&lt;li&gt;Under Use case, select CodeDeploy and CodeDeploy - ECS, then choose Next: Permissions.&lt;/li&gt;
&lt;li&gt;In the Attach permissions policy section, &lt;em&gt;AWSCodeDeployRoleForECS&lt;/em&gt; policy should come as selected, choose Next: Review.&lt;/li&gt;
&lt;li&gt;For Role Name, type &lt;em&gt;ecsCodeDeployRole&lt;/em&gt; and choose Create role&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Create Container Repository
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open the Amazon ECR console.&lt;/li&gt;
&lt;li&gt;In the navigation pane, under Private Registry choose Repositories.&lt;/li&gt;
&lt;li&gt;On the Repositories page, choose Create repository.&lt;/li&gt;
&lt;li&gt;For Repository name, enter a name for your repository like &lt;em&gt;devops/tripmgmtdemo&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;For Tag immutability, keep it Mutable for this workshop. Repositories configured with immutable tags will prevent image tags from being overwritten. For more information, see Image Tag Mutability.&lt;/li&gt;
&lt;li&gt;For Encryption settings, select AWS Key Management Service (KMS). Use an AWS managed key. To read more about encrypting at rest, see ECR Encryption at Rest.&lt;/li&gt;
&lt;li&gt;For Scan on push, keep it Disabled for this workshop. Repositories configured to scan on push will start an image scan whenever an image is pushed, otherwise image scans need to be started manually. For more information, see Image Scanning.&lt;/li&gt;
&lt;li&gt;Choose Create repository.&lt;/li&gt;
&lt;li&gt;Please save value of the Repository URL in the open text file to use in the later section of the workshop.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Setup Aurora PostgreSQL RDS Database
&lt;/h3&gt;

&lt;p&gt;In this section, we will setup Aurora PostgreSQL RDS with Multi-AZ configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the AWS Management Console and open the Amazon RDS console.&lt;/li&gt;
&lt;li&gt;In the navigation pane, choose Databases.&lt;/li&gt;
&lt;li&gt;Choose Create database.&lt;/li&gt;
&lt;li&gt;In Choose a database creation method, choose Standard Create.&lt;/li&gt;
&lt;li&gt;In Engine options, choose Aurora (PostgreSQL Compatible).&lt;/li&gt;
&lt;li&gt;In Templates, choose Dev/Test template. 

&lt;ol&gt;
&lt;li&gt;Clear Auto generate a password check box.&lt;/li&gt;
&lt;li&gt;Enter Master password value as &lt;em&gt;SuperSecretPGSqlPwd##2006&lt;/em&gt; and enter the same password in Confirm password.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;In the DB cluster identifier field, give Aurora DB cluster name, &lt;em&gt;tripmgmtdb-cluster&lt;/em&gt;
&lt;/li&gt;

&lt;li&gt;To enter your master password, do the following in Credential Settings&lt;/li&gt;

&lt;li&gt;For Instance configuration, choose &lt;em&gt;db.t4g.medium&lt;/em&gt; under &lt;em&gt;Burstable classes (includes t classes)&lt;/em&gt;
&lt;/li&gt;

&lt;li&gt;For Availability &amp;amp; durability, choose Create an Aurora Replica/Reader node in a different AZ (recommended for scaled availability)&lt;/li&gt;

&lt;li&gt;Keep defaults for &lt;strong&gt;Connectivity, Babelfish settings, Database authentication, Monitoring sections&lt;/strong&gt;.&lt;/li&gt;

&lt;li&gt;For Additional configuration, enter &lt;em&gt;tripmgmt&lt;/em&gt; under Initial database name.&lt;/li&gt;

&lt;li&gt;Choose Create database.&lt;/li&gt;

&lt;li&gt;For Databases, choose the name of the new Aurora DB cluster.
On the RDS console, the details for new DB cluster appear. The DB cluster and its DB instance have a status of creating until the DB cluster is ready to use. When the state changes to available for both, you can connect to the DB cluster. Depending on the DB instance class and the amount of storage, it can take up to 20 minutes before the new DB cluster is available.&lt;/li&gt;

&lt;li&gt;On the Connectivity &amp;amp; security tab, note the port and the endpoint of the writer DB instance. Please save value of the endpoint and port of the cluster in the open text file to use in the later section of the workshop. Endpoint URL should be of format tripmgmtdb-cluster.cluster-UNIQUEID.AWSREGION.rds.amazonaws.com&lt;/li&gt;

&lt;li&gt;Click on Writer Node and on the Connectivity &amp;amp; security tab, please save value of the Security Group Id under Security section (i.e. sg-xxxxxxxx) in the open text file to use in the later section of the workshop.&lt;/li&gt;

&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create Application Load Balancer and Target Groups&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will create an Amazon EC2 application load balancer. This will be the public endpoint to access Trip Management Monolith Application. The load balancer must use a VPC with two public subnets in different Availability Zones. &lt;br&gt;
First create Target groups for your load balancer&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sign in to the AWS Management Console and open the Amazon EC2 console &lt;/li&gt;
&lt;li&gt;In the navigation pane, choose Target groups and select Create target group.&lt;/li&gt;
&lt;li&gt;Under Basic configuration, select IP addresses target type.&lt;/li&gt;
&lt;li&gt;In Name, enter a target group name &lt;em&gt;alb-tg-tripmgmtdemo-1&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;In Protocol choose &lt;em&gt;HTTP&lt;/em&gt;. In Port, enter &lt;em&gt;80&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Keep rest of the settings as defaults.&lt;/li&gt;
&lt;li&gt;Select Next: Register Targets.&lt;/li&gt;
&lt;li&gt;Select Create target group.&lt;/li&gt;
&lt;li&gt;Repeat above steps to create another target group for Protocol &lt;em&gt;HTTP&lt;/em&gt; and Port &lt;em&gt;8080&lt;/em&gt;, name it &lt;em&gt;alb-tg-tripmgmtdemo-2&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;To create an Amazon EC2 application load balancer&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sign in to the AWS Management Console and open the Amazon EC2 console &lt;/li&gt;
&lt;li&gt;In the navigation pane, choose Load Balancers, choose Create Load Balancer.&lt;/li&gt;
&lt;li&gt;Choose Application Load Balancer, and then choose Create.&lt;/li&gt;
&lt;li&gt;In Name, enter the name of your load balancer &lt;em&gt;tripmgmtdemo-alb&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;In Scheme, choose internet-facing.&lt;/li&gt;
&lt;li&gt;In IP address type, choose &lt;em&gt;ipv4&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Under Network mapping, in VPC, choose the default VPC, and then choose any two availability zones under Mappings. Please save value of the Availability Zone / Subnet ids in the open text file to use in the later section of the workshop.&lt;/li&gt;
&lt;li&gt;Under Security groups, choose Create new security group

&lt;ol&gt;
&lt;li&gt;Give it the name &lt;em&gt;ALBSecurityGroup&lt;/em&gt; in the Security group name field.&lt;/li&gt;
&lt;li&gt;Give it the description  in the Description field.&lt;/li&gt;
&lt;li&gt;Add Inbound Rule, Allow 80 port (HTTP) inbound traffic from My IP&lt;/li&gt;
&lt;li&gt;Add Inbound Rule, Allow 8080 port (CustomTCPPort) inbound traffic from My IP&lt;/li&gt;
&lt;li&gt;Select Create security group&lt;/li&gt;
&lt;li&gt;Please save value of the newly created Security Group Id (i.e. sg-xxxxxxxx..) in the open text file to use in the later section of the workshop.&lt;/li&gt;
&lt;li&gt;Come back to Create Application Load Balancer tab, refresh Security groups and select newly created Security group, removing any existing pre-selected Security groups.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Under Listeners and routing, configure two listener ports for your load balancer:

&lt;ol&gt;
&lt;li&gt;Under Protocol, choose HTTP, and Under Port, enter 80.&lt;/li&gt;
&lt;li&gt;Under Default action, select alb-tg-tripmgmtdemo-1 Target Group.&lt;/li&gt;
&lt;li&gt;Choose Add listener.&lt;/li&gt;
&lt;li&gt;Under Protocol, choose HTTP, and Under Port, enter 8080.&lt;/li&gt;
&lt;li&gt;Under Default action, select alb-tg-tripmgmtdemo-2 Target Group.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Choose Create load balancer.&lt;/li&gt;
&lt;li&gt;Go to Load Balancers and click on the newly created load balancer. From the Description tab, please save value of the DNS name of the Load Balancer in the open text file to use in the later section of the workshop.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Setup ECS Cluster
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Create ECS Cluster
&lt;/h3&gt;

&lt;p&gt;Amazon ECS creates an Amazon EC2 Auto Scaling launch template and Auto Scaling group on your behalf as part of the AWS CloudFormation stack.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the Amazon ECS console.&lt;/li&gt;
&lt;li&gt;In the navigation pane, choose &lt;em&gt;Clusters&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;On the Clusters page, choose &lt;em&gt;Create Cluster&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Under Cluster configuration, for Cluster name, enter &lt;em&gt;ecs-cluster-tripmgmtdemo&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Under Infrastructure, keep &lt;em&gt;AWS Fargate (serverless)&lt;/em&gt; selected and also select &lt;em&gt;Amazon EC2 instances&lt;/em&gt;. Next, configure the Auto Scaling group which acts as the capacity provider.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Select Create new group, and then provide the following details about the group:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For Operating system/Architecture, choose Amazon Linux 2.&lt;/li&gt;
&lt;li&gt;For EC2 instance type, choose t3.large. Here, t3.large selected as required for this workshop to complete in given time.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For Capacity, enter 2 for the minimum number and 4 for the maximum number of instances to launch in the Auto Scaling group.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under Network settings for Amazon EC2 instances, choose default VPC and same two subnets, which were selected at that time of creating Application Load Balancer in previous section.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose Create&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Create Security Group for EC2 Container Instance&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the Amazon EC2 console.&lt;/li&gt;
&lt;li&gt;On the navigation pane, under Network &amp;amp; Security, choose Security Groups&lt;/li&gt;
&lt;li&gt;On the next page, choose Create security group.&lt;/li&gt;
&lt;li&gt;For Security group name, enter ECS-ALB-SecurityGroup for the security group name and give meaningful description under Description.&lt;/li&gt;
&lt;li&gt;Choose default VPC&lt;/li&gt;
&lt;li&gt;Add Inbound Rule, Allow 80 port (HTTP) inbound traffic from Application Loadbalancer Security Group you have created in earlier section (i.e. sg-xxxxx).&lt;/li&gt;
&lt;li&gt;Add Inbound Rule, Allow 8080 port (CustomTCPPort) inbound traffic from Application Loadbalancer Security Group you have created in earlier section (i.e. sg-xxxxx).&lt;/li&gt;
&lt;li&gt;Select Create security group&lt;/li&gt;
&lt;li&gt;Please save value of the newly created Security Group Id (i.e. sg-xxxxxxxx..) in the open text file to use in the later section of the workshop.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Create ECS Task
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First create Amazon CloudWatch Log Group, where taskdef is configured to send all logs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to CloudWatch Console &lt;/li&gt;
&lt;li&gt;Select Log Groups,&lt;/li&gt;
&lt;li&gt;Click Create log group button,&lt;/li&gt;
&lt;li&gt;Log Group Name: enter &lt;em&gt;tripmgmt-demo-ecstask-loggrp&lt;/em&gt; and Retention setting select 5 days&lt;/li&gt;
&lt;li&gt;Choose Create&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In order to create an ECS Task, we will need to create a ECS Task Definition file. Go to you cli, make sure it is pointing to the folder &lt;em&gt;tripmgmt&lt;/em&gt; and delete the file &lt;em&gt;taskdef.json&lt;/em&gt; by running the command&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rm taskdef.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Copy below given environment variables in plain text-file and change respective environment variable values as per the workshop resources created by you in the previous sections. After modifying values of respective environment variables, execute these export commands on the commandline.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;LOG_GROUP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tripmgmt-demo-ecstask-loggrp
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DB_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgres
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SuperSecretPGSqlPwd##2006
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_DEFAULT_REGION&lt;/span&gt;&lt;span class="o"&gt;=&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;AWS&lt;/span&gt;&lt;span class="sh"&gt;-REGION&amp;gt;&amp;gt;

export TASK_EXECUTION_ROLE_ARN="arn:aws:iam::&amp;lt;&amp;lt;AccountID&amp;gt;&amp;gt;:role/ecsTaskExecutionRole"
export AURORA_PGSQL_RDS_URL="tripmgmtdb-cluster.cluster-&amp;lt;&amp;lt;UNIQUEID&amp;gt;&amp;gt;.&amp;lt;&amp;lt;AWS-REGION&amp;gt;&amp;gt;.rds.amazonaws.com"
export ECR_LATEST_IMAGE_URL="&amp;lt;&amp;lt;AccountID&amp;gt;&amp;gt;.dkr.ecr.&amp;lt;&amp;lt;AWS-REGION&amp;gt;&amp;gt;.amazonaws.com/devops/tripmgmtdemo:latest"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;LOG_GROUP&lt;/code&gt; : Verify name as you have created in Step No 1 in this section, only change if you have used different log group name.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DB_USERNAME&lt;/code&gt;: Database username set while creating Aurora PostgreSQL DB Cluster.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DB_PASSWORD&lt;/code&gt;: Database password set while creating Aurora PostgreSQL DB Cluster.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TASK_EXECUTION_ROLE_ARN&lt;/code&gt;: Task Execution Role created in Create IAM Roles section.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AURORA_PGSQL_RDS_URL&lt;/code&gt;: Aurora PostgreSQL RDS Cluster URL as created in Create Aurora PostgreSQL DB section.&lt;/li&gt;
&lt;li&gt; &lt;code&gt;ECR_LATEST_IMAGE_URL&lt;/code&gt;: Elastic Container Registry Image URL from Create Container Repository section.&lt;/li&gt;
&lt;li&gt;Create the task definition from the command line by running
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;envsubst &amp;lt; "taskdef_src.json" &amp;gt; "taskdef.json"
aws ecs register-task-definition --cli-input-json file://taskdef.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Please save the value of the TaskDefinition ARN from output in the open text file to use in the later section of the workshop. It is at the very top of the output and should look something like arn:aws:ecs:&amp;lt;&amp;gt;:&amp;lt;&amp;gt;:task-definition/task-tripmgmt:1.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commit taskdef.json in repository.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add taskdef.json
git commit -m "Updated Taskdef"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;You can also verify the Task Definition in the Amazon ECS console , left navigation bar under Amazon ECS, Task Definitions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Prepare AppSpec File&lt;/strong&gt;&lt;br&gt;
AWS CodeDeploy requires AppSpec YAML-formatted file to manage deployment. In the project folder on the terminal, run the code below and edit the value of the taskdefinition arn to reflect what you had in step 4 above(similar to: arn:aws:ecs:&amp;lt;&amp;gt;:&amp;lt;&amp;gt;:task-definition/task-tripmgmt:1.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nano appspec.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Commit appspec.yaml in repository
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add appspec.yaml
git commit -m "appspec file with Taskdef url"
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Optional: Deploy the infrastructure with Cloudformation (Recommended)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Login to the console and search for cloudformation&lt;/li&gt;
&lt;li&gt;Create a new stack&lt;/li&gt;
&lt;li&gt;Prerequisite - Prepare template: Choose existing stack&lt;/li&gt;
&lt;li&gt;Specify template: Upload a template file&lt;/li&gt;
&lt;li&gt;Upload a template file: Choose file -&amp;gt; search on your computer, in the tripmgmt/cloudformation-infra folder/subfolder and choose tripmgmt.yml&lt;/li&gt;
&lt;/ol&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%2F44cy9ddsubuf4rjqcaw4.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%2F44cy9ddsubuf4rjqcaw4.png" alt=" " width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On specify Stack details&lt;br&gt;
&lt;code&gt;&lt;br&gt;
Stack name: tripmgmt&lt;br&gt;
KeyPairName: &amp;lt;select a keypair in you account or create on if absent&amp;gt;&lt;br&gt;
PublicSubnet1Id: &amp;lt;select a public subnet&amp;gt;&lt;br&gt;
PublicSubnet2Id: &amp;lt;select a public subnet&amp;gt;&lt;br&gt;
VpcId: &amp;lt;select the default vpc id&amp;gt;&lt;br&gt;
click next&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Scroll down and acknowledge, &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%2Fw0xw2ij4jauqfeynhky4.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%2Fw0xw2ij4jauqfeynhky4.png" alt=" " width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and click next scroll and click submit&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%2Fyufpcenfheyzswjc2lrx.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%2Fyufpcenfheyzswjc2lrx.png" alt=" " width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will create the infrastructure needed to run our Pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  DevOps Pipeline with Blue/Green Deployment
&lt;/h2&gt;

&lt;p&gt;The Engineering team commit changes to code base and then push those changes to a git repository. It triggers AWS CodePipeline action. AWS CodeBuild will compile source code and build &amp;amp; store container image in an Elastic Container Registry. AWS CodeDeploy will initiate Blue/Green deployment of ECS Task(s) in an ECS Cluster through ECS Service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup CodeBuild with GitLab Integration
&lt;/h3&gt;

&lt;p&gt;To setup AWS CodeBuild, first we need to create/modify buildspec.yml file to describe build steps. After that, we need to configure the CodeBuild Project linking with the GitLab Repository.&lt;br&gt;
On the cli, run the code below and edit the values of the following parameters to suite those you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_ACCOUNT_ID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AWS_DEFAULT_REGION&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;REPOSITORY_URI&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nano buildspec.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After editing, run &lt;code&gt;ctrl + x&lt;/code&gt;, when prompted to save changes press &lt;code&gt;Y&lt;/code&gt; then press enter to confirm.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup CodeBuild Project&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the CodeBuild console.&lt;/li&gt;
&lt;li&gt;On the Build projects page, choose Create build project.&lt;/li&gt;
&lt;/ol&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%2F5wt4ghqwv0xh1k7c5278.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%2F5wt4ghqwv0xh1k7c5278.png" alt=" " width="800" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In Project configuration: Enter a name for this build project &lt;em&gt;tripmgmt-demo-build&lt;/em&gt;. Build project names must be unique across each AWS account. You can also include an optional description of the build project to help other users understand what this project is used for.&lt;/li&gt;
&lt;/ol&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%2Fpef83dgmvnqug8fygt7r.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%2Fpef83dgmvnqug8fygt7r.png" alt=" " width="800" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If required, Select Build badge to make your project's build status visible and embeddable.&lt;/li&gt;
&lt;li&gt;In Source: For Source provider, choose GitLab.&lt;/li&gt;
&lt;li&gt;You will then get an error stating that you have not connected to GitLab.&lt;/li&gt;
&lt;li&gt;Press the Manage account credentials link.&lt;/li&gt;
&lt;li&gt;Select GitLab as your credential type.&lt;/li&gt;
&lt;li&gt;In Connection, press create a new GitLab connection.&lt;/li&gt;
&lt;li&gt;Give the connection the name &lt;em&gt;tripmgmt-connection&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Press the Connect to GitLab button and authenticate.&lt;/li&gt;
&lt;li&gt;Authorize AWS Connector for GitLab.&lt;/li&gt;
&lt;li&gt;After being redirected back to the AWS Console, press Connect.&lt;/li&gt;
&lt;li&gt;You should now be able to save and add your new GitLab connection.&lt;/li&gt;
&lt;li&gt;From Repository, choose the repository you have created for this project demo.&lt;/li&gt;
&lt;/ol&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%2F4w9xw1nplc5h9e3gr4on.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%2F4w9xw1nplc5h9e3gr4on.png" alt=" " width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For Source version, type main.&lt;/li&gt;
&lt;li&gt;In Environment: choose Managed Image with Operating system as Ubuntu,&lt;/li&gt;
&lt;li&gt;For Runtime(s) choose Standard and Image choose the one with Standard:5, having Image Version as Always use the latest image for this runtime version&lt;/li&gt;
&lt;/ol&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%2Fgzrxwe5ae6mro3d4eno6.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%2Fgzrxwe5ae6mro3d4eno6.png" alt=" " width="800" height="659"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For Service role choose New service role and give it a meaningful name &lt;em&gt;codebuild-tripmgmt-demo-build-service-role&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Open Aditional configuration in the same section. Check mark Privileged action.&lt;/li&gt;
&lt;li&gt;For Buildspec, select that you want to Use a buildspec file, add the buildspec.yml file location and name - &lt;em&gt;buildspec.yml&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&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%2Fpsfdx20tchso6gy3eq6c.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%2Fpsfdx20tchso6gy3eq6c.png" alt=" " width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For Logs, check mark CloudWatch logs and give Group name as &lt;em&gt;codebuild-logs&lt;/em&gt;, Stream name as &lt;em&gt;tripmgmtdemo-build&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Click Create build project.&lt;/li&gt;
&lt;/ol&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%2Fi6ncspkv38basuoblg06.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%2Fi6ncspkv38basuoblg06.png" alt=" " width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Now edit newly created service role &lt;em&gt;codebuild-tripmgmt-demo-build-service-role&lt;/em&gt; to allow accessing ECR repository through &lt;em&gt;AmazonEC2ContainerRegistryPowerUser&lt;/em&gt; managed policy.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open codebuild-tripmgmt-demo-build-service-role role from IAM console .&lt;/li&gt;
&lt;li&gt;Choose Attach policies.&lt;/li&gt;
&lt;li&gt;To narrow the available policies to attach, for Filter, type AmazonEC2ContainerRegistryPowerUser&lt;/li&gt;
&lt;li&gt;Check the box to the left of the AWS managed policy and choose Attach policy and Update.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Select the build project and Start build to test GitLab and CodeBuild integration.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Post successful build, you can verify new docker image in Amazon ECR console.&lt;/p&gt;&lt;/li&gt;

&lt;/ol&gt;

&lt;h3&gt;
  
  
  Deploy on Amazon ECS with EC2
&lt;/h3&gt;

&lt;p&gt;As per the architectural diagram, Engineering team commit changes to code base and then push those changes to a Git repository. It triggers AWS CodePipeline action, AWS CodeBuild will compile source code and build &amp;amp; store container image in an Elastic Container Registry. AWS CodeDeploy will initiate Blue/Green deployment of ECS Task(s) in an ECS Cluster through ECS Service. Upon successful deployment of ECS Task(s), users can access Web Portal through DNS URL pointing to ALB endpoint. ALB endpoint serves client requests from ECS Cluster after automatically adjusting capacity to maintain steady state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create CodeDeploy Application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To create a CodeDeploy application&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the CodeDeploy console  and choose Create application.&lt;/li&gt;
&lt;li&gt;In Application name, enter the name you want to use &lt;em&gt;Deploy-Tripmgmt-Demo-App&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;In Compute platform, choose Amazon ECS.&lt;/li&gt;
&lt;li&gt;Choose Create application.&lt;/li&gt;
&lt;/ol&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%2Fx06my0prcus5l8makaj2.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%2Fx06my0prcus5l8makaj2.png" alt=" " width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;To create a CodeDeploy deployment group&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On your application page's Deployment groups tab, choose Create deployment group.&lt;/li&gt;
&lt;li&gt;In Deployment group name, enter a name that describes the deployment group &lt;em&gt;deploygrp-tripmgmt-demo&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;In Service role, choose a service role ecsCodeDeployRole, which was created in earlier section Create required AWS IAM Roles and grants CodeDeploy access to Amazon ECS.&lt;/li&gt;
&lt;li&gt;In Environment configuration, choose your Amazon ECS cluster name and service name.&lt;/li&gt;
&lt;li&gt;From Load balancers, choose the name of the load balancer that serves traffic to your Amazon ECS service.&lt;/li&gt;
&lt;li&gt;From Production listener port, choose the port and protocol for the listener that serves production traffic to your Amazon ECS service. (Production listener port : 80 and Test listener port : 8080)&lt;/li&gt;
&lt;li&gt;From Target group 1 name and Target group 2 name, choose the target groups used to route traffic during your deployment. Make sure that these are the target groups you created for your load balancer.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under Deployment settings,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose Specify when to reroute traffic and choose 0 days, 0 hours, and 5 minutes. This will reroute the traffic to successfully deployed updated tasks after 5 Minutes. This is the time required by you to verify the successfully deployed updated tasks and decide whether to rollback or continue reroute the traffic.&lt;/li&gt;
&lt;li&gt;Under Deployment configuration, choose CodeDeployDefault:ECSAllAtOnce. It will configure CodeDeploy to shift all traffic to the updated Amazon ECS container at once.&lt;/li&gt;
&lt;li&gt;Under Original revision termination, and choose 0 days, 0 hours, and 0 minutes. It will configure CodeDeploy to terminate the original tasks immediately after rerouting the traffic. You can choose to keep the original tasks for a desired duration as required. After termination of original tasks, you cannot rollback manually or automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose Create deployment group.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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%2Fdxyzd94oyhcx0s9lsb7j.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%2Fdxyzd94oyhcx0s9lsb7j.png" alt=" " width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create CodePipeline
&lt;/h3&gt;

&lt;p&gt;In this section, we will create a DevOps pipeline with the following actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A source stage with a GitLab action&lt;/li&gt;
&lt;li&gt;A build stage with a CodeBuild action&lt;/li&gt;
&lt;li&gt;A deployment stage with an Amazon ECS deploy action with Blue/Green Deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Sign in to the AWS Management Console and open the CodePipeline console &lt;/li&gt;
&lt;li&gt;On the Welcome page, Getting started page, or the Pipelines page, choose Create pipeline.&lt;/li&gt;
&lt;li&gt;In Step 1: Choose creation settings, pick Build custom pipeline&lt;/li&gt;
&lt;li&gt;In Step 2: Choose pipeline settings, in Pipeline name, enter &lt;em&gt;codepipeline-tripmgmt-demo&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;In Service role, Choose New service role to allow CodePipeline to create a new service role in IAM. Enter name as codepipeline-tripmgmt-demo-service-role&lt;/li&gt;
&lt;/ol&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%2F7r3s5wyfkpmdk1ol25ck.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%2F7r3s5wyfkpmdk1ol25ck.png" alt=" " width="800" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In Artifact store, Choose Default location to use the default artifact store, such as the Amazon S3 artifact bucket designated as the default, for your pipeline in the region you have selected for your pipeline.&lt;/li&gt;
&lt;li&gt;Choose Next.&lt;/li&gt;
&lt;li&gt;In Step 2: Add source stage, in Source provider, choose GitLab. In Connection select the connection you created earlier. Following this, select the repository and default branch you chose earlier. The rest can be kept at default.&lt;/li&gt;
&lt;li&gt;Choose Next.&lt;/li&gt;
&lt;li&gt;In Step 3: Add build stage, in Build provider, choose Other build providers and then AWS CodeBuild. In Project name choose the name of the build project. The rest can be kept default.&lt;/li&gt;
&lt;li&gt;Choose Next.&lt;/li&gt;
&lt;li&gt;Choose Skip test stage at the bottom of the page.&lt;/li&gt;
&lt;li&gt;In Step 4: Add deploy stage, in Deploy provider choose Amazon ECS (Blue/Green)&lt;/li&gt;
&lt;/ol&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%2Fww37yzij4yncd7buo43u.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%2Fww37yzij4yncd7buo43u.png" alt=" " width="800" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In AWS CodeDeploy application name, choose CodeDeploy Application name. In AWS CodeDeploy deployment group, choose CodeDeploy Application's Deployment Group.&lt;/li&gt;
&lt;li&gt;In Amazon ECS task definition, choose BuildArtifact and enter taskdef.json.&lt;/li&gt;
&lt;li&gt;In AWS CodeDeploy AppSpec file, choose BuildArtifact and enter appspec.yaml.&lt;/li&gt;
&lt;li&gt;Choose Next.&lt;/li&gt;
&lt;/ol&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%2F3nqwnam0m5jr7uc2y8lm.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%2F3nqwnam0m5jr7uc2y8lm.png" alt=" " width="800" height="671"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Review the information, and then choose Create pipeline. Immediately, stop the Pipeline Execution with Stop and Abandon pop-up action.&lt;br&gt;
Modify Deploy Stage&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open (or remain in) the CodePipeline console  &amp;amp; select the Pipeline name, for example codepipeline-tripmgmt-demo.&lt;/li&gt;
&lt;li&gt;Click Edit, and scroll down at bottom and "Edit Stage" , click on Edit icon of Deploy Action Group.&lt;/li&gt;
&lt;li&gt;In Input artifacts, choose SourceArtifact and remove BuildArtifact&lt;/li&gt;
&lt;li&gt;Modify Amazon ECS task definition, choose SourceArtifact and keep taskdef.json.&lt;/li&gt;
&lt;li&gt;Modify AWS CodeDeploy AppSpec file, choose SourceArtifact and keep appspec.yaml.&lt;/li&gt;
&lt;li&gt;Choose Done&lt;/li&gt;
&lt;li&gt;Scroll up and press Save.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  DevOps Pipeline in Action
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to Trip Management Monolith Application code base, preferrably home page and make a visible modification which you can identify after releasing a change. Look at the below screenshot, having (Tripment - New Change) at the end at line#7. File path: src/main/webapp/app/home/home.component.html&lt;/li&gt;
&lt;/ol&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%2Fkr3s8t7ftqtpclah41zd.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%2Fkr3s8t7ftqtpclah41zd.png" alt=" " width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Commit applied changes and push changes to the GitLab repository.
This will trigger the pipeline:
&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%2F0klfduiogqrjokrbncou.png" alt=" " width="800" height="220"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On the browser where you pasted the DNS of the load balancer, check the app that is deployed, it should still be the one without the changes&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%2Ff3hpy5zqdag3a81w18iv.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%2Ff3hpy5zqdag3a81w18iv.png" alt=" " width="800" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the deployment is complete, before traffic is rerouted, check the browser with the 8080 port, you should see the web page with the changes:&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%2Fkg6tz86vnmb1qdh9he4j.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%2Fkg6tz86vnmb1qdh9he4j.png" alt=" " width="800" height="372"&gt;&lt;/a&gt;&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%2F3mjyheevihss93hn257y.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%2F3mjyheevihss93hn257y.png" alt=" " width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code deploy still deploying the new container on ECS, traffic is still flowing to the initial deployment. Once the deployment stage is complete, it will forward test traffic to the same alb link but on a different port:8080&lt;/p&gt;

&lt;p&gt;The pipeline will wait 5 minutes for the newly deployed app to be tested(as configured in code pipeline). Once the time elapses, the pipeline will automatically route traffic&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%2Fqvszw9klkvdkb5egno88.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%2Fqvszw9klkvdkb5egno88.png" alt=" " width="800" height="137"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After tests, the engineer can now reroute traffic by clicking on reroute traffic, after they are sure their changes are as expected: &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%2Fzlu8j2p59xf0q60i4f25.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%2Fzlu8j2p59xf0q60i4f25.png" alt=" " width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The traffic will instantly be rerouted to the new tasks, and will keep the former tasks should incase there is need for rollback after live traffic is routed to it, now both links for test and prod will display the same app, while waiting for a termination of the former: &lt;br&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%2F084nnzbksj3ic5lnty84.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%2F084nnzbksj3ic5lnty84.png" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Traffic activity: &lt;br&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%2Fby3elazw7qvptl39scuc.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%2Fby3elazw7qvptl39scuc.png" alt=" " width="800" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;During the deployment phase, out of expected 2 task, ECS runs 4 tasks, this will ensure that the newly deployed app is stable before the termination of these can be authorized. &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%2F6398isnqwjwv606t4i23.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%2F6398isnqwjwv606t4i23.png" alt=" " width="800" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Clean-up
&lt;/h2&gt;

&lt;p&gt;On the console, go to Cloudformation stacks and delete tripmgmt stack, or if you created the resources on the console, then delete them in the order they were created. Go to Developer tools and delete the pipeline, in codebuild, delete the build job.&lt;/p&gt;

</description>
      <category>awscommunityday</category>
      <category>devops</category>
      <category>ecs</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Deploy an Amazon-Clone App on EKS with Kustomize and ArgoCD with GitOps best practices</title>
      <dc:creator>Jones Ndzenyuy</dc:creator>
      <pubDate>Mon, 04 Aug 2025 23:14:23 +0000</pubDate>
      <link>https://dev.to/ndzenyuy/deploy-an-amazon-clone-app-on-eks-with-kustomize-and-argocd-with-gitops-best-practices-58de</link>
      <guid>https://dev.to/ndzenyuy/deploy-an-amazon-clone-app-on-eks-with-kustomize-and-argocd-with-gitops-best-practices-58de</guid>
      <description>&lt;p&gt;In this Tutorial, we will deploy an Amazon Clone App on EKS with DevOps best practices. The App is a React based,so we'll deploy the infrastructure(EKS and OIDC Role) using Cloudformation, the CICD Pipeline will run with GitHub Actions, ArgoCD with Kustomize to deploy the kubernetes manifest files.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftkci29a4gh00w8jt4noh.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%2Ftkci29a4gh00w8jt4noh.png" alt=" " width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First the Cloud Engineer deploys the cloudformation code to deploy the infrastructure to AWS, once the infrastructure is configured with argoCD pointing to the Repo 2 with the manifest files, Prometheus and Grafana setup for monitoring the deployement, the developers can at anytime push an app update through the Repo 1 containing the App code. Once the developer pushes the code, Github actions triggers the pipeline to run tests; Security checks in Sonar Cloud, Dependencies and Vulnerabilities with OWASP, if these checks pass, the image is built and Trivy scans the image for known vulnerabilities, if the code and the docker image passes all the checks, Github actions, configured with OIDC role with policies to push images to ECR, pushes the image, then clones the second repository, updates the kustomization.yml file with the new image version and pushes it to the repository. ArgoCD will pick the changes and update the cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step by Step Guide
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Clone the App repository
&lt;/h3&gt;

&lt;p&gt;Clone the code repository, and initialise the code to be hosted on your repository, run the following code on the terminal(make sure you have vscode installed on your machine)&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/Ndzenyuy/Amazon-FE.git
&lt;span class="nb"&gt;cd &lt;/span&gt;Amazon-FE
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; .git .github
git init
code &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code will clone the repository, switch into the repository, initialize git for you to be able to create and push to your repository and finally open VSCode.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create and deploy the Cloudformation Stack
&lt;/h3&gt;

&lt;p&gt;On your local machine, create a file named infrastructure.yml and paste the following code:&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;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2010-09-09"&lt;/span&gt;
&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create an Amazon EKS Cluster with a managed node group.&lt;/span&gt;

&lt;span class="na"&gt;Parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ClusterName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Amazon-clone&lt;/span&gt;

  &lt;span class="na"&gt;ClusterVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.31"&lt;/span&gt;

  &lt;span class="na"&gt;VpcId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::VPC::Id&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;VPC&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;EKS&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cluster"&lt;/span&gt;

  &lt;span class="na"&gt;SubnetIds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;List&amp;lt;AWS::EC2::Subnet::Id&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Subnets&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(private/public)&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;worker&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;nodes&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;control&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;plane"&lt;/span&gt;

  &lt;span class="na"&gt;NodeInstanceType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;t3.medium&lt;/span&gt;

  &lt;span class="na"&gt;DesiredCapacity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Number&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;

  &lt;span class="na"&gt;GitHubOrg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name of GitHub Username (case sensitive)&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ndzenyuy"&lt;/span&gt;

  &lt;span class="na"&gt;RepositoryName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name of GitHub Repository (case sensitive)&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Amazon-FE"&lt;/span&gt;

  &lt;span class="na"&gt;OIDCProviderArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ARN of the GitHub OIDC Provider (Leave blank to create one)&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:iam::997450571655:oidc-provider/token.actions.githubusercontent.com"&lt;/span&gt;

  &lt;span class="na"&gt;OIDCAudience&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Audience supplied to configure-aws-credentials.&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sts.amazonaws.com"&lt;/span&gt;

&lt;span class="na"&gt;Conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;CreateOIDCProvider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Equals&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;OIDCProviderArn&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# IAM Role for EKS Cluster&lt;/span&gt;
  &lt;span class="na"&gt;EKSClusterRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::Role&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eks.amazonaws.com&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sts:AssumeRole&lt;/span&gt;
      &lt;span class="na"&gt;ManagedPolicyArns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::aws:policy/AmazonEKSClusterPolicy&lt;/span&gt;

  &lt;span class="c1"&gt;# EKS Cluster&lt;/span&gt;
  &lt;span class="na"&gt;EKSCluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EKS::Cluster&lt;/span&gt;
    &lt;span class="na"&gt;Properties&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="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;ClusterName&lt;/span&gt;
      &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;ClusterVersion&lt;/span&gt;
      &lt;span class="na"&gt;RoleArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;EKSClusterRole.Arn&lt;/span&gt;
      &lt;span class="na"&gt;ResourcesVpcConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;SubnetIds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;SubnetIds&lt;/span&gt;
        &lt;span class="na"&gt;EndpointPrivateAccess&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="na"&gt;EndpointPublicAccess&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="c1"&gt;# IAM Role for Node Group&lt;/span&gt;
  &lt;span class="na"&gt;NodeInstanceRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::Role&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ec2.amazonaws.com&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sts:AssumeRole&lt;/span&gt;
      &lt;span class="na"&gt;ManagedPolicyArns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy&lt;/span&gt;

  &lt;span class="c1"&gt;# Managed Node Group&lt;/span&gt;
  &lt;span class="na"&gt;NodeGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EKS::Nodegroup&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ClusterName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;EKSCluster&lt;/span&gt;
      &lt;span class="na"&gt;NodeRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;NodeInstanceRole.Arn&lt;/span&gt;
      &lt;span class="na"&gt;Subnets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;SubnetIds&lt;/span&gt;
      &lt;span class="na"&gt;ScalingConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;DesiredSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;DesiredCapacity&lt;/span&gt;
        &lt;span class="na"&gt;MaxSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
        &lt;span class="na"&gt;MinSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;InstanceTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;NodeInstanceType&lt;/span&gt;
      &lt;span class="na"&gt;AmiType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AL2_x86_64&lt;/span&gt;
      &lt;span class="na"&gt;NodegroupName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${ClusterName}-nodegroup"&lt;/span&gt;
      &lt;span class="na"&gt;DiskSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;

  &lt;span class="na"&gt;EKSPublicAccessSecurityGroupIngress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::SecurityGroupIngress&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;GroupId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;EKSCluster.ClusterSecurityGroupId&lt;/span&gt;
      &lt;span class="na"&gt;IpProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp&lt;/span&gt;
      &lt;span class="na"&gt;FromPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;ToPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;CidrIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;

  &lt;span class="na"&gt;GithubOidc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::OIDCProvider&lt;/span&gt;
    &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CreateOIDCProvider&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://token.actions.githubusercontent.com&lt;/span&gt;
      &lt;span class="na"&gt;ClientIdList&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;OIDCAudience&lt;/span&gt;
      &lt;span class="na"&gt;ThumbprintList&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;74f3a68f16524f15424927704c9506f55a9316bd"&lt;/span&gt; &lt;span class="c1"&gt;# Replace with actual thumbprint&lt;/span&gt;

  &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::Role&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sts:AssumeRoleWithWebIdentity&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Federated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!If&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CreateOIDCProvider&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;GithubOidc&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;OIDCProviderArn&lt;/span&gt;
            &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;StringEquals&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;token.actions.githubusercontent.com:aud&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;OIDCAudience&lt;/span&gt;
              &lt;span class="na"&gt;StringLike&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;token.actions.githubusercontent.com:sub&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s"&gt;repo:${GitHubOrg}/${RepositoryName}:*&lt;/span&gt;
      &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;PolicyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AllowECRAndEKSAccess&lt;/span&gt;
          &lt;span class="na"&gt;PolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
            &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:GetAuthorizationToken&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:BatchCheckLayerAvailability&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:CompleteLayerUpload&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:GetDownloadUrlForLayer&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:InitiateLayerUpload&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:PutImage&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:UploadLayerPart&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;

              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:DescribeCluster&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:ListClusters&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;

              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sts:GetCallerIdentity&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;

              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:Describe*&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:List*&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:Update*&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:AccessKubernetesApi&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;

&lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ClusterName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;EKSCluster&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name of the EKS Cluster&lt;/span&gt;

  &lt;span class="na"&gt;ClusterRoleArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;EKSClusterRole.Arn&lt;/span&gt;

  &lt;span class="na"&gt;RoleArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IAM Role ARN for GitHub Actions&lt;/span&gt;
    &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;Role.Arn&lt;/span&gt;

  &lt;span class="na"&gt;NodeGroupRoleArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;NodeInstanceRole.Arn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the Console, search cloudformation,then click -&amp;gt; Create stack -&amp;gt; with new resources, then enter the following parameters: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prepare template: Choose an existing template&lt;/li&gt;
&lt;li&gt;Specify template: Upload a template file&lt;/li&gt;
&lt;li&gt;Upload a template file: Choose the infrastructure.yml file&lt;/li&gt;
&lt;li&gt;Click Next&lt;/li&gt;
&lt;li&gt;Stack name: amazon-clone&lt;/li&gt;
&lt;li&gt;Under the parameters, leave the others at their defaults but edit SubnetIds by selecting the first 2 subnets, along with the VpcId, select the default.&lt;/li&gt;
&lt;li&gt;Next&lt;/li&gt;
&lt;li&gt;scroll down and Click: I acknowledge that AWS CloudFormation might create IAM resources.&lt;/li&gt;
&lt;li&gt;Next &lt;/li&gt;
&lt;li&gt;Submit.
This will create the infrastructure required to run this project, while waiting for the create to complete, go to Sonarcloud. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;- Create ECR Repository&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
On AWS console, create a repository named "amazon-clone". This will match the repo where the images will be pushed to.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Create a project in Sonarcloud
&lt;/h3&gt;

&lt;p&gt;Create a sonarcloud organization&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on the account icon on the top right of the screen&lt;/li&gt;
&lt;li&gt;My Organizations and click create organisation&lt;/li&gt;
&lt;li&gt;Create one manually&lt;/li&gt;
&lt;li&gt;Give it the name "amazon-clone"&lt;/li&gt;
&lt;li&gt;select the free plan
-&amp;gt; Create Organization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Copy the organization name as it will be needed shortly&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Analyse new project&lt;/li&gt;
&lt;li&gt;Display name, give it "amazon-clone-project"&lt;/li&gt;
&lt;li&gt;Project key: "amazon-clone-project" (copy project key as it will be used)&lt;/li&gt;
&lt;li&gt;Project visibility: public&lt;/li&gt;
&lt;li&gt;Next
The new code for this project will be based on: Previous version
choose your analysis method: With Github Actions
Copy the SONAR_TOKEN as will be needed in a safe location&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  4 Prepare Secrets
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;- AWS_GITHUB_ROLE&lt;/strong&gt; Return to cloudformation and select outputs, copy the value of the Role arn, this is the OIDC role arn that will be used by Github Actions&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- DEPLOY_KEY_PRIVATE&lt;/strong&gt; We need to create an ssh key pair that will be used to authenticate into Repo 2 containing the manifest files argoCD will be using. In the terminal(ubuntu)&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Press keyboard enter till the keypair is generated, now run&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
cat&lt;/span&gt; .ssh/id_rsa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will output the private key of the key pair file generated, copy it and save it in the &lt;strong&gt;DEPLOY_KEY_PRIVATE&lt;/strong&gt; variable.&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%2Fw6gf12zt5peyrhwriipi.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%2Fw6gf12zt5peyrhwriipi.png" alt=" " width="752" height="803"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now create a second repository in GitHub, call it &lt;strong&gt;Amazon-clone-infra&lt;/strong&gt;, we have to add the public ssh key file generated to the repository deploy keys in order to authenticate and push code to the repository. So back in our terminal, run&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;cat&lt;/span&gt; .ssh/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the keys to github repo 2, under settings -&amp;gt; Deploy keys -&amp;gt; add deploy key: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Title: deploy-infra, &lt;/li&gt;
&lt;li&gt;key: paste the content of the private key there and save it&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Store Secrets in the App Repository
&lt;/h3&gt;

&lt;p&gt;In VSCode, initialize git, create a remote repository and push the code to the repository, make it public. In the repository on Github, we have to store the secrets that will be used by our github actions workflow to successfully deploy the app to Kubernetes. Go to the repository in Github(Amazon-FE) -&amp;gt; Settings -&amp;gt; Secrets and variables -&amp;gt; actions -&amp;gt; New repository secrets. There create the secrets one after the other, the secrets required are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SONAR_TOKEN&lt;/li&gt;
&lt;li&gt;AWS_GITHUB_ROLE&lt;/li&gt;
&lt;li&gt;DEPLOY_KEY_PRIVATE&lt;/li&gt;
&lt;li&gt;SONAR_HOST_URL&lt;/li&gt;
&lt;li&gt;SONAR_ORGANIZATION&lt;/li&gt;
&lt;li&gt;SONAR_PROJECT_KEY&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After creating, we should have something like: &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%2F0izu6r72h2f1wd34ddih.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%2F0izu6r72h2f1wd34ddih.png" alt=" " width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Configure ArgoCD
&lt;/h3&gt;

&lt;p&gt;Back on your terminal, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;update kubeconfig
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws eks update-kubeconfig &lt;span class="nt"&gt;--name&lt;/span&gt; Netflix-clone &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install argoCD on the cluster
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; kubectl create namespace argocd
 kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; argocd &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;verify installation
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get all -n argocd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;expose argocd
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;export argocd dns
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export ARGOCD_SERVER=`kubectl get svc argocd-server -n argocd -o json | jq --raw-output '.status.loadBalancer.ingress[0].hostname'`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Get the argocd dns
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo $ARGOCD_SERVER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;export argocd password
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export ARGO_PWD=`kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;get the argocd PASSWORD
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo $ARGO_PWD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the argoCD dns displayed in the command to get the argoCD dns and run it in a browser. The user name is &lt;em&gt;admin&lt;/em&gt; and the password is the output of the cli command to get the argocd password. When successfully signed in, the display will be like:&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%2Fjtlk5dehljy4x9np6jx7.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%2Fjtlk5dehljy4x9np6jx7.png" alt=" " width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we need the manifest files(kubernetes files) in a repository where ArgoCD will monitor for changes.&lt;br&gt;
So clone the empty repo 2 to your local machine, in it we will put the manifest files for kubernetes. Create a folder named kubernetes containing the following files deployment.yml, service.yml, kustomization.yml and paste the following content:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deployment.yml
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amazon-app&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amazon-app&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amazon-app&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amazon-app&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;997450571655.dkr.ecr.us-east-1.amazonaws.com/amazon-clone:latest&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;service.yml
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amazon-app-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amazon-app&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;           &lt;span class="c1"&gt;# External port to expose the service&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;   &lt;span class="c1"&gt;# Port on the container&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;kustomization.yml
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kustomize.config.k8s.io/v1beta1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Kustomization&lt;/span&gt;

&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deployment.yml&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;service.yml&lt;/span&gt;

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

&lt;span class="na"&gt;commonLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amazon-clone&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;

&lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amazon-clone&lt;/span&gt;
    &lt;span class="na"&gt;newName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;997450571655.dkr.ecr.us-east-1.amazonaws.com/amazon-clone&lt;/span&gt;
    &lt;span class="na"&gt;newTag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&lt;/span&gt;

&lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amazon-app&lt;/span&gt;
    &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Commit and push the code to Github.&lt;/p&gt;

&lt;p&gt;On the web browser, where argoCD was opened, create a new application with the following fields: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application name: amazon-clone&lt;/li&gt;
&lt;li&gt;Project name: default&lt;/li&gt;
&lt;li&gt;Sync: automatic&lt;/li&gt;
&lt;li&gt;repository url: &lt;/li&gt;
&lt;li&gt;Revision: HEAD&lt;/li&gt;
&lt;li&gt;path: kubernetes&lt;/li&gt;
&lt;li&gt;Cluster url: select the dropdown&lt;/li&gt;
&lt;li&gt;namespace: default&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Leave the rest as defaults and click create. Within a moment argoCD will create the pods to sync with the kustomize files.&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%2Fzo66rvexhuk9l5ovnfnf.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%2Fzo66rvexhuk9l5ovnfnf.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will have the endpoint of the load balancer, copy and paste it on the browser, you will access the Application:&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%2Fydzj6h7z98txvnkjiqf0.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%2Fydzj6h7z98txvnkjiqf0.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In repo 1, open the VERSION file and change the version to 0.0.2, commit and push to trigger a pipeline deployment. Go to Github -&amp;gt; Actions, you will see the pipeline running automatically, and if observed, the pipeline will finish successfully like below: &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%2Frr4mt6barpni4uerl8xx.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%2Frr4mt6barpni4uerl8xx.png" alt=" " width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you check argoCD web app, you will see that it will automatically detect the change and update the pods with the new image version.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Configure Monitoring
&lt;/h3&gt;

&lt;p&gt;When the cluster is working, it is important to know the behavior of the resources. This can only be done when proper monitoring is put in place to Monitor Key Performance metrics. The steps include&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add Prometheus community Helm Repo
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add stable https://charts.helm.sh/stable
helm repo update  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create namespaces
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create namespace prometheus
kubectl create namespace grafana
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install Prometheus
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm &lt;span class="nb"&gt;install &lt;/span&gt;prometheus prometheus-community/prometheus &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; prometheus &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; server.service.type&lt;span class="o"&gt;=&lt;/span&gt;LoadBalancer &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; server.persistentVolume.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install Grafana
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add grafana https://grafana.github.io/helm-charts   
helm repo update     
helm &lt;span class="nb"&gt;install &lt;/span&gt;grafana grafana/grafana &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; grafana &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; service.type&lt;span class="o"&gt;=&lt;/span&gt;LoadBalancer &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nv"&gt;adminPassword&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'SuperSecret123!'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After 2-3mins, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; prometheus
kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; grafana
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Edit Security Group in AWS console&lt;br&gt;
Go to EC2 &amp;gt; Load Balancers and locate the ELB with the same name as in the EXTERNAL-IP, Click the description tab of the ELB, copy the SG ID, now go to the Security groups in EC2 and edit the inbound rules and add port 80, open to 0.0.0.0/0&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add Prometheus Data source to Grafana&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Log in to the grafana UI
- Go to settings -&amp;gt; Data sources -&amp;gt; Add data source
- Choose Prometheus
- Enter the url: http://prometheus-server.prometheus.svc.cluster.local
Click "Save &amp;amp; test"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Import Dashboards
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- go to + -&amp;gt; import
- Enter the id: 6417 (kubernetes cluster monitoring)
- click Import and select Prometheus as data source
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will load the Graphana UI for kubernetes cluster monitoring like the one below. Congratulations on finishing the project&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%2Fx5xx66jqg3ldnb1rkqyd.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%2Fx5xx66jqg3ldnb1rkqyd.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>github</category>
      <category>devops</category>
      <category>aws</category>
    </item>
    <item>
      <title>Deploy Netflix Clone App on EKS with Cloudformation and GitHub Actions</title>
      <dc:creator>Jones Ndzenyuy</dc:creator>
      <pubDate>Wed, 23 Jul 2025 00:59:24 +0000</pubDate>
      <link>https://dev.to/ndzenyuy/deploy-netflix-clone-app-on-eks-with-cloudformation-and-github-actions-4m2o</link>
      <guid>https://dev.to/ndzenyuy/deploy-netflix-clone-app-on-eks-with-cloudformation-and-github-actions-4m2o</guid>
      <description>&lt;p&gt;In this project, we will deploy a Netflix clone on an EKS Cluster. We will deploy the EKS cluster using Cloudformation and use GitHub Actions for the CICD pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmmgyjapj7802ugolof6t.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%2Fmmgyjapj7802ugolof6t.png" alt="Project architecture" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step by Step Guide
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Get the TMDB API Key
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open a web browser and navigate to TMDB (The Movie Database) website.&lt;/li&gt;
&lt;li&gt;Click on "&lt;strong&gt;Login&lt;/strong&gt;" and create an account.&lt;/li&gt;
&lt;li&gt;Once logged in, go to your profile and select "Settings."&lt;/li&gt;
&lt;li&gt;Click on "API" from the left-side panel.&lt;/li&gt;
&lt;li&gt;Create a new API key by clicking "Create" and accepting the terms and conditions.&lt;/li&gt;
&lt;li&gt;Provide the required basic details and click "Submit."&lt;/li&gt;
&lt;li&gt;You will receive your TMDB API key.&lt;/li&gt;
&lt;/ul&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%2Ftrf6qpxo883as24b2zb7.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%2Ftrf6qpxo883as24b2zb7.png" alt=" " width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Clone the Code
&lt;/h3&gt;

&lt;p&gt;Clone the code repository, and initialise the code to be hosted on your repository, run the following code on the terminal(make sure you have vscode installed on your machine)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/Ndzenyuy/NetFlix-Clone-app.git
cd NetFlix-Clone-app
rm -rf .git .github
git init
code .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Create Sonar Cloud Project
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Create a sonarcloud organization&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on the account icon on the top right of the screen&lt;/li&gt;
&lt;li&gt;My Organizations and click create organisation&lt;/li&gt;
&lt;li&gt;create one manually&lt;/li&gt;
&lt;li&gt;Give it the name "netflix-clone"&lt;/li&gt;
&lt;li&gt;select the free plan&lt;/li&gt;
&lt;li&gt;&lt;p&gt;-&amp;gt; Create Organization&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the organization name as it will be needed shortly&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Analyse new project&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Display name, give it "netflix-clone-project"&lt;/li&gt;
&lt;li&gt;Project visibility: public&lt;/li&gt;
&lt;li&gt;Next&lt;/li&gt;
&lt;li&gt;The new code for this project will be based on: Previous version&lt;/li&gt;
&lt;li&gt;choose your analysis methode: With Github Actions&lt;/li&gt;
&lt;li&gt;Copy the SONAR_TOKEN  as will be needed in a safe location&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Create the github actions workflow and test project scan with Sonar scanner&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a folder in the root folder with name .github, a subfolder workflows and create a file named "deployment.yml". In it paste the following code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Netflix Clone wih Github Actions&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dev"&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;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="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&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;AWS_REGION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&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;Testing&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Code checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup SonarQube&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;warchant/setup-sonar-scanner@v7&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;SonarQube Scan&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;sonar-scanner&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.host.url=${{ secrets.SONAR_HOST_URL }}&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.login=${{ secrets.SONAR_TOKEN }}&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.organization=${{ secrets.SONAR_ORGANIZATION }}&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.projectKey=${{ secrets.SONAR_PROJECT_KEY }}&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.sources=src/&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.junit.reportsPath=target/surefire-reports/&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.jacoco.reportsPath=target/jacoco.exec&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.java.checkstyle.reportPaths=target/checkstyle-result.xml&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.java.binaries=target/test-classes/com/visualpathit/account/controllerTest/&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now commit the code, publish the branch in a repository. The workflow will fail because the secrets are not stored. On GitHub, open the repository settings and added these secrets to the project:&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;TMDB_V3_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your api key for TMDB&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;SONAR_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your sonar token&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;IMAGE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;neflix-clone-image&lt;/span&gt;
&lt;span class="na"&gt;SONAR_ORGANIZATION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your sonar organization&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;SONAR_PROJECT_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your project key&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now push the code to GitHub once more to trigger a build. The build should be successful this time&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%2Fis8xrzkgdr2flxhww1zo.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%2Fis8xrzkgdr2flxhww1zo.png" alt=" " width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open Sonar cloud and open the organisation of this project. We should see the successful scan results&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%2F07ui6qtldql5pl00po22.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%2F07ui6qtldql5pl00po22.png" alt=" " width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Create an OIDC Role for our workflow
&lt;/h3&gt;

&lt;p&gt;We are going to deploy a cloudformation template which will create an IAM role that will permit github actions to deploy to our AWS account without exposing our keys.&lt;br&gt;
For the parameters, you will need your GitHub repository name and your GitHub usernames, create a Yaml file OIDC.yml and paste the following code:&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;Parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;GitHubOrg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name of GitHub Username (case sensitive)&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ndzenyuy"&lt;/span&gt;

  &lt;span class="na"&gt;RepositoryName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name of GitHub Repository (case sensitive)&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NetFlix-Clone-app"&lt;/span&gt;

  &lt;span class="na"&gt;OIDCProviderArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ARN of the GitHub OIDC Provider (Leave blank to create one)&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:iam::997450571655:oidc-provider/token.actions.githubusercontent.com"&lt;/span&gt;

  &lt;span class="na"&gt;OIDCAudience&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Audience supplied to configure-aws-credentials.&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sts.amazonaws.com"&lt;/span&gt;

&lt;span class="na"&gt;Conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;CreateOIDCProvider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Equals&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;OIDCProviderArn&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;GithubOidc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::OIDCProvider&lt;/span&gt;
    &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CreateOIDCProvider&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://token.actions.githubusercontent.com&lt;/span&gt;
      &lt;span class="na"&gt;ClientIdList&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;OIDCAudience&lt;/span&gt;
      &lt;span class="na"&gt;ThumbprintList&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;74f3a68f16524f15424927704c9506f55a9316bd"&lt;/span&gt; &lt;span class="c1"&gt;# Replace with actual thumbprint&lt;/span&gt;

  &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::Role&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sts:AssumeRoleWithWebIdentity&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Federated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!If&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CreateOIDCProvider&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;GithubOidc&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;OIDCProviderArn&lt;/span&gt;
            &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;StringEquals&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;token.actions.githubusercontent.com:aud&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;OIDCAudience&lt;/span&gt;
              &lt;span class="na"&gt;StringLike&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;token.actions.githubusercontent.com:sub&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s"&gt;repo:${GitHubOrg}/${RepositoryName}:*&lt;/span&gt;
      &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;PolicyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AllowECRAndEKSAccess&lt;/span&gt;
          &lt;span class="na"&gt;PolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
            &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:GetAuthorizationToken&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:BatchCheckLayerAvailability&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:CompleteLayerUpload&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:GetDownloadUrlForLayer&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:InitiateLayerUpload&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:PutImage&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:UploadLayerPart&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;

              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:DescribeCluster&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:ListClusters&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;

              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sts:GetCallerIdentity&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;

              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:Describe*&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:List*&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:Update*&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:AccessKubernetesApi&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;

&lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;RoleArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IAM Role ARN for GitHub Actions&lt;/span&gt;
    &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;Role.Arn&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Go to cloud formation and create a stack with new resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create stack&lt;/li&gt;
&lt;li&gt;choose an existing template&lt;/li&gt;
&lt;li&gt;upload a template file&lt;/li&gt;
&lt;li&gt;choose file and locate where the cloud formation template is stored on your local machine&lt;/li&gt;
&lt;li&gt;stack name: github-oidc&lt;/li&gt;
&lt;li&gt;GitHubOrg: &lt;/li&gt;
&lt;li&gt;OIDCAudience: sts.amazonaws.com&lt;/li&gt;
&lt;li&gt;OIDCProviderARN: leave blanc to create a new oidc provider&lt;/li&gt;
&lt;li&gt;Repository name: give your repository&lt;/li&gt;
&lt;li&gt;Acknowledge -&amp;gt; next and submit&lt;/li&gt;
&lt;li&gt;After it finishes creation, copy the role arn as it will be stored in Github secrets(with the name "AWS_GITHUB_ROLE").&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5 Add OWASP and Trivy File scan
&lt;/h3&gt;

&lt;p&gt;OWASP provides tools for scanning files and containers to identify vulnerabilities and security risks. OWASP Dependency Check, which allows users to scan project source code by providing a zip file or a GitHub URL. The container then generates a report through an API. Trivy is used for container scanning, it identifies known vulnerable packages inside the container and scans the built container as part of each commit and pull-request. It is also run as a nightly cron job against the default branch. If vulnerabilities are discovered, the maintainers are alerted via GitHub’s security tab. Adding these two to our workflow, we can therefore scan our project to be sure every known vulnerability is mitigated.&lt;/p&gt;

&lt;p&gt;The code quality check job should be as follows:&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;Code-Quality-checks&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Code checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&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;Set up Node.js&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="na"&gt;with&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;16"&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;Set up JDK &lt;/span&gt;&lt;span class="m"&gt;17&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-java@v4&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;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;17"&lt;/span&gt;
          &lt;span class="na"&gt;distribution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temurin"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup SonarQube&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;warchant/setup-sonar-scanner@v7&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;SonarQube Scan&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;sonar-scanner&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.host.url=${{ secrets.SONAR_HOST_URL }}&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.login=${{ secrets.SONAR_TOKEN }}&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.organization=${{ secrets.SONAR_ORGANIZATION }}&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.projectKey=${{ secrets.SONAR_PROJECT_KEY }}&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.sources=src/&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.junit.reportsPath=target/surefire-reports/&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.jacoco.reportsPath=target/jacoco.exec&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.java.checkstyle.reportPaths=target/checkstyle-result.xml&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.java.binaries=target/test-classes/com/visualpathit/account/controllerTest/&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;Install Dependencies&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 install&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;Download OWASP Dependency Check&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;curl -L -o dependency-check.zip https://github.com/jeremylong/DependencyCheck/releases/download/v8.4.0/dependency-check-8.4.0-release.zip&lt;/span&gt;
          &lt;span class="s"&gt;unzip dependency-check.zip -d dependency-check-dir&lt;/span&gt;
          &lt;span class="s"&gt;ls dependency-check-dir&lt;/span&gt;
          &lt;span class="s"&gt;chmod +x dependency-check-dir/dependency-check/bin/dependency-check.sh&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run OWASP Dependency Check&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;dependency-check-dir/dependency-check/bin/dependency-check.sh \&lt;/span&gt;
            &lt;span class="s"&gt;--project "Netflix" \&lt;/span&gt;
            &lt;span class="s"&gt;--scan . \&lt;/span&gt;
            &lt;span class="s"&gt;--format "XML" \&lt;/span&gt;
            &lt;span class="s"&gt;--disableYarnAudit \&lt;/span&gt;
            &lt;span class="s"&gt;--disableNodeAudit \&lt;/span&gt;
            &lt;span class="s"&gt;--disableAssembly \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude node_modules&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 OWASP Report&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/upload-artifact@v4&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dependency-check-report&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/dependency-check-report.xml"&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;Trivy FS Scan&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;aquasecurity/trivy-action@master&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;scan-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fs"&lt;/span&gt;
          &lt;span class="na"&gt;scan-ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;."&lt;/span&gt;
          &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trivyfs.txt"&lt;/span&gt;
          &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HIGH,CRITICAL"&lt;/span&gt;
          &lt;span class="na"&gt;exit-code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0"&lt;/span&gt;   &lt;span class="c1"&gt;# Do not fail build&lt;/span&gt;
          &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;table"&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 Trivy FS Scan Report&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/upload-artifact@v4&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;trivy-fs-scan&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;trivyfs.txt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Build and Push to ECR
&lt;/h3&gt;

&lt;p&gt;After Testing our code, we have to now build and push to ECR. Create an ECR Private repository with the name: netflix-clone, update your workflow code with:&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;Netflix Clone wih Github Actions&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dev"&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;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="na"&gt;workflow_dispatch&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;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;AWS_REGION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;
  &lt;span class="na"&gt;ECR_REPOSITORY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;neflix-clone&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;Code-Quality-checks&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Code checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&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;Set up Node.js&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="na"&gt;with&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;16"&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;Set up JDK &lt;/span&gt;&lt;span class="m"&gt;17&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-java@v4&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;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;17"&lt;/span&gt;
          &lt;span class="na"&gt;distribution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temurin"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup SonarQube&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;warchant/setup-sonar-scanner@v7&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;SonarQube Scan&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;sonar-scanner&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.host.url=${{ secrets.SONAR_HOST_URL }}&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.login=${{ secrets.SONAR_TOKEN }}&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.organization=${{ secrets.SONAR_ORGANIZATION }}&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.projectKey=${{ secrets.SONAR_PROJECT_KEY }}&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.sources=src/&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.junit.reportsPath=target/surefire-reports/&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.jacoco.reportsPath=target/jacoco.exec&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.java.checkstyle.reportPaths=target/checkstyle-result.xml&lt;/span&gt;
          &lt;span class="s"&gt;-Dsonar.java.binaries=target/test-classes/com/visualpathit/account/controllerTest/&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;Install Dependencies&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 install&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;Download OWASP Dependency Check&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;curl -L -o dependency-check.zip https://github.com/jeremylong/DependencyCheck/releases/download/v8.4.0/dependency-check-8.4.0-release.zip&lt;/span&gt;
          &lt;span class="s"&gt;unzip dependency-check.zip -d dependency-check-dir&lt;/span&gt;
          &lt;span class="s"&gt;ls dependency-check-dir&lt;/span&gt;
          &lt;span class="s"&gt;chmod +x dependency-check-dir/dependency-check/bin/dependency-check.sh&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run OWASP Dependency Check&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;dependency-check-dir/dependency-check/bin/dependency-check.sh \&lt;/span&gt;
            &lt;span class="s"&gt;--project "Netflix" \&lt;/span&gt;
            &lt;span class="s"&gt;--scan . \&lt;/span&gt;
            &lt;span class="s"&gt;--format "XML" \&lt;/span&gt;
            &lt;span class="s"&gt;--disableYarnAudit \&lt;/span&gt;
            &lt;span class="s"&gt;--disableNodeAudit \&lt;/span&gt;
            &lt;span class="s"&gt;--disableAssembly \&lt;/span&gt;
            &lt;span class="s"&gt;--exclude node_modules&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 OWASP Report&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/upload-artifact@v4&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dependency-check-report&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/dependency-check-report.xml"&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;Trivy FS Scan&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;aquasecurity/trivy-action@master&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;scan-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fs"&lt;/span&gt;
          &lt;span class="na"&gt;scan-ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;."&lt;/span&gt;
          &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trivyfs.txt"&lt;/span&gt;
          &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HIGH,CRITICAL"&lt;/span&gt;
          &lt;span class="na"&gt;exit-code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0"&lt;/span&gt; &lt;span class="c1"&gt;# Do not fail build&lt;/span&gt;
          &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;table"&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 Trivy FS Scan Report&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/upload-artifact@v4&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;trivy-fs-scan&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;trivyfs.txt&lt;/span&gt;

  &lt;span class="na"&gt;build-and-push&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;Code-Quality-checks&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Docker Buildx&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;docker/setup-buildx-action@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;Configure AWS Credentials&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;aws-actions/configure-aws-credentials@v4&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;role-to-assume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_GITHUB_ROLE }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.AWS_REGION }}&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;Login to Amazon ECR&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;login-ecr&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;aws-actions/amazon-ecr-login@v2&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;Get version from VERSION file&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get-version&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;if [ -f VERSION ]; then&lt;/span&gt;
            &lt;span class="s"&gt;VERSION=$(cat VERSION)&lt;/span&gt;
          &lt;span class="s"&gt;else&lt;/span&gt;
            &lt;span class="s"&gt;echo "VERSION file not found. Exiting..."&lt;/span&gt;
            &lt;span class="s"&gt;exit 1&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;
          &lt;span class="s"&gt;echo "Current version: $VERSION"&lt;/span&gt;
          &lt;span class="s"&gt;echo version=$VERSION &amp;gt;&amp;gt; $GITHUB_OUTPUT&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Docker image&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;docker build -t ${{ env.ECR_REPOSITORY }}:${{ steps.get-version.outputs.version }} .&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;Scan image with Trivy&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;aquasecurity/trivy-action@master&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;image-ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.ECR_REPOSITORY }}:${{ steps.get-version.outputs.version }}&lt;/span&gt;
          &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;table"&lt;/span&gt;
          &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CRITICAL,HIGH&lt;/span&gt;
          &lt;span class="na"&gt;ignore-unfixed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;exit-code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# fail if vulnerabilities are found&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;Tag and Push Docker image&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;docker tag ${{ env.ECR_REPOSITORY }}:${{ steps.get-version.outputs.version }} \&lt;/span&gt;
            &lt;span class="s"&gt;${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ steps.get-version.outputs.version }}&lt;/span&gt;

          &lt;span class="s"&gt;docker tag ${{ env.ECR_REPOSITORY }}:${{ steps.get-version.outputs.version }} \&lt;/span&gt;
            &lt;span class="s"&gt;${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:latest&lt;/span&gt;

          &lt;span class="s"&gt;docker push ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ steps.get-version.outputs.version }}&lt;/span&gt;
          &lt;span class="s"&gt;docker push ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:latest&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  6 Deploy a Kubernetes cluster
&lt;/h3&gt;

&lt;p&gt;Now go to Cloudformation and create a stack. This stack will create an IAM role for our OIDC and a kubernetes cluster. Create a file named cloudInfra.yml with the content:&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;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2010-09-09"&lt;/span&gt;
&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create an Amazon EKS Cluster with a managed node group.&lt;/span&gt;

&lt;span class="na"&gt;Parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ClusterName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Netflix-clone&lt;/span&gt;

  &lt;span class="na"&gt;ClusterVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.31"&lt;/span&gt;

  &lt;span class="na"&gt;VpcId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::VPC::Id&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;VPC&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;EKS&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cluster"&lt;/span&gt;

  &lt;span class="na"&gt;SubnetIds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;List&amp;lt;AWS::EC2::Subnet::Id&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Subnets&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(private/public)&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;worker&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;nodes&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;control&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;plane"&lt;/span&gt;

  &lt;span class="na"&gt;NodeInstanceType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;t3.medium&lt;/span&gt;

  &lt;span class="na"&gt;DesiredCapacity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Number&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;

  &lt;span class="na"&gt;GitHubOrg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name of GitHub Username (case sensitive)&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ndzenyuy"&lt;/span&gt;

  &lt;span class="na"&gt;RepositoryName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name of GitHub Repository (case sensitive)&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NetFlix-Clone-app"&lt;/span&gt;

  &lt;span class="na"&gt;OIDCProviderArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ARN of the GitHub OIDC Provider (Leave blank to create one)&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:iam::997450571655:oidc-provider/token.actions.githubusercontent.com"&lt;/span&gt;

  &lt;span class="na"&gt;OIDCAudience&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Audience supplied to configure-aws-credentials.&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sts.amazonaws.com"&lt;/span&gt;

&lt;span class="na"&gt;Conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;CreateOIDCProvider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Equals&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;OIDCProviderArn&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# IAM Role for EKS Cluster&lt;/span&gt;
  &lt;span class="na"&gt;EKSClusterRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::Role&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eks.amazonaws.com&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sts:AssumeRole&lt;/span&gt;
      &lt;span class="na"&gt;ManagedPolicyArns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::aws:policy/AmazonEKSClusterPolicy&lt;/span&gt;

  &lt;span class="c1"&gt;# EKS Cluster&lt;/span&gt;
  &lt;span class="na"&gt;EKSCluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EKS::Cluster&lt;/span&gt;
    &lt;span class="na"&gt;Properties&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="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;ClusterName&lt;/span&gt;
      &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;ClusterVersion&lt;/span&gt;
      &lt;span class="na"&gt;RoleArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;EKSClusterRole.Arn&lt;/span&gt;
      &lt;span class="na"&gt;ResourcesVpcConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;SubnetIds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;SubnetIds&lt;/span&gt;
        &lt;span class="na"&gt;EndpointPrivateAccess&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="na"&gt;EndpointPublicAccess&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="c1"&gt;# IAM Role for Node Group&lt;/span&gt;
  &lt;span class="na"&gt;NodeInstanceRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::Role&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ec2.amazonaws.com&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sts:AssumeRole&lt;/span&gt;
      &lt;span class="na"&gt;ManagedPolicyArns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy&lt;/span&gt;

  &lt;span class="c1"&gt;# Managed Node Group&lt;/span&gt;
  &lt;span class="na"&gt;NodeGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EKS::Nodegroup&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ClusterName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;EKSCluster&lt;/span&gt;
      &lt;span class="na"&gt;NodeRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;NodeInstanceRole.Arn&lt;/span&gt;
      &lt;span class="na"&gt;Subnets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;SubnetIds&lt;/span&gt;
      &lt;span class="na"&gt;ScalingConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;DesiredSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;DesiredCapacity&lt;/span&gt;
        &lt;span class="na"&gt;MaxSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
        &lt;span class="na"&gt;MinSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;InstanceTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;NodeInstanceType&lt;/span&gt;
      &lt;span class="na"&gt;AmiType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AL2_x86_64&lt;/span&gt;
      &lt;span class="na"&gt;NodegroupName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${ClusterName}-nodegroup"&lt;/span&gt;
      &lt;span class="na"&gt;DiskSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;

  &lt;span class="na"&gt;EKSPublicAccessSecurityGroupIngress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::SecurityGroupIngress&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;GroupId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;EKSCluster.ClusterSecurityGroupId&lt;/span&gt;
      &lt;span class="na"&gt;IpProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp&lt;/span&gt;
      &lt;span class="na"&gt;FromPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;ToPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;CidrIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;
  &lt;span class="na"&gt;PrometheusIngress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::SecurityGroupIngress&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;GroupId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;EKSCluster.ClusterSecurityGroupId&lt;/span&gt;
      &lt;span class="na"&gt;IpProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp&lt;/span&gt;
      &lt;span class="na"&gt;FromPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9090&lt;/span&gt;
      &lt;span class="na"&gt;ToPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9090&lt;/span&gt;
      &lt;span class="na"&gt;CidrIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;

  &lt;span class="na"&gt;GrafanaIngress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::SecurityGroupIngress&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;GroupId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;EKSCluster.ClusterSecurityGroupId&lt;/span&gt;
      &lt;span class="na"&gt;IpProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp&lt;/span&gt;
      &lt;span class="na"&gt;FromPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
      &lt;span class="na"&gt;ToPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
      &lt;span class="na"&gt;CidrIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;

  &lt;span class="na"&gt;GithubOidc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::OIDCProvider&lt;/span&gt;
    &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CreateOIDCProvider&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://token.actions.githubusercontent.com&lt;/span&gt;
      &lt;span class="na"&gt;ClientIdList&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;OIDCAudience&lt;/span&gt;
      &lt;span class="na"&gt;ThumbprintList&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;74f3a68f16524f15424927704c9506f55a9316bd"&lt;/span&gt; &lt;span class="c1"&gt;# Replace with actual thumbprint&lt;/span&gt;

  &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::Role&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sts:AssumeRoleWithWebIdentity&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Federated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!If&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CreateOIDCProvider&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;GithubOidc&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;OIDCProviderArn&lt;/span&gt;
            &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;StringEquals&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;token.actions.githubusercontent.com:aud&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;OIDCAudience&lt;/span&gt;
              &lt;span class="na"&gt;StringLike&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;token.actions.githubusercontent.com:sub&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s"&gt;repo:${GitHubOrg}/${RepositoryName}:*&lt;/span&gt;
      &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;PolicyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AllowECRAndEKSAccess&lt;/span&gt;
          &lt;span class="na"&gt;PolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
            &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:GetAuthorizationToken&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:BatchCheckLayerAvailability&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:CompleteLayerUpload&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:GetDownloadUrlForLayer&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:InitiateLayerUpload&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:PutImage&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ecr:UploadLayerPart&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;

              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:DescribeCluster&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:ListClusters&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;

              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sts:GetCallerIdentity&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;

              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:Describe*&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:List*&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:Update*&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eks:AccessKubernetesApi&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;

&lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ClusterName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;EKSCluster&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name of the EKS Cluster&lt;/span&gt;

  &lt;span class="na"&gt;ClusterRoleArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;EKSClusterRole.Arn&lt;/span&gt;

  &lt;span class="na"&gt;RoleArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IAM Role ARN for GitHub Actions&lt;/span&gt;
    &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;Role.Arn&lt;/span&gt;

  &lt;span class="na"&gt;NodeGroupRoleArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;NodeInstanceRole.Arn&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Wait for a while for the EKS cluster to be created, it can take about 5-10 minutes. &lt;/p&gt;

&lt;p&gt;Copy the OIDC role arn and create a secret the secrets for the application repository(NetFlix-Clone-app) in GitHub under the name: AWS_GITHUB_ROLE&lt;/p&gt;

&lt;p&gt;Back on your terminal, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;update kubeconfig
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws eks update-kubeconfig &lt;span class="nt"&gt;--name&lt;/span&gt; Netflix-clone &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install argoCD on the cluster
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; kubectl create namespace argocd
 kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; argocd &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;verify installation
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get all -n argocd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;expose argocd
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;export argocd dns
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export ARGOCD_SERVER=`kubectl get svc argocd-server -n argocd -o json | jq --raw-output '.status.loadBalancer.ingress[0].hostname'`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Get the argocd dns
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo $ARGOCD_SERVER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;export argocd password
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export ARGO_PWD=`kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;get the argocd PASSWORD
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo $ARGO_PWD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the argoCD dns displayed in the command to get the argoCD dns and run it in a browser. The user name is &lt;em&gt;admin&lt;/em&gt; and the password is the output of the cli command to get the argocd password. When successfully signed in, the display will be like:&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%2Fqu5lgtw7msq8h1ziqv7g.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%2Fqu5lgtw7msq8h1ziqv7g.png" alt=" " width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Now we need the manifest files(kubernetes files) in a repository where ArgoCD will monitor for changes.
&lt;/h3&gt;

&lt;p&gt;So in a new folder, let's create a repository (neflix-clone-manifest) and initialize it with the following commands[make sure it is not a subfolder of the app repository folder.&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;mkdir &lt;/span&gt;neflix-clone-manifest
&lt;span class="nb"&gt;cd &lt;/span&gt;neflix-clone-manifest
&lt;span class="nb"&gt;touch &lt;/span&gt;deployment.yml service.yml Chart.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the different folders, enter the following codes for each of the yaml files&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;deployment.yml
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;.Release.Name&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;-app&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;.Release.Name&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;-app&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;.Values.replicaCount&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;.Release.Name&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;-app&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;.Release.Name&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;-app&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;.Release.Name&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;-app&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&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;.Values.image.repository&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}:{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;.Values.image.tag&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IfNotPresent&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;service.yml
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;.Release.Name&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;-app&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;.Release.Name&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;-app&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;.Release.Name&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;-app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Chart.yml
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v2&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;netflix-clone&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;A Helm chart for the Netflix clone app&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.1.0&lt;/span&gt;
&lt;span class="na"&gt;appVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;values.yml
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;replicaCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your image repository URI&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&lt;/span&gt;
&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="na"&gt;nodeSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="na"&gt;tolerations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;span class="na"&gt;affinity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now install helm on your local machine and run the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm create netflix-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will create a new folder called netflix-app, open this folder and delete all the files inside the charts subfolder, then paste the files values.yml and Chart.yml. Open templates folder and delete all files &lt;strong&gt;exept&lt;/strong&gt; for __helpers.tpl, then paste the files deployment.yml, node-service.yml and service.yml. Your folder should be of the structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;netflix&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;infra&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;netflix&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Chart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yml&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt; 
&lt;span class="err"&gt;│&lt;/span&gt;    &lt;span class="err"&gt;│&lt;/span&gt;    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;deployment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yml&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;    &lt;span class="err"&gt;│&lt;/span&gt;    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yml&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;    &lt;span class="err"&gt;│&lt;/span&gt;    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yml&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;    &lt;span class="err"&gt;│&lt;/span&gt;    &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;__helpers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tpl&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;deployment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yml&lt;/span&gt;    
&lt;span class="err"&gt;│&lt;/span&gt;    &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yml&lt;/span&gt;  
&lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;Kubernetes&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;      
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now return to the root folder of this repo and push the code to github repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure ArgoCD to monitor this Repository
&lt;/h3&gt;

&lt;p&gt;To argocd on the web browser, click on create an application, and fill the fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application name: netflix-clone
Project name: default
repository url: &amp;lt;your repo url&amp;gt;
Revision: HEAD
path: netflix-clone
Cluster url: select the dropdown
namespace: default
Values file: values.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the App, after creation, ArgoCD will sync with the repository and create the pods required.&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%2Fdlzyl0zqntop708nr2s9.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%2Fdlzyl0zqntop708nr2s9.png" alt=" " width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will have the endpoint of the load balancer, copy and paste it on the browser, you will access the Application:&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%2Fga54uhxv1l8qpxqu8o2d.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%2Fga54uhxv1l8qpxqu8o2d.png" alt=" " width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Monitoring with Prometheus and Grafana
&lt;/h3&gt;

&lt;p&gt;When the cluster is working, it is important to know the behavior of the resources. This can only be done when proper monitoring is put in place to Monitor Key Performance metrics. The steps include&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add Prometheus community Helm Repo
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add stable https://charts.helm.sh/stable
helm repo update  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create namespaces
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create namespace prometheus
kubectl create namespace grafana
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install Prometheus
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm &lt;span class="nb"&gt;install &lt;/span&gt;prometheus prometheus-community/prometheus &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; prometheus &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; server.service.type&lt;span class="o"&gt;=&lt;/span&gt;LoadBalancer &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; server.persistentVolume.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install Grafana
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add grafana https://grafana.github.io/helm-charts   
helm repo update     
helm &lt;span class="nb"&gt;install &lt;/span&gt;grafana grafana/grafana &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; grafana &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; service.type&lt;span class="o"&gt;=&lt;/span&gt;LoadBalancer &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nv"&gt;adminPassword&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'SuperSecret123!'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After 2-3mins, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; prometheus
kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; grafana
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Edit Security Group in AWS console&lt;br&gt;
Go to EC2 &amp;gt; Load Balancers and locate the ELB with the same name as in the EXTERNAL-IP, Click the description tab of the ELB, copy the SG ID, now go to the Security groups in EC2 and edit the inbound rules and add port 80, open to 0.0.0.0/0&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add Prometheus Data source to Grafana&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Log in to the grafana UI
- Go to settings -&amp;gt; Data sources -&amp;gt; Add data source
- Choose Prometheus
- Enter the url: http://prometheus-server.prometheus.svc.cluster.local
Click "Save &amp;amp; test"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Import Dashboards
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- go to + -&amp;gt; import
- Enter the id: 6417 (kubernetes cluster monitoring)
- click Import and select Prometheus as data source
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will load the Graphana UI for kubernetes cluster monitoring like the one below. Congratulations on finishing the project&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%2F8tqr2f4rjlastqhz86md.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%2F8tqr2f4rjlastqhz86md.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>kubernetes</category>
      <category>aws</category>
      <category>devops</category>
    </item>
    <item>
      <title>Deploy a Microservices application on ECS</title>
      <dc:creator>Jones Ndzenyuy</dc:creator>
      <pubDate>Wed, 25 Jun 2025 23:30:50 +0000</pubDate>
      <link>https://dev.to/ndzenyuy/deploy-a-microservices-application-on-ecs-4ol2</link>
      <guid>https://dev.to/ndzenyuy/deploy-a-microservices-application-on-ecs-4ol2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Elastic Compute Service&lt;/strong&gt; - ECS can be a game changer for startups with low initial traffic and a vision to scale. It allows you to deploy Docker containers in an AWS managed environment, eliminating the need to manage the control plane. ECS is a free service, you only pay for the resources deployed. With its auto scaling feature, there's no need to worry about over provisioning infrastructure. You can start with the minimum resources and scale up as traffic grows.&lt;br&gt;
In this article, I'll guide you step by step on how to deploy a microservices infrastructure on ECS. The Application consists of an Nginx server acting as a reverse proxy, intelligently routing traffic to downstream applications(Angular, Node and Java) based on user requests. The architecture of the application is as follows:&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%2Fyb6am4hijrlkhuwdj9ti.jpg" 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%2Fyb6am4hijrlkhuwdj9ti.jpg" alt="App Architecture" width="641" height="491"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Re-architecting the Application to be deployed on ECS
&lt;/h3&gt;

&lt;p&gt;The different services of the App communicates with each other, in ECS, we need to ensure that there is communication among services. ECS doesn't manage volumes like in EKS, so we need to deploy an RDS-MySQL database and a MongoDB Atlas DB, then configure our containers to access the external services via our network setup. To ensure there is communication between services, we will use ECS' Service Discover, which will register a private hosted zone and permit the services to discover each other and send API calls amongst them. Nginx should be configured to use the domain names that will be used in the private Hosted zone for communications and routing of traffic. The Architecture to be deployed is as follows: &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%2Fn2i5w84vlv4p21bxe8md.jpg" 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%2Fn2i5w84vlv4p21bxe8md.jpg" alt="Infra Architecture" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  How to build it
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Create IAM Roles
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Github Actions via OIDC and attach policies&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Go to Console -&amp;gt; Cloudformation and create a new deployment. Give the name of the stack github-iam-oidc, copy the code below into a yaml file and choose it for cloudformation to deploy it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  GitHubOrg:
    Description: Name of GitHub Username (case sensitive)
    Type: String
    Default: "YOUR-GITHUB-USERNAME"

  RepositoryName:
    Description: Name of GitHub Repository (case sensitive)
    Type: String
    Default: "THE-REPO_NAME-FOR-THI-PROJECT"

  OIDCProviderArn:
    Description: ARN of the GitHub OIDC Provider (Leave blank to create one)
    Type: String
    Default: "arn:aws:iam::997450571655:oidc-provider/token.actions.githubusercontent.com"

  OIDCAudience:
    Description: Audience supplied to configure-aws-credentials.
    Type: String
    Default: "sts.amazonaws.com"

Conditions:
  CreateOIDCProvider: !Equals 
    - !Ref OIDCProviderArn
    - ""

Resources:
  GithubOidc:
    Type: AWS::IAM::OIDCProvider
    Condition: CreateOIDCProvider
    Properties:
      Url: https://token.actions.githubusercontent.com
      ClientIdList:
        - !Ref OIDCAudience
      ThumbprintList:
        - "74f3a68f16524f15424927704c9506f55a9316bd"  # Replace with actual thumbprint

  Role:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action: sts:AssumeRoleWithWebIdentity
            Principal:
              Federated: !If
                - CreateOIDCProvider
                - !Ref GithubOidc
                - !Ref OIDCProviderArn
            Condition:
              StringEquals:
                token.actions.githubusercontent.com:aud: !Ref OIDCAudience
              StringLike:
                token.actions.githubusercontent.com:sub: !Sub repo:${GitHubOrg}/${RepositoryName}:*

Outputs:
  RoleArn:
    Description: IAM Role ARN for GitHub Actions
    Value: !GetAtt Role.Arn

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Update the policy in the created role
Now search the IAM roles that is created(github-iam-oidc-XXX) and add policies that will permit us to push to ECR and deploy to ECS. Add an inline policy with name github-deploy-to-ecs, We will add the following policies:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ecs:CreateService",
                "ecs:DescribeServices",
                "ecs:DescribeClusters",
                "ecs:UpdateService",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:CompleteLayerUpload",
                "ecr:DescribeImages",
                "ecr:UploadLayerPart",
                "ecr:ListImages",
                "ecr:InitiateLayerUpload",
                "ecr:BatchCheckLayerAvailability",
                "ecr:PutImage",
                "ecs:DescribeTaskDefinition",
                "ecs:RegisterTaskDefinition",
                "ecs:ListTasks",
                "ec2:DescribeNetworkInterfaces",
                "ecs:DescribeTasks",
                "ecr:GetAuthorizationToken",
                "iam:PassRole"
            ],
            "Resource": [
                "*"
            ]
        }       
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create ecsTaskExecutionRole and give it admin access(just for this project)&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Create ECR Repository
&lt;/h4&gt;

&lt;p&gt;We have to create 4 different repositories for the the different containers. On the console, navigate to ECR and select create(do it for the 4 different containers), give the names to the different repos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;client&lt;/li&gt;
&lt;li&gt;javaapi&lt;/li&gt;
&lt;li&gt;nodeapi&lt;/li&gt;
&lt;li&gt;nginx
Leave the other settings as defaults and select create.&lt;/li&gt;
&lt;/ul&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%2Fuq27piv4kv4ubz1p298g.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%2Fuq27piv4kv4ubz1p298g.png" alt=" " width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Create MySQL database in RDS
&lt;/h4&gt;

&lt;p&gt;In the console navigate to RDS and create a MySQL database with the following settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Choose a database creation method: Standard create
Engine Options: MySQL
Engine version: select the latest
Templates: Free tier
Db instance identifier: books
Master username: root
password: give-your-password
Storage: 20Gb
VPC security group: create new
 - SG name: rds-sg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Leave the rest as defaults and create the database. When created, record the db URL, username and password, Instance identifier.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create MongoDB Atlas database
&lt;/h4&gt;

&lt;p&gt;Navigate to &lt;a href="https://cloud.mongodb.com" rel="noopener noreferrer"&gt;https://cloud.mongodb.com&lt;/a&gt;, create a free account and create a free database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db name: epoc
username: GIVE-YOUR-USERNAME
password: GIVE-YOUR-PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under database clusters click on connect and select Drivers&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%2Fs8hv3j19kz9pra6xt58b.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%2Fs8hv3j19kz9pra6xt58b.png" alt="Connect to Mongodb" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scroll down and copy the Connection string to be add to our environment variables. The string will be similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mongodb+srv://ndzenyuyjones:&amp;lt;db_password&amp;gt;@epoc.fezqjvq.mongodb.net/?retryWrites=true&amp;amp;w=majority&amp;amp;appName=epoc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have to edit this string to include the DB name, and the password(replace  with your password, then add the db name to the string(after mongodb.net/) Your string should be something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mongodb+srv://ndzenyuyjones:&amp;lt;db_password&amp;gt;@epoc.fezqjvq.mongodb.net/epoc?retryWrites=true&amp;amp;w=majority&amp;amp;appName=epoc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy this to a variables file including the other values registered above. We will need them for deployment.&lt;/p&gt;

&lt;h4&gt;
  
  
  Clone Project Repository
&lt;/h4&gt;

&lt;p&gt;Open git on your local machine and run the following to clone the project repository and initialize for usage in the steps ahead&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/Ndzenyuy/day-1-deploy_microservices_to_ecs.git

cd day-1-deploy_microservices_to_ecs

sudo rm -rf .github
sudo rm -rf .git

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

&lt;/div&gt;



&lt;p&gt;Initialise git and Create a folder with the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git init
mkdir .github/workflows
touch .github/workflows/nginx.yml .github/workflows/client.yml .github/workflows/nodeapi.yml .github/workflows/javaapi.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will create deployment files for the different services. Each of the pipelines will run only when there is a change in the folder containing the source files.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;open the nginx.yml file and paste the following
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Deploy to ECS

on:
  push:
    paths:
      - "nginx/**"
  pull_request:
    paths:
      - "nginx/**"

  workflow_dispatch:

permissions:
  id-token: write
  contents: read

env:
  AWS_REGION: "us-east-1"
  AWS_GITHUB_ROLE: ${{ secrets.AWS_GITHUB_ROLE }}
  ECS_PROJECT: ${{ secrets.ECS_PROJECT }}

  ECR_REPOSITORY_NGINX: "nginx"
  ECS_NGINX_TASK: "nginx-task"
  ECS_CLUSTER: "ecs-task"
  ECS_SERVICE: "nginx-task-service"

jobs:
  build:
    name: Build and Push to ECR
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_GITHUB_ROLE }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Get version from VERSION file
        id: get-version
        run: |
          if [ -f VERSION ]; then
            VERSION=$(cat VERSION)
          else
            echo "VERSION file not found. Exiting..."
            exit 1
          fi
          echo "Current version: $VERSION"
          echo version=$VERSION &amp;gt;&amp;gt; $GITHUB_OUTPUT

      # Build and push nginx image
      - name: Build and push Nginx image
        id: build-image-nginx
        uses: docker/build-push-action@v5
        with:
          context: ./nginx
          file: ./nginx/Dockerfile
          push: true
          provenance: false
          tags: |
            ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_NGINX }}:${{ steps.get-version.outputs.version }}
            ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_NGINX }}:latest

  deploy:
    needs: build
    name: Deploy to ECS-nginx task
    runs-on: ubuntu-latest
    steps:
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_GITHUB_ROLE }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Checkout code
        uses: actions/checkout@v4

      - name: Download task definition
        run: |
          aws ecs describe-task-definition \
          --task-definition ${{ env.ECS_NGINX_TASK }} \
          --query taskDefinition \
          --region ${{ env.AWS_REGION }} &amp;gt; task-definition.json

      - name: Get version from VERSION file
        id: get-version
        run: |
          if [ -f VERSION ]; then
            VERSION=$(cat VERSION)
          else
            echo "VERSION file not found. Exiting..."
            exit 1
          fi
          echo "Current version: $VERSION"
          echo version=$VERSION &amp;gt;&amp;gt; $GITHUB_OUTPUT

      - name: Fill in the new image ID in the Amazon ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: ${{ env.ECR_REPOSITORY_NGINX }}
          image: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_NGINX }}:${{ steps.get-version.outputs.version }}

      - name: Deploy to ECS
        id: deploy-ecs
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          wait-for-service-stability: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;angular.yml
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Angular CI/CD

on:
  push:
    paths:
      - "client/**"
  pull_request:
    paths:
      - "client/**"

  workflow_dispatch:

permissions:
  id-token: write
  contents: read

env:
  MONGO_URI: ${{ secrets.MONGO_URI }}
  MYSQL_HOST: ${{ secrets.MYSQL_HOST }}
  MYSQL_USER: ${{ secrets.MYSQL_USER }}
  MYSQL_PASS: ${{ secrets.MYSQL_PASS }}
  MYSQL_DB: ${{ secrets.MYSQL_DB }}

  AWS_REGION: ${{ secrets.AWS_REGION }}
  AWS_GITHUB_ROLE: ${{ secrets.AWS_GITHUB_ROLE }}
  ECS_PROJECT: ${{ secrets.ECS_PROJECT }}

  ECR_REPOSITORY_CLIENT: "client"
  ECR_REPOSITORY_JAVA: "javaapi"
  ECR_REPOSITORY_NODEAPI: "nodeapi"
  ECR_REPOSITORY_NGINX: "nginx"

  ECS_ANGULAR_TASK: "angular-task"
  ECS_CLUSTER: "ecs-task"
  ECS_SERVICE: "angular-task-service"

jobs:
  build-angular:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_GITHUB_ROLE }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      #Angular
      - name: Build and push Angular image
        id: build-image-angular
        uses: docker/build-push-action@v5
        with:
          context: ./client
          file: ./client/Dockerfile
          push: true
          provenance: false
          tags: |
            ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_CLIENT }}:${{ github.run_number }}
            ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_CLIENT }}:latest

  deploy:
    needs: build-
    name: Deploy to ECS-angula task
    runs-on: ubuntu-latest
    steps:
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_GITHUB_ROLE }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Checkout code
        uses: actions/checkout@v4

      - name: Download task definition
        run: |
          aws ecs describe-task-definition \
          --task-definition ${{ env.ECS_ANGULAR_TASK }} \
          --query taskDefinition \
          --region ${{ env.AWS_REGION }} &amp;gt; task-definition.json

      - name: Get version from VERSION file
        id: get-version
        run: |
          if [ -f VERSION ]; then
            VERSION=$(cat VERSION)
          else
            echo "VERSION file not found. Exiting..."
            exit 1
          fi
          echo "Current version: $VERSION"
          echo version=$VERSION &amp;gt;&amp;gt; $GITHUB_OUTPUT

      - name: Fill in the new image ID in the Amazon ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: ${{ env.ECR_REPOSITORY_CLIENT }}
          image: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_CLIENT }}:${{ steps.get-version.outputs.version }}

      - name: Deploy to ECS
        id: deploy-ecs
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          wait-for-service-stability: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;javaapi.yml
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Java-api CI/CD

on:
  push:
    paths:
      - "javaapi/**"
  pull_request:
    paths:
      - "javaapi/**"

  workflow_dispatch:

permissions:
  id-token: write
  contents: read

env:
  MONGO_URI: ${{ secrets.MONGO_URI }}
  MYSQL_HOST: ${{ secrets.MYSQL_HOST }}
  MYSQL_USER: ${{ secrets.MYSQL_USER }}
  MYSQL_PASS: ${{ secrets.MYSQL_PASS }}
  MYSQL_DB: ${{ secrets.MYSQL_DB }}

  AWS_REGION: ${{ secrets.AWS_REGION }}
  AWS_GITHUB_ROLE: ${{ secrets.AWS_GITHUB_ROLE }}
  ECS_PROJECT: ${{ secrets.ECS_PROJECT }}

  ECR_REPOSITORY_CLIENT: "client"
  ECR_REPOSITORY_JAVA: "javaapi"
  ECR_REPOSITORY_NODEAPI: "nodeapi"
  ECR_REPOSITORY_NGINX: "nginx"

  ECS_JAVA_TASK: "java-task"
  ECS_CLUSTER: "ecs-task"
  ECS_SERVICE: "java-task-service"

jobs:
  build-javaapi:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_GITHUB_ROLE }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

        # Java API
      - name: Build and push Java image
        id: build-image-java
        uses: docker/build-push-action@v5
        with:
          push: true
          provenance: false
          tags: |
            ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_JAVA }}:${{ github.run_number }}
            ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_JAVA }}:latest

  deploy:
    needs: build-javaapi
    name: Deploy to ECS-javaapi task
    runs-on: ubuntu-latest
    steps:
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_GITHUB_ROLE }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Checkout code
        uses: actions/checkout@v4

      - name: Download task definition
        run: |
          aws ecs describe-task-definition \
          --task-definition ${{ env.ECS_JAVA_TASK }} \
          --query taskDefinition \
          --region ${{ env.AWS_REGION }} &amp;gt; task-definition.json

      - name: Get version from VERSION file
        id: get-version
        run: |
          if [ -f VERSION ]; then
            VERSION=$(cat VERSION)
          else
            echo "VERSION file not found. Exiting..."
            exit 1
          fi
          echo "Current version: $VERSION"
          echo version=$VERSION &amp;gt;&amp;gt; $GITHUB_OUTPUT

      - name: Fill in the new image ID in the Amazon ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: ${{ env.ECR_REPOSITORY_JAVA }}
          image: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_JAVA }}:${{ steps.get-version.outputs.version }}

      - name: Deploy to ECS
        id: deploy-ecs
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          wait-for-service-stability: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;nodeapi.yml
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Node-api CI/CD

on:
  push:
    paths:
      - "nodeapi/**"
  pull_request:
    paths:
      - "nodeapi/**"

  workflow_dispatch:

permissions:
  id-token: write
  contents: read

env:
  MONGO_URI: ${{ secrets.MONGO_URI }}
  MYSQL_HOST: ${{ secrets.MYSQL_HOST }}
  MYSQL_USER: ${{ secrets.MYSQL_USER }}
  MYSQL_PASS: ${{ secrets.MYSQL_PASS }}
  MYSQL_DB: ${{ secrets.MYSQL_DB }}

  AWS_REGION: ${{ secrets.AWS_REGION }}
  AWS_GITHUB_ROLE: ${{ secrets.AWS_GITHUB_ROLE }}
  ECS_PROJECT: ${{ secrets.ECS_PROJECT }}

  ECR_REPOSITORY_CLIENT: "client"
  ECR_REPOSITORY_JAVA: "javaapi"
  ECR_REPOSITORY_NODEAPI: "nodeapi"
  ECR_REPOSITORY_NGINX: "nginx"

  ECS_NODEAPI_TASK: "node-task"
  ECS_CLUSTER: "ecs-task"
  ECS_SERVICE: "node-task-service"

jobs:
  build-nodeapi:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_GITHUB_ROLE }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

        # Node API
      - name: Build and push Node.js image
        id: build-image-node
        uses: docker/build-push-action@v5
        with:
          context: ./nodeapi
          file: ./nodeapi/Dockerfile
          push: true
          provenance: false
          tags: |
            ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_NODEAPI }}:${{ github.run_number }}
            ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_NODEAPI }}:latest

  deploy:
    needs: build-nodeapi
    name: Deploy to ECS-javaapi task
    runs-on: ubuntu-latest
    steps:
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_GITHUB_ROLE }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Checkout code
        uses: actions/checkout@v4

      - name: Download task definition
        run: |
          aws ecs describe-task-definition \
          --task-definition ${{ env.ECS_NODEAPI_TASK }} \
          --query taskDefinition \
          --region ${{ env.AWS_REGION }} &amp;gt; task-definition.json

      - name: Get version from VERSION file
        id: get-version
        run: |
          if [ -f VERSION ]; then
            VERSION=$(cat VERSION)
          else
            echo "VERSION file not found. Exiting..."
            exit 1
          fi
          echo "Current version: $VERSION"
          echo version=$VERSION &amp;gt;&amp;gt; $GITHUB_OUTPUT

      - name: Fill in the new image ID in the Amazon ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: ${{ env.ECR_REPOSITORY_NODEAPI }}
          image: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_NODEAPI }}:${{ steps.get-version.outputs.version }}

      - name: Deploy to ECS
        id: deploy-ecs
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          wait-for-service-stability: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now Commit and push the project code to Github, create a repository in your github account. This will trigger Github actions to launch the different pipelines which will obviously fail because of the missing secrets and variables.&lt;/p&gt;

&lt;h4&gt;
  
  
  Github Secrets
&lt;/h4&gt;

&lt;p&gt;On Github, navigate to the created repository in the previous steps, go to settings and check secrets and variables -&amp;gt; actions.&lt;br&gt;
Now create repository secrets, put the values of the following as recorded when the different services where created for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS_GITHUB_ROLE (the oidc role created with cloudformation)
AWS_REGION
MONGO_URI
MYSQL_DB
MYSQL_HOST
MYSQL_PASS
MYSQL_PORT
MYSQL_USER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fxwa3tje68876md1gmcga.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%2Fxwa3tje68876md1gmcga.png" alt=" " width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Re-run the failed workflows for at least the docker images be pushed to ECR&lt;/p&gt;

&lt;h4&gt;
  
  
  Create the task definitions
&lt;/h4&gt;

&lt;p&gt;Navigate to ECS service on the console and select task definitions. Create task definitions for the different service-containers that we will be deploying.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Nginx Task definition:&lt;br&gt;
Task definition family: nginx-task&lt;br&gt;
Infrastructure requirements: AWS Fargate&lt;br&gt;
container name: nginx&lt;br&gt;
Image URI: copy and paste the nginx image URI from ECR&lt;br&gt;
container port: 80&lt;br&gt;
use log collection = true&lt;br&gt;
create&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Angular task definition&lt;br&gt;
Task definition family: angular-task&lt;br&gt;
Infrastructure requirements: AWS Fargate&lt;br&gt;
container name: client&lt;br&gt;
Image URI: copy and paste the client image URI from ECR&lt;br&gt;
container port: 4200&lt;br&gt;
use log collection = true&lt;br&gt;
create&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Java task definition&lt;br&gt;
Task definition family: java-task&lt;br&gt;
Infrastructure requirements: AWS Fargate&lt;br&gt;
container name: java&lt;br&gt;
Image URI: copy and paste the java image URI from ECR&lt;br&gt;
container port: 9000&lt;br&gt;
environment variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MYSQL_PASS : &lt;/li&gt;
&lt;li&gt;MYSQL_DB:  (books)&lt;/li&gt;
&lt;li&gt;MYSQL_HOST: &lt;/li&gt;
&lt;li&gt;MYSQL_USER: root&lt;/li&gt;
&lt;li&gt;MONGO_URI: 
use log collection = true
create&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Node task definition&lt;br&gt;
Task definition family: node-task&lt;br&gt;
Infrastructure requirements: AWS Fargate&lt;br&gt;
container name: node&lt;br&gt;
Image URI: copy and paste the node image URI from ECR&lt;br&gt;
container port: 5000&lt;br&gt;
environment variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MONGO_URI: 
use log collection = true
create&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Create ECS Cluster
&lt;/h4&gt;

&lt;p&gt;Navigate to the console and create a cluster under ECS service with the following parameters:&lt;br&gt;
Cluster name: ecs-cluster&lt;br&gt;
Leave the rest as defaults and create cluster.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create ECS services
&lt;/h4&gt;

&lt;p&gt;We have to now create services for each of the tasks. Go to create services and configure each with the following: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Angular service
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Task definition family: angular-task
revision: choose the latest
service name: angular-task-service
Compute options: Launch type
Desired tasks: 1
Service discovery: use service discovery
Configure namespace: create a new namespace
namespace name: ecs-microservice-ns
Service discovery name: client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;leave the rest as defaults and create&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Node Service
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Task definition family: node-task
revision: choose the latest
service name: node-task-service
Compute options: Launch type
Desired tasks: 1
Service discovery: use service discovery
Configure namespace: select existing namespace
namespace name: ecs-microservice-ns
Service discovery name: nodeapi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;leave the rest as defaults and create&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Java Service
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Task definition family: java-task
revision: choose the latest
service name: java-task-service
Compute options: Launch type
Desired tasks: 1
Service discovery: use service discovery
Configure namespace: select existing namespace
namespace name: ecs-microservice-ns
Service discovery name: javaapi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;leave the rest as defaults and create&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Nginx Service
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Task definition family: nginx-task
revision: choose the latest
service name: nginx-task-service
Compute options: Launch type
Desired tasks: 1
Service discovery: use service discovery
Configure namespace: select existing namespace
namespace name: ecs-microservice-ns
Service discovery name: nginx
Load balancing: Use load balancing
Load balancer type: Aplication load balancer
Application Load Balancer: create a new ALB
Load balancer name: ecs-alb
listener: create new listener
target group: create a new target group
target group name: ecs-nginx-tg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;leave the rest as defaults and create&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%2Fd9z9imbtqjxihanqvuo1.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%2Fd9z9imbtqjxihanqvuo1.png" alt=" " width="800" height="337"&gt;&lt;/a&gt;&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%2Foybppc27nc09blwjk2nx.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%2Foybppc27nc09blwjk2nx.png" alt=" " width="800" height="228"&gt;&lt;/a&gt;&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%2Ferwkb0kno83xgqovmyrl.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%2Ferwkb0kno83xgqovmyrl.png" alt=" " width="800" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After some time, the different services will be created, check the load balancer DNS record and paste it on the browser, the app will appear as such: &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%2Fvptm0eyxe8yf0a63rw0v.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%2Fvptm0eyxe8yf0a63rw0v.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The App is up and running. Congratulations !!!&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>ecs</category>
      <category>aws</category>
    </item>
    <item>
      <title>Streamlining Kubernetes Deployments: CI/CD with GitHub Actions and Helm for EKS</title>
      <dc:creator>Jones Ndzenyuy</dc:creator>
      <pubDate>Tue, 10 Dec 2024 15:53:34 +0000</pubDate>
      <link>https://dev.to/ndzenyuy/streamlining-kubernetes-deployments-cicd-with-github-actions-and-helm-for-eks-535e</link>
      <guid>https://dev.to/ndzenyuy/streamlining-kubernetes-deployments-cicd-with-github-actions-and-helm-for-eks-535e</guid>
      <description>&lt;p&gt;In this project, I will guide you in building a pipeline with GitHub actions that will deploy an infrastructure using Terraform(VPC, public and private subnets, nat gatway) and run containers on EKS, updates EKS each time there's a new application version. The new version is automatically built each time the developper pushes application code to the code repository. Necessary security scans are run in order to ensure a secure and complaint code. The infrastructure code and application code are stored in two different repositories. &lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsu4yg3wpep84lndfle8p.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%2Fsu4yg3wpep84lndfle8p.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to build it
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prepare Repositories
&lt;/h3&gt;

&lt;p&gt;Login to your github account, choose a location and open gitbash terminal on your local machine and clone the code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/Ndzenyuy/githubactions-infra.git
git clone https://github.com/Ndzenyuy/githubactions-appl.git
rm -rf githubactions-infra/.git/ githubactions-infra/.github/
rm -rf githubactions-appl/.git/ githubactions-appl/.github/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two repositories contain the infrastructure(githubactions-infra) and the application code(githubactions-appl). Now we have to initialize git for code management, first for the infrastructure. Back to the console, run the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd githubactions-infra
git init
code .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code will open the infrastructure in VScode and initialise git. Under the source control icon in VScode, publish the branch to GitHub, choose public repository. Return to the console and run the following code (make sure you are in the githubactions-infra folder)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ../githubactions-appl
git init
code .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another VScode window will open, Under the source control icon in VScode, publish the branch to GitHub, choose public repository. We are now ready to deploy our application.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Secrets
&lt;/h3&gt;

&lt;p&gt;Here we are going to create and store AWS access keys, S3 bucket, ECR repository and store in Github secrets.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create IAM user
&lt;/h4&gt;

&lt;p&gt;Go to AWS console and create an admin user IAM -&amp;gt; User -&amp;gt; create user -&amp;gt; attach policies -&amp;gt; administrator access -&amp;gt; create access keys&lt;/p&gt;

&lt;p&gt;On github, &lt;strong&gt;githubactions-infra&lt;/strong&gt; repository go to settings -&amp;gt; Secrets and variables -&amp;gt; actions -&amp;gt; new repository secret and store the following keys&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name: AWS_ACCESS_KEY_ID,  Secret: &lt;/li&gt;
&lt;li&gt;Name: AWS_SECRET_ACCESS_KEY: secret: &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do the same for the repository &lt;strong&gt;githubactions-appl&lt;/strong&gt;, store both secrets with the same name.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create S3 bucket
&lt;/h4&gt;

&lt;p&gt;Goto AWS console, and create an S3 bucket, we can call it "githubactions-infra-xxx" (xxx is a random number to make bucket unique)&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%2Fcmcutc3ni1ni0ov3b0xi.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%2Fcmcutc3ni1ni0ov3b0xi.png" alt=" " width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back to Github secrets(&lt;strong&gt;githubactions-infra&lt;/strong&gt;), create a new secret having the bucket name:&lt;/p&gt;

&lt;p&gt;Name: BUCKET_TF_STATE, secret: githubactions-infra-xxx&lt;/p&gt;

&lt;h4&gt;
  
  
  Create ECR repository
&lt;/h4&gt;

&lt;p&gt;On to AWS console, Elastic Container Registry -&amp;gt; Create repository -&amp;gt; name: githubactions-appl -&amp;gt; create repository. Copy the repository URI(XXXXXXXXX.dkr.ecr.us-east-2.amazonaws.com/githubactions-appl)&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%2Ftt4iajks8533sm9jf3cq.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%2Ftt4iajks8533sm9jf3cq.png" alt=" " width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back to github secrets (githubactions-appl), Create another secret&lt;/p&gt;

&lt;p&gt;Name: REGISTRY, secret: XXXXXXXXX.dkr.ecr.us-east-1.amazonaws.com&lt;/p&gt;

&lt;p&gt;githubactions-infra secrets should be similar to &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%2F65d3ccfgt1tkb4bf2ag8.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%2F65d3ccfgt1tkb4bf2ag8.png" alt=" " width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Terraform Code Adjustments
&lt;/h3&gt;

&lt;p&gt;In the githubactions-infra repo code, open it in VSCode and move to the folder terraform, modify the contents of terraform.tf while updating the name of your s3 bucket and the region where the infrastructure will be deployed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~&amp;gt; 5.25.0"
    }

    random = {
      source  = "hashicorp/random"
      version = "~&amp;gt; 3.5.1"
    }

    tls = {
      source  = "hashicorp/tls"
      version = "~&amp;gt; 4.0.4"
    }

    cloudinit = {
      source  = "hashicorp/cloudinit"
      version = "~&amp;gt; 2.3.2"
    }

    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "~&amp;gt; 2.23.0"
    }
  }

  backend "s3" {
    bucket = "&amp;lt;Your bucket name&amp;gt;"
    key    = "terraform.tfstate"
    region = "your working region"
  }

  #required_version = "~&amp;gt; 1.5.1"
  required_version = "~&amp;gt; 1.10.1"

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Github actions workflow
&lt;/h3&gt;

&lt;p&gt;In this workflow terraform will not apply the code for the infrastructure to be created(staging), but when a pull request is made, the pipeline is triggered and this time and the pipeline get applied(main), we need to put conditions. In the file .github/workflow/terraform.yml, we should have the code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: "Github Actions IaC"
on:
    push:
        branches:
            - main
            - stage
        paths:
            - terraform/**
    pull_request:
        branches:
            - main
        paths:
            - terraform/**

env:
    # Credentials for deployment to AWS
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    # S3 bucket for the Terraform state
    BUCKET_TF_STATE: ${{ secrets.BUCKET_TF_STATE }}
    AWS_REGION: us-east-1
    EKS_CLUSTER: infra-eks

jobs:
    terraform:
        name: "Apply terraform code changes"
        runs-on: ubuntu-latest
        defaults:
            run:
                shell: bash
                working-directory: ./terraform

        steps:
            - name: Checkout source code
              uses: actions/checkout@v4           

            - name: Setup Terraform with specified version on the runner
              uses: hashicorp/setup-terraform@v2
              #with:
              #  terraform_version: 1.6.3

            - name: Terraform init
              id: init
              run: terraform init -backend-config="bucket=$BUCKET_TF_STATE"

            - name: Terraform format
              id: fmt
              run: terraform fmt -check

            - name: Terraform validate
              id: validate
              run: terraform validate

            - name: Terraform plan
              id: plan
              run: terraform plan -no-color -input=false -out planfile
              continue-on-error: true

            - name: Terraform plan status
              if: steps.plan.outcome == 'failure'
              run: exit 1

            - name: Terraform Apply
              id: apple
              if: github.ref == 'refs/heads/main' &amp;amp;&amp;amp; github.event_name == 'push'
              run: terraform apply -auto-approve -input=false -parallelism=1 planfile

            - name:  Configure AWS credentials
              uses: aws-actions/configure-aws-credentials@v1
              with: 
                aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
                aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
                aws-region: ${{ env.AWS_REGION }}

            - name: Get Kube config file
              id: getconfig
              if: steps.apple.outcome == 'success' 
              run: aws eks update-kubeconfig --region ${{ env.AWS_REGION }} --name ${{ env.EKS_CLUSTER }}

            - name: Install Ingress controller
              if: steps.apple.outcome == 'success' &amp;amp;&amp;amp; steps.getconfig.outcome == 'success'
              run: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.3/deploy/static/provider/aws/deploy.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test Pipeline
&lt;/h3&gt;

&lt;p&gt;We need to first test the pipeline with a dry run by creating a &lt;strong&gt;staging&lt;/strong&gt; branch. This will trigger the pipeline but will not apply so we are sure it can run. Got to the &lt;strong&gt;githubactions-infra&lt;/strong&gt; window in VScode and open a new terminal, make sure any changes have been committed then run the following:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This will create a new branch, on the source control icon in VSCode, publish the branch. This will run the pipeline and skip the apply step because there is a a condition set to only run apply when the main branch is active&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%2Fd7r5pfkr3zgevx8jb1qw.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%2Fd7r5pfkr3zgevx8jb1qw.png" alt=" " width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the run is successful, we can now be certain the pipeline will run, if it fails, read the logs, the terraform version might have been outdated. Change it to the new and push the code again.&lt;/p&gt;

&lt;p&gt;Merge the staging branch to main branch, this will cause the pipeline again to run but this time, will apply the changes and setup the infrastructure on AWS eks.&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%2Fg91ihfc0c4drx0b85tcc.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%2Fg91ihfc0c4drx0b85tcc.png" alt=" " width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  App workflow
&lt;/h3&gt;

&lt;p&gt;The next workflow will use the infrastructure created from the previous job, then deploy the application with best practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an organization in sonarcloud
&lt;/h3&gt;

&lt;p&gt;Open the browser and navigate to &lt;a href="http://www.sonarcloud.io" rel="noopener noreferrer"&gt;www.sonarcloud.io&lt;/a&gt;, click the "+" at the top right corner and create a new organization -&amp;gt; create one manually&lt;/p&gt;

&lt;p&gt;&lt;code&gt;name: github-actions-cicd&lt;br&gt;
key: github-actions-cicd -&amp;gt; Create&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Click analyze new project&lt;br&gt;
&lt;code&gt;&lt;br&gt;
Organization: github-actions-cicd&lt;br&gt;
display name: github-actions&lt;br&gt;
Project key: github-actions -&amp;gt; Next&lt;br&gt;
The new code for this project will be based on: Previous version=true&lt;br&gt;
 -&amp;gt; Create project&lt;/code&gt;&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%2Fp53zmaq4yrd2qmq1xrdj.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%2Fp53zmaq4yrd2qmq1xrdj.png" alt=" " width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose analysis method: With Github actions:&lt;/p&gt;

&lt;p&gt;Copy the sonar token and paste it in notepad, click on information on the left, copy the values of organization, project key and create  secrets in Github repo &lt;strong&gt;githubactions-infra&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;name: SONAR_TOKEN, secret: &amp;lt;COPIED TOKEN&amp;gt;&lt;br&gt;
name: SONAR_ORGANIZATION, secret: &amp;lt;COPIED ORGANIZATION&amp;gt;&lt;br&gt;
name: SONAR_PROJECT_KEY, secret: &amp;lt;COPIED PROJECT KEY&amp;gt;&lt;br&gt;
name: SONAR_URL, secret: https://sonarcloud.io&lt;/code&gt;&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%2Fp3atuptnsxrrtiblx92w.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%2Fp3atuptnsxrrtiblx92w.png" alt=" " width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create quality gate in sonarcloud -&amp;gt; Administration -&amp;gt; Organization's settings -&amp;gt; Create:&lt;br&gt;
&lt;code&gt;name: githubactionsQG&lt;br&gt;
add condition: &lt;br&gt;
  where: on overall code = true&lt;br&gt;
  Quality gate fails when Bugs &amp;gt; 50&lt;br&gt;
  select project: github-actions&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Go back to project administration, select Quality gate then "githubactionsQG"&lt;/p&gt;
&lt;h2&gt;
  
  
  Deployment to EKS
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Install helm charts
&lt;/h3&gt;

&lt;p&gt;In terminal, run the code(for ubuntu users, other users can check their operating system installation)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install helm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configure helm
&lt;/h4&gt;

&lt;p&gt;Change to the directory where the project is githubactions-appl, then run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm create githubactions-charts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A new directory(githubactions-charts) will be created, next&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mv githubactions-charts helm/
rm -rf helm/githubactions-charts/templates/*
cp kubernetes/vpro-app/* helm/githubactions-charts/templates/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Deploy code
&lt;/h4&gt;

&lt;p&gt;We need to first git the workflow the permissions to write trivy scan results in the security tab. To do so, Navigate to githubactions-appl repository on GitHub. Click on the Settings tab; In the sidebar, click on Actions. Under the Actions permissions section, click general and scroll down to Workflow permissions and select Read and write permissions then save.&lt;/p&gt;

&lt;p&gt;Back to VSCode, commit and push the changes. In github actions, run the workflow. This time the pipeline will not be triggered automatically(as configured in our code), we'll have to trigger it manually on our github actions tab.&lt;/p&gt;

&lt;p&gt;Check the security tab in github actions to see the report of the security scans with trivy &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%2Fobdzy1vto6o4shkazjkq.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%2Fobdzy1vto6o4shkazjkq.png" alt=" " width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Modify domain name
&lt;/h2&gt;

&lt;p&gt;In the file helm/githubactions-charts/templates/vproingress.yaml, modify the domain name to your own after creating a hosted zone in Route53&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: vpro-ingress
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  ingressClassName: nginx
  rules:
  - host: github.ndzenyuyjones.link
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-app
            port:
              number: 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modify the line - host: github.ndzenyuyjones.link to contain your domain name, will put a CNAME record in the hosted zone.&lt;/p&gt;

&lt;p&gt;On the AWS console, we need to search and copy the url of the load balancer created for this project by the previous stack, copy the url and create a hosted zone with a cname record&lt;/p&gt;

&lt;p&gt;Type: CNAME&lt;br&gt;
Name: githubactions&lt;br&gt;
value: &lt;br&gt;
Wait about 5-10mins and search the link of our project on a browser github.ndzenyuyjones.link(use the link you created in the hosted zone), the landing page should appear.&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%2Fq91cq6hth9fw2af02vgb.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%2Fq91cq6hth9fw2af02vgb.png" alt=" " width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Login with&lt;/p&gt;

&lt;p&gt;&lt;code&gt;username: admin_vp&lt;br&gt;
passwrd: admin_vp&lt;/code&gt;&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%2Fjfit086ayyhwbt2h10rc.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%2Fjfit086ayyhwbt2h10rc.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Clean up
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Remove ingress controller
&lt;/h3&gt;

&lt;p&gt;First we need to make sure there is no existing kubeconfig file in our local machine by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rm -rf /.kube/config
aws eks update-kubeconfig --region us-east-1 --name infra-eks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now navigate to the repository on your local machine, where ever it was cloned and run&lt;/p&gt;

&lt;p&gt;kubectl delete -f &lt;a href="https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.3/deploy/static/provider/aws/deploy.yaml" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.3/deploy/static/provider/aws/deploy.yaml&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now delete the helm list, you can first run  helm list and copy the name of the list to be uninstalled&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm uninstall githubactions-charts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Move to terraform folder&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd terraform/
Then initialize terraform

Change the content of terraform.tf file to match the following
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;terraform {&lt;br&gt;
  required_providers {&lt;br&gt;
    aws = {&lt;br&gt;
      source  = "hashicorp/aws"&lt;br&gt;
      version = "~&amp;gt; 5.25.0"&lt;br&gt;
    }&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;random = {
  source  = "hashicorp/random"
  version = "~&amp;gt; 3.5.1"
}

tls = {
  source  = "hashicorp/tls"
  version = "~&amp;gt; 4.0.4"
}

cloudinit = {
  source  = "hashicorp/cloudinit"
  version = "~&amp;gt; 2.3.2"
}

kubernetes = {
  source  = "hashicorp/kubernetes"
  version = "~&amp;gt; 2.23.0"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend "s3" {
bucket = "githubactions-infra-012"
key    = "terraform.tfstate"
region = "us-east-1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;required_version = "~&amp;gt; 1.5.1"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Then we initialise the local machine to have the same state as the created cloud infrastructure.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Now we run destroy command, when prompted type "yes"&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



</description>
      <category>terraform</category>
      <category>kubernetes</category>
      <category>githubactions</category>
      <category>docker</category>
    </item>
    <item>
      <title>Mastering CI/CD: How to Build a Robust Pipeline with GitHub Actions, Docker, and ECS</title>
      <dc:creator>Jones Ndzenyuy</dc:creator>
      <pubDate>Tue, 03 Dec 2024 06:07:21 +0000</pubDate>
      <link>https://dev.to/ndzenyuy/mastering-cicd-how-to-build-a-robust-pipeline-with-github-actions-docker-and-ecs-34l9</link>
      <guid>https://dev.to/ndzenyuy/mastering-cicd-how-to-build-a-robust-pipeline-with-github-actions-docker-and-ecs-34l9</guid>
      <description>&lt;p&gt;I will guide you in this project how to build a secure CI/CD pipeline on AWS that detects code on a Github repository, runs static code analysis on sonar cloud, builds a docker image, scans the image for known vulnerabilities and deploys to ECS using DevSecOps Best practices.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuhj2krev2wsbpzste9b6.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%2Fuhj2krev2wsbpzste9b6.png" alt="Architecture" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Principle
&lt;/h2&gt;

&lt;p&gt;Each time a developer commits code to GitHub, it triggers GitHub actions to run static code analysis. The static code analysis consists of maven tests, checkstyle tests, junit, jacoco and quality gates. These static test will ensure that code works as expected, checks for adherence to a set of defined coding conventions, provide annotations to define test methods, assertions to test expected results and runners to execute the tests, generates reports that show which parts of the code base are covered by tests and enforce rules regarding code quality such as minimum code coverage, number of code smells or the absence of critical bugs.&lt;/p&gt;

&lt;p&gt;The next step is to build a docker image, the steps involved are declared in the Dockerfile which will be in the code repository, after building the image, it will be safe to run Trivy scan for known vulnerabilities using OWASP scans; the various security assessment techniques to obtain a secure docker image. The image is then Pushed to ECR, AWS' image repository from where we can easily pull to deploy on ECS&lt;/p&gt;

&lt;h2&gt;
  
  
  How to build it
&lt;/h2&gt;

&lt;h3&gt;
  
  
  GitHub Setup
&lt;/h3&gt;

&lt;p&gt;Login to your github account, open gitbash terminal on your local machine and clone the code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/Ndzenyuy/Mastering-CICD.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make a new folder and copy the files to it, initialize git and open VS Code with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  mkdir CICD-with-GitActions
  cp -r Mastering-CICD/* CICD-with-GitActions
  cd CICD-with-GitActions
  git init
  code .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now VSCode opens, under source control icon, publish project to your github under a public repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sonar Analysis and Quality Gates
&lt;/h3&gt;

&lt;p&gt;We need to start checking our workflow step by step, first we analyse our code for bugs with sonarqube in the file CICD-with-GitActions/.github/workflows/main.yml replace all its contents with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: CICD-with-GitActions
on: workflow_dispatch

jobs: 
  Testing:
    runs-on: ubuntu-latest
    steps:
      - name: Testing workflow
        uses: actions/checkout@v4

      - name: Maven test
        run: mvn test

      - name: Checkstyle
        run: mvn checkstyle:checkstyle
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This portion of code does three things: downloads the source code to github actions, runs maven test and runs mvn checkstyle. This is the first set of tests to be sure the code structure and styles are good and bug free. Now push this code and run it going to: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Github -&amp;gt; Mastering-CICD -&amp;gt; Actions -&amp;gt; Run Workflow&lt;/code&gt;&lt;br&gt;
Upon successful completion, we'll have the following &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%2Fpknsbcsezjwr9atay455.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%2Fpknsbcsezjwr9atay455.png" alt=" " width="800" height="244"&gt;&lt;/a&gt;&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%2Ftlrjo0dlsv5fe986mdqr.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%2Ftlrjo0dlsv5fe986mdqr.png" alt=" " width="2" height="2"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Create a sonar cloud organization
&lt;/h4&gt;

&lt;p&gt;Login to &lt;a href="https://sonarcloud.io" rel="noopener noreferrer"&gt;Sonar Cloud&lt;/a&gt; create an account   and link it to your github then &lt;br&gt;
Create a new organization -&amp;gt; Create an organization manually and give the following parameters&lt;br&gt;
&lt;code&gt;Organization name: mastercicd &lt;br&gt;
choose plan: free plan -&amp;gt; create organization&lt;br&gt;
&lt;/code&gt;&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%2Fyz0czo5n6drqhgp5ozr7.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%2Fyz0czo5n6drqhgp5ozr7.png" alt=" " width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next select choose Analyse new project and configure with the following &lt;br&gt;
&lt;code&gt;Organization: mastercicd&lt;br&gt;
Display name: github-actions&lt;br&gt;
Project key: mastercicd_github-actions &lt;br&gt;
Project visibility: public -&amp;gt; next&lt;br&gt;
Previous version = true -&amp;gt; create project&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Choose analysis method: Github actions&lt;/p&gt;

&lt;p&gt;Copy the sonar token to a sticky note&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%2F4pb5affzpuyyr7y1yd0j.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%2F4pb5affzpuyyr7y1yd0j.png" alt=" " width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Create a quality gate
&lt;/h4&gt;

&lt;p&gt;Under organizations select &lt;code&gt;mastercicd -&amp;gt; Quality gates -&amp;gt; Create -&amp;gt; Name: actionsQG&lt;/code&gt;&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%2Fbkd374i5rslxhicc77nv.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%2Fbkd374i5rslxhicc77nv.png" alt=" " width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Add conditions -&amp;gt; Where?: on overall code &lt;br&gt;
Quality gate fails when: Bugs  &lt;br&gt;
Operator: is greater than, Value 35; &lt;br&gt;
Projects: mastercicd_github-actions&lt;/code&gt;&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%2Fh6ksp561ykxwjapep7o0.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%2Fh6ksp561ykxwjapep7o0.png" alt=" " width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Store Secrets in GitHub
&lt;/h4&gt;

&lt;p&gt;In out Github project repository, go to settings -&amp;gt; secrets and variables -&amp;gt; Actions -&amp;gt; new repository secret: add the following secrets(name: value):&lt;/p&gt;

&lt;p&gt;SONAR_TOKEN : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (input the token retrieved from above when creating project)&lt;br&gt;
SONAR_URL : &lt;a href="https://sonarcloud.io" rel="noopener noreferrer"&gt;https://sonarcloud.io&lt;/a&gt;&lt;br&gt;
SONAR_ORGANIZATION: mastercicd&lt;br&gt;
SONAR_PROJECT_KEY: mastercicd_github-actions&lt;/p&gt;

&lt;p&gt;Test the sonar scanner and the quality gates, replace the content of the workflow(main.yml) with the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  name: github Actions
on: [push, workflow_dispatch]   
jobs: 
  Testing:
    runs-on: ubuntu-latest
    steps:
      - name: Testing workflow
        uses: actions/checkout@v4

      - name: Maven test
        run: mvn test

      - name: Checkstyle
        run: mvn checkstyle:checkstyle

# Setup java 17 to be default (sonar-scanner requirement as of 5.x)
      - name: Set Java 17
        uses: actions/setup-java@v3
        with:
          distribution: 'temurin' # See 'Supported distributions' for available options
          java-version: '17' 

      # Setup sonar-scanner
      - name: Setup SonarQube
        uses: warchant/setup-sonar-scanner@v7

      # Run sonar-scanner
      - name: SonarQube Scan
        run: sonar-scanner
          -Dsonar.host.url=${{ secrets.SONAR_URL }}
          -Dsonar.login=${{ secrets.SONAR_TOKEN }}
          -Dsonar.organization=${{ secrets.SONAR_ORGANIZATION }}
          -Dsonar.projectKey=${{ secrets.SONAR_PROJECT_KEY }}
          -Dsonar.sources=src/
          -Dsonar.junit.reportsPath=target/surefire-reports/ 
          -Dsonar.jacoco.reportsPath=target/jacoco.exec 
          -Dsonar.java.checkstyle.reportPaths=target/checkstyle-result.xml
          -Dsonar.java.binaries=target/test-classes/com/visualpathit/account/controllerTest/

              # Check the Quality Gate status.

      - name: SonarQube Quality Gate check
        id: sonarqube-quality-gate-check
        uses: sonarsource/sonarqube-quality-gate-action@master
        # Force to fail step after specific time.
        timeout-minutes: 5
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_URL }} #OPTIONAL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Job should build successfully&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%2F3222q4mkn9q6aqdu70mc.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%2F3222q4mkn9q6aqdu70mc.png" alt=" " width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And sonar cloud should have data&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%2Fk2d5t24toy6oq9sy5skt.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%2Fk2d5t24toy6oq9sy5skt.png" alt=" " width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS IAM, ECR and RDS Setup
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Create an IAM user
&lt;/h4&gt;

&lt;p&gt;Go to the console and search IAM then create a user with the following policies&lt;br&gt;
&lt;code&gt;&lt;br&gt;
Cloudwatch full access&lt;br&gt;
ECR full access&lt;br&gt;
RDS full access&lt;br&gt;
Create access keys -&amp;gt; use case: CLI&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Save the access keys in a sticky note.&lt;/p&gt;
&lt;h4&gt;
  
  
  Setup ECR
&lt;/h4&gt;

&lt;p&gt;Create a new private repository in ECR&lt;br&gt;
&lt;code&gt;name: github-actions -&amp;gt; create&lt;br&gt;
Copy repository URI of the form xxxxxxxxx.dkr.ecr.us-east-2.amazonaws.com and store in sticky notes&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Create RDS Database
&lt;/h4&gt;

&lt;p&gt;Goto console and search RDS, create a database with the following parameters&lt;br&gt;
&lt;code&gt;Standard create = true&lt;br&gt;
  engine options: MySQL&lt;br&gt;
  engine version: 8.0.35&lt;br&gt;
  templates: freetier&lt;br&gt;
  db instance identifier: github-actions-db&lt;br&gt;
  credentials settings:&lt;br&gt;
     master username: admin&lt;br&gt;
     password: admin123&lt;br&gt;
  Instance configuration: db.t3.micro&lt;br&gt;
  Connectivity:&lt;br&gt;
     VPC security group: create new; -&amp;gt; name: github-actions-sg&lt;br&gt;
  Additional configuration:&lt;br&gt;
     initial database name: accounts&lt;br&gt;
  Leave defaults and Create database&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After the database finishes the creating phase, we need to spin an EC2 instance to set up the database with initial data for our configuration. Start an ec2 instance&lt;br&gt;
&lt;code&gt;&lt;br&gt;
  instance type: t2.micro&lt;br&gt;
  OS: ubuntu&lt;br&gt;
  security group: ubuntu-actions-sg&lt;br&gt;
  edit inbound rules: allow all traffic from my IP&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Go to the RDS security group and edit the inbound rules to allow MySQL traffic(3306) from ubuntu-actions-sg. Wait for the RDS to be available and copy the endpoint. Go back in our terminal on local machine, ssh into the ec2 isntance and run the following code(make sure to replace  with the RDS endpoint)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; sudo apt-get update
 sudo apt-get install mysql-server -y      
 wget https://raw.githubusercontent.com/Ndzenyuy/vprofile-project/refs/heads/cd-aws/src/main/resources/db_backup.sql
mysql -h &amp;lt;enter-rds-edpoint&amp;gt; -u admin -padmin123 accounts &amp;lt; db_backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code will install mysql server, used to connect to mysql database, clone the project code and import the mysql dump found in db_backup.sql to the db server. At this point, the ec2 instance can be terminated. The Database is ready to be used in our app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build and Publish image to ECR
&lt;/h3&gt;

&lt;p&gt;Back to GitHub secrets, add the following secrets&lt;br&gt;
&lt;code&gt;RDS_USER: admin&lt;br&gt;
RDS_PASS: admin123&lt;br&gt;
RDS_ENDPOINT: (url of your rds endpoint)&lt;br&gt;
AWS_ACCESS_KEY_ID: &amp;lt; access key of the created IAM user &amp;gt;&lt;br&gt;
AWS_SECRET_ACCESS_KEY:&lt;br&gt;
REGISTRY: paste the URI of the copied ECR registry that was saved above and remove the /github-actions at the end, it should be like: XXXXXXXXXXXX.dkr.ecr.us-east-1.amazonaws.com&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now update the content of .github/main.yml with the following content&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: github Actions
on: [push, workflow_dispatch]

jobs: 
  Testing:
    runs-on: ubuntu-latest
    steps:
      - name: Testing workflow
        uses: actions/checkout@v4

      - name: Maven test
        run: mvn test

      - name: Checkstyle
        run: mvn checkstyle:checkstyle

# Setup java 17 to be default (sonar-scanner requirement as of 5.x)
      - name: Set Java 17
        uses: actions/setup-java@v3
        with:
          distribution: 'temurin' # See 'Supported distributions' for available options
          java-version: '17' 

      # Setup sonar-scanner
      - name: Setup SonarQube
        uses: warchant/setup-sonar-scanner@v7

      # Run sonar-scanner
      - name: SonarQube Scan
        run: sonar-scanner
          -Dsonar.host.url=${{ secrets.SONAR_URL }}
          -Dsonar.login=${{ secrets.SONAR_TOKEN }}
          -Dsonar.organization=${{ secrets.SONAR_ORGANIZATION }}
          -Dsonar.projectKey=${{ secrets.SONAR_PROJECT_KEY }}
          -Dsonar.sources=src/
          -Dsonar.junit.reportsPath=target/surefire-reports/ 
          -Dsonar.jacoco.reportsPath=target/jacoco.exec 
          -Dsonar.java.checkstyle.reportPaths=target/checkstyle-result.xml
          -Dsonar.java.binaries=target/test-classes/com/visualpathit/account/controllerTest/

              # Check the Quality Gate status.

      - name: SonarQube Quality Gate check
        id: sonarqube-quality-gate-check
        uses: sonarsource/sonarqube-quality-gate-action@master
        # Force to fail step after specific time.
        timeout-minutes: 5
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 

  BUILD_AND_PUBLISH:
    needs: Testing
    runs-on: ubuntu-latest
    steps:
      - name: Code checkout
        uses: actions/checkout@v4

      - name: Update application.properties file
        run: |
          sed -i "s/^jdbc.username.*$/jdbc.username\=${{ secrets.RDS_USER }}/" src/main/resources/application.properties
          sed -i "s/^jdbc.password.*$/jdbc.password\=${{ secrets.RDS_PASS }}/" src/main/resources/application.properties
          sed -i "s/db01/${{ secrets.RDS_ENDPOINT }}/" src/main/resources/application.properties

      - name: Build &amp;amp; Upload image to ECR
        uses: appleboy/docker-ecr-action@master
        with:
          access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
          secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          registry: ${{ secrets.REGISTRY }}
          repo: github-actions
          region: ${{ env.AWS_REGION }}
          tags: latest,${{ github.run_number }}
          daemon_off: false
          dockerfile: ./Dockerfile
          context: ./
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this pipeline code, we just added the build and publish stage. It'll will build the docker image and push it to ECR. &lt;/p&gt;

&lt;p&gt;Now push the code to Github and see the pipeline triggered, If everything works well, we should see a success and the image hosted in ECR.&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%2Fziigczs6kttahe3xvywg.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%2Fziigczs6kttahe3xvywg.png" alt=" " width="800" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I succeeded in my 12th build because i had to update most library versions. That is part of the DevOps Career, solving similar issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  ECS Setup
&lt;/h3&gt;

&lt;p&gt;Once the image is in ECR, we need to setup ECS to pick this image and deploy it. In AWS console, goto ECS&lt;/p&gt;

&lt;p&gt;Create a cluster -&amp;gt; name: github-actions-app -&amp;gt; create. Wait for few minutes for the creation to complete&lt;br&gt;
Create a task definition:&lt;br&gt;
&lt;code&gt;Task definition configuration: github-td&lt;br&gt;
CPU: 1vCPU, memery: 2GiB&lt;br&gt;
Task execution role: create new role&lt;br&gt;
Container details:&lt;br&gt;
name: github-actions&lt;br&gt;
container port: 8080&lt;br&gt;
image URI: &amp;lt;paste the image uri from ECR&amp;gt; : leave the rest as defaults&lt;/code&gt;&lt;br&gt;
  Now create it. After creation, click on the task execution role which will lead you to IAM. Make sure the policy in this role has AmazonECSTaskExecutionRolePolicy(AWS managed) now we have to add cloudwatch logs full access(CloudWatchLogsFullAccess).&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%2F5sjsr459er0kangb76ey.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%2F5sjsr459er0kangb76ey.png" alt=" " width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back to clusters, create a service with the following configurations:&lt;br&gt;
&lt;code&gt;Deployment configuration:&lt;br&gt;
   family: github-actions&lt;br&gt;
   service name: github-actions-svc&lt;br&gt;
Deployment failue detection&lt;br&gt;
   Use the Amazon ECS deployment circuit breaker = false(uncheck)&lt;br&gt;
Networking:&lt;br&gt;
   Security group: create new&lt;br&gt;
     name: github-actions-sg&lt;br&gt;
     inbound rules: HTTP from anywhere, custom tcp 8080 from anywhere&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Load balancing:&lt;br&gt;
   Application load balancer &lt;br&gt;
      name: github-actions&lt;br&gt;
      healthcheck grace period: 30s&lt;br&gt;
      listener: create new listener: port 80&lt;br&gt;
   Create new target group:&lt;br&gt;
     name: github-actions-tg&lt;br&gt;
     healthcheck path: /login&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Click create, this will take about 10 minutes to create the service and launch the container. &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%2Fgj9gqa9q8ke2uhuusxok.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%2Fgj9gqa9q8ke2uhuusxok.png" alt=" " width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the service github-actions-svc, it opens a new tab, select configuration and networking, scroll down and Copy the DNS of the load balancer &lt;br&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%2Fo35766ptm2se11bx3byv.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%2Fo35766ptm2se11bx3byv.png" alt=" " width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste it in a browser to verify the app is running and is stable&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%2Ftnwpooxjsn3tlfexyczi.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%2Ftnwpooxjsn3tlfexyczi.png" alt=" " width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we need to automate our pipeline to update the environment every time there is a new build&lt;/p&gt;
&lt;h3&gt;
  
  
  Deployment
&lt;/h3&gt;

&lt;p&gt;The last job will be to deploy the latest version of the app each time the pipeline runs. Replace the main.yaml code with the following(I had to comment out Trivy scan because this code had many severe vulnerabilities causing the pipeline to fail. In real life situations, the Developers are to fix the vulnerabilities)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: github Actions
on: [push, workflow_dispatch]
env: 
  AWS_REGION: us-east-1
  ECR_REPOSITORY: github-actions
  ECS_SERVICE: github-actions-svc
  ECS_CLUSTER: github-actions
  ECS_TASK_DEFINITION: aws-files/taskdeffile.json
  CONTAINER_NAME: github  
jobs: 
  Testing:
    runs-on: ubuntu-latest
    steps:
      - name: Testing workflow
        uses: actions/checkout@v4

      - name: Maven test
        run: mvn test

      - name: Checkstyle
        run: mvn checkstyle:checkstyle

# Setup java 17 to be default (sonar-scanner requirement as of 5.x)
      - name: Set Java 17
        uses: actions/setup-java@v3
        with:
          distribution: 'temurin' # See 'Supported distributions' for available options
          java-version: '17' 

      # Setup sonar-scanner
      - name: Setup SonarQube
        uses: warchant/setup-sonar-scanner@v7

      # Run sonar-scanner
      - name: SonarQube Scan
        run: sonar-scanner
          -Dsonar.host.url=${{ secrets.SONAR_URL }}
          -Dsonar.login=${{ secrets.SONAR_TOKEN }}
          -Dsonar.organization=${{ secrets.SONAR_ORGANIZATION }}
          -Dsonar.projectKey=${{ secrets.SONAR_PROJECT_KEY }}
          -Dsonar.sources=src/
          -Dsonar.junit.reportsPath=target/surefire-reports/ 
          -Dsonar.jacoco.reportsPath=target/jacoco.exec 
          -Dsonar.java.checkstyle.reportPaths=target/checkstyle-result.xml
          -Dsonar.java.binaries=target/test-classes/com/visualpathit/account/controllerTest/

              # Check the Quality Gate status.

      - name: SonarQube Quality Gate check
        id: sonarqube-quality-gate-check
        uses: sonarsource/sonarqube-quality-gate-action@master
        # Force to fail step after specific time.
        timeout-minutes: 5
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 

  BUILD_AND_PUBLISH:
    needs: Testing
    runs-on: ubuntu-latest
    steps:
      - name: Code checkout
        uses: actions/checkout@v4

      - name: Update application.properties file
        run: |
          sed -i "s/^jdbc.username.*$/jdbc.username\=${{ secrets.RDS_USER }}/" src/main/resources/application.properties
          sed -i "s/^jdbc.password.*$/jdbc.password\=${{ secrets.RDS_PASS }}/" src/main/resources/application.properties
          sed -i "s/db01/${{ secrets.RDS_ENDPOINT }}/" src/main/resources/application.properties

      - name: Build &amp;amp; Upload image to ECR
        uses: appleboy/docker-ecr-action@master
        with:
          access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
          secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          registry: ${{ secrets.REGISTRY }}
          repo: github-actions
          region: ${{ env.AWS_REGION }}
          tags: latest,${{ github.run_number }}
          daemon_off: false
          dockerfile: ./Dockerfile
          context: ./
    #- name: Run Trivy vulnerability scanner
     #  uses: aquasecurity/trivy-action@master
     #  with:
       #   image-ref: ${{ secrets.REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ github.run_number }}
      #    format: 'json'
      #    exit-code: '1'
       #   ignore-unfixed: true
       #   vuln-type: 'os,library'
      #    severity: 'HIGH' 

Deploy:
    needs: BUILD_AND_PUBLISH
    runs-on: ubuntu-latest
    steps:
      - name: Code checkout
        uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Fill in the new image ID in the Amazon ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: ${{ env.ECS_TASK_DEFINITION }}
          container-name: ${{ env.CONTAINER_NAME }}
          image: ${{ secrets.REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ github.run_number }}

      - name: Deploy Amazon ECS task definition
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On ECS, goto Task definitions -&amp;gt; github-td -&amp;gt; Revision 1, select the json tab on the page and copy the JSON content of the task definition and paste it in the file /aws-files/taskdeffile.json.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "taskDefinitionArn": "arn:aws:ecs:us-east-1:XXXXXXXXXXXX:task-definition/github-td:2",
    "containerDefinitions": [
        {
            "name": "github",
            "image": "781655249241.dkr.ecr.us-east-1.amazonaws.com/github-actions",
            "cpu": 0,
            "portMappings": [
                {
                    "name": "github-actions-port",
                    "containerPort": 8080,
                    "hostPort": 8080,
                    "protocol": "tcp",
                    "appProtocol": "http"
                }
            ],
            "essential": true,
            "environment": [],
            "environmentFiles": [],
            "mountPoints": [],
            "volumesFrom": [],
            "ulimits": [],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "/ecs/github-td",
                    "mode": "non-blocking",
                    "awslogs-create-group": "true",
                    "max-buffer-size": "25m",
                    "awslogs-region": "us-east-1",
                    "awslogs-stream-prefix": "ecs"
                },
                "secretOptions": []
            },
            "systemControls": []
        }
    ],
    "family": "github-td",
    "executionRoleArn": "arn:aws:iam::XXXXXXXXXXXX:role/ecsTaskExecutionRole",
    "networkMode": "awsvpc",
    "revision": 2,
    "volumes": [],
    "status": "ACTIVE",
    "requiresAttributes": [
        {
            "name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
        },
        {
            "name": "ecs.capability.execution-role-awslogs"
        },
        {
            "name": "com.amazonaws.ecs.capability.ecr-auth"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.28"
        },
        {
            "name": "ecs.capability.execution-role-ecr-pull"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
        },
        {
            "name": "ecs.capability.task-eni"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.29"
        }
    ],
    "placementConstraints": [],
    "compatibilities": [
        "EC2",
        "FARGATE"
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "1024",
    "memory": "2048",
    "runtimePlatform": {
        "cpuArchitecture": "X86_64",
        "operatingSystemFamily": "LINUX"
    },
    "registeredAt": "2024-12-03T03:24:41.874Z",
    "registeredBy": "arn:aws:iam::XXXXXXXXXXXX:user/ndzenyuyjones@gmail.com",
    "tags": []
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now edit the different environment variables to match those you gave in your setup. Push your code to GitHub and watch the pipeline gets built and deployed. The pipeline should be successful with all three stages.&lt;/p&gt;

&lt;p&gt;Now edit the security group of the data base to accept inbound transfer of MySQL traffic(3306) from the security group(githubactions-sg) of the ECS service.&lt;/p&gt;

&lt;p&gt;Back to our web page, login with the following credentials&lt;br&gt;
&lt;code&gt;username: admin_vp&lt;br&gt;
password: admin_vp&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
You should land on the welcome page. &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%2Fm1w924dvqyhtsxe9cnvp.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%2Fm1w924dvqyhtsxe9cnvp.png" alt=" " width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations, you just succesfully deployed your application on a pipeline using GitHub actions.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cicd</category>
      <category>githubactions</category>
      <category>devops</category>
    </item>
    <item>
      <title>Build a Simple AWS CI/CD Pipeline with deployment to Elastic Beanstalk</title>
      <dc:creator>Jones Ndzenyuy</dc:creator>
      <pubDate>Mon, 25 Nov 2024 21:54:48 +0000</pubDate>
      <link>https://dev.to/ndzenyuy/build-an-aws-cicd-pipeline-with-deployment-to-beanstalk-n4n</link>
      <guid>https://dev.to/ndzenyuy/build-an-aws-cicd-pipeline-with-deployment-to-beanstalk-n4n</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Building a pipeline for automated tests and deployment is every developers'  dream, not having to manually verify security vulnerabilities or functioning before making it live. A wrongly configured pipeline or choosing tools without prior load considerations can either end up over spending or crashing. In this project I will guide you through the building of an AWS native pipeline, it will build our code and host directly on AWS, cost considerations are made to ensure very little expenditure with every build, AWS Build only charges for the build time, no servers running.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The code is hosted in Bitbucket, whenever there is an update, the pipeline is triggered and fetches the code, Code build runs a test on Sonar cloud, if the quality gate is passed, the pipeline launches the build phase, stores the built artifact in an S3 bucket next Elastic Beanstalk is triggered to pick the artifact from S3 and update its environment. After a 360 seconds waiting, the final stage of the pipeline is triggered which tests the deployed software, the credentials of a test user, initially stored in DB is used to login to the web App and takes screenshots which are stored in another S3 bucket.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhajkdu3qi9n0xj3g4qjc.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%2Fhajkdu3qi9n0xj3g4qjc.png" alt="Pipeline architecture" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Build It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Host code in Bitbucket
&lt;/h3&gt;

&lt;p&gt;Create an account on bitbucket a guide to create it can be found &lt;a href="https://guides.co/g/bitbucket-101/11151" rel="noopener noreferrer"&gt;here&lt;/a&gt;. and clone the code by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/Ndzenyuy/cicd-on-aws.git
cd cicd-on-aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command will clone the source code and change the working directory in to cicd-on-aws folder. &lt;/p&gt;

&lt;p&gt;Now we have to configure a Bitbucket repository and upload the code. Go to your browser and create a repository in Bitbucket. To learn how to create a repository in bitbucket check this guide &lt;a href="https://support.atlassian.com/bitbucket-cloud/docs/create-a-git-repository/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The repository should the following &lt;br&gt;
&lt;code&gt;workspace: aws-cicd-beanstalk&lt;br&gt;
repo name: cicd-with-elastic_beanstalk&lt;br&gt;
access level: private&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now back to the terminal, run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote rm origin
git remote add source https://path/to/your/bitbucket/repo.git
git push -u 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the code should be present on Bitbucket. Verify if it is the case or troubleshoot were you may have gone wrong. Leave the bitbucket tab open and open a different one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure CodeArtifact
&lt;/h3&gt;

&lt;p&gt;The App is a java based app, we will be using Maven to build it, so we are configuring CodeArtifact so that we can download and store maven dependencies, this will help reduce build times in subsequent builds. On the AWS console, search CodeArtifact and create a repository and give it the following configurations:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;repo name: cicd-aws&lt;br&gt;
Public upstream repositories: maven-central-store -&amp;gt; next&lt;br&gt;
aws account: this account&lt;br&gt;
domain: give your domain, could be any name -&amp;gt; next&lt;br&gt;
verify and create repository&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The created repository will display as follows: &lt;br&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%2F9xyi2cjqwb1y9tgcn52g.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%2F9xyi2cjqwb1y9tgcn52g.png" alt="created repository" width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now open maven-central-store repository and click on &lt;strong&gt;View connection instructions&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Mac &amp;amp; Linux&lt;/strong&gt; = true -&amp;gt; &lt;strong&gt;Select package manager client&lt;/strong&gt; = mvn.  &lt;/p&gt;

&lt;p&gt;Here you'll have the connection instructions on how to connect to the repository from your project. &lt;/p&gt;

&lt;p&gt;Copy &lt;strong&gt;Step 3: Export a CodeArtifact authorization token for authorization to your repository from your preferred shell.&lt;/strong&gt; and open the buildspec.yml file in vscode and replace the line 15. The code should be as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; - export CODEARTIFACT_AUTH_TOKEN=`aws codeartifact get-authorization-token --domain sparxinc --domain-owner 781655249241 --region us-east-1 --query authorizationToken --output text`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy &lt;strong&gt;Step 4: Add your server to the list of servers to your settings.xml&lt;/strong&gt; to &lt;em&gt;settings.xml&lt;/em&gt;. Scroll to line 5 and replace the server section with what was copied from the artifact repos instructions. It should look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;servers&amp;gt;
  &amp;lt;server&amp;gt;
    &amp;lt;id&amp;gt;sparxinc-cicd-aws&amp;lt;/id&amp;gt;
    &amp;lt;username&amp;gt;aws&amp;lt;/username&amp;gt;
    &amp;lt;password&amp;gt;${env.CODEARTIFACT_AUTH_TOKEN}&amp;lt;/password&amp;gt;
  &amp;lt;/server&amp;gt;
&amp;lt;/servers&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next copy &lt;strong&gt;Step 5: Add a profile containing your repository to your settings.xml.&lt;/strong&gt; and replace the contents of the profile section and the mirrors, it should look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#Profiles
&amp;lt;profiles&amp;gt;
  &amp;lt;profile&amp;gt;
    &amp;lt;id&amp;gt;sparxinc-cicd-aws&amp;lt;/id&amp;gt;
    &amp;lt;activation&amp;gt;
      &amp;lt;activeByDefault&amp;gt;true&amp;lt;/activeByDefault&amp;gt;
    &amp;lt;/activation&amp;gt;
    &amp;lt;repositories&amp;gt;
      &amp;lt;repository&amp;gt;
        &amp;lt;id&amp;gt;sparxinc-cicd-aws&amp;lt;/id&amp;gt;
        &amp;lt;url&amp;gt;https://sparxinc-XXXXXXXXXXXX.d.codeartifact.us-east-1.amazonaws.com/maven/maven-central-store/&amp;lt;/url&amp;gt;
      &amp;lt;/repository&amp;gt;
    &amp;lt;/repositories&amp;gt;
  &amp;lt;/profile&amp;gt;
&amp;lt;/profiles&amp;gt;
#mirrors
&amp;lt;mirrors&amp;gt;
  &amp;lt;mirror&amp;gt;
    &amp;lt;id&amp;gt;sparxinc-maven-central-store&amp;lt;/id&amp;gt;
    &amp;lt;name&amp;gt;sparxinc-maven-central-store&amp;lt;/name&amp;gt;
    &amp;lt;url&amp;gt;https://sparxinc-XXXXXXXXXXXX.d.codeartifact.us-east-1.amazonaws.com/maven/maven-central-store/&amp;lt;/url&amp;gt;
    &amp;lt;mirrorOf&amp;gt;*&amp;lt;/mirrorOf&amp;gt;
  &amp;lt;/mirror&amp;gt;
&amp;lt;/mirrors&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the settings.xml file and open pom.xml. Back on the console, copy only the url from the instructions and replace those that is on line 303 and . The copied url is similar to:&lt;br&gt;
&lt;code&gt;&amp;lt;url&amp;gt;https://sparxinc-XXXXXXXXXXXX.d.codeartifact.us-east-1.amazonaws.com/maven/maven-central-store/&amp;lt;/url&amp;gt;&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Create build jobs
&lt;/h3&gt;

&lt;p&gt;Here we are going to creat two build jobs, the first will analyse the code on sonar cloud and the second will build the artifact.&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%2Ff7izy71mq6oxzoz1odm7.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%2Ff7izy71mq6oxzoz1odm7.png" alt=" " width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We need to first create a connection for bitbucket app, go under developer tools, search for settings -&amp;gt; connection and create a new connection.&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%2F6evqema8yrt4yvgoo453.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%2F6evqema8yrt4yvgoo453.png" alt=" " width="800" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Select a provider: bitbucket&lt;br&gt;
connection name: awscicd  -&amp;gt; connect to bitbucket&lt;/code&gt;&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%2Fwp7pstyb2rqklrcddmyh.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%2Fwp7pstyb2rqklrcddmyh.png" alt=" " width="800" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next page click install new app and grant access to bitbucket when prompted. It'll return to the previous page, now click on the connect button. Our pipeline can now connect to bitbucket.&lt;/p&gt;
&lt;h4&gt;
  
  
  Code analysis job on sonar cloud
&lt;/h4&gt;

&lt;p&gt;On the console, search CodeBuild -&amp;gt; Create project and give the following configurations:&lt;br&gt;
&lt;code&gt;Project name: code-analysis&lt;br&gt;
source provider: bitbucket &lt;br&gt;
Credential: Bitbucket app&lt;br&gt;
connection: awscicd&lt;br&gt;
repository: cicd-with-elastic_beanstalk&lt;br&gt;
operating system: ubuntu&lt;br&gt;
new service role name: codebuild-code-analysis-service-role&lt;br&gt;
Build spec -&amp;gt; use a buildspec file -&amp;gt; buildspec name: buildspec.yml&lt;br&gt;
Cloudwatch logs -&amp;gt; stream name prefix = awscicd-logs&lt;br&gt;
click create build project&lt;/code&gt;&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%2Fbz3ix8e08c8oag1ign4z.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%2Fbz3ix8e08c8oag1ign4z.png" alt=" " width="800" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you open buildspec.yml file, you'll notice the parameters are stored in the parameter store, we need values for &lt;strong&gt;LOGIN&lt;/strong&gt;, &lt;strong&gt;HOST&lt;/strong&gt;, &lt;strong&gt;Organization&lt;/strong&gt; and &lt;strong&gt;Project&lt;/strong&gt;. For extra security, we need to store in Parameter store. But before then, we need to create a project in Sonarcloud before storing it's access information on parameter store. Go to &lt;a href="https://sonarcloud.io/" rel="noopener noreferrer"&gt;sonarcloud&lt;/a&gt; and create an account if you don't have any yet by following &lt;a href="https://www.slideshare.net/slideshow/instructions-on-how-to-create-account-in-sonarcloud/233060177" rel="noopener noreferrer"&gt;this&lt;/a&gt;  tutorial. &lt;br&gt;
&lt;strong&gt;Login token&lt;/strong&gt;: In the sonar cloud welcome page, on the top right corner of the screen, click you account icon and select My Account -&amp;gt; Security. Now give a token name of your choice and click generate. Copy the generated code to a sticky note for later use&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Organization&lt;/strong&gt;: On the same tab, open organizations and create a new organization, select &lt;code&gt;create one manually&lt;/code&gt; &lt;br&gt;
&lt;code&gt;name: aws-cicd-organization&lt;br&gt;
key: aws-cicd-organization&lt;br&gt;
plan: free plan -&amp;gt; create organization&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project&lt;/strong&gt;: On the page that opens, click analyse new project&lt;br&gt;
&lt;code&gt;organization: aws-cicd-organization&lt;br&gt;
display name: beanstalk-app&lt;br&gt;
project key: aws-cicd-organization_beanstalk-app -&amp;gt; next&lt;br&gt;
The new code for this project will be based on: Previous version&lt;br&gt;
create project&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Open a new tab and open AWS console and search &lt;strong&gt;systems manager&lt;/strong&gt; -&amp;gt; &lt;strong&gt;parameter store&lt;/strong&gt; and &lt;strong&gt;create parameter&lt;/strong&gt; with the following configurations.&lt;br&gt;
&lt;strong&gt;HOST&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;parameter: HOST&lt;br&gt;
Tier: standard&lt;br&gt;
Type: String&lt;br&gt;
datatype: text&lt;br&gt;
value: https://sonarcloud.io&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Organization&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;parameter: Organization&lt;br&gt;
Tier: standard&lt;br&gt;
Type: String&lt;br&gt;
datatype: text&lt;br&gt;
value: aws-cicd-organization&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LOGIN&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;parameter: LOGIN&lt;br&gt;
Tier: standard&lt;br&gt;
Type: Secure String&lt;br&gt;
datatype: text&lt;br&gt;
value: (paste the value of the token generated in sonarcloud)&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;parameter: Project&lt;br&gt;
Tier: standard&lt;br&gt;
Type: String&lt;br&gt;
datatype: text&lt;br&gt;
value: aws-cicd-organization_beanstalk-app&lt;/code&gt; &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%2Fesu4pxpgo1bijv3dzbe1.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%2Fesu4pxpgo1bijv3dzbe1.png" alt=" " width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Return to the codebuild tab, we need to modify the IAM role of the build project in order to access parameter store, on the page&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%2Frp6oblrvteizhgrjgzu9.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%2Frp6oblrvteizhgrjgzu9.png" alt=" " width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under service role, top right, click on the IAM arn, it opens a new tab in IAM. Create a &lt;strong&gt;System manager&lt;/strong&gt; policy with the following &lt;strong&gt;allow&lt;/strong&gt; permissions: &lt;br&gt;
&lt;code&gt;under list: DescribeParameters&lt;br&gt;
under read: GetParameter, GetParametersByPath, GetParameterHistory, GetParameters, DescribeDocumentParameters&lt;/code&gt;&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%2Ft2bf6j0z4697d0ra9yr2.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%2Ft2bf6j0z4697d0ra9yr2.png" alt=" " width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click next, for policy name &lt;code&gt;parameteraccess&lt;/code&gt; and create. Return and open the service role for the build project and add the created policy to it. Next search for another policy named "AWSCodeArtifactReadOnlyAccess" and add it to the same role. You should have policies as in the image below&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%2Fhrgblvm6j1buv82wxgj2.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%2Fhrgblvm6j1buv82wxgj2.png" alt=" " width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now return to the build project in codebuild tab and start build. If everything turns out well&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%2F67rnags4pqu2rhl69vba.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%2F67rnags4pqu2rhl69vba.png" alt=" " width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the Code analysis on sonar cloud should be populated with the statistics of the job that ran.&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%2F71zz1t4yx30unw4djm6n.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%2F71zz1t4yx30unw4djm6n.png" alt=" " width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Build artifact job
&lt;/h4&gt;

&lt;p&gt;Back to creating a build job console -&amp;gt; create build project and configure with the following: &lt;br&gt;
&lt;code&gt;name: build-artifact&lt;br&gt;
source provider: bitbucket&lt;br&gt;
select "custom source provider"&lt;br&gt;
repository: aws-cicd-beanstalk&lt;br&gt;
source version: main&lt;br&gt;
operating system: ubuntu&lt;br&gt;
select "new service role"&lt;br&gt;
build spec: select 'use buildspec file'&lt;br&gt;
buildspec name: aws-files/build_buildspec.yml&lt;br&gt;
create build project&lt;br&gt;
&lt;/code&gt; &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%2Fwov1n1h5goijsvnyb9a4.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%2Fwov1n1h5goijsvnyb9a4.png" alt=" " width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next we need to add the policy to access CodeArtifact to read the dependencies. To do so, click on the &lt;strong&gt;Service role url&lt;/strong&gt; and add policy to this role. Add the policy named AWSCodeArtifactReadOnlyAccess. &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%2Finbc0llx4ystwa3fxprj.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%2Finbc0llx4ystwa3fxprj.png" alt=" " width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Close the tab and return to CodeBuild and run build-artifact project by clicking start build. The project should finish successfully.&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%2F35nhw4xgh958dolus0p2.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%2F35nhw4xgh958dolus0p2.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Create pipeline
&lt;/h3&gt;

&lt;p&gt;Create an S3 bucket to store the artifact after the build job runs, give the parameters: &lt;br&gt;
&lt;code&gt;name: pipeline-storage-for-artifacts-xxx (xxx are random numbers to make the bucket name unique)&lt;br&gt;
region: us-east-1&lt;br&gt;
create bucket&lt;/code&gt;&lt;br&gt;
Now create a folder in the bucket named &lt;strong&gt;artifacts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the AWS console, search pipeline -&amp;gt; create pipeline -&amp;gt; Build custom pipeline -&amp;gt; next&lt;br&gt;
&lt;code&gt;name: aws-cicd-pipeline&lt;br&gt;
leave defaults and click next&lt;br&gt;
source provider: bitbucket&lt;br&gt;
connection: connect to bitbucket &lt;br&gt;
        -&amp;gt; enter a connection name &lt;br&gt;
        -&amp;gt; create connection&lt;br&gt;
        -&amp;gt; choose the app or create one if none exists and connect&lt;br&gt;
repository name: aws-cicd-beanstalk&lt;br&gt;
default branch: main  -&amp;gt; next&lt;br&gt;
Build provider: select other build providers and choose AWS CodeBuild&lt;br&gt;
Project name: build-artifact&lt;br&gt;
input artifacts: source artifacts  -&amp;gt; next&lt;br&gt;
Deploy provider: S3&lt;br&gt;
input artifacts: BuildArtifact&lt;br&gt;
key: artifacts&lt;br&gt;
next, review and create pipeline&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
The pipeline will be automatically triggered, we need to stop it and add the code analysis stage. So click on &lt;strong&gt;stop execution&lt;/strong&gt; select the pipeline and stop it. Click on edit and add a stage just before the &lt;strong&gt;build&lt;/strong&gt; stage&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%2Fmqvm0vbnuu4s5pu0e6bh.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%2Fmqvm0vbnuu4s5pu0e6bh.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;stage name: codeanalysis -&amp;gt; add -&amp;gt; add action group&lt;br&gt;
&lt;code&gt;action name: analyse-code&lt;br&gt;
action provider: aws codebuild&lt;br&gt;
input artifacts: SourceArtifact&lt;br&gt;
project name: code-analysis -&amp;gt; done&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Edit the deploy stage action and select &lt;em&gt;Extract file before deploy&lt;/em&gt; then -&amp;gt; done&lt;/p&gt;

&lt;p&gt;Make sure all the edited stages are validated with done. Save the changes and return to the pipeline. Click on release change to trigger the pipeline.&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%2F0cihtywdo49thy508bm8.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%2F0cihtywdo49thy508bm8.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&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%2F0vfqvre371my2cscy2js.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%2F0vfqvre371my2cscy2js.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And voila, the pipeline has been successfully built. If you open the S3 bucket, you will find the artifact stored there&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%2Fzwusprb04dzp3oe2zhem.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%2Fzwusprb04dzp3oe2zhem.png" alt=" " width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Configure SNS
&lt;/h3&gt;

&lt;p&gt;Go to the console and search SNS -&amp;gt; create a new topic&lt;br&gt;
&lt;code&gt;type: standard&lt;br&gt;
name: awscicd-notification -&amp;gt; create notification&lt;/code&gt;&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%2Fd17iqqqkqb45tije36z6.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%2Fd17iqqqkqb45tije36z6.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on create subscription&lt;br&gt;
&lt;code&gt;protocol: email&lt;br&gt;
endpoint: youremail@email.com&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
An email will be sent to the provided email. The status will be pending until you open the email and validate the subscription.&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%2Fstx95boo3mt00xmp82yd.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%2Fstx95boo3mt00xmp82yd.png" alt=" " width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To the left pane, under pipelines -&amp;gt; settings -&amp;gt; notifications -&amp;gt; create notification rule&lt;br&gt;
&lt;code&gt;name: aws-cicd-rule&lt;br&gt;
Events that trigger notifications: select all&lt;br&gt;
targets: awscicd-notification  -&amp;gt; submit&lt;/code&gt;&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%2Ftwlkbtxfs9adle99yifc.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%2Ftwlkbtxfs9adle99yifc.png" alt=" " width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The notification rule will be created.&lt;br&gt;
Now back to our pipeline, if we run the pipeline anew, notifications will be sent about the status of the pipeline&lt;/p&gt;
&lt;h2&gt;
  
  
  Launch Elastic Beanstalk
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Create an IAM role
&lt;/h3&gt;

&lt;p&gt;Console -&amp;gt; IAM -&amp;gt; roles -&amp;gt; Create role:&lt;br&gt;
`Trusted entity type: AWS service&lt;br&gt;
use case: EC2&lt;br&gt;
Permissions policies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AdministratorAccess-AWSElasticBeanstalk&lt;/li&gt;
&lt;li&gt;AWSElasticBeanstalkCustomPlatformforEC2Role&lt;/li&gt;
&lt;li&gt;AWSElasticBeanstalkRoleSNS&lt;/li&gt;
&lt;li&gt;AWSElasticBeanstalkWebTier&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;role name: elasticbean-role-awscicd    -&amp;gt; Create role`&lt;/p&gt;
&lt;h3&gt;
  
  
  Create keypair
&lt;/h3&gt;

&lt;p&gt;Console -&amp;gt; EC2 -&amp;gt; Keypairs -&amp;gt; create keypair&lt;br&gt;
&lt;code&gt;Name: beanstalk-key  -&amp;gt; create keypair&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Launch Elastic beanstalk
&lt;/h3&gt;

&lt;p&gt;Search Elastic Beanstalk on the console -&amp;gt; Create Application then &lt;br&gt;
&lt;code&gt;Application name: awscicd-beanstalk&lt;br&gt;
-&amp;gt; create&lt;/code&gt;&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%2Fewyed44atwoa1cf9i61c.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%2Fewyed44atwoa1cf9i61c.png" alt=" " width="800" height="147"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click create new environment&lt;br&gt;
&lt;code&gt;Environment tier: web-server-environment&lt;br&gt;
platform: Tomcat&lt;br&gt;
Platform branch: Tomcat 10 with Corretto 21 running on 64bit Amazon Linux 2023&lt;br&gt;
Platform version: 5.4.1 (Recommended)&lt;br&gt;
Presets: Custom configuration &lt;br&gt;
Leave any other as default and -&amp;gt; click next&lt;br&gt;
Service role: Create and use new service role&lt;br&gt;
EC2 key pair: beanstalk-key&lt;br&gt;
EC2 instance profile: elasticbean-role-awscicd&lt;br&gt;
Virtual Private Cloud (VPC): choose VPC with internet access&lt;br&gt;
Public IP address: activated =true&lt;br&gt;
Instance subnets: select all   -&amp;gt; Next&lt;br&gt;
Root volume type: General Purpose 3(ssd)&lt;br&gt;
size: 10GB&lt;br&gt;
IOPS: 3000&lt;br&gt;
Throughput: 125&lt;br&gt;
Autoscaling group -&amp;gt; Environment type: load balanced&lt;br&gt;
min instances: 1&lt;br&gt;
max instances: 4&lt;br&gt;
Instance types: t2.micro&lt;br&gt;
Processes: select default -&amp;gt; actions -&amp;gt; edit &lt;br&gt;
-&amp;gt; sessions -&amp;gt; session stickiness = Enabled&lt;br&gt;
Monitoring: Enhanced&lt;br&gt;
email notifications: &amp;lt;enter your email&amp;gt;&lt;br&gt;
Deployment policy: Rolling&lt;br&gt;
Deployment batch size: 50    -&amp;gt; next&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Review all the settings&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%2F3dr8vtvaolzlf954tk08.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%2F3dr8vtvaolzlf954tk08.png" alt=" " width="800" height="299"&gt;&lt;/a&gt;&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%2Fhunpr7fhhroxhl981hud.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%2Fhunpr7fhhroxhl981hud.png" alt=" " width="800" height="300"&gt;&lt;/a&gt;&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%2Fia4s88i86cty1ia8cmmg.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%2Fia4s88i86cty1ia8cmmg.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&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%2Fp49hhunr1x0etii5soqg.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%2Fp49hhunr1x0etii5soqg.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&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%2Fkuwf1l9y5oymtmntee3o.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%2Fkuwf1l9y5oymtmntee3o.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Review all the settings and click on create. This will take about 4-5 minutes to create the infrastructure. &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%2Fmrnj9wrhgzpo0lghjjvq.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%2Fmrnj9wrhgzpo0lghjjvq.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When Beanstalk is ready, you can click on the DNS link to access the page: &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%2Fppqqu5g02woxzzo68yfz.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%2Fppqqu5g02woxzzo68yfz.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our beanstalk environment is up and running, we will configure the pipeline to update the code with the built artifact. &lt;/p&gt;
&lt;h2&gt;
  
  
  Create RDS Database
&lt;/h2&gt;

&lt;p&gt;Console -&amp;gt; RDS -&amp;gt; Create database and configure it as follows&lt;br&gt;
&lt;code&gt;choose a database creation method: standard create&lt;br&gt;
Engine options: MySQL&lt;br&gt;
Engine version: 8.0.35&lt;br&gt;
Templates: free tier&lt;br&gt;
DB instance identifier: awscicd-mysql&lt;br&gt;
master username: admin&lt;br&gt;
password: admin123&lt;br&gt;
Burstable classes (includes t classes): db.t3.micro&lt;br&gt;
storage: 20GB&lt;br&gt;
Security group: create new(name: awscicd-sg)&lt;br&gt;
Additional configuration: Initial database name: accounts&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Review and create database. Wait for a while till the database is created. When the status changes from &lt;code&gt;creating -&amp;gt; available&lt;/code&gt; before we can proceed.&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%2Farqc7r1uh09l36za4awc.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%2Farqc7r1uh09l36za4awc.png" alt=" " width="800" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the created database and copy the endpoint. It should be like &lt;code&gt;awscicd-mysql.cjrs4jngtznx.us-east-1.rds.amazonaws.com&lt;/code&gt; &lt;/p&gt;
&lt;h2&gt;
  
  
  Initialize Database
&lt;/h2&gt;

&lt;p&gt;We have to login into the beanstalk instance and initialize the database with the initial data. But first we need to configure the &lt;em&gt;awscicd-sg&lt;/em&gt; to receive traffic from beanstalk.&lt;/p&gt;

&lt;p&gt;Go to console -&amp;gt; EC2 -&amp;gt; Security groups and open the Security group for the running beanstalk instance and copy the security group ID. Now open &lt;code&gt;awscicd-sg -&amp;gt; Edit inbound rules&lt;/code&gt;. &lt;br&gt;
Add a new rule allowing 3306 from the security group of the beanstalk instance. This will permit us to connect to the database through the beanstalk instance.&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%2Ffgdvgzclb75i47qkod22.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%2Ffgdvgzclb75i47qkod22.png" alt=" " width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the changes. Now ssh into the running instance and run the following: (make sure to replace  with the rds endpoint copied earlier)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo -i
dnf install mariadb105 -y
wget https://raw.githubusercontent.com/Ndzenyuy/vprofile-project/refs/heads/cd-aws/src/main/resources/db_backup.sql
mysql -h &amp;lt;enter-rds-edpoint&amp;gt; -u admin -padmin123 accounts &amp;lt; db_backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add other parameters to Parameter store
&lt;/h2&gt;

&lt;p&gt;We need to add the RDS endpoint, the database user and password to our parameters because Elastic beanstalk connects to the database. So we go to parameter store -&amp;gt; create new parameter and create the following parameters:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RDS-Endpoint&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;parameter: RDS-Endpoint&lt;br&gt;
Tier: standard&lt;br&gt;
Type: String&lt;br&gt;
datatype: text&lt;br&gt;
value: &amp;lt;enter your RDS End point&amp;gt;&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RDPUSER&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;parameter: RDUSER&lt;br&gt;
Tier: standard&lt;br&gt;
Type: String&lt;br&gt;
datatype: text&lt;br&gt;
value: admin&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RDPASS&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;parameter: RDPASS&lt;br&gt;
Tier: standard&lt;br&gt;
Type: Secure String&lt;br&gt;
datatype: text&lt;br&gt;
value: admin123&lt;/code&gt; // or enter the password you used when creating db&lt;/p&gt;

&lt;p&gt;Save all the parameters and edit the last stage of the pipeline, the deploy stage so that we can now deploy to beanstalk. Go to pipelines -&amp;gt; select the pipeline we created earlier(aws-cicd) and select it, choose edit and scroll to the deploy stage and update with the following parameters: &lt;br&gt;
&lt;code&gt;action name: deploy&lt;br&gt;
Action provider: AWS Elastic beanstalk&lt;br&gt;
Input artifact: BuildArtifact (what we defined in the build stage)&lt;br&gt;
Application name: awscicd-beanstalk&lt;br&gt;
Environment: web-server-environment&lt;/code&gt; and update the environment.&lt;/p&gt;

&lt;p&gt;Now Click on done:&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%2Fkofcjlepq7e8588m6qx9.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%2Fkofcjlepq7e8588m6qx9.png" alt=" " width="800" height="227"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scroll up and Save the pipeline. Now to test the pipeline, Click on Release change. This will trigger the pipeline to build all the steps and deploy to our beanstalk environment.&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%2Frc5gcfo90un4nmvjwnur.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%2Frc5gcfo90un4nmvjwnur.png" alt=" " width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the build successfully completes, after about 5 minutes, check the Enviroment DNS on beanstalk and see how the application is displayed&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%2Fvzy3l759eqgksybbhi1u.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%2Fvzy3l759eqgksybbhi1u.png" alt=" " width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To check if the RDS database is connected, try to log-in with the credentials&lt;br&gt;
&lt;code&gt;Username: admin_vp&lt;br&gt;
password: admin_vp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If the database is connected, we'll be channeled to the welcome page:&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%2F2mu1r6qumx4px8cav3nh.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%2F2mu1r6qumx4px8cav3nh.png" alt=" " width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wooow!!!!!!!! Congratulations, you just deployed a cicd pipeline with AWS Pipeline. Each code update detected on your branch and pushed to bitbucket will automatically deploy to beanstalk.&lt;/p&gt;

&lt;p&gt;If you succedded to build this project, please let me know in the comments, if you have difficulties i will be glad to help, just put it in the comments.&lt;/p&gt;

&lt;p&gt;I haven't included Selenium test stage for the moment, but will certainly do when all is ripe&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>cicd</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Build a Chatbot to streamline customer queries and automate tasks integrating amazon Lex and Bedrock</title>
      <dc:creator>Jones Ndzenyuy</dc:creator>
      <pubDate>Tue, 12 Nov 2024 20:20:52 +0000</pubDate>
      <link>https://dev.to/ndzenyuy/build-a-chatbot-to-streamline-customer-queries-and-automate-tasks-integrating-amazon-lex-and-bedrock-2pog</link>
      <guid>https://dev.to/ndzenyuy/build-a-chatbot-to-streamline-customer-queries-and-automate-tasks-integrating-amazon-lex-and-bedrock-2pog</guid>
      <description>&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Have you ever wondered about the technology behind chatbots found on websites that interacts with users and answers FAQs? If you have ever looked for a solution to a problem about a service on any website and you happen to have to scroll through all the other irrelevant answers before finally getting the answer you wanted, then you'll agree with me it is time consuming. In this article, I will guide you on how to build a bot that can give precise answers about queries the users might have concerning the services on any company website as well as run automated tasks like booking a ticket, cancelling it, reschedule etc.&lt;/p&gt;

&lt;p&gt;When the user opens the website, the web UI loads and appears at the bottom right corner of the screen. Once clicked, it displays a pre-configured welcome message. If the user types any questions related to the company, the AI model searches the pre-loaded PDF files containing every information about the company, if the answer is found, the bot gives the user a human friendly and summarized response. In our case, the bot will not only answer FAQs, but will help users book travel tickets, give the different destinations, let them choose between classic or VIP travel options with their different tariffs.&lt;br&gt;
The technologies involved are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon Lex&lt;/li&gt;
&lt;li&gt;AWS S3&lt;/li&gt;
&lt;li&gt;Amazon Bedrock&lt;/li&gt;
&lt;li&gt;Amazon Polly&lt;/li&gt;
&lt;li&gt;AWS IAM&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd0z9cod5cn0hzflvqx35.jpg" 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%2Fd0z9cod5cn0hzflvqx35.jpg" alt="Architecture" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step by Step guide to build it
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Create a Lex Bot
&lt;/h3&gt;

&lt;p&gt;Open the AWS console and search &lt;strong&gt;Amazon Lex&lt;/strong&gt;, choose &lt;strong&gt;create Bot&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Descriptive Bot&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Bot name: web-assistant&lt;br&gt;
 runtime role: Create a role with basic Amazon Lex permissions = true&lt;br&gt;
 Children’s Online Privacy Protection Act (COPPA) = no&lt;br&gt;
 Idle session timeout = 5mins&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now click Next, for the &lt;strong&gt;Descriptive Bot Builder - GenAI&lt;/strong&gt; enter this text: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Objective: we are a travel agency that transport passengers to different destinations in Cameroon. I want a bot that can book a journey, cancel a journey, check reservation details, Get travel status, reschedule a journey. We use ticket_id to identify the client. we offer two travel classes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For the other parameters, allow defaults and click done. Give it between two to 3 minutes to create the intents. When the intents are created on the green success bar that appears above to notify the intents were successfully created, click on review. In the next page that appears, you will see the different intents created. If you are happy with the intents, click "Accept intents" these intents will be included in the prompt for building the model.&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%2F5py86i8562w41a0nkrbp.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%2F5py86i8562w41a0nkrbp.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Till now all the intents are the automatically generated, meaning the bot knows nothing about our company, only expects specific data in order to treat the request, say if the destination city isn't in it's database, then it'll not accept any other answer. So we have to personalize the bot in order to accept our company data, say we only travel to few towns, our tarrifs are in local currency. My generated intents are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BookJourney&lt;/li&gt;
&lt;li&gt;CheckReservationDetails&lt;/li&gt;
&lt;li&gt;GetTravelStatus&lt;/li&gt;
&lt;li&gt;CancelJourney&lt;/li&gt;
&lt;li&gt;RescheduleJourney&lt;/li&gt;
&lt;li&gt;FallbackIntent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are therefore going to add a knowledge base which Amazon Lex will interact with in order to give us answers specific to our company. In order to personalize the different intents to go into the knowledge base and look for the required information, we need to configure each of them:&lt;/p&gt;
&lt;h3&gt;
  
  
  Configure BookJourney intent
&lt;/h3&gt;

&lt;p&gt;Click &lt;strong&gt;BookJourney&lt;/strong&gt; inside the intents page and scroll down to slots&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%2Fppykib2qn6jt3fkreg8y.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%2Fppykib2qn6jt3fkreg8y.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;em&gt;Prompt for slot: DepartureCity&lt;/em&gt; &lt;br&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%2Fd0hvpoymhewkwft5bpdg.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%2Fd0hvpoymhewkwft5bpdg.png" alt=" " width="800" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then go to Advanced options and configure the following&lt;br&gt;
&lt;code&gt;Enhance this slot with the assisted slot resolution feature: enable&lt;br&gt;
Runtime generative AI features: enable&lt;br&gt;
Select model: Anthropic, Claude instant and save&lt;/code&gt; &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%2Fmprgtflfc7h6cc2fy3zj.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%2Fmprgtflfc7h6cc2fy3zj.png" alt=" " width="800" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back on go to intents -&amp;gt; BookJourney -&amp;gt; advanced options -&amp;gt; *&lt;em&gt;Enable assisted slot resolution - GenAI = true *&lt;/em&gt; -&amp;gt; Save intent.  This sets the chatbot to seek the knowledge base for specific type of answers.&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%2Fxyxei77l97bskwu53j0u.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%2Fxyxei77l97bskwu53j0u.png" alt=" " width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repeat the same activity for all the slots that have as type &lt;strong&gt;AMAZON.city&lt;/strong&gt; or &lt;strong&gt;AMAZON.date&lt;/strong&gt;, remember to save each time you enable the assisted slot resolution. Check for the intents and make sure they are configured to seek assistance from AI in order to manage the &lt;strong&gt;City&lt;/strong&gt; and &lt;strong&gt;Date&lt;/strong&gt; slots. This will help users give cities that are in the company data and for dates, the user can be prompted and they respond with either today, tomorrow or in two weeks and the model figures out the date based on the present date.&lt;/p&gt;

&lt;p&gt;After finishing and saving the intents, go to &lt;strong&gt;Slot types&lt;/strong&gt; and select &lt;strong&gt;ClassType&lt;/strong&gt;&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%2Fujyg3zqevf3orwve181i.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%2Fujyg3zqevf3orwve181i.png" alt=" " width="800" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the class values, we will input VIP and Classic, just as it is done in the image below: &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%2F71apla5y1p19u4csrhc4.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%2F71apla5y1p19u4csrhc4.png" alt=" " width="800" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click save slot type. Then Click on &lt;strong&gt;Build&lt;/strong&gt; to make sure all changes are saved&lt;/p&gt;
&lt;h3&gt;
  
  
  Create S3 bucket and store company data
&lt;/h3&gt;

&lt;p&gt;Go to the console and search &lt;strong&gt;S3&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Create bucket&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Bucket name: knowledge-base-bucket-xxx (xxx are random numbers to make the bucket name unique)&lt;br&gt;
region: us-east-1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Upload data that has the data of the company, this include every service, cost etc that the company sells. In our case, lets use this text and convert to pdf and upload to our S3 bucket.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;General Express Description:
Welcome to the General Express chatbot! We are dedicated to providing exceptional travel services across various destinations in Cameroon, with our headquarters located in Bafoussam. Our mission is to ensure a comfortable, convenient, and enjoyable travelexperience for all our customers. Key Features:
Travel Destinations and Pricing:
Our chatbot can assist you in exploring our travel routes and pricing options:
Bafoussam to Douala: 4000 XAF (Classic) | 6000 XAF (VIP)
Bafoussam to Yaoundé: 5000 XAF (Classic) | 6500 XAF (VIP)
Bafoussam to Bangante: 1000 XAF (Classic) | 1500 XAF (VIP)
Bafoussam to Bafang: 1000 XAF (Classic) | 1500 XAF (VIP)
Bafoussam to Bamenda: 2000 XAF (Classic) | 2500 XAF (VIP)
Bafoussam to Buea: 6000 XAF (Classic) | 7000 XAF (VIP)
Luggage Handling:
Our team will assess the value of your luggage before departure, ensuring safe and secure transport. Travel Schedules:
The chatbot provides information about our travel times:
Morning Journeys: 6 AM to 10 AM
Day Journeys: 11 AM to 5 PM
Night Journeys: 6 PM to 2 AM
Complimentary Meals:
Enjoy complimentary meals during your journey, enhancing your travel experience without any additional costs. Customer Service:
Our friendly and welcoming personnel are committed to ensuring your comfort and satisfaction throughout your travels. If you have any questions or need assistance, our chatbot is here to help!
Contact Information:
For further inquiries or to make a reservation, feel free to reach us at:
Phone: 600000000
Phone: 800000000
Conclusion:
The General Express chatbot is designed to make your travel
planning seamless and efficient. Whether you need information about
routes, pricing, or travel schedules, we are here to assist you at every step. Experience the joy of travel with General Express, where customer satisfaction is our top prior

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a knowledge base for Amazon Bedrock
&lt;/h3&gt;

&lt;p&gt;Go to the search bar in the console and search &lt;strong&gt;Amazon Bedrock&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Builder Tools&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Knowledge basses&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Create knowledge Base&lt;/strong&gt;. &lt;br&gt;
Provide the following details:&lt;br&gt;
&lt;code&gt;Knowledge base name: travel-assistant-knowledge-base&lt;br&gt;
IAM: Create and use a new service role&lt;br&gt;
choose data source: S3 -&amp;gt; Next&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Configure data source: &lt;br&gt;
&lt;code&gt;data source name: travel-assistant-knowledge-base&lt;br&gt;
Data source location: this account&lt;br&gt;
S3 URI: Browse S3&lt;br&gt;
choose: knowledge-base-bucket-xxx&lt;br&gt;
next&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Select embeddings model and configure vector store&lt;br&gt;
&lt;code&gt;Embeddings modele: Titan Embeddings G1 - Text v1.2&lt;br&gt;
vector database: Quick create a new vector store = true&lt;br&gt;
next&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Review everything and create knowledge base. It will take few minutes to create. After that, we'll need to sync the knowledge base so that the LLM can read the pdf documents that are stored in our S3.&lt;/p&gt;

&lt;p&gt;After the data source is created, click on sync for the LLM to read the PDF documents in our S3 bucket. If other information or services are added to the company, it just needs to be documented and uploaded to S3, not forgetting to sync the knowledge base.&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%2Fph0fflzm3muu0qxxz3ai.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%2Fph0fflzm3muu0qxxz3ai.png" alt=" " width="800" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Lex bot QnA intent
&lt;/h3&gt;

&lt;p&gt;Go back to the Lex console and select the bot we created and select Add intent -&amp;gt; use built-in intent -&amp;gt; AMAZON.QnAIntent-GenAI feature, give intent name as GenAiIntent as in the following image&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%2Fei27lmu47moza3lsl2ro.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%2Fei27lmu47moza3lsl2ro.png" alt=" " width="632" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click Add. Next configure the intent, &lt;br&gt;
&lt;strong&gt;QnA configuration:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Select model: Anthropic Claude instant&lt;br&gt;
Knowledge store: Knowledge base for Amazon bedrock&lt;br&gt;
Knowledge base for Amazon Bedrock Id: (return to knowledge base console and copy the knowledge base id we created earlier, it has 10 characters)&lt;br&gt;
click save intent&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
 The saved intent should appear to the left of the screen amongst the intents. &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%2F5birtdnmewwsd64byno9.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%2F5birtdnmewwsd64byno9.png" alt=" " width="800" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then we have to build the the bot by clicking on the Build button(top right) and wait for the build to complete&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the Chatbot
&lt;/h3&gt;

&lt;p&gt;Click on the test button in order to start testing the bot. We need to verify the functionality of the bot before deployment. To the left of the screen, the test window opens, click on the inpect button so as to see the values. We will ask questions related to the uploaded document:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What are the destinations&lt;/li&gt;
&lt;li&gt;What are the tariffs,&lt;/li&gt;
&lt;/ul&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%2Fdmu1frpl534599uhlxwa.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%2Fdmu1frpl534599uhlxwa.png" alt=" " width="800" height="734"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Woow, we have our bot answer questions based on the knowledge base information. Next we can try to book a ticket:&lt;br&gt;
I will just type in Book a ticket, the model will identify the intent and ask the relevant questions in order to book the ticket&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%2Frptvy8yznm9z1jriy5ut.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%2Frptvy8yznm9z1jriy5ut.png" alt=" " width="800" height="734"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that instead of giving a date, i wrote tomorrow and the bot figured out and selected the date of tomorrow. With human friendly interactions, we can book a ticket for a travel agency with little efforts&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%2Ff0rt8k8yhm4j1nw1ubh4.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%2Ff0rt8k8yhm4j1nw1ubh4.png" alt=" " width="800" height="734"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking at the Inspect dashboard, the bot asks questions and populates it, this can be used to trigger lambda functions to carryout the desired task in the backend.&lt;/p&gt;

&lt;p&gt;Now we need to integrate it to our website by building a web UI chat icon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a WebUI and attach to the website
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create a version
&lt;/h3&gt;

&lt;p&gt;On the Lex console select the bot we created and select bot versions on the left panel and create a new version. This creates a snapshot of what we just built. It will create Version 1&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%2Fm5k6qb31eghdh70124pv.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%2Fm5k6qb31eghdh70124pv.png" alt=" " width="800" height="142"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an Alias
&lt;/h3&gt;

&lt;p&gt;On the left panel, under deployments, select Aliases -&amp;gt;  create Alias and fill the following &lt;br&gt;
&lt;code&gt;Alias name: travel-assistant-alias&lt;br&gt;
associate with a version: version 1&lt;br&gt;
click create&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Copy the alias ID and the bot ID as we will use it when creating the webUI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a cloud formation stack
&lt;/h3&gt;

&lt;p&gt;Open this page in a new tab &lt;a href="https://aws.amazon.com/blogs/machine-learning/deploy-a-web-ui-for-your-chatbot/" rel="noopener noreferrer"&gt;Deploy webUI for Chatbot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under the section &lt;strong&gt;Getting started with the AWS CloudFormation deployment option&lt;/strong&gt; we choose the region where we want to create the stack which should also be the same region where the bot is located(North Virginia) and click &lt;strong&gt;launch stack&lt;/strong&gt;. Search the following fields and populate them with the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lex V2 Bot configuration parameters:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;LexV2BotId: XXXXXXX (Replace X with the bot id you copied)&lt;br&gt;
LexV2BotAliasId: XXXXXXX (Replace with the alias Id)&lt;/code&gt;&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%2F0um6khfl40ja2ynp2l31.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%2F0um6khfl40ja2ynp2l31.png" alt=" " width="800" height="149"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next look for &lt;strong&gt;Web Application Parameters&lt;/strong&gt; and populate with the following:&lt;br&gt;
&lt;code&gt;WebAppParentOrigin: https://domain.com (enter the domain name where the web app is running)&lt;br&gt;
WebAppPath: /index.html   (provide the name of the file that runs the home page)&lt;br&gt;
WebAppConfBotInitialText: You can ask me for help booking a ticket or FAQ about our company Just type "Book ticket" or click on the mic and say it.&lt;br&gt;
WebAppConfBotInitialSpeech: Say 'Book ticket' to get started.&lt;br&gt;
WebAppConfToolbarTitle: Book Ticket&lt;/code&gt;&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%2Fme72gzgsy9pjnovxuiqr.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%2Fme72gzgsy9pjnovxuiqr.png" alt=" " width="800" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Acknowledge the two radio buttons under &lt;strong&gt;Capabilities&lt;/strong&gt; and create the stack.&lt;/p&gt;

&lt;p&gt;It will open a cloud formation console, wait for it to finish creating.&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%2Fqor50844lc4amigc8bbw.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%2Fqor50844lc4amigc8bbw.png" alt=" " width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creation is completed, go to outputs and look for the SnippetsUrl&lt;br&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%2F03psh0u2fthc7mqktrx9.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%2F03psh0u2fthc7mqktrx9.png" alt=" " width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the code snippet and go to the index.html file of the running website and paste it in the body part of the html code. Do necessary updates on the website to display the newly configured index.html file. In my case, it is a static website hosted in an S3 bucket. So i will upload the index.html to the S3.&lt;/p&gt;

&lt;p&gt;Now open the website, you should see the chatbot open to the bottom right side of the screen&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%2F1wah0u8mwefirr0r0726.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%2F1wah0u8mwefirr0r0726.png" alt=" " width="800" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you click the chat icon&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%2Fyty8swxg7en69lrn5gni.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%2Fyty8swxg7en69lrn5gni.png" alt=" " width="800" height="644"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And voila!! We have successfully integrated a chatbot to our website.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>devops</category>
      <category>cloudcomputing</category>
      <category>bedrock</category>
    </item>
    <item>
      <title>Harnessing AWS Bedrock: Create a Generative AI PDF Chatbot</title>
      <dc:creator>Jones Ndzenyuy</dc:creator>
      <pubDate>Sat, 02 Nov 2024 20:58:56 +0000</pubDate>
      <link>https://dev.to/ndzenyuy/harnessing-aws-bedrock-create-a-generative-ai-pdf-chatbot-3d4h</link>
      <guid>https://dev.to/ndzenyuy/harnessing-aws-bedrock-create-a-generative-ai-pdf-chatbot-3d4h</guid>
      <description>&lt;p&gt;Have you started your AI journey and want to implement a project that will help you build hands on experience with Gen AI using Amazon Bedrock? Well worry no more because in this project, I will guide you through an end to end project to build a sophisticated chatbot. It will enable users to interact with PDF documents smoothly. The app is conceived such that, a user can ask a question and the bot responds with an answer from the uploaded file. If it doesn’t find a response, it will report it. The user can upload files of maximum 200MB and the app will manage without difficulties thanks to the power of Bedrock LLM&lt;/p&gt;

&lt;p&gt;I will guide you through a set of tools and technologies to create this application so as to guarantee reliable performance and an easy to use user interface, these tools include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon bedrock&lt;/li&gt;
&lt;li&gt;AWS S3&lt;/li&gt;
&lt;li&gt;AWS EC2&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Langchain&lt;/li&gt;
&lt;li&gt;Streamlit&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0rvysxbc4xbm2leb2up.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%2Fj0rvysxbc4xbm2leb2up.png" alt=" " width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Principle
&lt;/h2&gt;

&lt;p&gt;The app is conceived such that, when a user visits the web page, the first thing he is asked to do is to upload a pdf file. The file is processed using PyPDF and divides it into chunks. The chunks are then converted into vectors which is a representation of the PDF’s content. The generated vectors are stored in an S3 bucket for access and retrieval when the user asks a question. &lt;br&gt;
When there is a query from the user, the application processes the vector from the S3 to seek similarities, it then generates a prompt with a query and context which are then used as input for our LLM(Jurassic-2 Mid) which then generates the answer for the user. The application runs in a Docker container, using Streamlit to create a visually appealing UI. &lt;/p&gt;

&lt;h2&gt;
  
  
  How to build It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Launch an EC2 instance
&lt;/h3&gt;

&lt;p&gt;Login to AWS console and Launch a  t2.micro instance with the following configuration&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Name: pdf-Chat-Bot&lt;br&gt;
    Instance type: t2.micro&lt;br&gt;
    AMI: Ubuntu:latest&lt;br&gt;
    Volume: 8GiB&lt;br&gt;
    Security gate: Create new&lt;br&gt;
        - inbound rules &lt;br&gt;
            =&amp;gt; allow 8083 from everywhere&lt;br&gt;
            =&amp;gt; allow ssh from my IP  &lt;br&gt;
    launch template:&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!bin/bash
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release &amp;amp;&amp;amp; echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;`&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an IAM Role for the EC2 instance to access Bedrock and S3
&lt;/h3&gt;

&lt;p&gt;Go to AWS console -&amp;gt; IAM -&amp;gt; Roles -&amp;gt; Create role&lt;/p&gt;

&lt;p&gt;&lt;code&gt;    name: pdfBotRole&lt;br&gt;
     attach policies: &lt;br&gt;
       - AmazonBedrockFullAccess&lt;br&gt;
       - AmazonS3FullAccess&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Attach role to EC2 instance
&lt;/h3&gt;

&lt;p&gt;Go to the EC2 console, select the instance then go to Actions -&amp;gt; Security -&amp;gt; Modify IAM role&lt;br&gt;
Select the IAM role previously created "pdfBotRole" and click Apply&lt;/p&gt;

&lt;h3&gt;
  
  
  Create S3 bucket
&lt;/h3&gt;

&lt;p&gt;On the console, search S3 then create a bucket with the following(xxx are random numbers to make the bucket name unique)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;name: bedrock-chatpdf-xxx&lt;br&gt;
    region: us-east-1&lt;br&gt;
    allow defaults and choose create&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Copy the bucket name as we'll use it in the next steps&lt;/p&gt;

&lt;h3&gt;
  
  
  SSH into the instance and clone Source code
&lt;/h3&gt;

&lt;p&gt;Copy the public address of the instance and open a terminal&lt;br&gt;
&lt;code&gt;ssh -i "path/to/.pem-file" &lt;br&gt;
 ubuntu@public-ip-address&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Verify docker installation&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker ps&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If docker is installed, will see a table for existing docker containers which will of course be empty.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clone source
&lt;/h3&gt;

&lt;p&gt;Open a terminal and run the following&lt;br&gt;
&lt;code&gt;    git clone https://github.com/Ndzenyuy/chatPdf.git&lt;br&gt;
    cd chatPdf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the cloned source code, we have the following files/folders &lt;br&gt;
&lt;code&gt;Dockerfile&lt;br&gt;
 application.py&lt;br&gt;
 requirements.txt&lt;br&gt;
 /images&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Access for LLM models in Amazon Bedrock
&lt;/h3&gt;

&lt;p&gt;On the console Amazon Bedrock -&amp;gt; Base models -&amp;gt; Model Access&lt;br&gt;
Make sure you have access to &lt;code&gt;&lt;/code&gt;&lt;code&gt;Jurassic-2 Ultra&lt;/code&gt;&lt;code&gt;&lt;/code&gt; and &lt;code&gt;&lt;/code&gt;&lt;code&gt;Titan Embeddings G1 - Text&lt;/code&gt;&lt;code&gt;&lt;/code&gt;, if not you can request access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build and Run App docker image
&lt;/h3&gt;

&lt;p&gt;Make sure you are inside chatPdf folder and run the following command&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker build -t chatPdf-app .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The image will be built, then we can run it with the following&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run -d -e BUCKET_NAME="yourBucketName" -p 8083:8083 chatPdf&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now copy the public IP of the EC2 instance and type it on the browser followed by the port number 8083. For instance&lt;/p&gt;

&lt;p&gt;&lt;code&gt;XX.XX.XX.XX:8083&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use the App
&lt;/h2&gt;

&lt;p&gt;The landing page will first require the user to upload a pdf document&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%2Fq45o6nfi4frigwsb3yan.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%2Fq45o6nfi4frigwsb3yan.png" alt="Landing Page" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Either drag and drop or Click on the button "Browse files" Load the PDF document and ask questions based on its content&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%2Fh3wi7siwxtug0wt9503c.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%2Fh3wi7siwxtug0wt9503c.png" alt="Query Page" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;This project happens to be an innovative PDF chatbot application that will reduce significantly the time researchers spend on reading PDF of articles and books. It transforms hours of traditional page by page reading and trying to understand irrelevant information as to the current needs, into just few prompts and interactive engagements, users can efficiently understand the content, authorship, summaries and in depth knowledge of pdf documents&lt;/p&gt;

&lt;p&gt;This app will serve as a valuable tool for students harnessing their ability of interacting with academic articles and literature. By leveraging the procedure of further breaking complex texts, it does not only save time but builds a sense of critical thinking and asking of relevant questions&lt;/p&gt;

</description>
      <category>devops</category>
      <category>aws</category>
      <category>amazonbedrock</category>
    </item>
  </channel>
</rss>
