Nowadays, most companies try to implement CI/CD pipelines to deploy applications to be easier. But how to implement it?
This article shows how to implement it to deploy your application on Kubernetes with GitHub Actions and ArgoCD.
I hope it can help your deployment process easier.
Before starting, Let me explain about what is GitOps. Because I will follow this methodology.
What is GitOps?
GitOps is an operational framework that takes DevOps best practices used for application development such as version control, collaboration, compliance, and CI/CD tooling, and applies them to infrastructure automation. GitOps was first coined by Weaveworks.
Based on that I will implement like below CI/CD.
Let's start building the CI/CD!
There are 5 steps to deploy your application on Kubernetes with GitHub Actions and ArgoCD.
- Build CI
- Login to ECR
- Build docker image and push it to ECR
- Update manifest file in manifest file repository
- Create PR
- Prepare Manifest file
- Build CD
- Recap 5.
1. Build CI
The first step is building the CI by using Github Actions. yaml file should be in application source code repository.
During CI, we can do testing, building docker, push docker image to repository and update manifest file!
You must create ECR on AWS and IAM role to login and push docker image to ECR. I will omit these part in this time.
Complete GHA file is below. I will explain each step by step.
on: push: branches: [deploy/stg] permissions: id-token: write contents: read jobs: prepare: name: code-deploy runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: ${{ secrets.IAM_ROLE }} aws-region: ${{ secrets.AWS_REGION }} - name: login to Amazon ECR id: ecr uses: aws-actions/amazon-ecr-login@v1 - name: docker build and push id: build-image env: ECR_REGISTRY: ${{ steps.ecr.outputs.registry }} ECR_REPOSITORY: ${{ secrets.ECR_REPOSITORY }} IMAGE_TAG: ${{ github.sha }} run: | docker build -f ./Dockerfile -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG --target release . docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" - name: fetch manifest repository uses: actions/checkout@v3 with: repository: github-organization/manifest-repository token: ${{ secrets.PAT }} path: manifest-repo fetch-depth: 1 - name: update manifest file image tag run: | wget -q https://github.com/mikefarah/yq/releases/download/v4.27.5/yq_linux_amd64 sudo mv yq_linux_amd64 /usr/local/bin/yq sudo chmod +x /usr/local/bin/yq yq e -i '.spec.template.spec.containers[0].image |= "${{ steps.build-image.outputs.image }}"' 'manifest-repo/k8s/sample/dev/deployment.yaml' - name: setup Repository working-directory: manifest-repo run: | git fetch origin main git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" git remote set-url --push origin https://github.com/***/manifest-repo.git git checkout -b release-${{ github.sha }} - name: commit working-directory: manifest-repo run: | git add . git commit -m "Release bff-admin" git push origin HEAD - name: create PR working-directory: manifest-repo run: | gh pr create -B main -H release-${{ github.sha }} -t "deploy-${{ github.sha }}" -b ""
- Login to ECR The security reason, you must avoid to pass your access key and secret key. Instead pass credential, we can use GitHub's OIDC provider in conjunction with a configured AWS IAM Identity Provider endpoint. You must create Assume role and set it to
role-to-assume
- name: configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: ${{ secrets.IAM_ROLE }} aws-region: ${{ secrets.AWS_REGION }} - name: login to Amazon ECR id: ecr uses: aws-actions/amazon-ecr-login@v1
ref: aws-actions/configure-aws-credentials
- Build docker image and push it to ECR The next step, build a docker image and push it to ECR. I prefer to import the registry name and repository name from secret. After setting these variables, run the docker command to build and push to ECR.
- name: docker build and push id: build-image env: ECR_REGISTRY: ${{ steps.ecr.outputs.registry }} ECR_REPOSITORY: ${{ secrets.ECR_REPOSITORY }} IMAGE_TAG: ${{ github.sha }} run: | docker build -f ./Dockerfile -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG --target target . docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
- Update manifest file in manifest file repository After pushing the docker image, do update the manifest file to create PR to the manifest repository. Assume the manifest repository manages your k8s manifest files. At the first, fetch the latest code from the manifest repository, and after that update file using yq. We just need to update the container image to the newest image which we uploaded to ECR in the previous step.
- name: fetch manifest repository uses: actions/checkout@v3 with: repository: github-organization/manifest-repository token: ${{ secrets.PAT }} path: manifest-repo fetch-depth: 1 - name: update manifest file image tag run: | wget -q https://github.com/mikefarah/yq/releases/download/v4.27.5/yq_linux_amd64 sudo mv yq_linux_amd64 /usr/local/bin/yq sudo chmod +x /usr/local/bin/yq yq e -i '.spec.template.spec.containers[0].image |= "${{ steps.build-image.outputs.image }}"' 'manifest-repo/k8s/sample/dev/deployment.yaml'
- Create PR After updating the manifest file, finally, create PR to trigger CD. Merging PR can be your deploy your latest code to the production environment. I use gh to create PR.
- name: commit working-directory: manifest-repo run: | git add . git commit -m "Release bff-admin" git push origin HEAD - name: create PR working-directory: manifest-repo run: | gh pr create -B main -H release-${{ github.sha }} -t "deploy-${{ github.sha }}" -b ""
2. Prepare Manifest file
Prepare the manifest file in the manifest repository. It will update by CI.
Below is a sample manifest file.
You must create namespace first. This time I create deploy-test.
manifest-repository/k8s/deploy-test/deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: deploy-test namespace: deploy-test spec: selector: matchLabels: app: deploy-test template: metadata: labels: app: deploy-test spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: eks.amazonaws.com/nodegroup operator: In values: - sample-ng containers: - name: deploy-test image: yourAccountId.dkr.ecr.yourRegion.amazonaws.com/yourRepositoryName:yourImageTag
Remember, during CI, I use yq to update the image tag. the update part is yourImageTag
.
So your pod will pull the latest image from ECR after PR is merged.
containers: - name: deploy-test image: yourAccountId.dkr.ecr.yourRegion.amazonaws.com/yourRepositoryName:yourImageTag
3. Build CD
Finally, build a CD using ArgoCD!
*You must create namespace and cluster.
The first step is to set up a GitHub access token to access the cluster to your repository.
You can type the below cmd to set your GitHub token to your cluster.
This time namespace that I set is argocd.
export GITHUB_TOKEN=<github-token> kubectl create secret generic github-cred -n argocd \ --from-literal url=https://github.com/${GITHUB_USER}/manifest-repository \ --from-literal username=<github-user> \ --from-literal password=${GITHUB_TOKEN} \ --from-literal name=github-cred kubectl label secret task-tool-cluster-config-cred argocd.argoproj.io/secret-type=repository -n argoc
Then write argocd manifest file.
file path is manifest-repository/k8s/deploy-test/argocd/deploy.yaml
apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: deploy-test namespace: argocd spec: project: default source: repoURL: https://github.com/${GITHUB_USER}/manifest-repository targetRevision: main path: k8s/deploy-test syncPolicy: automated: selfHeal: true prune: true destination: server: https://kubernetes.default.svc namespace: deploy-test
The ArgoCD will sync with the repository that you set on spec.source
part.
After all setup, finally, apply it.
kubectl apply -f k8s/deploy-test/argocd/deploy.yaml
That's it!!! you are all done setting CI/CD!
4. Recap
You created an application source code repository and manifest repository.
In the source code repo, we added CI to build and push the docker image to ECR, update the manifest file, and create PR.
You can manage your deployment whether you merge PR. After merging PR, ArgoCD will sync with your newest code.
The pod will replace to newest image from ECR!
Thank you for reading my article, Happy Coding!
Top comments (0)