---
title: "From On-Prem to the Cloud: A Complete Guide to Automating Next.js Deployments to Google Kubernetes Engine with Jenkins"
description: "A complete guide to creating a Jenkins Pipeline for automated deployment of a Next.js application to Google Kubernetes Engine, covering GCP service account setup, pushing to Artifact Registry, and GKE Kubernetes Engine Builder integration."
canonical_url: "https://blog.markkulab.net/en/post/jenkins-deploy-nextjs-to-gke"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/en/author/mark-ku"
site: "Mark Ku's Tech Notes"
date_published: "2024-11-24T01:01:35+08:00"
category: "Cloud"
tags: ["jenkins", "gke", "kubernetes", "google cloud", "next.js", "ci/cd", "devops"]
language: "en"
license: "CC BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
attribution: "when reusing or quoting, credit the author and link back to the original"
---

# From On-Prem to the Cloud: A Complete Guide to Automating Next.js Deployments to Google Kubernetes Engine with Jenkins

## Introduction
Following up on the previous article, [Deploying to GKE with Google Cloud SDK Scripts](https://blog.markkulab.net/deploy-nextjs-app-to-google-kubernetes-service/), this time I'll show how to automate GKE deployments using Jenkins.

## Prerequisites
Before you begin, please ensure the following environment and resources are ready:
1. **Kubernetes Master Node**: At least one available K8s Master Node.
2. **Jenkins**: Installed and running.
3. **Docker**: To containerize the application.
4. **Google Artifact Registry**: An Artifact Registry created beforehand in GCP.
5. **Next.js Project**: The project must include the necessary K8s YAML configuration files.
6. **GitHub**: A webhook configured to automatically trigger a Jenkins build on push.

## Install Google Cloud CLI
1. **Install Google Cloud CLI according to the official tutorial**: Refer to the [official Google documentation](https://cloud.google.com/sdk/docs/install) for installation.
2. **Log in to Google Cloud**:
   Run the following command:
   ```bash
   gcloud auth login --no-launch-browser
   ```
   The system will generate a verification URL (as shown in the image below), which you can use to complete the login process on another device with a browser.

   ![get login url](https://blog.markkulab.net/content/markku/posts/jenkins-deploy-nextjs-to-gke/images/get-login-url.png)

## Create a Google Service Account
1. **Go to the GCP Console**:
   - Navigate to **IAM & Admin > Service Accounts**.
   - Click **CREATE SERVICE ACCOUNT**.

   ![create service account](https://blog.markkulab.net/content/markku/posts/jenkins-deploy-nextjs-to-gke/images/create-service-account.png)

2. **Set the role**:
   - Set the role to **Owner**.
   - Click **DONE**.

   ![give the owner permission](https://blog.markkulab.net/content/markku/posts/jenkins-deploy-nextjs-to-gke/images/give-the-owner-permission.png)

3. **Download the service account key**:
   - In the **Service accounts > select your service account > KEYS** tab:
     - Click **ADD KEY**, select **JSON** format, and download the key.

   ![add-key](https://blog.markkulab.net/content/markku/posts/jenkins-deploy-nextjs-to-gke/images/add-key.png)

## Jenkins Configuration

1. **Install necessary plugins**:
   - In the Jenkins Dashboard, navigate to **Manage Jenkins > Plugin Manager** and install the following plugins:
     - Google Kubernetes Engine Plugin
     - Kubernetes CLI Plugin
     - Pipeline: AWS Steps Plugin
   

2. **Add credentials**:
   - Upload the downloaded GCP key to Jenkins:
     - Navigate to **Dashboard > Manage Jenkins > Credentials > System > Global credentials (unrestricted)**.
     - Click **Add Credentials**, select the **Secret file** type, and upload the JSON key file.

   ![set up service account key](https://blog.markkulab.net/content/markku/posts/jenkins-deploy-nextjs-to-gke/images/set-up-service-account-key.png)

   **Note**: You need to upload two keys here, one for each of the following purposes:
   - **SSH Username with private key (gke-ssh)**: Used by `withCredentials`.
   - **Google Service Account from private key (gke-gsa)**: Used by the Kubernetes Engine Builder.

## Create a Jenkins Pipeline
1. **Create a new Pipeline**:
   - Navigate to **Dashboard > New Item**.
   - Select **Pipeline** and name it `GCP - Deploy to GKE`.

2. **Write the Pipeline script**:
   Here is an example script:
   ```groovy
   properties([
       pipelineTriggers([githubPush()])
   ])

   pipeline {
       agent any

       environment {
           TAG = ':latest'
           IMAGE_SHORT_NAME = 'k8s-next-ec'
           IMAGE_NAME = "${IMAGE_SHORT_NAME}${TAG}"
           CONTAINER_NAME = "${IMAGE_SHORT_NAME}-1"
           DOCKERFILE_PATH = './Dockerfile'
           REGISTRY_URL = 'asia-east1-docker.pkg.dev/careful-span-384313/my-registry'
           REGISTRY = "${REGISTRY_URL}/${IMAGE_SHORT_NAME}"
           GCP_PROJECT_ID = 'careful-span-384313'
           GIT_REPO_URL = 'git@github.com:markku636/ec.git'
           GIT_BRANCH = 'main'
           GKE_CLUSTER_NAME = 'blog-autopilot-cluster'
           GKE_LOCATION = 'asia-east1'
           DEPLOYMENT_MANIFEST = './gc-next-js-deployment.yaml'
       }

       stages {
           stage('Authenticate with GCP') {
               steps {
                   withCredentials([file(credentialsId: 'gke-ssh', variable: 'GCLOUD_CREDS')]) {
                       sh '''
                           gcloud version
                           gcloud auth activate-service-account --key-file="$GCLOUD_CREDS"
                           gcloud config set project $GCP_PROJECT_ID
                           gcloud auth configure-docker asia-east1-docker.pkg.dev
                       '''
                   }
               }
           }

           stage("GitHub Pull") {
               steps {
                   git branch: "${GIT_BRANCH}", 
                   credentialsId: 'e85233ad-a3c5-448b-a6ea-9f53e4f9b3f1', 
                   url: "${GIT_REPO_URL}"
               }
           }

           stage('Build Docker Image') {
               steps {
                   sh "docker build -t ${IMAGE_NAME} -f ${DOCKERFILE_PATH} ."
               }
           }

           stage('Push to GCR') {
               steps {
                   sh "docker tag ${IMAGE_NAME} ${REGISTRY}${TAG}"
                   sh "docker push ${REGISTRY}${TAG}"
               }
           }

           stage("Cleaning Up") {
               steps {
                   sh "docker rmi --force ${REGISTRY}${TAG}"
               }
           }

           stage('Deploy via GKE Plugin') {
               steps {
                   step([
                       $class: 'KubernetesEngineBuilder',
                       projectId: "${GCP_PROJECT_ID}",
                       clusterName: "${GKE_CLUSTER_NAME}",
                       location: "${GKE_LOCATION}",
                       manifestPattern: "${DEPLOYMENT_MANIFEST}",
                       credentialsId: 'gke-gsa',
                       verifyDeployments: true
                   ])
                   echo "Deployment Finished ..."
               }
           }
       }
   }
   ```

## Addendum: Deployment YAML Configuration in the Project Folder
Below is the sample content for `./gc-next-js-deployment.yaml`:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: k8s-next-ec
  labels:
    app: k8s-next-ec
spec:
  selector:
    matchLabels:
      app: k8s-next-ec
      tier: web
  template:
    metadata:
      labels:
        app: k8s-next-ec
        tier: web
    spec:
      containers:
      - name: k8s-next-ec-app
        image: asia-east1-docker.pkg.dev/careful-span-384313/my-registry/k8s-next-ec:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 3000            
---

apiVersion: v1
kind: Service
metadata:
  name: k8s-next-ec
  labels:
    app: k8s-next-ec
spec:
  selector:
    app: k8s-next-ec
  type: LoadBalancer
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 3000  
```

## Final Result
![Jenkins build successful](https://blog.markkulab.net/content/markku/posts/jenkins-deploy-nextjs-to-gke/images/result-2.png)![The deployment is visible in the GCP GKE console](https://blog.markkulab.net/content/markku/posts/jenkins-deploy-nextjs-to-gke/images/result-3.png)


## References
* [Day 17 — Terraform/GCP Basics — Setting up a GCP Service Account](https://ithelp.ithome.com.tw/articles/10332886)
* [How to Deploy application on GKE using Jenkins](https://blog.knoldus.com/how-to-deploy-application-on-gke-using-jenkins/)

---

## About this article and its author

Originally published on [Mark Ku's Tech Notes](https://blog.markkulab.net/en/post/jenkins-deploy-nextjs-to-gke)

License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — when reusing or quoting, credit the author and link back to the original

### About the author

**[Mark Ku](https://blog.markkulab.net/en/author/mark-ku)** — Software Solution Provider

- 10+ years senior software engineer, now an AI Builder
- Focused on large-platform architecture — North-American e-commerce, AI SaaS subscription billing
- Combining AI Agents and automation to build evolvable product foundations

### Free tools built by the author

All of these are free to use:

- [Free PDF Sign Tool](https://blog.markkulab.net/en/tools/pdf-sign): Online PDF sign tool — draw, type, or upload a signature, then drag, resize, and download. Everything runs in your browser; nothing is uploaded.
- [VS Code Refactory](https://blog.markkulab.net/en/tools/refactory): Refactory is a VS Code refactoring extension: 34 actions plus a 37-rule code-smell inspection layer with a Code Health dashboard, across 18 languages, backed by 534 tests. It learns your repo's conventions: where interfaces live, where DI is registered, whether 'use client' belongs. It ranks files by git churn × complexity so you know what to fix first, and hands any smell to the Claude Code already on your machine. Free to use, and your source never leaves your computer.
- [DB-Kit Database Manager](https://blog.markkulab.net/en/tools/db-kit): DB-Kit is a lightweight, cross-platform database manager built with Tauri + Rust + React. Manage MySQL, MariaDB, PostgreSQL, SQL Server, Oracle, SQLite, MongoDB, Redis, Kafka, Elasticsearch and RabbitMQ from one consistent interface: passwords encrypted in the OS keychain, SSH tunnels, full CRUD, a visual query builder, stacked multi-statement result sets, cross-connection data transfer and compare/sync, Excel / CSV import & export, visualized execution plans, ER diagrams, scheduled backups, SQL stress testing with p50–p99 latency percentiles, a 15-rule SQL review engine, Kafka message browsing with monitoring & alerts, a bilingual UI (Traditional Chinese / English), a built-in AI assistant (natural-language SQL, AI review and tuning advice) and the dbk CLI. Free and open source (MIT), with installers for Windows, macOS and Linux.
- [VS Code Super Mermaid](https://blog.markkulab.net/en/tools/super-mermaid): Super Mermaid is a VS Code extension for beautiful Mermaid diagrams out of the box: auto-colored live preview, mouse pan & zoom, high-res PNG / SVG export, 21 templates and multiple themes. Free and open source (MIT).
- [React Super Mermaid](https://blog.markkulab.net/en/tools/react-super-mermaid): react-super-mermaid is an open-source React component library: render beautiful Mermaid diagrams with a single <MermaidViewer>, with built-in colorful / sketch themes, pan & zoom, in-diagram search, and high-res SVG / PNG export. Lightweight, SSR-safe, fully typed. Free and open source (MIT).
- [Jira / Confluence Super Mermaid](https://blog.markkulab.net/en/tools/jira-super-mermaid): An Atlassian Forge app: write Mermaid syntax directly inside a Jira issue or a Confluence page and get flowcharts, sequence diagrams, state machines and Gantt charts. 11 diagram types, SVG / PNG export, light and dark themes, full CJK support. Runs on Atlassian: your diagrams live in your own site and the app calls no third-party service. Free, coming soon to the Atlassian Marketplace.
- [Mermaid Live Preview](https://blog.markkulab.net/en/tools/mermaid-preview): Write Mermaid in your browser, see it render instantly, and share the whole diagram as a single link. No sign-up, nothing uploaded to a server, and mermaid.live share links work as-is.
- [React Intl Phone Number](https://blog.markkulab.net/en/tools/react-intl-phone-number): react-intl-phone-number is an open-source React component: framework-agnostic and antd-free, with E.164 in/out, a searchable flag / country-code dropdown, configurable validation levels (strict / mobile-strict / loose), themeable CSS, and i18n — phone logic powered by google-libphonenumber. Lightweight and fully typed. Free and open source (MIT).
- [Uptime Kuma Cluster](https://blog.markkulab.net/en/tools/uptime-kuma-cluster): Turn single-node Uptime Kuma into a highly available cluster: OpenResty + Lua smart load balancing, shared MariaDB state, health checks and automatic failover, plus cluster-management REST APIs. One Docker Compose command to start. Free and open source (MIT).
- [Special Education](https://blog.markkulab.net/en/education): Learning materials crafted for special education students

### Daily podcasts

- [Mark's Tech Insights — Daily AI News](https://blog.markkulab.net/en/category/tech-news): Daily curated AI and tech trends. Catch the latest developments via audio summaries — covering AI applications, software architecture, DevOps, and engineering practice. — RSS: https://blog.markkulab.net/feed.xml
- [AI股市蝦聊](https://blog.markkulab.net/en/category/ai-stock-chat): Every trading day, an AI-analyzed take on the Taiwan stock market, delivered as a two-host conversation covering the session and the next-day outlook. — RSS: https://blog.markkulab.net/ai-stock-chat/feed.xml
- [開源好物週報](https://blog.markkulab.net/en/category/open-source-weekly): A weekly two-host pick of free open-source tools surfaced from real Hacker News, GitHub, and Reddit buzz — what pain they solve and the fastest way to get started. — RSS: https://blog.markkulab.net/open-source-weekly/feed.xml

### Newsletter

[Subscribe to the newsletter](https://blog.markkulab.net/en/subscribe) — Be the first to know about new posts. No spam, unsubscribe anytime.
