iT邦幫忙

2025 iThome 鐵人賽

DAY 15
0
DevOps

DevOps 進化論:從全能型戰士到安全守門員系列 第 15

Day 15:從 YAML 到 Helm:打造可重用的部署模板

  • 分享至 

  • xImage
  •  

● 前言

在 Day 11~14,我們依序完成了 Deployment / Service / Ingress / ConfigMap / Secret 的基礎實作。然而,單純撰寫 YAML 檔案在多環境(dev / prod)維運時會面臨重複與難以管理的問題。為此,我們引入 Helm Chart 來將資源模板化,並利用 values.yaml 做環境參數化管理,讓部署更彈性且可控。

● 核心元件

Helm Chart 的組成包含:

▪Chart.yaml:描述 Chart 基本資訊(名稱、版本、描述)。

▪values.yaml:環境參數設定,可再用 values.dev.yaml / values.prod.yaml 覆寫。

▪templates/:主要存放 Deployment、Service、Ingress、ConfigMap、Secret 等模板檔案。

▪_helpers.tpl:定義命名規則與共用的 labels,避免硬編碼。

這些元素搭配起來,能實現「一份模板,多種環境」的彈性部署。

● 實作步驟

1.啟動Minikube並切回 Minikube 的 Docker 環境

🔹minikube start --driver=docker

2. 安裝 Helm v3

🔹sudo apt-get install helm

👉 成功後用 helm version 驗證

3.移除不必要檔案並建立 Chart:

🔹helm create app

👉建立 Chart

🔹cd app

👉進入app目錄

🔹rm -f templates/tests/test-connection.yaml templates/hpa.yaml

👉刪除不必要檔案

4.撰寫設定及模板:

▪values.yaml:定義 replicaCount、image、env、secretEnv、ingress。

replicaCount: 1

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

service:
  type: ClusterIP
  port: 80
  targetPort: 80

ingress:
  enabled: true
  className: nginx
  host: app.local.test
  path: /
  tls: false
  annotations: {}

env:
  APP_ENV: "dev"
  LOG_LEVEL: "debug"

secretEnv:
  DUMMY: "ok"

probes:
  readinessPath: "/"
  livenessPath: "/"

resources: {}

▪deployment.yaml:引用 ConfigMap / Secret,並加上健康檢查與 checksum annotation。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "app.fullname" . }}
  labels:
    {{- include "app.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ include "app.fullname" . }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ include "app.fullname" . }}
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
        checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: {{ .Values.service.targetPort }}
          envFrom:
            - configMapRef:
                name: {{ include "app.fullname" . }}-cm
            - secretRef:
                name: {{ include "app.fullname" . }}-secret
          readinessProbe:
            httpGet:
              path: {{ .Values.probes.readinessPath }}
              port: http
            initialDelaySeconds: 5
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: {{ .Values.probes.livenessPath }}
              port: http
            initialDelaySeconds: 10
            periodSeconds: 10
          resources:
            {{- toYaml .Values.resources | nindent 12 }}

▪service.yaml:設定對外暴露的服務型別與 Port。

apiVersion: v1
kind: Service
metadata:
  name: {{ include "app.fullname" . }}
  labels:
    {{- include "app.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  selector:
    app.kubernetes.io/name: {{ include "app.fullname" . }}
  ports:
    - name: http
      port: {{ .Values.service.port }}
      targetPort: {{ .Values.service.targetPort }}
      protocol: TCP

▪ingress.yaml:設定 host/path 與 TLS(配合 cert-manager)。

{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "app.fullname" . }}
  labels:
    {{- include "app.labels" . | nindent 4 }}
  annotations:
    {{- toYaml .Values.ingress.annotations | nindent 4 }}
spec:
  {{- if .Values.ingress.className }}
  ingressClassName: {{ .Values.ingress.className }}
  {{- end }}
  {{- if .Values.ingress.tls }}
  tls:
    - hosts:
        - {{ .Values.ingress.host }}
      secretName: {{ include "app.fullname" . }}-tls
  {{- end }}
  rules:
    - host: {{ .Values.ingress.host }}
      http:
        paths:
          - path: {{ .Values.ingress.path }}
            pathType: Prefix
            backend:
              service:
                name: {{ include "app.fullname" . }}
                port:
                  number: {{ .Values.service.port }}
{{- end }}

▪configmap.yaml / secret.yaml:自 values 載入環境變數。

👉configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "app.fullname" . }}-cm
  labels:
    {{- include "app.labels" . | nindent 4 }}
data:
  {{- range $k, $v := .Values.env }}
  {{ $k }}: {{ $v | quote }}
  {{- end }}

👉secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: {{ include "app.fullname" . }}-secret
  labels:
    {{- include "app.labels" . | nindent 4 }}
type: Opaque
stringData:
  {{- range $k, $v := .Values.secretEnv }}
  {{ $k }}: |-
    {{- $v | nindent 4 }}
  {{- end }}

5.部署流程:

🔹helm upgrade --install app . -n app-ns --create-namespace -f values.yaml --dry-run --debug

👉Dry-run 預覽

🔹helm upgrade --install app . -n app-ns -f values.yaml -f values.dev.yaml

👉部署到 dev

🔹helm upgrade --install app . -n app-ns -f values.yaml -f values.prod.yaml

👉 部署到 prod

6.回滾與除錯:

kubectl -n app-ns rollout status deploy/app-app
helm history app -n app-ns
helm rollback app <REVISION> -n app-ns

● 注意事項

1.Ingress DNS:需確認 Host 有正確解析,本地可透過 /etc/hosts 測試。

2.健康檢查:務必設置 readiness / liveness,避免 Rolling Update 卡住。

3.ConfigMap/Secret 更新:加上 checksum annotation 才能觸發滾動更新。

4.values 覆寫:多環境部署時,務必指定對應的 values.{env}.yaml。

5.Secrets 管理:範例用 values,實務建議 External Secrets / Vault。

● 總結

Helm,我們成功將 Day 11~14的Kubernetes資源模板化,並依環境做彈性切換,實現更高效的部署與維運。這個最小可用 Chart 已能支援基本應用上線,接下來可以逐步加入 HPA、資源限制、Observability(Prometheus/Grafana)、以及 CI/CD自動化流程。

👉 下一篇:Day 16|高可用與擴展性(觀念+輕實作)


上一篇
Day 14 : K8s 設定管理必修課:ConfigMap與Secret實戰
下一篇
Day 16 : 高可用與自動擴展:HPA、PDB 與 Deployment 策略圖解
系列文
DevOps 進化論:從全能型戰士到安全守門員19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言