Kubernetes 叢集的管理核心在於應用程式狀態的宣告式定義,這需要透過版本控制和程式碼審查等最佳實務來確保組態檔案的一致性和可靠性。檔案系統佈局應以目錄組織元件,並妥善管理容器映像檔版本,避免供應鏈攻擊。Deployment 資源則能有效管理複製服務,結合 ReplicaSet 的複製功能與版本控制,實作高用性和可擴充套件性。同時,Service 和 Ingress 資源的運用,讓外部流量得以有效導向至正確的 Pod,確保服務的穩定執行。此外,ConfigMap 和 Secret 的使用,分別提供應用程式組態和敏感資訊的管理方案,提升應用程式的靈活性和安全性。最後,以 Redis 佈署為例,說明如何利用 StatefulSet 和 PersistentVolumeClaim 管理有狀態應用程式的持久化儲存,確保資料的完整性和一致性。

在 Kubernetes 中管理組態檔案與建立複製服務

在探討如何在 Kubernetes 中構建應用程式之前,瞭解如何管理組態檔案本身是非常重要的。在 Kubernetes 中,一切都是以宣告式的方式呈現。這意味著你需要在 YAML 或 JSON 檔案中定義應用程式在叢集中的期望狀態,這些宣告的期望狀態定義了應用程式的所有組成部分。

管理組態檔案的最佳實踐

由於這些 YAML 檔案中所包含的宣告式狀態是應用程式的真實來源,因此正確管理這種狀態對於應用程式的成功至關重要。在修改應用程式的期望狀態時,你需要能夠管理變更、驗證其正確性、審核誰進行了變更,並可能在變更失敗時將其回復。幸運的是,在軟體工程的背景下,我們已經開發出了管理宣告式狀態變更以及審核和回復所需的工具。也就是說,圍繞版本控制和程式碼審查的最佳實踐直接適用於管理應用程式的宣告式狀態。

大多數人將 Kubernetes 組態檔案儲存在 Git 中。儘管版本控制系統的具體細節並不重要,但 Kubernetes 生態系統中的許多工具都預期檔案儲存在 Git 儲存函式庫中。對於程式碼審查,存在更多的異質性;儘管 GitHub 非常流行,但其他人使用原生程式碼審查工具或服務。無論你如何實施應用程式組態的程式碼審查,你都應該像對待原始碼控制一樣嚴格對待它。

檔案系統佈局

在佈局應用程式的檔案系統時,使用檔案系統附帶的目錄組織來組織元件是值得的。通常,一個單獨的目錄用於包含一個應用程式服務。對於我們的應用程式,我們將檔案佈局如下:

journal/
  frontend/
  redis/
  fileserver/

在每個目錄中,都包含定義服務所需的具體 YAML 檔案。

使用佈署建立複製服務

為了描述我們的應用程式,我們將從前端開始,向下推進。前端應用程式是一個使用 TypeScript 實作的 Node.js 應用程式。完整的應用程式太大,無法包含在本文中,因此我們將其託管在 GitHub 上。

映像檔管理的最佳實踐

儘管一般來說,構建和維護容器映像檔超出了本文的範圍,但識別一些構建和命名映像檔的通用最佳實踐是值得的。一般來說,映像檔構建過程可能容易受到「供應鏈攻擊」。在這種攻擊中,惡意使用者將程式碼或二進位制檔案注入到來自受信任來源的某些依賴項中,然後將其構建到你的應用程式中。

由於這種風險,在構建映像檔時,根據僅知名和受信任的映像檔提供者是非常重要的。另外,你可以從頭開始構建所有映像檔。對於一些語言(例如 Go),可以輕鬆地從頭開始構建,因為它們可以構建靜態二進位制檔案,但對於像 Python、JavaScript 或 Ruby 這樣的解釋型語言來說,這要複雜得多。

對於映像檔命名的最佳實踐,儘管映像檔登入檔中容器映像檔的版本理論上是可變的,但你應該將版本標籤視為不可變的。特別是,語義版本和構建映像檔時提交的 SHA 雜湊值的某種組合是命名映像檔的好做法(例如,v1.0.1-bfeda01f)。

建立複製應用程式

我們的前端應用程式是無狀態的;它完全依賴 Redis 後端來保持其狀態。因此,我們可以任意複製它,而不會影響流量。儘管我們的應用程式不太可能維持大規模的使用,但執行至少兩個副本仍然是一個好主意,這樣你就可以處理意外的當機或推出新版本的應用程式,而不會造成停機。

在 Kubernetes 中,ReplicaSet 資源是直接管理特定版本容器化應用程式複製的資源。然而,由於所有應用程式的版本都會隨著時間的推移而變化,因此直接使用 ReplicaSet 並不是最佳實踐。相反,你應該使用 Deployment 資源。Deployment 結合了 ReplicaSet 的複製功能與版本控制和分階段推出的能力。

Kubernetes Deployment 資源範例

