Kubernetes 作為容器協調框架,能有效管理容器化應用程式。本文介紹如何使用 Python 與 Kubernetes 進行整合,包含 Pod 的 Liveness 和 Readiness 檢查設定,尤其針對啟動緩慢的應用程式提供最佳化策略。此外,文章也說明如何使用 Python 操作 Kubernetes API,實作自動化管理 Kubernetes 資源,例如建立、更新和刪除 Pod 與服務等。組態管理對於不同環境的佈署至關重要,本文將探討如何使用環境變數和 ConfigMap 管理應用程式設定,並示範如何在 Python 應用程式中讀取這些設定。最後,文章還會介紹 Secrets 的使用,確保敏感資訊的安全管理,以及 Sidecar 容器的應用,擴充套件 Pod 的功能,例如 readiness checks 的實作。

Kubernetes 自動化與 Python 應用整合

Kubernetes 是一個流行的容器協調框架,能夠根據各種引數在 Linux 機器(虛擬或實體)上執行容器。Python 與 Kubernetes 的互動主要有兩種方式:首先,Kubernetes 可以執行 Python 應用程式;其次,Python 可以透過 Kubernetes 的 API 實作自動化管理。

Pod:Kubernetes 的基本單位

Pod 是 Kubernetes 中的一個重要概念,它是一組分享相同網路名稱空間但不分享檔案系統的容器。這些容器總是一起執行。許多 Pod(甚至在某些 Kubernetes 安裝中所有的 Pod)只包含一個容器。如果有多個容器,通常會有一個主容器和其他輔助容器(有時稱為 sidecar)。Sidecar 容器可以執行從終止 SSL 流量到匯出指標等各種任務。

Liveness 和 Readiness 檢查

在組態 Pod 時,有兩個重要的概念:Readiness 和 Liveness。

  • Liveness 檢查:用於判斷容器是否需要重新啟動。如果 Liveness 檢查失敗,Kubernetes 將重新啟動 Pod。
  • Readiness 檢查:用於判斷 Pod 是否準備好接收流量。只有 Readiness 檢查成功的 Pod 才會被納入服務中。

對於根據 Web 的應用程式,通常會組態一個或多個專用的端點來確定健康狀態和準備情況。如果應用程式啟動緩慢,最好在啟動初期就開始回應 Liveness 檢查,同時組態 Readiness 檢查以指示初始組態完成,應用程式已準備好接收流量。

慢速啟動的處理

對於啟動緩慢的應用程式,一種常見的原因是需要進行一些初始資料處理。以下是一個簡單的例子,展示了一個需要大量計算才能啟動的 Web 服務。

def fibonacci(n):
    if n < 2:
        return 1
    return fibonacci(n - 1) + fibonacci(n - 2)

fibonacci_results = {}
fibonacci_results[40] = fibonacci(40)

這個例子中,fibonacci 函式使用樸素的、慢速的演算法來計算 Fibonacci 數。這種慢速計算可以代表那些難以最佳化的計算任務。為了加快應用程式的啟動速度,可以對相關的 Fibonacci 數進行快取。

組態 Liveness 和 Readiness 檢查

在組態 Liveness 檢查時,應該設定較短的超時時間。如果應用程式啟動後 Liveness 檢查仍然超時,可能意味著某些地方出了問題。然而,如果應用程式啟動太慢,Liveness 檢查可能會導致 Pod 進入當機迴圈。在這種情況下,結合更好的啟動策略和分離的 Liveness 和 Readiness 檢查會很有幫助。

使用 Python 與 Kubernetes API

Python 可以透過 Kubernetes API 自動化管理 Kubernetes 資源。這使得開發者能夠編寫指令碼來建立、更新或刪除 Kubernetes 資源,如 Pod 和服務。

Kubernetes 應用程式開發與組態管理

在為 Kubernetes 開發應用程式時,考量組態管理是至關重要的。組態管理涉及不同環境(開發、測試、生產等)之間的差異。任何在不同環境之間不變的組態都可以被封裝到容器映像中。

環境變數

環境變數是一種常見的用於傳遞組態引數的機制。例如,在 The Twelve-Factor App 方法論中,這被認為是正確的做法。環境變數提供了一個簡單的名稱空間,可以在應用程式碼中的任何地方被存取,並包含任意資料。透過 Kubernetes 設定環境變數,可以在容器規格中新增 env 小節來實作。

env:
- name: GEM_LEVEL
  value: "diamond"

在應用程式碼中,可以使用 os.environ 字典類別物件來存取環境變數。

gem_level = os.environ["GEM_LEVEL"]

為了使程式碼更具可測試性,最好在盡可能高的層級進行此操作。在 Web 應用程式中,這可以在構建 WSGI 應用程式時完成。

Pyramid Web 框架範例

以下範例使用了 Pyramid Web 框架。一個使用 GEM_LEVEL 環境變數的 Web 應用程式碼可能如下所示。

from pyramid import config as configlib, response

def gem_level(request):
    level = request.registry.settings["gem_level"]
    return response.Response(f"Level: {level}")

