How to Deploy a Go Web App on AWS EKS Using CI/CD with GitHub Actions and More

Introduction

In this blog post, Iโ€™ll walk you through the process of deploying a Go web application on an Amazon EKS cluster using Docker, Helm, and ArgoCD. We'll also set up a CI/CD pipeline with GitHub Actions to automate the deployment process.

This project was inspired by Abhishek Veermalla, whose tutorial helped me navigate through these technologies. ๐Ÿš€

GitHub repository (VishuPatel-27).

Prerequisites

Before we dive into the steps, make sure you have the following tools installed:

  • Go (1.22 or later)

  • Docker

  • Kubernetes (kubectl)

  • AWS CLI

  • eksctl (for EKS cluster management)

  • Helm

  • ArgoCD

  • GitHub Actions (for CI/CD automation)


Step-by-Step Implementation

Step 1: Clone the Go Web Application

First, we clone the Go web application from the GitHub repository:

git clone https://github.com/iam-veeramalla/go-web-app.git
cd go-web-app

Step 2: Containerizing the Application

Next, we create a multi-stage Dockerfile to build and package our Go web app efficiently.

Hereโ€™s a Dockerfile:

# we are using golang image to build our application
FROM golang:1.22 AS builder

# Set the Current Working Directory inside the container
WORKDIR /app

# Copy go mod
COPY . .

# Download all dependencies. Dependencies will be cached if the go.mod is not changed
RUN go mod download

# Build the Go app
RUN go build -o main .

# Start a new stage from scratch
FROM gcr.io/distroless/base

# Copy the Pre-built binary file from the previous stage
COPY --from=builder /app/main .

# Copy the static files
COPY --from=builder /app/static /static

# expose the port on which the application will run
EXPOSE 8080

# Command to run the executable
CMD ["./main"]

Step 3: Run the Docker Image Locally

To verify our Docker image, we build and run it locally:

docker build -t go-webapp:v1.0 .
docker run -p 8080:8080 go-webapp:v1.0

Check if the app is accessible at http://localhost:8080/courses.

Step 4: Push the Docker Image to Docker Hub

Once verified, push the image to Docker Hub:

docker tag go-webapp:v1.0 <your-dockerhub-username>/go-webapp:v1
docker push <your-dockerhub-username>/go-webapp:v1

Step 5: Create Kubernetes Manifests

We create three K8s manifest files:

  1. deployment.yaml: Defines how the app is deployed.

  2. service.yaml: Exposes the app internally.

  3. ingress.yaml: Handles external traffic routing.

Apply the manifests later when the cluster is ready.

Step 6: Create an EKS Cluster

We use eksctl to set up an EKS cluster with a single t2.medium instance:

eksctl create cluster --name go-webapp-cluster \
  --region us-east-1 \
  --nodegroup-name go-webapp-ng \
  --node-type t2.medium \
  --nodes 1

Step 7: Install the Nginx Controller and Configure DNS

To manage incoming traffic, we install the Nginx Ingress Controller:

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

Then, configure the local DNS record for the app.

How to Add a Custom DNS Record to Your Hosts File

In this guide, I'll show you how to map the domain go-webapp.local to the IP address of nginx controller by editing your host file. This is especially useful for local development and testing environments. Follow the step-by-step instructions below for both Windows and Ubuntu.

This Nginx controller on the EKS cluster is basically a network load balancer. You can find this IP address by using the command kubectl get all -o wide -n ingress-nginx or kubectl get ingress. After that, take that IP address and run this command nslookup <ip-address> on your terminal, and you will get the IP address of the Nginx controller.

For Windows

  1. Open Notepad as Administrator:

    • Click the Start menu, search for Notepad, right-click the app, and choose Run as administrator.

    • Accept the UAC prompt if it appears.

  2. Open the Hosts File:

    • In Notepad, go to File > Open.

    • Navigate to:
      C:\Windows\System32\drivers\etc\

    • Change the file type to All Files (.) at the bottom right, then select the file named hosts and click Open.

  3. Add Your DNS Record:

    • Scroll to the bottom of the file and add the following line:

        <ip-address> go-webapp.local
      
    • Ensure a space or tab between the IP address and the domain.

  4. Save the File:

    • Click File > Save and then close Notepad.
  5. Flush the DNS Cache (Optional but Recommended):

    • Open Command Prompt as Administrator (search for cmd, right-click, and select Run as administrator).

    • Run the following command:

        ipconfig /flushdns
      
    • Press Enter to ensure your system uses the updated DNS settings immediately.

For Ubuntu

  1. Open the Terminal:

    • Press Ctrl+Alt+T to launch the Terminal.
  2. Edit the Hosts File:

    • Use your favourite text editor. For example, with nano, type:

        sudo nano /etc/hosts
      
    • Enter your password if prompted.

  3. Insert the DNS Record:

    • Scroll down to the bottom of the file and add:

        <ip-address> go-webapp.local
      
    • Ensure at least one space or tab between the IP address and the domain.

  4. Save and Exit:

    • If using nano, press Ctrl+O to save (confirm with Enter) and then Ctrl+X to exit.
  5. Flush the DNS Cache (If Needed):

    • While Ubuntu usually applies changes to the hosts file immediately, if youโ€™re using a DNS cache (like systemd-resolved), restart it with:

        sudo systemctl restart systemd-resolved
      
    • Alternatively, a reboot will also apply the changes.


Verification

To ensure everything is set up correctly, open a terminal (or Command Prompt on Windows) and run:

ping go-webapp.local