# Kubernetes Deployment 資源定義範例
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: frontend
        image: your-docker-image-name:latest
        ports:
        - containerPort: 8080

內容解密:

  1. apiVersionkind 定義了 Kubernetes 資源的版本和型別。
  2. metadata 部分提供了有關 Deployment 的後設資料,如名稱。
  3. spec 部分定義了 Deployment 的期望狀態,包括副本數量、選擇器和 Pod 範本。
  4. replicas 指定了要執行的 Pod 副本數量。
  5. selectortemplate 部分定義了 Deployment 如何找到要管理的 Pod,以及如何建立新的 Pod。
  6. containers 部分定義了 Pod 中執行的容器,包括映像檔名稱和埠組態。

透過使用 Deployment 資源,你可以利用 Kubernetes 的內建工具,將應用程式從一個版本遷移到下一個版本,同時保持高用性和可擴充套件性。

Kubernetes 佈署與服務設定

在現代化的雲端應用佈署中,Kubernetes 提供了強大的容器協調功能。本文將探討如何使用 Kubernetes Deployment 資源佈署應用程式,並透過 Service 和 Ingress 資源對外提供服務。

建立可複製的服務

首先,我們需要定義一個 Deployment 資源來佈署我們的應用程式。以下是一個範例 YAML 檔案:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: frontend
  name: frontend
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - image: my-repo/journal-server:v1-abcde
        imagePullPolicy: IfNotPresent
        name: frontend
        resources:
          requests:
            cpu: "1.0"
            memory: "1G"
          limits:
            cpu: "1.0"
            memory: "1G"

內容解密:

  • apiVersionkind 定義了資源的型別和版本。
  • metadata 包含了資源的名稱、名稱空間和標籤。
  • spec 定義了 Deployment 的詳細規格,包括副本數量、選擇器和容器範本。
  • replicas 設定為 2,以確保服務的高用性。
  • selector.matchLabelstemplate.metadata.labels 確保 Deployment 可以正確管理由它建立的 Pod。
  • resources.requestsresources.limits 設定了容器的資源需求和限制,確保容器不會超出指定的資源範圍。

將 Deployment 資源佈署到 Kubernetes

定義好 Deployment 資源後,我們需要將其佈署到 Kubernetes 叢集中。首先,將 YAML 檔案提交到版本控制系統:

git add frontend/deployment.yaml
git commit -m "Added deployment" frontend/deployment.yaml
kubectl apply -f frontend/deployment.yaml

採用 GitOps 方法可以確保叢集的狀態與版本控制系統中的組態一致。

設定外部 Ingress 以提供 HTTP 服務

要使應用程式能夠被外部存取,我們需要建立一個 Service 和一個 Ingress 資源。Service 負責將流量導向正確的 Pod,而 Ingress 提供 HTTP(S) 負載平衡和智慧路由。

首先,定義一個 Service 資源:

apiVersion: v1
kind: Service
metadata:
  labels:
    app: frontend
  name: frontend
  namespace: default
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: frontend
  type: ClusterIP

內容解密:

  • spec.ports 定義了 Service 的埠和協定。
  • selector 將 Service 與具有 app: frontend 標籤的 Pod 相關聯。
  • type: ClusterIP 表示這是一個叢集內部的 Service。

接下來,定義一個 Ingress 資源:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: frontend-ingress
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend
            port:
              number: 8080

內容解密:

  • spec.rules 定義了 Ingress 的路由規則。
  • host 指定了網域名稱。
  • http.paths 定義了路徑和後端 Service 的對映關係。

Kubernetes基礎服務設定:Ingress、ConfigMaps與Secrets管理

在前面的章節中,我們已經成功建立了基本的Kubernetes服務。本章節將探討如何使用Ingress資源來管理外部流量、如何透過ConfigMaps進行應用程式組態,以及如何使用Secrets來安全管理敏感資訊。

使用Ingress管理外部流量

Kubernetes的Ingress資源允許您管理進入叢集的HTTP和HTTPS流量。透過定義Ingress資源,您可以指定如何將外部請求路由到叢集內的服務。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: frontend-ingress
spec:
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 8080

內容解密:

  • apiVersionkind 定義了資源的API版本和型別,這裡是Ingress
  • metadata.name 指定了Ingress資源的名稱。
  • spec.rules 定義了路由規則,這裡設定了一個HTTP規則,將/testpath開頭的請求路由到名為test的服務的8080埠。

使用ConfigMaps進行應用程式組態

ConfigMaps允許您將組態資料與應用程式碼分離,使得應用程式更加靈活和可組態。

建立ConfigMap

kubectl create configmap frontend-config --from-literal=journalEntries=10

在Deployment中使用ConfigMap

containers:
- name: frontend
  ...
  env:
  - name: JOURNAL_ENTRIES
    valueFrom:
      configMapKeyRef:
        name: frontend-config
        key: journalEntries