def make_app(environ):
    settings = dict(gem_level=os.environ["GEM_LEVEL"])
    with configlib.Configurator(settings=settings) as config:
        config.add_route('gem_level', '/')
        config.add_view(gem_level, route_name='gem_level')
        app = config.make_wsgi_app()
    return app

import os
application = make_app(os.environ)

Dockerfile 設定

相關的 Dockerfile 可能以如下行結束。

ENTRYPOINT ["gunicorn", "gem_level"]

例如,對於一個概念驗證,可以編寫一個簡短的 Dockerfile。

FROM python
RUN pip install gunicorn pyramid
COPY gem_level.py /
ENTRYPOINT ["gunicorn", "gem_level"]

程式碼解說:

  1. 環境變數的使用:透過 os.environ["GEM_LEVEL"] 取得環境變數 GEM_LEVEL 的值。
  2. WSGI 應用程式的構建make_app 函式根據環境變數建立一個 WSGI 應用程式。
  3. Dockerfile 組態:將應用程式碼複製到 Docker 容器中,並設定啟動命令。

組態檔案

Kubernetes pods 和佈署支援 ConfigMap。雖然 ConfigMap 設定可以設定環境變數或命令列引數,但有不同的方法來設定它們。

Kubernetes 組態管理流程

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 組態檔案

rectangle "包含" as node1
rectangle "設定" as node2
rectangle "被應用程式" as node3

node1 --> node2
node2 --> node3

@enduml

此圖示說明瞭 Kubernetes 中組態管理的流程,包括 ConfigMap 如何設定環境變數和命令列引數,並被應用程式讀取。

Kubernetes 設定管理與 Secrets 應用

Kubernetes 的 ConfigMap 與 Secrets 是兩種重要的資源管理工具,分別用於管理應用程式的設定與敏感資訊。本文將探討這兩者的使用方式及其在 Python 應用程式中的實踐。

ConfigMap:應用程式設定的靈活管理

ConfigMap 允許將設定資料以檔案形式掛載到容器中,這對於移植現有的 Python 應用程式至 Kubernetes 叢集尤其有用。例如,使用 gunicorn 執行 WSGI 應用程式時,可以透過 ConfigMap 設定 Paste 相容的設定檔。

範例:使用 ConfigMap 設定 Pyramid 應用程式

首先,定義一個 Pyramid 應用程式的工廠函式 make_app_ini

def make_app_ini(global_config, **settings):
    with configlib.Configurator(settings=settings) as config:
        config.add_route('gem_level', '/')
        config.add_view(gem_level, route_name='gem_level')
        app = config.make_wsgi_app()
    return app

接著,建立一個 ConfigMap 資源,包含 paste.ini 設定檔:

apiVersion: v1
kind: ConfigMap
metadata:
  name: gem-level-config-diamond
data:
  paste.ini: |
    [app:main]
    use = call:gem_level:make_app_ini
    [DEFAULT]
    gem_level = diamond

在 Pod 設定中,將 ConfigMap 掛載到容器內的特定路徑:

apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo-pod
spec:
  containers:
  - name: gemlevel
    image: ...
    command: ["gunicorn", "--paste", "/etc/gemlevel/paste.ini"]
    volumeMounts:
    - name: config
      mountPath: "/etc/gemlevel"
      readOnly: true
  volumes:
  - name: config
    configMap:
      name: gem-level-config-diamond
      items:
      - key: "paste.ini"
        path: "paste.ini"

程式碼解析

此範例展示瞭如何將 ConfigMap 中的 paste.ini 設定檔掛載到容器內的 /etc/gemlevel 目錄。gunicorn 命令透過 --paste 引數讀取該設定檔,啟動 Pyramid 應用程式。

內容解密:

  1. ConfigMap 定義:建立了一個名為 gem-level-config-diamond 的 ConfigMap,其中包含 paste.ini 設定檔的內容。
  2. Pod 設定:在 Pod 設定中,將 gem-level-config-diamond ConfigMap 掛載到容器內的 /etc/gemlevel 目錄。
  3. 容器啟動命令:gunicorn 命令透過 --paste 引數指定了 /etc/gemlevel/paste.ini 設定檔的路徑。

Secrets:安全地管理敏感資訊

Secrets 用於儲存敏感資訊,如資料函式庫密碼、API 金鑰等。與 ConfigMap 類別似,Secrets 可以被掛載為容器內的檔案或環境變數。

範例:使用 Secrets 管理敏感資訊

建立一個 Secret 資源,包含加密的敏感資訊:

apiVersion: v1
kind: Secret
metadata:
  name: luggage
type: Opaque
data:
  code: MTIzNDU=

在 Pod 設定中,將 Secret 掛載到容器內的特定路徑:

spec:
  containers:
  - name: acontainer
    # ...
    env:
    - name: SECRET_CODE
      value: /etc/secrets/code
    volumeMounts:
    - name: secrets
      mountPath: "/etc/secrets"
      readOnly: true
  volumes:
  - name: secrets
    secret:
      secretName: luggage
      items:
      - key: code
        path: code

程式碼解析

此範例展示瞭如何將 Secret 中的敏感資訊掛載到容器內的 /etc/secrets 目錄。應用程式透過讀取 /etc/secrets/code 檔案取得敏感資訊。

