Skip to content

Kubernetes 維運技巧速查

日常維運高頻使用的 Kubernetes 指令、設定技巧與 YAML 片段:跨 Namespace 存取、環境變數注入、kubeconfig 管理、儲存與安全設定。

概述

本文收錄 Kubernetes 日常維運中常用但散落各處的技巧,作為快速查找的速查手冊。涵蓋跨 Namespace 服務存取的 DNS 命名規則、ConfigMap/Secret 批次注入、kubeconfig 多叢集管理、Azure 特有的 Internal LoadBalancer 設定、PVC 寫入權限排除,以及 emptyDir 暫存 Volume 的使用方式。

這些技巧的共同特點是:各自獨立、使用頻率高,但每次需要時都得重新查文件——適合整理成速查手冊。

核心內容

跨 Namespace 存取服務

Pod 預設只能透過短名稱存取同一 Namespace 內的 Service。若要存取其他 Namespace 的 Service,需使用完整的叢集 DNS FQDN(Fully Qualified Domain Name):

<servicename>.<namespacename>.svc.cluster.local

例如,app Namespace 的 Pod 存取 ingress-basic Namespace 的 Squid Proxy:

squid-service.ingress-basic.svc.cluster.local:3128

K8s 的 CoreDNS 會解析此 FQDN 為對應 Service 的 ClusterIP,不需要任何額外設定。

環境變數注入(envFrom)

將個別 key 注入環境變數需逐一設定 env.valueFrom.configMapKeyRef;使用 envFrom 可一次將整份 ConfigMap 或 Secret 的所有 key-value 注入為環境變數,更為簡潔:

ConfigMap 整組注入:

yaml
envFrom:
- configMapRef:
    name: special-config

Secret 整組注入:

yaml
envFrom:
- secretRef:
    name: mysecret

ConfigMap 或 Secret 中的每個 key 會直接成為環境變數名稱。注意若有多份來源存在同名 key,後者會覆蓋前者。

Kubeconfig 管理

合併多份 config 為一份:

bash
export KUBECONFIG=~/.kube/config:~/someotherconfig
kubectl config view --flatten > new-config

--flatten 會將憑證資料內嵌(base64 embed)到輸出檔案中,而非保留外部路徑引用,確保輸出的單一檔案可攜。

從合併的 config 輸出特定 context:

bash
# 切換至目標 context
kubectl config use-context CONTEXT_NAME

# 只輸出目前 context 的獨立設定檔(--minify 過濾掉其他 context)
kubectl config view --minify --flatten > exported_context.yaml

# base64 單行編碼,常用於 CI/CD Pipeline 中注入為 Secret
cat master1-config | base64 -w0 > master1-config-base64

NFS Provisioner 安裝

NFS Subdir External Provisioner 建立一個 StorageClass,讓 Pod 能透過 PVC 動態掛載 NFS 共享目錄:

bash
helm repo add nfs-subdir-external-provisioner \
  https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/ \
  --insecure-skip-tls-verify

helm repo update

helm install nfs-subdir-external-provisioner \
  nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
  --insecure-skip-tls-verify \
  --set nfs.server=10.248.36.109 \
  --set nfs.path=/mnt/nfs_share \
  --namespace nfs

安裝後會建立名為 nfs-subdir-external-provisioner 的 StorageClass,Pod 申請 PVC 時指定此 StorageClass 即可自動在 NFS 上建立子目錄。

建立 KeyVault Secret(Azure AKS)

.env 檔案批次建立 K8s Secret,常用於存放 Azure Key Vault 或 Service Principal 連線認證:

bash
kubectl create secret generic keyvault-secret \
  --from-env-file=.keyvault.env \
  -n ingress-basic \
  -o yaml --dry-run=client | kubectl apply -f -

.keyvault.env 範例:

bash
AZURE_CLIENT_ID=2fe43815-a524-405d-8b57-460f42dbfe99
AZURE_TENANT_ID=da6e0628-fc83-4caf-9dd2-73061cbab167
AZURE_CLIENT_SECRET=64k.AgXqp_tOVxiY9u0ISD-FZ6u3~qLk3j

--dry-run=client | kubectl apply -f - 的好處是冪等(idempotent):Secret 已存在時會更新而非因「already exists」報錯,適合在自動化腳本中重複執行。

Azure Internal LoadBalancer

將 Service 暴露為 VNet 內部專用 LoadBalancer(不對公網開放),是 Azure AKS 上暴露叢集內服務給 VNet 內其他資源(如 VM、其他 AKS 叢集)存取的標準做法:

yaml
apiVersion: v1
kind: Service
metadata:
  name: squid-service
  namespace: ingress-basic
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"
    service.beta.kubernetes.io/azure-load-balancer-ipv4: 10.30.196.60
  labels:
    app: squid
spec:
  type: LoadBalancer
  ports:
  - port: 3128
  selector:
    app: squid

兩個 annotation 的作用:

  • azure-load-balancer-internal: "true" — 建立 Azure Internal LB(VNet 內部)而非 Public LB
  • azure-load-balancer-ipv4 — 指定靜態內部 IP(必須在 AKS Subnet 的可用範圍內)

靜態 IP 讓下游服務的連線目標固定,避免 LB IP 因重建而改變。

