當前位置: 妍妍網 > 碼農

【運維幹貨分享】Kubernetes Init 容器:完整指南

2024-08-27碼農


在這篇博文中,我們將深入探討 Kubernetes Init Containers。我們將探討它們是什麽、它們如何工作以及它們為容器化應用程式帶來什麽好處。

這是 Init Container 的完整指南。

在容器編排領域,Kubernetes 已成為管理和擴充套件容器化應用程式的解決方案。它提供了一個強大的框架,用於跨節點集群自動部署、擴充套件和管理容器。Kubernetes 的最佳功能之一是 Init Containers。

什麽是 Init 容器?

Kubernetes Pod 可以有多個容器。Pod 中的這些容器協同工作以實作一個共同的目標。

Init 容器是在啟動 Pod 中的主容器之前啟動並執行完成的容器。它充當準備步驟,允許我們在主容器中執行初始化任務、配置先決條件或配置應用程式所需的依賴項。

讓我們透過一個例子來理解這一點。

假設我們有一個應用程式,它需要一個金鑰來連線到 API。由於合規性原因,你無法將此金鑰寫死到應用程式中或使用 Kubernetes 金鑰。在這種情況下,你可以使用 init 容器從 Vault 或 AWS Secrets Manager 等秘密管理服務獲取金鑰,並將其寫入 Pod 中應用程式容器可以存取它的位置。

這樣,當應用程式 Pod 啟動時,它將可以存取 secret 以連線到 API。

簡而言之,init 容器可以確保你的應用程式在啟動之前始終得到正確配置和初始化。

Init 容器如何工作?

