The Guide to Terraform DevOps: Implementing CI/CD Pipelines for EKS workloads with GitHub Actions for Multi-Environments Approach
This technical handbook offers a comprehensive guide on implementing CI/CD Pipelines for EKS workloads using GitHub Actions for Multi-Environments, alongside Terraform for provisioning and HashiCorp Vault for securing secrets, SonarCloud for code quality analysis, and Trivy for vulnerability scanning. GitHub Actions will manage the conventional DevOps workflows, establishing multiple predefined environments for the deployment pipeline, such as DEV, Staging, UAT, Pre-prod, and production. Throughout this article, we’ll illustrate our approach using a React-based e-commerce application as a case study.
-
More links: [@The Guide to Terraform DevOps: Kubernetes Tools in Infrastructure as Code (IaC)] (https://towardsaws.com/the-guide-to-terraform-devops-kubernetes-tools-e39f2fc6b554) [@The Guide to Terraform DevOps: Implementing CI/CD Pipelines for EKS workloads with GitHub Actions for Multi-Environments Approach] (https://towardsaws.com/the-guide-to-terraform-devops-implementing-ci-cd-pipelines-for-eks-workloads-with-github-actions-b6a08cc984b0)
To enhance readability, this handbook is divided into chapters and split into parts. The first, part, “A step-by-step guide for AWS EC2 provisioning using Terraform: HA, ALB, VPC, and Route53 — Part 1”, and the second part “A step-by-step guide for AWS EC2 provisioning using Terraform: HA, CloudFront, WAF, and SSL Certificate — Part 2”, and “A step-by-step guide for AWS EC2 provisioning using Terraform: Cloud Cost Optimization, AWS EC2 Spot Instances, CloudWatch, SNS, Lambda — Part 3”, was covered in a separate article to keep the reading time manageable and ensure focused content. The next part or chapter will be published in the next post, upcoming in a few days, “A step-by-step guide for AWS EC2 provisioning using Terraform: VPC peering, VPN, Site-to-site Connection, tunnels ( multi-Cloud ) — Part 12“ and so much more !!
🌟Upcoming Next !! https://joelotepawembo.medium.com/the-guide-to-terraform-devops-aws-ec2-instance-using-iac-9e39075a48fb 🚀 A step-by-step guide for AWS EC2 provisioning using Terraform: Azure VM and Networking (multi-cloud preparations) - Part 4 🚀 A step-by-step guide for AWS EC2 provisioning using Terraform: Terraform Error locking state error acquiring the state lock - Part 5 🚀 A step-by-step guide for AWS EC2 provisioning using Terraform: remote-exec Provisioner & user data - Part 6 🚀A step-by-step guide for AWS EC2 provisioning using Terraform: AWS EC2 Pricing - Part 7 🚀A step-by-step guide for AWS EC2 provisioning using Terraform: Automating aws ec2 ubuntu AMIs using terraform aws_ami data source - Part 8 🚀 A step-by-step guide for AWS EC2 provisioning using Terraform: EC2 Auto scaling using Terraform for high availability and resource optimization - Part 9 🚀 A step-by-step guide for AWS EC2 provisioning using Terraform: Deploying React with NGINX to EC2 using GitHub Actions (end-to-end CI/CD pipeline ) - Part 10 🚀 A step-by-step guide for AWS EC2 provisioning using Terraform: EC2 and Compliance - Part 11 🚀 A step-by-step guide for AWS EC2 provisioning using Terraform: VPN, VPC peering, Site-to-site Connection, tunnels, AWS VPN, Azure VPN client & Gateway (multi-cloud) using Terraform - Part 12 🚀 A step-by-step guide for AWS EC2 provisioning using Terraform: Azure and AWS VPN Site-to-site Connection for EC2 (multi-cloud) using Terraform - Part 13 🚀 A step-by-step guide for AWS EC2 provisioning using Terraform: How to set up SSM ( AWS Systems Manager ) for EC2? - Part 14 and Much More …
Before we get into the good stuff, we first need to make sure we have the required services on our local machine or dev server, which are:
- AWS Account
- GitHub Account
- AWS CLI installed and configured.
- Docker installed locally.
- NPM
- NodeJS
- Terraform
- Basic Understanding of Jenkins
- A Domain name Hosted by any domain name provider ( Ex: AWS Route 53 )
- Basic familiarity with YAML and GitHub workflows.
- A React Project hosted in a GitHub repository
- Basic knowledge of HTML or React
- Any Browser for testing
- #1 Create AWS Access Keys
- Set Up Custom Domain
- Create your React / Front-End Application 🎉
- #2 Provision an AWS EC2 instance with Ansible
- Jenkins Installation
- Setting up a CI/CD pipeline using Terraform 🎉
- Terraform Cloud Configuration
- Check result in your AWS Management Console 🎉
@octocat 👍 This project looks great - Let’s Get It Started!
In the project directory, you can run:
Runs the app in the development mode.
Open http://localhost:3000 to view it in your browser.
The page will reload when you make changes.
You may also see any lint errors in the console.
DOCKER_SCAN_SUGGEST=false docker build -t prodxcloud-store:latest .
docker run -p 80:80 --name react prodxcloud-store:latest
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
Next, configure your aws account in your computer using the following command:
aws configure
npm run build
# 1. This creates a public (.pub) and private key in the ~/.ssh/ directory
ssh-keygen -t rsa -b 4096 -f ~/.ssh/myKey
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): # Can be left blank
# 2. Ensure private key is not publicly viewable
chmod 400 ~/.ssh/mykey
Note
This project contains multiple types of deployments.
# Github Workflows Terraform Pipeline Provision To Deploy to AWS EKS
name: PRODUCTION --> Terraform CI/CD pipeline To AWS EKS Cluster - Enterprise
concurrency:
group: production
cancel-in-progress: true
on:
push:
branches: [master, production/*]
pull_request:
types: [review_requested]
branches: [master, production/*]
workflow_dispatch:
inputs:
git-ref:
description: Git Ref (Optional)
default: master
required: false
account:
description: production
default: production
required: true
account_prod:
description: production
default: production
required: true
environment:
description: production (final, latest)
default: production
required: false
env:
TF_LOG: INFO
APP_NAME: prodxcloud-store
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
DOCKER_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }}
KUBE_CONFIG_DATA: ${{ secrets.KUBE_CONFIG_DATA }}
AWS_DEFAULT_REGION: "us-east-1"
CONFIG_DIRECTORY: "./deployment/terraform/terraform-provision-ekscluster-use-case-1"
jobs:
CodeScan-SonarCloud:
name: SonarCloud Scaning
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Code Scaning process
run: pwd
build:
name: build
runs-on: ubuntu-latest
needs: [CodeScan-SonarCloud]
strategy:
matrix:
node-version: [18]
steps:
- uses: actions/checkout@v3
# caching mechanisme
- name: Cache dependencies
uses: actions/cache@v2
with:
path: |
**/node_modules
key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
# npm install all packages
- name: Install dependencies
run: npm install --legacy-peer-deps
# run: npm version
- name: Build reactjs application
run: npm run build --if-present
- name: list all packages & dependencies
run: npm list
# Dockerhub Build and Push
- name: Build docker docker image for production
uses: docker/login-action@v2
with:
username: ${{ env.DOCKER_USERNAME }}
password: ${{ env.DOCKER_PASSWORD }}
- run: docker build -t joelwembo/prodxcloud-store:prod .
- run: docker push joelwembo/prodxcloud-store:prod
- run: docker version
trivyScanDockerImage:
name: trivy scan - security scanner
runs-on: ubuntu-latest
if: ${{ always() }}
needs: [CodeScan-SonarCloud, build]
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Build an image from Dockerfile
run: |
docker version
# docker build -t docker.io/joelwembo/prodxcloud-store:prod .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'docker.io/joelwembo/prodxcloud-store:prod'
format: 'table'
# exit-code: '1'
ignore-unfixed: true
vuln-type: 'os,library'
severity: 'CRITICAL,HIGH'
- name: Push Docker Image for production
run: docker push joelwembo/prodxcloud-store:prod
qa:
name: QA Deploy to Staging
environment:
name: staging
url: https://staging.production.net/
runs-on: ubuntu-latest
needs: [build, trivyScanDockerImage]
steps:
- name: Running Tests
uses: actions/checkout@v3
- run: echo "running Tests"
# - run: npm test
deploy:
name: Deploy to EKS
environment:
name: production
url: https://production.prodxcloud.net/
runs-on: ubuntu-latest
needs: qa
strategy:
matrix:
environment: [production]
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Terraform Setup and Apply
id: terraform_apply
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.1.7
# cli_config_credentials_hostname: 'terraform.example.com'
# cli_config_credentials_token: ${{ env.TF_API_TOKEN }}
- name: Terraform Init
run: terraform init
working-directory: ./deployment/terraform/terraform-provision-ekscluster-use-case-1
- name: Terraform Plan
id: terraform_plan
run: terraform plan -out=tfplan -var="environment=${{ matrix.environment }}"
working-directory: ./deployment/terraform/terraform-provision-ekscluster-use-case-1
- name: Terraform Apply
if: matrix.environment == 'qa' || matrix.environment == 'production'
run: terraform apply -auto-approve -input=false -lock=false
working-directory: ./deployment/terraform/terraform-provision-ekscluster-use-case-1
- name: Kubernetes Setup
uses: azure/k8s-set-context@v1
with:
kubeconfig: ${{ env.KUBE_CONFIG_DATA }}
- name: Update kubeconfig
run: aws eks --region us-east-1 update-kubeconfig --name prodxcloud-cluster
env:
AWS_ACCESS_KEY_ID: ${{ env.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ env.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ env.AWS_DEFAULT_REGION}}
- name: Get Kubernetes Pods
run: kubectl get pods --namespace default
- name: Get Kubernetes Nodes
run: kubectl get nodes
- name: Get Kubernetes Services
run: kubectl get services --namespace default
- name: Get Load Balancer DNS
run: kubectl get services prodxcloud-store
outputs:
APP_NAME: prodxcloud-store
AWS_ACCESS_KEY_ID: ${{ env.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ env.AWS_SECRET_ACCESS_KEY }}
DOCKER_USERNAME: ${{ env.DOCKERHUB_USERNAME }}
DOCKER_PASSWORD: ${{ env.DOCKERHUB_TOKEN }}
KUBE_CONFIG_DATA: ${{ env.KUBE_CONFIG_DATA }}
AWS_DEFAULT_REGION: ${{ env.AWS_DEFAULT_REGION }}
# - name: Kubernetes Deployment
# run: kubectl apply -f k8s/deployment.yaml
kubectl get svc
kubectl apply -f k8s/aws-test.yaml
kubectl exec aws-cli -- aws s3api list-buckets
kubectl get pods
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/public-lb.yaml
kubectl apply -f k8s/private-lb.yaml
kubectl get pods
kubectl get services
kubectl apply -f k8s/cluster-autoscaler.yaml
kubectl get pods -n kube-system
kubectl expose deployment prodxcloud-store --type=LoadBalancer --port=80 --target-port=80 -n prodxcloud-store --name=prodxcloud-store
Expose the application without namespace because we are the default namespace
kubectl expose deployment prodxcloud-store --type=LoadBalancer --port=80 --target-port=80 --name=prodxcloud-store
kubectl get services prodxcloud-store
kubectl get svc
- commit : added new feature for multi stage deployment
- commit : add new environment before production
Thank you for Reading !! 🙌🏻, see you in the next article.🤘
- @Joel O. Wembo
- More links:
[@The Guide to Terraform DevOps: Kubernetes Tools in Infrastructure as Code (IaC)] (https://towardsaws.com/the-guide-to-terraform-devops-kubernetes-tools-e39f2fc6b554)
[@The Guide to Terraform DevOps: Implementing CI/CD Pipelines for EKS workloads with GitHub Actions for Multi-Environments Approach] (https://towardsaws.com/the-guide-to-terraform-devops-implementing-ci-cd-pipelines-for-eks-workloads-with-github-actions-b6a08cc984b0)
- Email : [email protected]