PVC 寫入權限問題(Permission Denied)

Container 執行時若 UID/GID 與 PVC 掛載目錄的擁有者不符,會出現 Permission Denied 錯誤。在 spec.template.spec 加入 securityContext.fsGroup 可讓 K8s 在掛載時自動將 Volume 的群組擁有權設為指定 GID,並確保容器中的程序可寫入:

yaml
spec:
  template:
    spec:
      securityContext:
        fsGroup: 999

fsGroup 的值對應 Container 內應用程式使用的 GID(例如:postgres 為 999、mysql 為 999、www-data 為 33)。

檔案傳輸(kubectl cp)

從 Pod 複製檔案到本機:

bash
kubectl cp ingress-basic/carbon-form-server-7fbf99c95-f28z6:/root/server/sqlite/58.db /tmp/58.db

格式為 <namespace>/<pod-name>:<容器路徑> <本機路徑>

替代作法(適用於 kubectl cp 因 tar 版本問題失敗時):

bash
kubectl exec -n ingress-basic carbon-form-server-7fbf99c95-f28z6 -- cat /root/server/sqlite/58.db > /tmp/58.db

kubectl cp 底層使用 tar 封裝,若容器內的 tar 版本與本機不相容會失敗。kubectl exec -- cat > 直接透過 stdout redirect,繞開 tar 相容問題,但缺點是不支援目錄複製。

emptyDir — 臨時共享與記憶體暫存 Volume

emptyDir 是 Pod 生命週期內的臨時 Volume,Pod 刪除後資料即消失。主要兩種使用場景:

  1. 同一 Pod 內多個 Container 共用儲存(例如 init container 寫入、main container 讀取)
  2. 高頻 I/O 暫存(使用記憶體模式)

記憶體模式(使用 tmpfs,速度等同 RAM):

yaml
volumes:
- name: cache-volume
  emptyDir:
    sizeLimit: 500Mi
    medium: Memory

不指定 medium 時預設使用節點本機硬碟;指定 medium: Memory 時使用 tmpfs,速度更快但會佔用節點的實體記憶體,需注意資源用量。

關鍵要點

  • 跨 Namespace 存取必須使用完整 DNS 名稱:<svc>.<ns>.svc.cluster.local
  • envFrom 可整組注入 ConfigMap 或 Secret,比逐一設定 env 更簡潔
  • kubectl config view --flatten 內嵌憑證,--minify 只輸出目前 context
  • Azure Internal LB 需兩個 annotation:internal: "true" + 靜態 IP
  • PVC 寫入權限問題通常可透過 securityContext.fsGroup 解決
  • kubectl exec -- cat >kubectl cp 因 tar 版本問題失敗時的可靠替代方案
  • emptyDir medium: Memory 使用 tmpfs,速度快但佔節點記憶體,需設定 sizeLimit 防止 OOM

實際應用

這些技巧在日常維運中反覆用到:跨 Namespace DNS 是微服務架構中服務互通的基礎;envFrom 讓環境設定從 Pod spec 中解耦;kubeconfig 合併與匯出在管理多叢集時不可缺少;NFS Provisioner 提供多 Pod 可讀寫的共享儲存;Azure Internal LB 確保內部服務不暴露於公網;fsGroup 排除了最常見的 PVC 掛載問題之一。

部署設定參考

以下為實際部署時使用的參數與指令,供日後查詢與複製使用。

環境參數

項目
NFS Server IP10.248.36.109
NFS Share Path/mnt/nfs_share
Internal LB 靜態 IP10.30.196.60
Internal LB Port(Squid)3128
KeyVault Secret Namespaceingress-basic
Azure Client ID2fe43815-a524-405d-8b57-460f42dbfe99
Azure Tenant IDda6e0628-fc83-4caf-9dd2-73061cbab167
Azure Client Secret64k.AgXqp_tOVxiY9u0ISD-FZ6u3~qLk3j

操作指令

bash
# NFS Provisioner 安裝
helm repo add nfs-subdir-external-provisioner \
  https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/ \
  --insecure-skip-tls-verify
helm repo update
helm install nfs-subdir-external-provisioner \
  nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
  --insecure-skip-tls-verify \
  --set nfs.server=10.248.36.109 \
  --set nfs.path=/mnt/nfs_share \
  --namespace nfs

# KeyVault Secret 冪等建立
kubectl create secret generic keyvault-secret \
  --from-env-file=.keyvault.env \
  -n ingress-basic \
  -o yaml --dry-run=client | kubectl apply -f -

# Kubeconfig 合併與匯出
export KUBECONFIG=~/.kube/config:~/someotherconfig
kubectl config view --flatten > new-config
kubectl config use-context CONTEXT_NAME
kubectl config view --minify --flatten > exported_context.yaml
cat master1-config | base64 -w0 > master1-config-base64

# 檔案傳輸
kubectl cp ingress-basic/carbon-form-server-7fbf99c95-f28z6:/root/server/sqlite/58.db /tmp/58.db
# 替代(繞過 tar 版本問題)
kubectl exec -n ingress-basic carbon-form-server-7fbf99c95-f28z6 -- cat /root/server/sqlite/58.db > /tmp/58.db

相關概念

來源