最近進到新專案,需要開始熟悉 GCP 相關服務,順手先嘗試將一個 Nginx 應用部署到 Google Kubernetes Engine (GKE) 上。過程中,使用 Helm 來簡化與管理部署流程,將過程記錄下來分享。

開發環境與前置準備

安裝 GKE 認證插件: bash gcloud components install gke-gcloud-auth-plugin

登入 GCP 帳號: bash gcloud auth login

在開始之前,需要先確認了本地環境已具備以下工具,並且 GKE Cluster 也已備妥。

  1. Google Cloud SDK (gcloud): 用於與 GCP 互動。在 macOS 上,我習慣用 Homebrew 安裝:

    brew install --cask google-cloud-sdk
    
  2. kubectl: Kubernetes 的命令列工具。gcloud 中其實已包含 kubectl,可以透過以下指令安裝:

    gcloud components install kubectl
    
  3. Helm: Kubernetes 的套件管理器。同樣,用 Homebrew 就能快速安裝:

    brew install helm
    
  4. 一個已啟用的 GCP 專案: 確保專案已啟用計費 (Billing) 與 GKE API。

  5. 一個執行中的 GKE Cluster: 需要一個 Kubernetes Cluster 來部署應用。這次我選擇建立一個 GKE Autopilot Cluster,因為它會自動管理節點,省去不少維運心力。建立的指令如下:

    # 將 your-cluster-name 替換為你的 Cluster 名稱
    gcloud container clusters create-auto your-cluster-name --region=us-central1
    
  6. 取得 Cluster 憑證:

本地,設定 gcloud 與 kubeconfig,這會把 GKE 的 kubeconfig 設定寫入本地 ~/.kube/config,讓你能用 kubectl / helm 操作 GKE。

gcloud config set project [YOUR_PROJECT_ID]
gcloud container clusters get-credentials your-cluster-name --region=[REGION]

可以查看本地 kubconfig

 cat ~/.kube/config
  1. 建立一個 namespace

建立 Namespace

kubectl create ns myk8s-ns

確認 namespace 是否建立,這樣 GKE 環境就準備好了,接下來就可以在這個 namespace 中用 Helm 安裝應用

kubectl get namespace

透過 kubectl 查看 namespace 內部的資源:

> kubectl -n myk8s-ns get all
NAME                               READY   STATUS    RESTARTS   AGE
pod/myk8s-nginx-755fff4646-rxlqf   1/1     Running   0          9m12s

NAME                  TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
service/myk8s-nginx   LoadBalancer   34.118.230.147   34.44.164.237   80:31815/TCP,443:32628/TCP   9m13s

NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/myk8s-nginx   1/1     1            1           9m14s

NAME                                     DESIRED   CURRENT   READY   AGE
replicaset.apps/myk8s-nginx-755fff4646   1         1         1       9m13s

起手式:建立 Helm Chart

第一步,為 Nginx 建立了一個基本的 Helm Chart。Helm 提供了方便的指令來生成一個標準的 Chart 結構。

> helm create myk8s
Creating myk8s

這個指令會建立一個 myk8s 資料夾,裡面包含了部署應用所需的所有模板檔案。

加入 chart repo(這裡以 Bitnami 的 nginx 為例)

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

注意!Bitnami 預告 2025/8/28 起會限制免費的 chart/image,建議你:

備份重要 chart 和 Docker image

考慮改用其他 Helm Chart source(例如官方 NGINX 或自己維護的)

關注 Bitnami 的 GitHub 通知:bitnami/containers/issues/83267

安裝與部署

透過 helm install 就可以安裝及部署服務到你的 k8s cluster

這裡先不修改設定,直接快速安裝一個 nginx 推送到 k8s 裡,安裝 chart 到指定 namespace

helm install myk8s bitnami/nginx --namespace myk8s-ns

可以看到 GKE 上面會建立

名稱         狀態 類型        Pod  機群        命名空間     叢集

myk8s-nginx	 OK	Deployment	1/1	 myk8s-web	myk8s-ns	myk8s-cluster

查看 namespace 取得外部 IP

kubectl -n myk8s-ns get all

從輸出的內容可以看出 EXTERNAL-IP ,透過外部 IP 可以直接確認是否有 Nginx 歡迎頁面

NAME                               READY   STATUS    RESTARTS   AGE
pod/myk8s-nginx-755fff4646-rxlqf   1/1     Running   0          17m

NAME                  TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
service/myk8s-nginx   LoadBalancer   <CLUSTER IP>   <外部IP>   80:31815/TCP,443:32628/TCP   17m

NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/myk8s-nginx   1/1     1            1           17m

NAME                                     DESIRED   CURRENT   READY   AGE
replicaset.apps/myk8s-nginx-755fff4646   1         1         1       17m

現階段,已經走完一個 Helm 安裝及部署服務到 K8S,接著來繼續一些參數調整設定。

客製化部署:調整 values.yaml

先從基礎客製化的 Value 開始,values.yaml 是 Helm Chart 的靈魂,它讓可以方便地客製化部署參數。為了控制資源用量,這裏主要調整了 CPU 和 Memory 的設定。

myk8s/values.yaml 中,找到 resources 區塊,並設定如下:

# myk8s/values.yaml
replicaCount: 1

image:
  repository: nginx
  pullPolicy: IfNotPresent
  tag: "stable"

# ... 其餘設定 ...

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 200m
    memory: 256Mi

這裡定義了 Pod 啟動時最少需要的資源 (requests),以及它最多能使用的資源上限 (limits)。

前面安裝的 nginx ,也可以先查看 values

helm show values bitnami/nginx

執行部署

一切就緒後,使用 helm install 指令來部署 Nginx Chart。

# 我在 myk8s 的上一層目錄執行此指令
helm install myk8s ./myk8s/