在深入研究 Init 容器之前,我們先了解一下它們的工作原理。

  • kubelet按照 Init 容器在 Pod 的 spec 中出現的順序執行它們,確保每個容器在開始下一個容器之前完成其任務。這意味著一次只執行一個 init 容器。

  • Init Containers 在主應用程式容器啟動之前執行。

  • 如果 Pod 重新開機,則其所有 init 容器將再次執行。

  • 在 Pod 生命周期中,init 容器在 pending 階段執行完成。

  • 雖然 init 容器具有相同的容器規範,但它們不支持 lifecycle、livenessProbe、readinessProbe 和 startupProbe 欄位。(本機 sidecar Alpha 功能除外)

  • 這是顯示 init 容器工作原理的動畫影像。

    Init 容器使用案例

    init 容器的實際用例可能會因應用程式的特定需求而異。以下是一些常見的使用案例:

  • 載入和配置依賴項::Init 容器可以在主應用程式容器開始執行之前載入和配置主應用程式容器所需的依賴項。

  • 建立資料庫架構:你可以使用 init 容器建立資料庫架構。

  • 預熱緩存:你可以使用 init 容器預熱緩存。例如,將一些常用數據預載入到 Redis 緩存中。

  • 網路配置:Init 容器可以處理建立網路配置或建立與外部服務的連線等任務。

  • Git 複制:Init 容器可以複制 Git 儲存庫或將檔寫入附加的 Pod 卷。

  • 安全檢查:Init 容器可以在啟動主應用程式容器之前執行安全檢查,例如漏洞掃描或 TLS 證書驗證。

  • 存取 Secrets:Init 容器可以存取應用程式容器無法存取的 Secret,例如從檔庫中檢索 Secret。

  • 環境設定::Init 容器可以處理建立目錄、套用許可權或執行自訂指令碼等任務,以為主應用程式設定環境。

  • Wait for Services::Init 容器可以等待服務啟動後再啟動主應用程式。

  • Init 容器例項

    Init 容器在 Pod 的 manifest 欄位中定義。這類似於常規定義。我們可以在 p 下定義盡可能多的容器。spec.initContainersspec.containersinitContainers

    讓我們看一個實際範例。這是我們的使用者案例。我們需要一個在索引頁面上顯示 Pod IP 的 Nginx Web 伺服器 pod。

    以下是我們如何利用 init 容器來部署顯示其 IP 地址的 pod。

  • 一個名為 write-ip 的 init 容器使用從 Pod 自身狀態填充的 MY_POD_IP env 變量獲取 Pod IP。並寫入附加到 Pod 的 /web-content 卷內的 ip.txt 檔。

  • 名為 create-html 的第二個 Init 容器從 /web-content/ip.txt 檔中讀取 Pod IP,該檔包含第一個 Init 容器建立的 Pod IP,並將其寫入 /web-content/index.html 檔。

  • 現在,主 nginx 容器 (web-container) 將預設的 /usr/share/nginx/html 掛載到我們擁有 index.html 檔的 /web-content 卷中。

  • 這是我們用例的完整 Pod YAML 檔。另存為 init-container.yaml

  • apiVersion: v1
    kind: Pod
    metadata:
    name: web-server-pod
    spec:
    initContainers:
    - name: write-ip
    image: busybox
    command: ["sh""-c""echo $MY_POD_IP > /web-content/ip.txt; echo 'Wrote the Pod IP to ip.txt'"]
    env:
    - name: MY_POD_IP
    valueFrom:
    fieldRef:
    fieldPath: status.podIP
    volumeMounts:
    - name: web-content
    mountPath: /web-content
    - name: create-html
    image: busybox
    command: ["sh""-c""echo 'Hello, World! Your Pod IP is: ' > /web-content/index.html; cat /web-content/ip.txt >> /web-content/index.html; echo 'Created index.html with the Pod IP'"]
    volumeMounts:
    - name: web-content
    mountPath: /web-content
    containers:
    - name: web-container
    image: nginx
    volumeMounts:
    - name: web-content
    mountPath: /usr/share/nginx/html
    volumes:
    - name: web-content
    emptyDir: {}

    我們來部署這個 pod。

    kubectl apply -f init-container.yaml

    現在,如果你獲得 Pod 狀態,你將看到 1/1 容器正在執行

    $ kubectl get pods
    NAME READY STATUS RESTARTS AGE
    web-server-pod 1/1 Running 0 22s

    我們在 Pod 中有三個容器,但只有一個處於執行狀態。這是因為正如我們之前討論的,init contianers 執行到完成。在這種情況下,兩個 init 容器建立了 nginx 索引 HTML 頁面並以非零結束程式碼結束,然後主 nginx 容器開始與自訂 html 頁面一起執行。

    即使 init 容器沒有執行,我們也可以檢查已完成的容器日誌。我們向兩個 init 容器添加了一個簡單的 echo 命令。讓我們檢查 init 容器日誌,看看它是否成功執行。

    如你所見,兩個 init 容器都已成功執行,並在日誌中顯示回顯訊息。

    $ kubectl logs web-server-pod -c write-ip
    Wrote the Pod IP to ip.txt
    $ kubectl logs web-server-pod -c create-html
    Created index.html with the Pod IP

    現在,為了驗證 Nginx Pod 是否正在使用自訂 HTML,讓我們使用埠轉發來存取 Nginx Pod

    kubectl port-forward pod/web-server-pod 8080:80

    現在,如果你嘗試從工作站存取 localhost:8080 上的 Nginx 應用程式,則可以看到 Nginx 索引頁面顯示一條帶有 Pod IP 地址的訊息,如下圖所示。

    添加 CPU/記憶體資源

    Init 容器需要執行 CPU 和記憶體資源才能完成特定任務。可以根據任務的嚴重程度設定限制和請求。

    如果有多個 init 容器,則為任何 init 容器設定的最大值稱為有效 init 請求/限制。這意味著,如果你有一個沒有設定 CPU/記憶體限制的 init 容器,它可以使用有效 init 請求/限制的最大值。

    我們可以使用 Kubernetes 資源規範來指定 CPU 和記憶體資源限制以及 Init 容器的請求,如下所示:

    spec:
    initContainers:
    - name: init-container
    image: init-container-image
    resources:
    requests:
    cpu: 50m
    memory: 64Mi
    limits:
    cpu: 100m
    memory: 128Mi

    根據 Init 容器的實際使用模式監控和調整資源限制是最佳化集群資源分配的一種很好的做法。但是,我們必須確保 Init 容器和主容器請求的資源之和不超過集群節點上的可用資源。

    添加卷

    Init Containers 中的卷在主應用程式容器開始執行之前執行數據設定、初始化和準備任務方面發揮著至關重要的作用。我們可以用同樣的方式在 Init 容器中掛載卷。

    例如,有時應用程式可能需要存取由於大小限制而我們不想捆綁在容器映像中的數據集或檔。在這種情況下,可以使用 Init Container 將這些數據集提取並載入到共享卷中,此外,主容器可以使用此卷。下面是範例 YAML 檔:

    apiVersion: v1
    kind: Pod
    metadata:
    name: volume-example-pod
    spec:
    initContainers:
    - name: download-dataset
    image: busybox
    command: ["wget""-O""/data/dataset.zip""https://example.com/dataset.zip"]
    volumeMounts:
    - name: data-volume
    mountPath: /data
    - name: unzip-dataset
    image: busybox
    command: ["unzip""/data/dataset.zip""-d""/data"]
    volumeMounts:
    - name: data-volume
    mountPath: /data
    containers:
    - name: main-app
    image: main-app-image
    volumeMounts:
    - name: data-volume
    mountPath: /app-data
    volumes:
    - name: data-volume
    emptyDir: {}

    使用 Init 容器的原生 Sidecar

    在 Kubernetes 版本 1.28 中,引入了一個新欄位,該欄位的值設定為 。.在撰寫本文時,它是一個 Alpha 功能。restartPolicyAlways

    此功能依賴於 「持久 init 容器」 的概念,其中初始化過程從 init 容器開始,並利用 來增強 sidecar 容器的功能。它在主容器之前啟動,並在 Pod 的整個生命周期內保持執行。restartPolicy

    所以簡單地說,要使 init 容器成為 sidecar,我們需要將 attribute 添加到其 spec 中。它是一個可選欄位,如果不存在,容器將充當常規的 init 容器。"restartPolicy: Always"restartPolicy

    請註意,當集群中啟用特性門控時,init 容器中的欄位可用。目前,它是一個 Alpha 功能。如果你想測試原生的 sidecar 功能,我們有一個指南,展示了如何使用最新的 kubernetes 版本在 Kubeadm 中啟用功能門控。restartPolicySidecarContainers

    現在讓我們看一個帶有用例的實際範例。

    讓我們假設以下場景

  • 一個 nginx Web 伺服器 Pod,帶有一個 nginx 主容器,用於將日誌寫入 /var/log/nginx 卷掛載。

  • 我們需要一個原生 sidecar fluentd 日誌代理容器,用於從 /var/log/nginx 讀取所有 nginx 日誌。

  • 以下是上述用例的 Pod YAML。nginx-logs 卷掛載對於 logging-agent sidecar 容器和 nginx 主容器很常見。將 restartPolicy:Always 添加到 logging-agent init 容器中,使其行為類似於 sidecar 容器。

    apiVersion: v1
    kind: Pod
    metadata:
    name: webserver-pod
    spec:
    initContainers:
    - name: logging-agent
    image: fluentd:latest
    restartPolicy: Always
    volumeMounts:
    - name: nginx-logs
    mountPath: /var/log/nginx
    containers:
    - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80
    volumeMounts:
    - name: nginx-logs
    mountPath: /var/log/nginx
    volumes:
    - name: nginx-logs
    emptyDir: {}

    要測試它,請將其另存為 sidecar.yaml 並使用 kubectl 進行部署。

    kubectl apply -f sidecar.yaml

    現在,如果你檢查 Pod 狀態,則可以使用 2/2 的容器處於執行狀態。一個是原生 sidecar init 容器,另一個是主 Nginx 容器。

    總體而言,原生 sidecar 容器具有以下關鍵內容:

  • 專用生命周期:原生 Sidecar 容器具有專用的生命周期,獨立於 Pod 中主要容器的生命周期

  • 它不會像非原生 sidecar 那樣阻止 Pod 的終止。

  • 生命周期處理常式和探測:我們可以添加PostStart和PreStop生命周期處理常式和探測(啟動、準備、活躍)以確保邊車準備和pod準備。

  • 全面的 Init Container YAML

    讓我們看看如果我們添加所有支持的參數,Init Container 物件 YAML 檔會是什麽樣子。要獲取有關所有受支持欄位的資訊,你可以使用以下 kubectl 命令。

    kubectl explain pod.spec.initContainers

    下面是全面的 Init Container YAML。

    spec:
    initContainers:
    - name: init-container
    image: busybox:latest
    command:
    "sh"
    "-c"
    "echo Initializing... && sleep 5"
    imagePullPolicy: IfNotPresent
    env:
    - name: INIT_ENV_VAR
    value: "init-value"
    resources:
    limits:
    memory: "128Mi"
    cpu: "500m"
    requests:
    memory: "64Mi"
    cpu: "250m"
    volumeMounts:
    - name: init-container-volume
    mountPath: /init-data
    ports:
    - containerPort: 80
    securityContext:
    runAsUser: 1000
    runAsGroup: 1000
    capabilities:
    add: ["NET_ADMIN"]
    readinessProbe:
    httpGet:
    path: /
    port: 80
    initialDelaySeconds: 5
    periodSeconds: 10
    livenessProbe:
    httpGet:
    path: /
    port: 80
    initialDelaySeconds: 15
    periodSeconds: 20
    startupProbe:
    httpGet:
    path: /
    port: 80
    initialDelaySeconds: 5
    periodSeconds: 5
    lifecycle:
    postStart:
    exec:
    command: ["/bin/sh""-c""echo 'PostStart'"]
    preStop:
    exec:
    command: ["/bin/sh""-c""echo 'PreStop'"]
    restartPolicy: Always
    volumes:
    - name: init-container-volume
    emptyDir: {}

    還有其他欄位,如 workingDir、volumeDevices、resizePolicy 與 init 容器卷相關。

    Init 容器最佳實踐

    以下是一些要遵循的最佳實踐:

  • 確保 Init 容器設計為快速執行特定任務,而不會使用太多資源。

  • 如果你有多個初始化任務,請為每個任務使用單獨的 init 容器。這有助於單獨管理和排查它們。

  • Init 容器可能會失敗,因此請做好計劃。實施重試、回退策略和清除錯誤訊息,以有效地診斷和解決問題。

  • 利用 Kubernetes 提供的執行前和執行後勾點,在容器生命周期的特定階段執行自訂指令碼或命令。

  • 保護初始化期間使用的敏感資訊並避免泄露。

  • 確保 init 容器分配了足夠的資源。缺少資源可能會導致初始化任務失敗或延遲。

  • Init 容器與 Sidecar 容器

  • Init Container 執行需要在主容器啟動之前完成的任務,而 Sidecar Container 則為主容器提供補充功能。

  • Init Container 不與主容器共享相同的網路和儲存資源,而 Sidecar Container 共享相同的網路和儲存資源。

  • Init Container 按順序執行,並在主容器啟動之前完成。另一方面,Sidecar Container 與主容器一起啟動、執行和終止。

  • Init Container 確保主容器從必要的先決條件開始,而 Sidecar Container 直接影響主容器的行為和功能。

  • Init Containers 可用於為主應用程式設定環境,例如下載配置檔或初始化共享卷。Sidecar Containers 可用於將數據記錄到外部系統、收集指標或處理與安全相關的功能等任務。

  • Init Containers 常見問題

    我們來看一些基於 Init Containers 的常見問題。

    Init 容器和普通容器有什麽區別?

    Init 容器和常規容器之間的主要區別在於它們的用途和生命周期。Init Containers 專註於初始化任務和確保就緒狀態,而 Regular Containers 處理核心應用程式邏輯和功能。

    我可以在一個 Pod 中擁有多個 init 容器嗎?

    是的,你可以在 Pod 中擁有多個 init 容器。它們按順序執行,每個 init 容器在下一個 init 容器開始之前完成。

    Init Containers 和 Sidecar Containers 有什麽區別?

    Init Containers 專註於為主容器準備環境的初始化任務,而 Sidecar Containers 則提供與主容器配合使用的其他功能和服務,以增強其整個生命周期的功能。

    結論

    在本教程中,我們了解了 init 容器及其在 Kubernetes Cluster 節點中的用法。我們討論了功能和優勢。此外,我們還討論了它的工作和用例。

    最近整理了2023年最火的軟體神器,回復關鍵字 2023合集 獲取

    推薦閱讀 ⬇️ 都是高贊

    PS:求求啦! 在看 支持下吧!