---
title: "From On-Prem to the Cloud: Deploying Your Next.js Container Application with Google Kubernetes Engine"
description: "A step-by-step guide to packaging a Next.js application as a Docker image, pushing it to Google Artifact Registry, and deploying to a GKE cluster."
canonical_url: "https://blog.markkulab.net/en/post/deploy-nextjs-app-to-google-kubernetes-service"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/en/author/mark-ku"
site: "Mark Ku's Tech Notes"
date_published: "2024-11-13 01:01:35 +0800"
category: "Cloud"
tags: ["gke", "kubernetes", "google cloud", "docker", "artifact registry", "nextjs", "deployment", "cloud"]
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: Deploying Your Next.js Container Application with Google Kubernetes Engine

## Introduction
I've previously written about [running containerized applications on Cloud Run](https://blog.markkulab.net/on-prem-to-cloud-gcp-docker-deployment-artifact-registry-cloud-run/) and have also [tried setting up Kubernetes on-premises](https://blog.markkulab.net/intsll-kubernetes-in-ubuntu/). This post will focus on GKE (Google Kubernetes Engine). Most cloud providers today offer managed Kubernetes services, such as AWS's EKS, Azure's AKS, and Google's GKE. This makes a foundational knowledge of Kubernetes crucial. However, the official Kubernetes documentation is vast, so the best approach is to learn by doing.

## A Quick Comparison: Cloud Run vs. Google Kubernetes Engine
- **Google Cloud Run**: Ideal for single-container applications. Offers simple and fast deployment, suitable for small applications, APIs, and microservices.
- **Google Kubernetes Engine**: Provides cluster management and high-availability support. Suitable for applications requiring multi-container orchestration, auto-scaling, and high fault tolerance.

