π Deploying Kubernetes on GCP with Terraform & GitHub CI/CD π β¨ Infrastructure as Code, Automated Deployments, and Scalable Cloud Solutions! β¨
π§ What We Built A fully automated pipeline to deploy a Kubernetes cluster on Google Cloud Platform (GCP) using Terraform and GitHub Actions.
π οΈ Infrastructure as Code: Terraform scripts to provision GKE clusters, compute resources, and load balancers.
π€ CI/CD Automation: GitHub Actions for seamless, secure, and repeatable deployments.
π¦ Scalable & Secure: Kubernetes deployments with static IPs, workload identity federation, and role-based access control.
π Key Features βοΈ GCP Integration: Leveraged GKE, Compute Engine, and Cloud Storage for a robust cloud infrastructure.
π Secure Authentication: GitHub OIDC with GCP Workload Identity Federation for secure, tokenless access.
βοΈ Terraform Magic: Infrastructure defined as code for consistency and reproducibility.
π CI/CD Pipeline: Automated testing, planning, and deployment with GitHub Actions.
π¦ Kubernetes Deployment: Containerized applications managed effortlessly with GKE.
π‘ Why Itβs Awesome
π‘οΈ Security First: OIDC authentication ensures no long-lived credentials are stored.
β© Speed & Efficiency: Automated pipelines reduce manual errors and deployment time.
π Scalability: Kubernetes and GKE enable horizontal scaling for high-traffic applications.
π Reproducibility: Terraform ensures the same infrastructure can be deployed across environments.
π Tech Stack
Cloud: GCP (GKE, Compute Engine, Cloud Storage)
IaC: Terraform
CI/CD: GitHub Actions
Orchestration: Kubernetes
Authentication: GitHub OIDC + GCP Workload Identity Federation
π The Future
π Monitoring: Integrate Prometheus and Grafana for real-time insights.
π Multi-Environment Support: Staging, production, and rollback strategies.
π οΈ Advanced Networking: Implement ingress controllers and network policies.
π― Impact This project demonstrates how to build a modern, scalable, and secure cloud-native infrastructure using cutting-edge tools and best practices. Perfect for DevOps engineers, cloud enthusiasts, and anyone passionate about automation! π
Deploying a Node.js Application to GKE Using Terraform and GitHub Actions This guide walks you through the process of deploying a simple Node.js application to Google Kubernetes Engine (GKE) using Terraform and GitHub Actions.
π Table of Contents
-
π οΈ Create a Simple Node.js/Express Application Kickstart your journey by building a simple yet powerful Node.js application using Express!
-
π³ Write Dockerfile for the Application Containerize your app like a pro with a sleek and efficient Dockerfile.
-
π Write Terraform Scripts for GKE Cluster, Deployment, and Service Unleash the power of Infrastructure as Code with Terraform to provision a GKE cluster, deploy your app, and set up services.
-
π Set Up GitHub OIDC Authentication with GCP Secure your deployments with GitHub OIDC and GCP Workload Identity Federationβno more hardcoded credentials!
-
π¦ Create a GCS Bucket for Terraform State Store your Terraform state securely in a Google Cloud Storage (GCS) bucket.
-
π Add Secrets to GitHub Repository Keep your sensitive information safe by adding secrets like GCP_PROJECT_ID and GCP_TF_STATE_BUCKET to your GitHub repository.
-
π€ Write GitHub Actions Workflow Automate your deployments with a GitHub Actions CI/CD pipelineβbuild, test, and deploy with ease!
-
π Deploy the Application Push your code and watch the magic happen as your app gets deployed to GKE automatically.
-
π§Ή Clean Up Resources Donβt forget to clean up! Use Terraform to destroy all resources and keep your GCP environment tidy.
π Get ready to build, deploy, and scale like never before! π
-
Create a simple nodejs/express application.
-
Write Dockerfile for the application
FROM --platform=linux/amd64 node:14 WORKDIR /usr/app COPY package.json . RUN npm install COPY . . EXPOSE 80 CMD ["node","app.js"]
-
Write Terraform scripts for GKE Cluster, Deployment and service.
providers.tf: use google and kubernetes providersterraform { required_version = ">= 0.12" backend "gcs" { } } provider "google" { project = var.project_id region = var.region } provider "kubernetes" { host = google_container_cluster.default.endpoint token = data.google_client_config.current.access_token client_certificate = base64decode( google_container_cluster.default.master_auth[0].client_certificate, ) client_key = base64decode(google_container_cluster.default.master_auth[0].client_key) cluster_ca_certificate = base64decode( google_container_cluster.default.master_auth[0].cluster_ca_certificate, ) }main.tf: for creating GKE Clusterdata "google_container_engine_versions" "default" { location = "us-central1-c" } data "google_client_config" "current" { } resource "google_container_cluster" "default" { name = "my-first-cluster" location = "us-central1-c" initial_node_count = 3 min_master_version = data.google_container_engine_versions.default.latest_master_version node_config { machine_type = "g1-small" disk_size_gb = 32 } provisioner "local-exec" { when = destroy command = "sleep 90" } }
k8s.tf: For deployment and service deployment on K8sresource "kubernetes_deployment" "name" { metadata { name = "nodeappdeployment" labels = { "type" = "backend" "app" = "nodeapp" } } spec { replicas = 1 selector { match_labels = { "type" = "backend" "app" = "nodeapp" } } template { metadata { name = "nodeapppod" labels = { "type" = "backend" "app" = "nodeapp" } } spec { container { name = "nodecontainer" image = var.container_image port { container_port = 80 } } } } } } resource "google_compute_address" "default" { name = "ipforservice" region = var.region } resource "kubernetes_service" "appservice" { metadata { name = "nodeapp-lb-service" } spec { type = "LoadBalancer" load_balancer_ip = google_compute_address.default.address port { port = 80 target_port = 80 } selector = { "type" = "backend" "app" = "nodeapp" } } }
variables.tfvariable "region" { } variable "project_id" { } variable "container_image" { }
outputs.tfoutput "cluster_name" { value = google_container_cluster.default.name } output "cluster_endpoint" { value = google_container_cluster.default.endpoint } output "cluster_location" { value = google_container_cluster.default.location } output "load-balancer-ip" { value = google_compute_address.default.address }
-
Setup Github OIDC Authentication with GCP
- Create a new workload Identity pool
gcloud iam workload-identity-pools create "k8s-pool" \ --project="${PROJECT_ID}" \ --location="global" \ --display-name="k8s Pool"
- Create a oidc identity provider for authenticating with Github
gcloud iam workload-identity-pools providers create-oidc "k8s-provider" \ --project="${PROJECT_ID}" \ --location="global" \ --workload-identity-pool="k8s-pool" \ --display-name="k8s provider" \ --attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.aud=assertion.aud" \ --issuer-uri="https://token.actions.githubusercontent.com"
- Create a service account with these permissions
roles/compute.admin roles/container.admin roles/container.clusterAdmin roles/iam.serviceAccountTokenCreator roles/iam.serviceAccountUser roles/storage.admin
- Add IAM Policy bindings with Github repo, Identity provider and service account.
gcloud iam service-accounts add-iam-policy-binding "${SERVICE_ACCOUNT_EMAIL}" \ --project="${GCP_PROJECT_ID}" \ --role="roles/iam.workloadIdentityUser" \ --member="principalSet://iam.googleapis.com/projects/${GCP_PROJECT_NUMBER}/locations/global/workloadIdentityPools/k8s-pool/attribute.repository/${GITHUB_REPO}"
- Create a new workload Identity pool
-
Create a bucket in GCS for storing terraform state file.
-
Get your GCP Project number for reference.
gcloud projects describe ${PROJECT_ID} -
Add secrets to Github Repo
- GCP_PROJECT_ID
- GCP_TF_STATE_BUCKET
-
write GH Actions workflow for deploying our app to GKE using terraform
name: Deploy to kubernetes
on:
push:
branches:
- "Complete-CI/CD-with-Terraform-GKE"
env:
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
TF_STATE_BUCKET_NAME: ${{ secrets.GCP_TF_STATE_BUCKET }}
jobs:
deploy:
runs-on: ubuntu-latest
env:
IMAGE_TAG: ${{ github.sha }}
permissions:
contents: 'read'
id-token: 'write'
steps:
- uses: 'actions/checkout@v3'
- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@v1'
with:
token_format: 'access_token'
workload_identity_provider: 'projects/886257991781/locations/global/workloadIdentityPools/k8s-pool/providers/k8s-provider'
service_account: 'tf-gke-test@$GCP_PROJECT_ID.iam.gserviceaccount.com'
- name: 'Set up Cloud SDK'
uses: 'google-github-actions/setup-gcloud@v1'
- name: docker auth
run: gcloud auth configure-docker
- run: gcloud auth list
- name: Build and push docker image
run: |
docker build -t us.gcr.io/$GCP_PROJECT_ID/nodeappimage:$IMAGE_TAG .
docker push us.gcr.io/$GCP_PROJECT_ID/nodeappimage:$IMAGE_TAG
working-directory: ./nodeapp
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Terraform init
run: terraform init -backend-config="bucket=$TF_STATE_BUCKET_NAME" -backend-config="prefix=test"
working-directory: ./terraform
- name: Terraform Plan
run: |
terraform plan \
-var="region=us-central1" \
-var="project_id=$GCP_PROJECT_ID" \
-var="container_image=us.gcr.io/$GCP_PROJECT_ID/nodeappimage:$IMAGE_TAG" \
-out=PLAN
working-directory: ./terraform
- name: Terraform Apply
run: terraform apply PLAN
working-directory: ./terraform-
Deploy the Application Push your code to the main branch, and the GitHub Actions workflow will automatically deploy your application to GKE.
-
Clean Up Resources To clean up all resources, run the following command:
terraform destroy -var="region=us-central1" -var="project_id=$GCP_PROJECT_ID" -var="container_image=us.gcr.io/$GCP_PROJECT_ID/nodeappimage:$IMAGE_TAG" Screenshots Here are some screenshots of the deployment process:






