← Back to list

Production-Ready CI/CD: Deploying React application to Google Kubernetes Engine (GKE)

A complete guide to automating your frontend delivery using GitHub Actions, Artifact Registry, and GitOps with ArgoCD.

Suneel Kandali · 2026-06-05 21:51 · 0 claps · 8.2 min read
#github-actions #argo-cd #gcp #gke #cicd
Open on Medium ↗
Wiki topics: 🌐 · Web Development ☁️ · DevOps & Cloud 🔓 · Open Source 🏺 · Archaeology & Anthropology

Production-Ready CI/CD: Deploying React application to Google Kubernetes Engine (GKE)

A complete guide to automating your frontend delivery using GitHub Actions, Artifact Registry, and GitOps with ArgoCD.

💻 Important Note for Readers: The terminal commands, setup steps, and package managers (such as Homebrew) used throughout this tutorial are explicitly tailored for macOS. If you are running Windows or Linux, you will need to adjust your local environment setup and CLI installations accordingly.

What you will do

  1. Prerequisites
  2. Create a GKE cluster and connect kubectl.
  3. Install AgroCD
  4. Create a React application
  5. Add CI and CD manifests
  6. Add GitHub Secrets
  7. Configure Argo CD.
  8. Create GitHub Actions secrets for deployment.
  9. Deploy the app with GitHub Actions.
  10. Validate the deployment and test the app URL.
  11. Clean up resources when finished.
  12. GitHub repo for code

1. Prerequisites

You need the following installed on your computer:

  • gcloud
  • kubectl
  • docker
  • node and npm
  • access to your Google Cloud project
  • a GitHub repository for this project

If you do not already have the required tools installed, follow these steps.

Verify installed tools

Check that the required commands are already available before installing:

node --version
npm --version
docker version
kubectl version --client
gcloud version

If any command fails, install the missing tool using the instructions below.

Install Node.js and npm

Install Node.js and npm using the recommended installer for your platform from: https://nodejs.org/

For macOS with Homebrew:

brew install node

Verify installation:

node --version
npm --version

Install Docker

Download Docker Desktop for your platform from: https://www.docker.com/get-started

After installation, verify Docker is running:

docker version

Install kubectl

Follow the instructions at: https://kubernetes.io/docs/tasks/tools/

For macOS with Homebrew:

brew install kubectl

Verify installation:

kubectl version --client

Install Google Cloud SDK and Confirm the SDK is working

  1. Download and install the SDK for your platform from: https://cloud.google.com/sdk/docs/install
  2. Initialize the SDK:
gcloud init
  1. Log in to your Google account:
gcloud auth login
  1. Confirm SDK is working
gcloud auth list
gcloud config list

Create a Google Cloud project

If you do not already have a project, create one now:

gcloud projects create gke-githubactions-argocd-12345 --name="GKE GitHubActions ArgoCD"

Enable billing and link it to your project using the Cloud Console if needed.

Set the active project:

gcloud config set project gke-githubactions-argocd-12345

Create a GCP service account and key

Create a service account for GitHub Actions deployment:

gcloud iam service-accounts create github-actions-deployer \
  --description="GitHub Actions deployer account" \
  --display-name="GitHub Actions Deployer"

Grant the service account the required permissions:

gcloud projects add-iam-policy-binding gke-githubactions-argocd-12345 \
  --member="serviceAccount:github-actions-deployer@gke-githubactions-argocd-12345.iam.gserviceaccount.com" \
  --role="roles/container.admin"
gcloud projects add-iam-policy-binding gke-githubactions-argocd-12345 \
  --member="serviceAccount:github-actions-deployer@gke-githubactions-argocd-12345.iam.gserviceaccount.com" \
  --role="roles/artifactregistry.writer"
gcloud projects add-iam-policy-binding gke-githubactions-argocd-12345 \
  --member="serviceAccount:github-actions-deployer@gke-githubactions-argocd-12345.iam.gserviceaccount.com" \
  --role="roles/iam.serviceAccountUser"

If you need to use Artifact Registry with storage operations, also grant:

gcloud projects add-iam-policy-binding gke-githubactions-argocd-12345 \
  --member="serviceAccount:github-actions-deployer@gke-githubactions-argocd-12345.iam.gserviceaccount.com" \
  --role="roles/storage.admin"

Create a new JSON key for the service account and save it locally:

gcloud iam service-accounts keys create ./gcp-sa-key.json \
  --iam-account=github-actions-deployer@gke-githubactions-argocd-12345.iam.gserviceaccount.com

Add the contents of gcp-sa-key.json to the GitHub secret GCP_SA_KEY.

Enable the required APIs:

gcloud services enable container.googleapis.com artifactregistry.googleapis.com

gcloud services enable: This is the core Google Cloud CLI command used to activate APIs within your currently selected project.

container.googleapis.com: This is the internal name for the Google Kubernetes Engine (GKE) API. Enabling this allows you to create, manage, and scale Kubernetes clusters.

artifactregistry.googleapis.com: This is the internal name for Artifact Registry. Enabling this allows you to create secure, private repositories to store and manage your Docker container images, Maven/npm packages, or Helm charts.

gcloud artifacts repositories create githubactions-argocd-poc-repo \ — repository-format=docker \ — location=us-central1 \ — description=”Docker repository for CI/CD with GitHub Actions and ArgoCD”

2. Create the GKE cluster

Run these commands in your terminal:

gcloud container clusters create gcp-gke-githubactions-argocd-cluster \
  --zone us-central1-a \
  --num-nodes=1 \
  --machine-type=e2-medium \
  --disk-size=30 \
  --disk-type=pd-ssd

Then connect kubectl to the cluster, this adds kubeconfig entry on your local

gcloud container clusters get-credentials gcp-gke-githubactions-argocd-cluster \
  --zone us-central1-a \
  --project gke-githubactions-argocd-12345
kubectl config current-context

Screenshot: GKE cluster creation and kubectl context setup.

3. Install Argo CD

Install Argo CD into the argocd namespace:

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

Wait for Argo CD pods to start:

kubectl get pods -n argocd

Expose the Argo CD server with a LoadBalancer so it is reachable from GitHub Actions:

kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'

Get the external IP for Argo CD:

kubectl get svc -n argocd argocd-server

Get the default admin password:

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

Screenshot: Argo CD LoadBalancer external IP and initial admin login.

Open the Argo CD UI using the external IP and log in with:

  • Username: admin
  • Password: the value from the previous command

4. Create React application

If you do not already have a React app in this repository, create one with Vite:

npm create vite@latest . -- --template react
npm install

If the repository is not yet a Git repo, initialize it:

git init
git add .
git commit -m "Initial React app"

Add your GitHub repository as the remote and push:

git remote add origin https://github.com/<your-username>/<your-repo>.git
git branch -M main
git push -u origin main

If your repository already exists locally, simply commit and push your changes:

git add .
git commit -m "Add React app"
git push origin main

5. Add CI and CD manifests

Add k8s/deployment.yaml file as below, it is for creating k8s deployment and service resources

apiVersion: apps/v1
kind: Deployment
metadata:
  name: reactapp-gcp-gke-githubactions-cicd-deployment
  labels:
    app: reactapp-gcp-gke-githubactions-cicd
spec:
  replicas: 2
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  minReadySeconds: 5
  selector:
    matchLabels:
      app: reactapp-gcp-gke-githubactions-cicd
  template:
    metadata:
      labels:
        app: reactapp-gcp-gke-githubactions-cicd
    spec:
      containers:
      - name: react-app
        image: us-central1-docker.pkg.dev/gke-githubactions-argocd-12345/githubactions-argocd-poc-repo/gcp-gke-githubactions-agrocd-reactapp:3211f151febb44683c513fc0f5c3dc411ae55b6c
        ports:
        - containerPort: 80
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 10
          failureThreshold: 3
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 15
          periodSeconds: 20
          failureThreshold: 3
---
apiVersion: v1
kind: Service
metadata:
  name: reactapp-gcp-gke-githubactions-cicd-service
spec:
  type: LoadBalancer
  selector:
    app: reactapp-gcp-gke-githubactions-cicd
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Add .github/workflows/ci.yaml for continuous integration with GitHub Actions

name: CI/CD Pipeline
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
permissions:
  contents: write
env:
  GCP_PROJECT: gke-githubactions-argocd-12345
  GCP_REGION: us-central1
  GCP_ZONE: us-central1-a
  CLUSTER_NAME: gcp-gke-githubactions-argocd-cluster
  IMAGE_REPOSITORY: githubactions-argocd-poc-repo
  IMAGE_NAME: gcp-gke-githubactions-agrocd-reactapp
  DEPLOYMENT_MANIFEST: k8s/deployment.yaml
  ARGOCD_APP_NAME: reactapp-gcp-gke-githubactions-cicd
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Install dependencies
        run: npm ci
      - name: Build React app
        run: npm run build
      - name: Authenticate to Google Cloud
        uses: google-github-actions/auth@v1
        with:
          credentials_json: '${{ secrets.GCP_SA_KEY }}'
      - name: Configure Docker for Artifact Registry
        run: |
          gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
      - name: Build and push Docker image
        id: build-image
        run: |
          IMAGE=us-central1-docker.pkg.dev/${GCP_PROJECT}/${IMAGE_REPOSITORY}/${IMAGE_NAME}:${GITHUB_SHA}
          echo "IMAGE=${IMAGE}" >> $GITHUB_ENV
          docker build -t "$IMAGE" .
          docker push "$IMAGE"
      - name: Update deployment manifest image
        run: |
          IMAGE=${{ env.IMAGE }}
          python - <<'PY'
          from pathlib import Path
          import re
          path = Path('${{ env.DEPLOYMENT_MANIFEST }}')
          text = path.read_text()
          pattern = r'^(\s*image:\s*).*$'
          new_text = re.sub(pattern, r'\1' + '${{ env.IMAGE }}', text, flags=re.MULTILINE)
          path.write_text(new_text)
          PY
        env:
          IMAGE: ${{ env.IMAGE }}
      - name: Commit deployment manifest update
        run: |
          git config user.name 'github-actions[bot]'
          git config user.email 'github-actions[bot]@users.noreply.github.com'
          git add ${{ env.DEPLOYMENT_MANIFEST }}
          git diff --cached --quiet || (
            git commit -m "ci: update deployment image to ${{ env.IMAGE }}" && git push origin HEAD:main
          )
      - name: Install Argo CD CLI
        run: |
          curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
          chmod +x argocd
          sudo mv argocd /usr/local/bin/argocd
      - name: Get GKE credentials
        uses: google-github-actions/get-gke-credentials@v1
        with:
          cluster_name: ${{ env.CLUSTER_NAME }}
          location: ${{ env.GCP_ZONE }}
          credentials_json: '${{ secrets.GCP_SA_KEY }}'
      - name: Apply Argo CD application manifest
        run: |
          kubectl apply -f agrocd-app.yaml
      # - name: Login and sync Argo CD app
      #   env:
      #     ARGOCD_SERVER: ${{ secrets.ARGOCD_SERVER }}
      #     ARGOCD_PASSWORD: ${{ secrets.ARGOCD_PASSWORD }}
      #   run: |
      #     argocd login "$ARGOCD_SERVER" --username admin --password "$ARGOCD_PASSWORD" --insecure
      #     argocd app sync ${{ env.ARGOCD_APP_NAME }}
      #     argocd app wait ${{ env.ARGOCD_APP_NAME }} --health --timeout 300

6. Add GitHub Secrets

Store sensitive values in GitHub instead of hardcoding them in the workflow.

In GitHub, go to your repository Settings > Secrets and variables > Actions.

Create these repository secrets:

  • GCP_SA_KEY — paste the JSON content of your GCP service account key.
  • ARGOCD_SERVER — paste the Argo CD External Server IP.
  • ARGOCD_PASSWORD — paste the Argo CD admin password.

Screenshot: GitHub Actions secrets dashboard with GCP_SA_KEY and ARGOCD_PASSWORD set.

7. Configure Argo CD

Open agrocd-app.yaml and make sure the path matches where your Kubernetes manifest lives.

If deployment.yaml is in the repository root, use:

spec:
  source:
    path: .

If you move deployment.yaml into a folder named k8s, use:

