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:
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
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.
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.
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:
kustomize
changes structure of overlaykustomization.yaml
and sometimes it also automatically updates deprecated keywords if you used one in it.- Different
kubectl
installations bring with them different versions ofkustomize
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.