π‘«π™šπ’—π™Šπ’‘π™¨π’Šπ™›π’Šπ™˜π’‚π™©π’Šπ™€π’ 𝒐𝙛 𝙂𝒐 π‘Ύπ™šπ’ƒ 𝑨π™₯π’‘π™‘π’Šπ™˜π’‚π™©π’Šπ™€π’

πŸ’ Overview

This project demonstrates how to deploy a Go based web application to Amazon EKS (Elastic Kubernetes Service) with a complete CI/CD pipeline using GitHub Actions, Helm, and ArgoCD.

❇ Implementation

πŸ’  Clone the Repository

Firstly, clone the repository to your local using this command

git clone https://github.com/gmanne11/go-web-app.git
# change directory to go-web-app-devops
cd go-web-app-devops

πŸ’  Prerequisites

Ensure you have the following tools installed and configured:

  • eksctl

  • kubectl

  • AWS CLI

  • Docker

  • Docker Scout

  • Helm

πŸ’  Project Overview

This project includes:

  • A Go web application

  • Dockerfile for containerization

  • Kubernetes manifests

  • Helm chart for deployment

  • GitHub Actions workflow for CI

  • ArgoCD configuration for CD

πŸ’  Local Development

  1. Build the Docker image: Build the Docker image out of Dockerfile locally using the command

     docker build -t vivekmanne/go-web-app:v1 .
    
  2. Check for the image created locally,

    As you can see, the image named go-web-app of size less than 40MB. Since we used Multi-stage-Dockerfile with Distroless base image during the run time stage helps to build leaner and more secured image.

  3. Run the application locally:

     docker run -it -p 8080:8080 vivekmanne/go-web-app:v1
    
  4. Access the application at http://localhost:8080/courses

Push the image to Docker Hub using the command like

docker push vivekmanne/go-web-app:v1

πŸ’  Kubernetes Deployment

  1. Now, change the directory to view the Kubernetes manifests (Deployment, Service, Ingress)

     cd k8s/manifests
    
  2. Create EKS cluster using the command like

     eksctl create cluster --name demo-cluster-1 --region ca-central-1
    
  3. Ensure the cluster is up and running with 2 Nodes

  4. Verify that you are using the correct cluster context

  5. Deploy the manifests to EKS cluster

     kubectl apply -f deployment.yaml 
     kubectl apply -f service.yaml
     kubectl apply -f ingress.yaml
    
  6. Verify the deployment, service and ingress are created

  7. Let's edit the service go-web-app to make it LoadBalancer type

     kubectl edit service go-web-app
    

    Make the change of LoadBalancer type as shown above.

  8. Now, get the Load balancer DNS name assigned to the service and access it from browser

  9. Deploy NGINX Ingress Controller on AWS using the below manifest

     kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.1/deploy/static/provider/aws/deploy.yaml
    

    This will ensure the NGINX ingress controller is deployed inside the EKS cluster. By default all the resources for ingress controller will be deployed in namespace ingress-nginx

  10. Now, the NGINX ingress controller will create NLB(Network load balancer) in AWS and attach to ingress. Ingress controller will watch out for Ingress resource and implements the rules defined and also assigns load balancer DNS to the ingress.

    The NLB will route the incoming traffic to the NGINX Ingress Controller, which will then process the requests based on the Ingress rules and forward them to the appropriate services within your Kubernetes cluster.

    Verify that NLB is created in AWS

Here is ingress.yaml file

  1.  # Ingress resource for the application
     apiVersion: networking.k8s.io/v1
     kind: Ingress
     metadata:
       name: go-web-app
       annotations:
         nginx.ingress.kubernetes.io/rewrite-target: /
     spec:
       ingressClassName: nginx
       rules:
       - host: go-web-app.local
         http:
           paths: 
           - path: /
             pathType: Prefix
             backend:
               service:
                 name: go-web-app
                 port:
                   number: 80
    