內容解密:

  1. Secret 定義:建立了一個名為 luggage 的 Secret,其中包含 base64 編碼的敏感資訊 code
  2. Pod 設定:在 Pod 設定中,將 luggage Secret 掛載到容器內的 /etc/secrets 目錄。
  3. 應用程式讀取:應用程式透過讀取環境變數 SECRET_CODE 指定的檔案路徑 /etc/secrets/code 取得敏感資訊。

Python Sidecars:擴充套件 Pod 功能

Sidecars 是與主容器一起執行的輔助容器,可以用於執行額外的任務,如 readiness checks。

範例:使用 Sidecar 執行 readiness check

建立一個 Sidecar 容器,執行 readiness check:

def readiness(request):
    result = httpx.get("http://127.0.0.1:8080/status").json()
    if not result["database-connected"]:
        raise ValueError("database not connected", result)
    return Response("connected")

with configlib.Configurator() as config:
    config.add_route('readiness', '/ready')
    config.add_view(readiness, route_name='readiness')
    application = config.make_wsgi_app()

程式碼解析

此範例展示瞭如何使用 Sidecar 容器執行 readiness check。Sidecar 容器透過查詢主容器的 /status 端點檢查資料函式庫連線狀態。

內容解密:

  1. readiness check 邏輯:Sidecar 容器透過查詢主容器的 /status 端點取得資料函式庫連線狀態。
  2. 錯誤處理:如果資料函式庫未連線,Sidecar 容器會丟擲錯誤。
  3. Kubernetes 就緒檢查:Kubernetes 可以透過查詢 Sidecar 容器的 /ready 端點檢查 Pod 的就緒狀態。

Kubernetes 進階應用:Sidecars、REST API 與 Operators

Kubernetes 提供了多種強大的功能來擴充套件和自定義叢集的操作。其中,sidecars、REST API 和 Operators 是三個重要的工具,它們可以幫助開發者更有效地管理和自動化 Kubernetes 資源。

Sidecars 的應用

Sidecars 是與主容器一起執行的輔助容器,它們可以提供各種額外的功能,如日誌記錄、監控、代理等。由於 sidecar 容器映像通常是為現有的映像而建立的,因此即使主容器不是用 Python 編寫的,Python 也是一種有用的語言。

使用 Kubernetes REST API

Kubernetes 提供了一個根據 OpenAPI 的 RESTful API。由於 API 是使用 OpenAPI 描述的,因此可以為許多語言自動生成客戶端。Python Kubernetes 客戶端可以使用 pip install kubernetes 安裝。在這個套件中,經常會匯入兩個重要的模組:configclient

連線到 Kubernetes 叢集

要連線到 Kubernetes 叢集,可以使用 new_client_from_config() 函式讀取 kubectl 相容的組態。這個函式傳回一個客戶端物件,可以用來存取 Kubernetes API。

from kubernetes import config as k8config, client as k8client

client = k8config.new_client_from_config()
core = k8client.CoreV1Api(client)

使用 CoreV1Api 管理核心物件

CoreV1Api 是用來管理 Kubernetes 中的核心物件的 API,例如 pods、namespaces 等。可以使用這個 API 取得所有 pods 的列表。

res = core.list_pod_for_all_namespaces()
for pod in res.items:
    for container in pod.spec.containers:
        print(container.image)

這段程式碼會列印出目前在 Kubernetes 叢集中執行的所有容器的映像。

內容解密:

  1. list_pod_for_all_namespaces() 方法用於取得所有 namespaces 中的 pods 列表。
  2. res.items 傳回一個包含所有 pods 物件的列表。
  3. pod.spec.containers 傳回一個包含 pod 中所有容器的列表。
  4. container.image 傳回容器的映像名稱。

Kubernetes Operators

Kubernetes Operators 是一種用於自定義 Kubernetes 的強大工具。它們不是 Kubernetes 的概念,而是一種模式。Operators 由幾個部分組成,包括輸入、輸出和調解迴圈。

調解迴圈

調解迴圈是 Operator 的核心,它負責檢索輸入和輸出,計算正確的輸入以產生所需的輸出,並修復任何差異。

Permissions

Operators 需要許可權來讀取輸入和讀寫輸出。這些許可權是透過 Resource-Based Access Control (RBAC) 機制授予的。

自定義資源型別

許多 Operators 也定義了自定義資源型別,以避免輸入對叢集的其他部分產生影響。自定義資源型別是透過建立一個 CustomResourceDefinition 物件來定義的。

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: characters.wizardofoz.example.org
spec:
  group: wizardofoz.example.org
  versions:
  - name: v1
    served: true
    storage: true
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              name:
                type: string
              universe:
                type: integer
  scope: Namespaced
  names:
    plural: characters
    singular: character
    kind: Character

內容解密:

  1. apiVersionkind 指定了自定義資源型別的版本和型別。
  2. metadata.name 指定了自定義資源型別的名稱。
  3. spec.groupspec.versions 指定了自定義資源型別所屬的群組和版本。
  4. spec.schema 定義了自定義資源型別的架構,包括屬性和型別。