CI/CD Pipeline on GKE using GitHub Actions
The purpose of this post is to demonstrate how to deploy a containerized application in Kubernetes using GitHub Actions and a very simple CI/CD pipeline.
GitHub Actions makes it simple to automate all your development activities. GitHub action makes it easy all the activities right from writing, testing and deploying code.
We will learn how to use GitHub Actions to build a containerized application, push it to Google Container Registry (GCR), and deploy it to Google Kubernetes Engine (GKE) when there is a push to the main branch.
GitHub Actions allows you to establish software development workflows, such as continuous integration and delivery (CI/CD) processes, from the same code repository where you save code and collaborate on pull requests and issues.
GKE is a Google Cloud managed Kubernetes cluster solution that can host your containerized workloads in the cloud or on-premises.
The GitHub Container Registry allows you to host and manage Docker container images in your company or personal GitHub account. Fine-grained permissions can also be used to control who can manage and access packages.
GitHub Actions core components -
Github Actions is an extension of Github. It mostly consists of workflows saved in a git repository (.github/workflows/)
Workflows are often triggered by events in the repository like commits, or external events tirggered via repository webhooks.?
When a workflow is activated, the runner takes over and executes each job one at a time.?
The job is made up of steps with actions that complete a task in the process.
CI/CD Workflow -
When we commit the code –
CI - container images is created from Dockerfile (using nginx & index.html) and pushed to google container registry gcr.io
CD – container is pulled from gcr.io and deployed (deploy.yaml is used) on Google Kubernetes Cluster Engine GKE
Pre - requisites -
Implementation Steps -
Install gcloud cli and configure it
$ curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-388.0.0-linux-x86_64.tar.gz
$ tar -xf google-cloud-cli-388.0.0-linux-x86.tar.gz
$./google-cloud-sdk/install.sh
$ which gcloud
$ gcloud init
Create GKE cluster
# Set variables -
$ export GKE_CLUSTER=github-gke-cicd
$ echo $GKE_CLUSTER
$ export GKE_PROJECT=cloud-devops-demo-351618
$ echo $GKE_PROJECT
$export GKE_ZONE=us-central1-c
$echo $GKE_ZONE
$ export SA_NAME=github-gke-cicd-sa
$ echo $SA_NAME
Create cluster -
$ gcloud container clusters create $GKE_CLUSTER --project=$GKE_PROJECT --zone=$GKE_ZONE
In GUI check that GKE k8s cluster is created -
Enable APIs and Create service account to install GKE -
# Enable APIs -
$ gcloud services enable containerregistry.googleapis.com container.googleapis.com
# Create service account -
$ gcloud iam service-accounts create $SA_NAME
# Get Email address -
$ gcloud iam service-accounts list
# Set variable -
$ export SA_EMAIL=gcp-gitlab-sa@cloud-devops-demo-351618.iam.gserviceaccount.com?
# Get value of variable -
$ echo $SA_EMAIL
Add IAM policies based on service account and add roles -
We are adding below roles -
领英推荐
Container Admin, Storage Admin and Container Cluster Viewer
$ gcloud projects add-iam-policy-binding $GKE_PROJECT --member=serviceAccount:$SA_EMAIL --role=roles/container.admin
$ gcloud projects add-iam-policy-binding $GKE_PROJECT --member=serviceAccount:$SA_EMAIL --role=roles/storage.admin
$ gcloud projects add-iam-policy-binding $GKE_PROJECT --member=serviceAccount:$SA_EMAIL --role=roles/container.clusterViewer
Create Service Account Key which we will add as secret variable in GitHub -
$ export GKE_SA_KEY=$(cat key.json | base64)
$ echo $GKE_SA_KEY
Create two secret variables in GitHub –
GKE_SA_KEY and GKE_PROJECT
Create github repo with below files -
index.html
Dockerfile
deploy.yaml
kustomization.yaml
.github/workflows/github-gke-ci-cd.yml
$ cat index.html
Nginx HTML Demo App
$ cat Dockerfile
FROM nginx:alpine
COPY . /usr/share/nginx/html
$ cat kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
? - deploy.yaml
Deployment file
$ cat deploy.yaml
apiVersion: v1
kind: Service
metadata:
? name: nginx-html-app-svc
? labels:
? ? app: nginx-html-app
spec:
? type: NodePort
? ports:
? - port: 80
? ? nodePort: 30080
? selector:
? ? app: nginx-html-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
? name: nginx-html-app
? labels:
? ? app: nginx-html-app
spec:
? replicas: 1
? selector:
? ? matchLabels:
? ? ? app: nginx-html-app
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app: nginx-html-app
? ? spec:
? ? ? containers:
? ? ? - name: nginx-html-app
? ? ? ? image: gcr.io/PROJECT_ID/IMAGE:TAG
? ? ? ? ports:
? ? ? ? - containerPort: 80
? ? ? imagePullSecrets:
? ? ? - name: regcred
$ cat .github/workflows/github-gke-ci-cd.yml
name: Build and Deploy to GKE
on:
? push:
? ? branches:
? ? ? - main
env:
? PROJECT_ID: ${{ secrets.GKE_PROJECT }}
? GKE_CLUSTER: github-gke-cicd? ? # Add your cluster name here.
? GKE_ZONE: us-central1-c? ?# Add your cluster zone here.
? DEPLOYMENT_NAME: deploy.yaml # Add your deployment name here.
? IMAGE: nginx-html-app
jobs:
? setup-build-publish-deploy:
? ? name: Setup, Build, Publish, and Deploy
? ? runs-on: ubuntu-latest
? ? environment: production
? ? steps:
? ? - name: Checkout
? ? ? uses: actions/checkout@v3
? ? # Setup gcloud CLI
? ? - uses: google-github-actions/setup-gcloud@94337306dda8180d967a56932ceb4ddcf01edae7
? ? ? with:
? ? ? ? service_account_key: ${{ secrets.GKE_SA_KEY }}
? ? ? ? project_id: ${{ secrets.GKE_PROJECT }}
? ? # Configure Docker to use the gcloud command-line tool as a credential
? ? # helper for authentication
? ? - run: |-
? ? ? ? gcloud --quiet auth configure-docker
? ? # Get the GKE credentials so we can deploy to the cluster
? ? - uses: google-github-actions/get-gke-credentials@fb08709ba27618c31c09e014e1d8364b02e5042e
? ? ? with:
? ? ? ? cluster_name: ${{ env.GKE_CLUSTER }}
? ? ? ? location: ${{ env.GKE_ZONE }}
? ? ? ? credentials: ${{ secrets.GKE_SA_KEY }}
? ? # Build the Docker image
? ? - name: Build
? ? ? run: |-
? ? ? ? docker build \
? ? ? ? ? --tag "gcr.io/$PROJECT_ID/$IMAGE:$GITHUB_SHA" \
? ? ? ? ? --build-arg GITHUB_SHA="$GITHUB_SHA" \
? ? ? ? ? --build-arg GITHUB_REF="$GITHUB_REF" \
? ? ? ? .
? ? # Push the Docker image to Google Container Registry
? ? - name: Publish
? ? ? run: |-
? ? ? ? docker push "gcr.io/$PROJECT_ID/$IMAGE:$GITHUB_SHA"
? ? # Set up kustomize
? ? - name: Set up Kustomize
? ? ? run: |-
? ? ? ? curl -sfLo kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/v3.1.0/kustomize_3.1.0_linux_amd64
? ? ? ? chmod u+x ./kustomize
? ? # Deploy the Docker image to the GKE cluster
? ? - name: Deploy
? ? ? run: |-
? ? ? ? ./kustomize edit set image gcr.io/PROJECT_ID/IMAGE:TAG=gcr.io/$PROJECT_ID/$IMAGE:$GITHUB_SHA
? ? ? ? ./kustomize build . | kubectl apply -f -
? ? ? ? kubectl rollout status deployment/$DEPLOYMENT_NAME
? ? ? ? kubectl get services -o wide
Create and clone github repo nginx-html-app and add above files, commit and push -
$ git clone [email protected]:prayag-sangode/nginx-html-app.git
$ git config --global user.name prayag-sangode
$ git config --global user.email “[email protected]”
$ git config --global push.default current
$ git add .
$ git commit -m "added index.html page"
$ git branch -M main
$ git push -u origin main
$ git branch
On git push GitHub Actions is triggered and CI/CD pipeline is implemented. Check GitHub Actions for status of CI CD workflow
Check app deployment status using kubectl -
$ gcloud components install kubectl
$ gcloud components install gke-gcloud-auth-plugin
$ gcloud container clusters list
$ gcloud container clusters get-credentials --zone us-central1-c github-gke-cicd
$ kubectl get all
$ kubectl get nodes
Check google container images and tags in GCR
$ gcloud container images list
$ gcloud container images list-tags gcr.io/cloud-devops-demo-351618/nginx-html-app
I hope you found this article to be useful in some way. I'll be back with some more interesting new DevOps articles soon.