spec:
  source:
    path: k8s

Apply or update the Argo CD Application:

kubectl apply -f agrocd-app.yaml

8. How GitHub Actions works

The workflow in .github/workflows/ci.yaml will:

  1. check out your repository
  2. authenticate to Google Cloud using GCP_SA_KEY
  3. build and push a Docker image to Artifact Registry
  4. update the deployment manifest with the new image tag
  5. commit the updated manifest back to GitHub
  6. log in to Argo CD
  7. sync the application
  8. wait for the application to become healthy

9. Zero downtime updates

This deployment is configured to update pods without taking the app offline by using a rolling update strategy:

  • replicas: 2 keeps at least one pod available while a new pod starts.
  • strategy.rollingUpdate.maxSurge: 1 allows one extra pod to be created temporarily.
  • strategy.rollingUpdate.maxUnavailable: 0 ensures no pod is removed before a replacement is ready.
  • A readiness probe verifies each new pod is ready before traffic routes to it.

When a new image version is deployed, Kubernetes will:

  1. start a new pod with the updated image
  2. wait until the readiness probe passes
  3. terminate one old pod only after the new pod is ready
  4. repeat until all pods are updated

You can watch the rollout progress with:

kubectl rollout status deployment/reactapp-gcp-gke-githubactions-cicd-deployment

If you need to roll back after a failed deployment:

kubectl rollout undo deployment/reactapp-gcp-gke-githubactions-cicd-deployment

9. Run the deployment

Push your changes to the main branch:

git add .
git commit -m "Prepare deployment"
git push origin main

Then go to GitHub Actions and watch the workflow run.

Screenshot: GitHub Actions workflow run showing the build and deploy steps.

10. Validate the deployment

After the workflow completes, confirm the application is deployed and healthy.

10.1 Check Argo CD application status

Open the Argo CD UI and verify the app status is Healthy and Synced.

Or run:

argocd app get reactapp-gcp-gke-githubactions-cicd

Look for:

  • Sync Status: Synced
  • Health Status: Healthy

10.2 Check the Kubernetes deployment

Verify that the deployment is running in the target namespace:

kubectl get pods -n default
kubectl get svc -n default

10.3 Test the app URL in your browser

If your app is exposed via a Kubernetes service with an external IP or ingress, open that URL in your browser.

For example, if your service is exposed on port 80 and the external IP is 34.30.15.58, open:

http://34.30.15.58

If the app is not exposed externally, use port-forwarding to test it locally:

kubectl port-forward svc/<service-name> 8080:80 -n default

Then open:

http://localhost:8080

11. Troubleshooting

App path is wrong

If Argo CD shows an error like app path does not exist, set path in agrocd-app.yaml to the correct location.

Object 'Kind' is missing

This means Argo CD tried to parse a file such as package.json as a Kubernetes manifest. Only include manifest files in the Argo CD app path.

Permission denied on login

Verify that ARGOCD_SERVER in GitHub Secrets matches the current Argo CD External IP.

Verify that ARGOCD_PASSWORD in GitHub Secrets matches the current Argo CD admin password.

12. Clean up resources

When you are done, delete the GKE cluster:

gcloud container clusters delete gcp-gke-githubactions-argocd-cluster --zone us-central1-a

Remove any unnecessary service accounts or secrets from GitHub.

13. GitHub Repo

All code files and configuration can be found in the following GitHub repository: https://github.com/suneelkandali/gcp-gke-githubactions-argocd-reactapp


메타데이터
post_id
b5f29eb821cf
slug
react-app-deployment-to-google-cloud-kubernetes-environment-with-ci-using-github-actions-and-cd-b5f29eb821cf
url
https://medium.com/@suneelr.kandali/react-app-deployment-to-google-cloud-kubernetes-environment-with-ci-using-github-actions-and-cd-b5f29eb821cf
canonical_url
https://medium.com/@suneelr.kandali/react-app-deployment-to-google-cloud-kubernetes-environment-with-ci-using-github-actions-and-cd-b5f29eb821cf
author_url
https://medium.com/@suneelr.kandali
status
ok
fetched_at
2026-06-09 15:37:30