In our case, The Load balancer DNS route the traffic to ingress controller where ingress resource rules are validated and we used host based routing rules as you can see in the ingress.yaml. when you access go-web-app.local to forwards the traffic to service named go-web-app and eventually to target pods.

  1. Configure DNS mapping in /etc/hosts locally

    Look for the IP address of Load Balancer DNS using the following command

    nslookup afc4c1bfc57244af1948840ce42da85c-041e5d03fd06ee1c.elb.ca-central-1.amazonaws.com
    

    Then, add the DNS mapping in /etc/hosts file

Now, Access the application using go-web-app.local/home

πŸ’  Helm Chart Deployment

  1. Make sure the k8s resources are deleted before proceeding with deployment using helm chart

  2. Ensure you are in the correct directory of helm

     cd helm/
    
  3. Deploy using Helm and verify the objects are deployed

     helm install go-web-app ./go-web-app-chart
    

    The NLB automatically assigns Load Balancer DNS name to ingress hosts as u can see above.

  4. Try accessing the application again using go-web-app.local/home

πŸ’  CI/CD Pipeline

βœ… CI with GitHub Actions

  1. Check .github/workflows/cicd.yaml with the following stages:
    Checkout code

    Build and run unit tests

    Perform static code analysis

    Build and push Docker image

    Update image tag in Helm values.yaml

    Commit back to the repo Head

  2. Ensure the secrets defined in workflow file are added to Repository secrets.

    NOTE:
    Create DOCKERHUB_TOKEN in Dockerhub in case if you didn't have one

    Create Github Token and add the value for secret named TOKEN

  3. Perform a Dummy commit that should trigger workflow to build the image and pushed to Dockerhub and then update the image tag in values.yaml file.

βœ… CD with ArgoCD

  1. Install ArgoCD in the cluster

     kubectl create namespace argocd
     kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
    
  2. Verify that all resources are created in argocd namespace

  3. Now, edit the service argocd-server and make it LoadBalancer type

     kubectl edit service argocd-server -n argocd
    

  4. Verify the argocd service is gets the Loadbalancer DNS name

  5. Access the ArgoCD UI using the DNS of the load balancer

    Default Username is admin and look for the password in argocd-initial-admin-secret which was created out of the box.

     kubectl get secrets -n argocd
     kubectl edit secret argocd-initial-admin-secret -n argocd
    

  6. Now, access the ArgoCD UI using the decoded password

  7. Configure the Application

    Application name --> go-web-app

    Project Name ---> default

    Sync policy -----> Automatic
    Repository URL ---> your repo URL

    PATH ----> helm/go-web-app-chart

    Cluster URL ----> https://kubernetes.default.svc
    Namespace ----> default

    values -----> values.yaml

  8. ArgoCD will continuously reconcile the desired state from Git with the cluster state

Verify that the latest pod has pulled the most recent image and successfully started a container to run the application.

The latest image with tag 10049200755 was pulled to start a container to run the application.

πŸ’  Accessing the Application

After successful deployment, access the application at http://go-web-app.local/home in your browser.

TASK ACCOMPLISHED.....πŸ‘ βœ…

Make sure to Delete the Cluster using the command like

eksctl delete cluster --name demo-cluster-1 --region ca-central-1

For a detailed, step-by-step approach to implementing end-to-end DevOps on a Golang web application, please refer to the video.

0
Subscribe to my newsletter

Read articles from Gopi Vivek Manne directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Gopi Vivek Manne
Gopi Vivek Manne

I'm Gopi Vivek Manne, a passionate DevOps Cloud Engineer with a strong focus on AWS cloud migrations. I have expertise in a range of technologies, including AWS, Linux, Jenkins, Bitbucket, GitHub Actions, Terraform, Docker, Kubernetes, Ansible, SonarQube, JUnit, AppScan, Prometheus, Grafana, Zabbix, and container orchestration. I'm constantly learning and exploring new ways to optimize and automate workflows, and I enjoy sharing my experiences and knowledge with others in the tech community. Follow me for insights, tips, and best practices on all things DevOps and cloud engineering!