Release 就是「某個 Helm chart 被安裝到 Kubernetes 的一次實體部署實例

Helm Chart Release Kubernetes 中出現的東西
一份模板 一次部署實體 Deployment、Service、Pod、Ingress 等
  • myk8s 是這次部署的名稱 (Release Name),可以自訂。
  • ./myk8s 則是 Chart 的路徑。

部署後,習慣用這兩個指令來確認部署狀態:

helm list -A
kubectl get pods

也能隨時用 kubectl 來調整副本數。例如,將 Nginx 擴展到 2 個副本:

# deployment 名稱會與 helm install 的 release name 相同
kubectl scale deployment myk8s --replicas=2

刪除一個 K8S instance (Release)

首先,透過 helm 查看目前的 release, 可以看到 NAME(就是 Release name) 以及 NAMESPACE

helm list -A

透過以下指令可以刪除 Relase

helm uninstall <RELEASE_NAME> -n <NAMESPACE>

更新 value.yaml 同步到 K8S

如果需要調整 value.yaml 設定,執行 helm install 會遇到 INSTALLATION FAILED ,

陸續調整 value.yaml 後,可以透過以下指令 force 更新值到 K8S

helm upgrade [RELEASE] [CHART] [flags]

RELEASE 是你部署這個 chart 時取的名字(也叫 “release name”)

CHART 是 chart 的路徑(例如 .)或名稱(如 bitnami/nginx)

> helm upgrade myk8s ./myk8s -f ./myk8s/values.yaml --namespace=myk8s-ns
=
Release "myk8s" has been upgraded. Happy Helming!
NAME: myk8s
LAST DEPLOYED: Sat Jul 26 10:53:57 2025
NAMESPACE: myk8s-ns
STATUS: deployed
REVISION: 3

查看目前 k8s deployments

> helm list  

myk8s      	myk8s-ns 	1       	2025-07-26 09:52:06.049365 +0800 CST	deployed	nginx-21.0.8	1.29.0

查看設定細節

helm get all myk8s -n myk8s-ns

快速驗證:使用 Port-Forward 在本機測試

在正式對外開放前,通常會先用 port-forward 在本地快速驗證應用是否正常。

  1. 取得 Pod 名稱:

    export POD_NAME=$(kubectl get pods -l "app.kubernetes.io/name=myk8s,app.kubernetes.io/instance=myk8s" -o jsonpath="{.items[0].metadata.name}")
    
  2. 執行 Port-Forward:

    kubectl port-forward $POD_NAME 8080:80
    
  3. 在本機瀏覽: 接著就能在本地瀏覽器打開 http://127.0.0.1:8080 看到 Nginx 畫面了。

公開服務:讓外部存取 Nginx

要讓服務能被公開存取,有三種常見的方法,主要透過修改 values.yaml 來達成。

方法一:使用 LoadBalancer (最直接)

最簡單的方式,GCP 會自動配置一個網路負載平衡器並提供一個公開 IP。

  1. 設定 values.yaml
    service:
      type: LoadBalancer
      port: 80
    
  2. 更新部署並取得 IP:
    helm upgrade myk8s ./myk8s -f ./myk8s/values.yaml --namespace=myk8s-ns
    kubectl get svc myk8s
    
    kubectl get deployments myk8s -o yaml --namespace=myk8s-ns
    
    稍待幾分鐘,EXTERNAL-IP 欄位就會出現公開 IP。

方法二:使用 NodePort

NodePort 會在每個 Cluster 節點上開一個 Port,適合測試或特定網路架構。

  1. 設定 values.yaml

    service:
      type: NodePort
      port: 80
    

    更新部署

    helm upgrade myk8s ./myk8s -f ./myk8s/values.yaml --namespace=myk8s-ns
    kubectl get svc myk8s
    
    kubectl get deployments myk8s -o yaml --namespace=myk8s-ns
    

方法三:使用 Ingress 搭配 DNS (最靈活)

Ingress 是管理外部存取的 API 物件,功能最強大,適合生產環境。

  1. 設定 values.yaml
    ingress:
      enabled: true
      annotations:
        kubernetes.io/ingress.class: "gce" # GKE 預設 Ingress
      hosts:
        - host: your-app.your-domain.com # 替換成你的網域
          paths:
            - path: /
              pathType: Prefix
    
  2. 更新 DNS: 部署後,需要將 DNS your-app.your-domain.com 指向 Ingress Controller 提供的外部 IP。

管理與更新部署

當我修改了 Chart 設定後,會用 helm upgrade 來套用變更。在套用前,我習慣先用 helm diff 預覽一下變更點,確保一切都在預期之中。

# 預覽變更
helm diff upgrade myk8s ./myk8s

# 確認無誤後,正式更新
helm upgrade myk8s ./myk8s

最後一步:清理資源

測試完成後,為了避免產生不必要的費用,清理資源是很重要的一步。

方法一:使用 Helm Uninstall (推薦)

最推薦的方式是使用 helm uninstall,它會智慧地刪除所有相關資源。

helm uninstall myk8s

方法二:手動使用 kubectl 刪除

因為是測試用途,這裏順手用 kubectl 手動刪除節省資源。

  1. 暫停服務 (縮減副本至 0):
    kubectl scale deployment myk8s --replicas=0
    
  2. 刪除 Deployment、Service 等:
    kubectl delete deployment myk8s
    kubectl delete service myk8s
    
  3. 刪除 PVC (儲存卷):
    # 警告:此操作會刪除當前 namespace 中所有的 PVC
    kubectl delete pvc --all
    

以上就是這次使用 Helm 將 Nginx 部署到 GKE 的完整過程。希望這份經驗分享對正在研究雲端部署的朋友們能有所幫助。