## Prerequisites
1. Ensure you have Docker and the Google Cloud CLI installed locally.
2. Enable the Kubernetes Engine API in your GCP project.
   ![enable kubernetes api](https://blog.markkulab.net/content/markku/posts/deploy-nextjs-app-to-google-kubernetes-service/images/enable-kubernetes-api.png)
3. Create a Google Artifact Registry in GCP.
4. Log in with the Google Cloud CLI and set your project.
```
gcloud projects list
gcloud config set project [PROJECT_ID]
```
5. Install the `kubectl` component for gcloud.
```
gcloud components install kubectl  gke-gcloud-auth-plugin
gcloud components update
```

## First, Initialize a Next.js Project
```bash
npx create-next-app@latest nextjs-blog --use-npm --example "https://github.com/vercel/next-learn/tree/main/basics/learn-starter"
cd nextjs-blog
```

Next, [copy the `Dockerfile` and `next.config.js` from the official example into your project's root directory](https://github.com/vercel/next.js/tree/canary/examples/with-docker).

### Build and Push the Docker Image to Google Artifact Registry
```powershell
docker build -t asia-east1-docker.pkg.dev/gcr-my-project01/my-registry/blog:v2 .
docker run -d -p 8888:80 asia-east1-docker.pkg.dev/gcr-my-project01/my-registry/blog:v2
docker push asia-east1-docker.pkg.dev/gcr-my-project01/my-registry/blog:v2
```

## Create Kubernetes Clusters
Google offers two modes for GKE clusters:
- **Standard Cluster:**
  - You manually configure node resources and manage the cluster, offering greater flexibility.
  - Users have deeper custom control, but this comes with a higher management overhead.
  - Suitable for users who need fine-grained control and custom configurations.

- **Autopilot Cluster:**
  - The infrastructure is automatically managed, allowing you to focus solely on deploying applications and workloads.
  - The system automatically adjusts resources based on demand, and you are billed for usage.
  - Ideal for those who want to simplify management and avoid manual node configuration.

You can create Kubernetes clusters using either the web UI or command-line scripts.
### Kubernetes Engine > Cluster > Create
![Create cluster](https://blog.markkulab.net/content/markku/posts/deploy-nextjs-app-to-google-kubernetes-service/images/create-cluster.png)

### Create a Cluster Using Command-Line Scripts
**Standard Cluster**
```bash
gcloud container clusters create blog-cluster --num-nodes 2 --machine-type n1-standard-1 --zone asia-east1-a
```

**Autopilot Cluster**
```bash
gcloud container clusters create-auto blog-autopilot-cluster --region asia-east1
```
## Deploy the Application
### Deploy a Container Using the Web UI
1. Go back to the GCP console and navigate to Kubernetes Engine > Workloads > Deploy.
2. Configure the server nodes and deployment name.
   ![Deployment via web UI](https://blog.markkulab.net/content/markku/posts/deploy-nextjs-app-to-google-kubernetes-service/images/deployment-by-web-ui.png)
3. Select the image you previously uploaded to Google Artifact Registry.
   ![Select Docker image](https://blog.markkulab.net/content/markku/posts/deploy-nextjs-app-to-google-kubernetes-service/images/select-docker-image.png)
4. Configure the internal and external ports.
   ![Change port mapping](https://blog.markkulab.net/content/markku/posts/deploy-nextjs-app-to-google-kubernetes-service/images/change-mapping-port.png)
5. You can review the YAML configuration. After closing, click Deploy.
   ![Check YAML file](https://blog.markkulab.net/content/markku/posts/deploy-nextjs-app-to-google-kubernetes-service/images/check-yaml.png)

### Deploy Using Command-Line Scripts
**Connect to the cluster**: Use `kubectl` from Cloud Shell.

![Use kubectl in Cloud Shell](https://blog.markkulab.net/content/markku/posts/deploy-nextjs-app-to-google-kubernetes-service/images/use-kubectl-in-cloud-shell.png)
You can run `kubectl` commands from Cloud Shell, or copy the connection command and run it locally to connect.
![Use kubectl in Cloud Shell](https://blog.markkulab.net/content/markku/posts/deploy-nextjs-app-to-google-kubernetes-service/images/use-kubectl-in-cloud-shell-2.png)
```bash
kubectl get nodes
```

![kubectl get nodes in Cloud Shell](https://blog.markkulab.net/content/markku/posts/deploy-nextjs-app-to-google-kubernetes-service/images/kubectl-get-nodes-in-cloud-shell.png)

**Create a Deployment**
```bash
vim nextjs-blog-deployment.yaml
```

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nextjs-blog
  labels:
    app: nextjs-blog
spec:
  selector:
    matchLabels:
      app: nextjs-blog
      tier: web
  template:
    metadata:
      labels:
        app: nextjs-blog
        tier: web
    spec:
      containers:
      - name: nextjs-blog-app
        image: asia-east1-docker.pkg.dev/gcr-my-project01/my-registry/blog:v2
        ports:
        - containerPort: 3000
```

Run the application:
```bash
kubectl apply -f nextjs-blog-deployment.yaml
kubectl get deploy nextjs-blog
```

**Network Configuration - Load Balancer**
* Automatically creates an external service, configures a Load Balancer, and binds an external IP.
```bash
kubectl expose deployment nextjs-blog-deployment --type="LoadBalancer"
```
* Alternatively, you can create it by specifying the port.*
```bash
kubectl expose deployment nextjs-blog-deployment --name=nextjs-blog-service --port=80 --target-port=3000 --type=LoadBalancer
```
[Documentation on specifying ports](https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/)

#### Accessing the Service After Deployment
Click on the service to access it.
![Deployment finished](https://blog.markkulab.net/content/markku/posts/deploy-nextjs-app-to-google-kubernetes-service/images/deployment-finish.png)
Accessing the Next.js site:
![Check accessibility](https://blog.markkulab.net/content/markku/posts/deploy-nextjs-app-to-google-kubernetes-service/images/check-accessible.png)

#### If you need additional port mapping, you can also use the Expose button below:
![Manual expose](https://blog.markkulab.net/content/markku/posts/deploy-nextjs-app-to-google-kubernetes-service/images/manual-expose.png)

## Appendix - Common Methods for Updating Images in Kubernetes
In Kubernetes, you can typically update an image using one of the following methods:
### 1. Update the image using `kubectl set image`
This method is suitable for quickly updating the image version:
```bash
kubectl set image deployment/<deployment-name> <container-name>=<new-image>:<new-tag>
```
For example:
```bash
kubectl set image deployment/my-app my-container=my-app-image:v2
```

### 2. Update the Deployment YAML file and re-apply it
If you manage your configuration with YAML files, you can update the image tag in the file and then re-apply it:
```yaml
# my-app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: my-container
        image: my-app-image:v2  # 更新映像檔標籤
```
Re-apply the updated YAML file:
```bash
kubectl apply -f my-app-deployment.yaml
```

### 3. Restart the Deployment using `kubectl rollout restart`
If the image tag has been updated (e.g., you pushed a new version with the same tag), you can use a restart to force a refresh:
```bash
kubectl rollout restart deployment/<deployment-name>
```

### 4. Update the image using `kubectl patch`
This method allows you to perform a partial update directly from the command line:
```bash
kubectl patch deployment <deployment-name> -p '{"spec":{"template":{"spec":{"containers":[{"name":"<container-name>","image":"<new-image>:<new-tag>"}]}}}}'
```
For example:
```bash
kubectl patch deployment my-app -p '{"spec":{"template":{"spec":{"containers":[{"name":"my-container","image":"my-app-image:v2"}]}}}}'
```
### Verify the Update
Regardless of the method used, you can use the following command to check if the update was successful:
```bash
kubectl rollout status deployment/<deployment-name>
```
All of these methods trigger a rolling update, which gradually replaces old containers with new ones to ensure service continuity.

## Appendix - For Next.js to support multiple servers, you need to additionally [configure `generateBuildId`](https://dev.to/writech/how-to-deploy-nextjs-on-multiple-servers-5db1) to ensure each application instance gets consistent files.

```
/_next/static/<build-ID>/<static-file>
```

## References
[How to deploy NextJS app to Kubernetes Cluster in GCP with Custom Domain?](https://walkthrough.so/pblc/FHQPWEGGWSPT/how-to-deploy-nextjs-app-to-kubernetes-cluster-in-gcp-with-custom-domain?sn=7)

---

## About this article and its author

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

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.