內容解密:

  • kubectl create configmap 命令用於建立一個ConfigMap。
  • 在Deployment的定義中,我們透過env欄位將ConfigMap中的journalEntries鍵值對注入到容器環境變數JOURNAL_ENTRIES中。

版本化ConfigMap以實作平滑更新

為了實作組態的平滑更新和版本控制,建議在ConfigMap的名稱中加入版本號,如frontend-config-v1。當需要更新組態時,建立新的ConfigMap(如frontend-config-v2),並更新Deployment以使用新的ConfigMap。

使用Secrets管理敏感資訊

Secrets用於儲存敏感資訊,如密碼、API金鑰等。與ConfigMaps類別似,但Secrets對資料進行了加密處理。

建立Secret

kubectl create secret generic redis-passwd --from-literal=passwd=${RANDOM}

在應用程式中使用Secret

您可以透過Volume將Secret掛載到容器中,或將其作為環境變數注入。

# 示例:將Secret作為環境變數注入
env:
- name: REDIS_PASSWORD
  valueFrom:
    secretKeyRef:
      name: redis-passwd
      key: passwd

內容解密:

  • kubectl create secret 命令用於建立一個Secret。
  • 將Secret中的資料以環境變數或檔案的形式提供給應用程式。

在 Kubernetes 中使用 Secret 管理驗證資訊

在容器化環境中,管理敏感資訊(如密碼、API 金鑰等)是一項重要的安全任務。Kubernetes 提供了一個名為 Secret 的資源,用於安全地儲存和管理這些敏感資料。

為何使用 Secret?

將敏感資訊直接寫入應用程式的程式碼或設定檔中存在極大的安全風險。Secret 允許開發人員將這些資訊與應用程式碼分離,從而降低洩露風險。

如何使用 Secret?

首先,您需要建立一個 Secret 資源。Kubernetes 提供了多種建立 Secret 的方法,包括使用 kubectl 命令列工具。

kubectl create secret generic redis-passwd --from-literal=password=your_password

建立 Secret 後,您可以在 Pod 的設定檔中參照它。以下是一個範例 YAML 檔案,展示瞭如何將 Secret 掛載到容器中的特定路徑:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: frontend
  name: frontend
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - image: my-repo/journal-server:v1-abcde
        imagePullPolicy: IfNotPresent
        name: frontend
        volumeMounts:
        - name: passwd-volume
          readOnly: true
          mountPath: "/etc/redis-passwd"
        resources:
          requests:
            cpu: "1.0"
            memory: "1G"
          limits:
            cpu: "1.0"
            memory: "1G"
      volumes:
      - name: passwd-volume
        secret:
          secretName: redis-passwd

內容解密:

  1. apiVersionkind 定義了 Kubernetes 資源的版本和型別。
  2. metadata 部分包含了 Deployment 的元資料,如名稱、標籤等。
  3. spec 部分定義了 Deployment 的具體規格,包括副本數量、選擇器、範本等。
  4. template.spec 下,定義了容器的詳細組態,包括映像檔、映像檔提取策略、名稱、掛載點等。
  5. volumeMounts 指定了將 Secret 掛載到容器中的 /etc/redis-passwd 路徑。
  6. volumes 部分定義了一個名為 passwd-volume 的 Volume,它參照了名為 redis-passwd 的 Secret。

使用 CSI 驅動程式

除了直接使用 Secret,您還可以使用 Container Storage Interface (CSI) 驅動程式來掛載外部金鑰管理系統(KMS)中的金鑰。這種方法特別適合於需要遵守嚴格安全和合規要求的組織。

volumes:
- name: passwd-volume
  csi:
    driver: secrets-store.csi.k8s.io
    readOnly: true
    volumeAttributes:
      secretProviderClass: "azure-sync"

內容解密:

  1. 使用 CSI 驅動程式可以將外部 KMS 中的金鑰掛載到 Pod 中。
  2. driver 指定了使用的 CSI 驅動程式名稱。
  3. volumeAttributes 部分包含了與特定 CSI 驅動程式相關的組態,例如 secretProviderClass

佈署簡單的有狀態資料函式庫

佈署有狀態應用(如 Redis)比佈署無狀態應用更為複雜,因為需要考慮資料的永續性和一致性。Kubernetes 中的 StatefulSet 資源提供了對有狀態應用的支援。

使用 PersistentVolume 和 PersistentVolumeClaim

要佈署 Redis,首先需要建立一個 PersistentVolumeClaim(PVC),用於請求儲存資源。然後,在 StatefulSet 的組態中參照這個 PVC。

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
spec:
  serviceName: redis
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis:latest
        volumeMounts:
        - name: data
          mountPath: /data
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 50Gi

內容解密:

  1. StatefulSet 用於管理有狀態應用,提供穩定的網路識別和持久化儲存。
  2. volumeClaimTemplates 部分定義了 PVC 的範本,用於為每個 Pod 請求儲存資源。
  3. accessModes 指定了儲存卷的存取模式,例如 ReadWriteOnce 表示該卷可以被單個節點以讀寫模式掛載。