GitHub Actions: Deployment to EKS with Kustomize

If your code is on GitHub you simply must use GitHub Actions for CI/CD.

GitHub Actions syntax is very intuitive and simple. I guarantee that once you get familiar with GitHub Actions you will spend at least twice less time for writing CI/CD flow comparing to Jenkins pipeline groovy madness.

Today I’ll show how to build simple GitHub Actions Workflow that deploys microservice to AWS EKS with Kustomize.

This is our project structure:

project-structure-github-actions-eks

Create GitHub Actions Workflow YAML

In order GitHub recognize the workflow file we must put it in specific location of the project. You should put all your workflow Yamls under .github/workflows

github-actions-workflow-structure

Let’s create cd.yml it will be our deployment workflow.

name: Deploy to EKS

on:
  workflow_dispatch:
    inputs:
      IMG_TAG:
        description: "IMG_TAG"
        required: true
        default: "latest"
      ENV_OVERRIDES:
        description: "ENV OVERRIDES"
        required: false
        default: ""

jobs:
  deploy:
    name: Deploy to EKS
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Splitting Inputs Args
        run: |-
          echo ${{ github.event.inputs.ENV_OVERRIDES }} | sed "s/,/\n/g"
          echo ${{ github.event.inputs.ENV_OVERRIDES }} | sed "s/,/\n/g" > k8s/overlays/crispr/crisman.env

      - name: Print crisman.env
        run: cat k8s/overlays/crispr/crisman.env

      - 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: eu-west-1

      - name: Setting kubeconfig
        uses: azure/k8s-set-context@v1
        with:
          method: kubeconfig
          kubeconfig: ${{ secrets.KUBE_CONFIG_DATA }}
        id: setcontext

      - name: Print kubectl & kustomize versions
        run: |-
          kubectl version
          kustomize version

      - name: Kustomize Set Image
        run: |-
          cd k8s/overlays/crispr
          kustomize edit set image crisman=77777777.dkr.ecr.eu-west-1.amazonaws.com/crisman:${{github.event.inputs.IMG_TAG}}

      - name: Show kustomization.yaml
        run: |-
          cd k8s/overlays/crispr
          cat kustomization.yaml

      - name: Deploy to EKS
        run: |-
          cd k8s/overlays/crispr
          kustomize build . | kubectl apply -f -

      - name: Update Image
        run: kubectl rollout restart deployment crisman

      - name: Status
        run: |-
          kubectl get pods

GitHub Actions Steps

After pushing cd.yml to master go to your GitHub repo and click on Actions tab. There you will see our Deploy to EKS workflow. It is manual triggered workflow because we stated workflow_dispatch. We defined inputs on the beginning of the yaml it means we can provide arguments on submission. If you’ll click on Run workflow you’ll see arguments list.

run-workflow-with-arguments

Now let’s click Run and I’ll explain what is going on here.

Step 1

I defined only one job with several steps, but you can run many jobs inside your workflow. In the first step I do checkout of the code. It’s just one line of code: - uses: actions/checkout@v2

Step 2

In the second step I splitting input arguments and write them into our overlay environment variables file. In the next steps I will use kustomize to merge these arguments with existing environment variables that were already stated in the base kustomization.yaml

Step 3

Here I simply printing environment variables file content just to see that arguments were correctly inserted.

Step 4

- 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: eu-west-1

In this step I provide AWS credentials in order to be able to connect to AWS. You will probably ask where AWS_ACCESS_KEY and AWS_SECRET_ACCESS_KEY come from. You should provide them to GitHub. Click Settings -> Secrets and add all your secrets here. I also added kubeconfig file as a secret in order to be able to connect to EKS in later steps.

github-actions-secrets

Step 5

I forgot to mention that another strength of GitHub Actions is that everyone can write his own customized action and others may use it in theirs workflows, so you don’t need to implement everything by yourself.

So in this step I’m using Kubernetes set context action which brings with it kubectl, kustomize and configures kubeconfig which you must provide via secret.

- name: Setting kubeconfig
  uses: azure/k8s-set-context@v1
  with:
    method: kubeconfig
    kubeconfig: ${{ secrets.KUBE_CONFIG_DATA }}
  id: setcontext

Step 6

In this step I’m just printing out kubectl and kustomize version just for debugging purposes.

Step 7

- name: Kustomize Set Image
  run: |
    cd k8s/overlays/crispr
    kustomize edit set image crisman=7777777.dkr.ecr.eu-west-1.amazonaws.com/crisman:${{ github.event.inputs.IMG_TAG }}

In this step I’m running kustomize edit set image command which updates image tag in the deployment.yaml manifest. Docker images are stored in  AWS ECR and were uploaded there by another workflow that was triggered by pull request.

The tricky part of this command is following:

  1. kustomize changes structure of overlay kustomization.yaml and sometimes it also automatically updates deprecated keywords if you used one in it. 
  2. Different kubectl installations bring with them different versions of kustomize and backward compatibility of one to another is not always guaranteed.

This is why in the next step I print out kustomization.yaml content after running kustomize edit set image

Step 8

- name: Show kustomization.yaml
  run: |
    cd k8s/overlays/crispr
    cat kustomization.yaml

Step 9

Here we finally performing deployment to EKS bu running this command: kustomize build . | kubectl apply -f -

I want to emphasize again this – once you run kustomize edit set image command it’s crucial to do deploy with kustomize build . | kubectl apply -f -  and not with kubectl apply -k because you might fall into compatibility issues that will be hard to detect.

Step 10

kubectl rollout restart deployment command forces to fetch image from ECR and update the pod with it.
 

Step 11

And in the last step I just printing the pods status.

Seems like we covered all the flow, anyway if you have any questions please write them in the comments section.

 

LEAVE A REPLY

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.