Step 8: Deploy the Application on EKS Using K8s Manifests

Now, we deploy our application using the created Kubernetes manifests. This step is completely optional. If you want to verify the deployment, then you can definitely go with this step.

kubectl apply -f k8s/manifests/

Verify the deployment:

kubectl get pods -n default

Step 9: Deploy Using Helm Charts

To simplify deployment, we create a Helm chart and deploy it (make sure you remove the previous deployment that you deployed using the k8โ€™s manifests):

helm install go-webapp-stack -n go-webapp-ns . -f values.yaml --create-namespace

Verification:

Go to your favourite browser and access the application on go-webapp.local/courses.

Step 10: Set Up CI/CD Pipeline with GitHub Actions

We define a GitHub Actions workflow (.github/workflows/ci.yaml) to automate builds, tests, and deployments.

# CI using the gihub actions

# name of the workflow
name: CI - GitHub Actions

# when the workflow should be triggered
on:
  push:
    branches:
      - main

    # paths to ignore
    paths-ignore:
      - README.md
      - helm/**

# jobs that will be executed

jobs:

  # job name
  build:

    # runs on ubuntu-latest
    runs-on: ubuntu-latest

    # steps to be executed
    steps:

      # checkout the repository
      - name: Checkout repository
        uses: actions/checkout@v4

      # setup go
      - name: Setup Go
        uses: actions/setup-go@v2
        with: # arguments for the action
          go-version: 1.22

      # build the application
      - name: Build
        run: go build -o go-webapp .

      # run the tests
      - name: Unit tests
        # run the tests in all possible directories
        # ./... means all possible directories
        run: go test ./...    


  # static code analysis
  code-quality:

    # defined the runner for the job
    runs-on: ubuntu-latest

    # steps to be executed
    steps:

      # checkout the repository
      - name: Checkout repository
        uses: actions/checkout@v4

      # static code analysis
      - name: static code analysis
        uses: golangci/golangci-lint-action@v6  
        with:
          version: latest

  # build and push the docker image
  docker:

      # defined the runner for the job
      runs-on: ubuntu-latest

      # need build job to complete before this job starts
      needs: build

      # steps to be executed
      steps:

        # checkout the repository
        - name: Checkout repository
          uses: actions/checkout@v4

        # login to docker hub
        - name: Login to Docker Hub
          uses: docker/login-action@v3
          with:
            # docker hub username and password
            username: ${{ secrets.DOCKER_USERNAME }}
            password: ${{ secrets.DOCKERHUB_TOKEN }}

        # we are using public docker registry
        # that is why we don't need to login to the docker registry

        # build the docker image
        - name: Build Docker image
          run: docker build -t go-webapp:${{ github.run_id }} .

        # tag the docker image
        - name: Tag Docker image
          # tag the image with the github sha
          # e.g. <docker-hub-username>/go-webapp:<github.run_id>
          run: docker tag go-webapp:${{ github.run_id }} ${{ secrets.DOCKER_USERNAME }}/go-webapp:${{ github.run_id }}

        # push the docker image
        - name: Push Docker image
          run: docker push ${{ secrets.DOCKER_USERNAME }}/go-webapp:${{ github.run_id }}

  update-helm-chart:

    # defined the runner for the job
    runs-on: ubuntu-latest

    # need build job to complete before this job starts
    needs: docker

    # steps
    steps:

      # checkout the repository
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          token: ${{ secrets.TOKEN }}

      # update the helm chart
      - name: Update Helm chart
        # sed [OPTIONS] 'SCRIPT' [INPUTFILE...]
        # -i: edit files in place
        #replace the tag in the values.yaml file
        run: |
          sed -i 's/tag: .*/tag: "${{ github.run_id }}"/' helm/go-webapp-helm/values.yaml

      # push the changes to the repository
      - name: Push changes
        run: |
          git config --global user.email ${{ secrets.EMAIL }}
          git config --global user.name "${{ secrets.NAME }}"
          git add helm/go-webapp-helm/values.yaml
          git commit -m "Update helm chart"
          git push

Push this file to the repo to trigger the pipeline.

Step 11: Install and Configure ArgoCD

ArgoCD ensures that our EKS deployments stay in sync with GitHub. Install ArgoCD:

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

Step 12: Verify ArgoCD Auto-Deployment

Now, edit values.yaml file in the repo and commit the changes. ArgoCD will automatically detect and deploy the changes.

Check the deployment status:

kubectl get applications -n argocd

Conclusion

Following these steps, we successfully deployed a Go web application on AWS EKS using Docker, Kubernetes, Helm, and ArgoCD. ๐Ÿš€

Key Takeaways:

  • CI/CD automation ensures seamless deployments.

  • Helm charts simplify application deployment.

  • ArgoCD enables GitOps, making deployments predictable and manageable.

Thanks again to Abhishek Veermalla, Sir, for his amazing content that helped me build this project! ๐ŸŽ‰

๐Ÿ’ฌ Have questions or feedback? Drop them in the comments! ๐Ÿ˜Š

#GoLang #Kubernetes #AWS #EKS #Docker #CI/CD #Helm #ArgoCD #GitOps #DevOps #CloudComputing

1
Subscribe to my newsletter

Read articles from Vishukumar Patel directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Vishukumar Patel
Vishukumar Patel

Hi there! Iโ€™m a DevOps enthusiast, certified in AWS, and passionate about crafting innovative cloud solutions. From designing scalable CI/CD pipelines to deploying microservices on cloud platforms, Iโ€™ve immersed myself in transforming ideas into impactful technologies.