本教學課程說明如何使用 DaemonSets 自訂 Google Kubernetes Engine (GKE) 叢集的節點。DaemonSet 可確保所有 (或選定的) 節點都執行 Pod 副本。在叢集中新增節點時,這些節點也會執行 DaemonSet 中的 Pod。
如果您用來初始化叢集的工具和系統,與用來執行工作負載的工具和系統不同,管理環境的難度就會提高。舉例來說,如果您使用設定管理工具初始化叢集節點,您會依賴程序,而該程序位於其餘工作負載執行的執行階段環境之外。使用 DaemonSet 時,您可以使用與修改 GKE 節點相同的工具來協調工作負載。
本教學課程旨在協助系統管理員、系統工程師或基礎架構營運人員簡化 Kubernetes 叢集的初始化作業。
閱讀本頁面前,請確認您已熟悉下列事項:
在本教學課程中,您將瞭解如何使用 Kubernetes taint 和容許條件,確保節點是由 DaemonSet 設定,應用程式工作負載才能排定在節點上。
目標
在本教學課程中,您將執行下列操作:
- 佈建 GKE 叢集。
- 在套用節點設定前,先汙染節點集區,防止工作負載排程。
- 部署 DaemonSet,設定節點並移除汙點。
- 確認叢集節點已設定,且污點已移除。
費用
在本文件中,您會使用下列 Google Cloud計費元件:
您可以使用 Pricing Calculator,根據預測用量估算費用。
完成本文所述工作後,您可以刪除建立的資源,避免繼續計費,詳情請參閱「清除所用資源」。
事前準備
- 登入 Google Cloud 帳戶。如果您未曾使用過 Google Cloud,歡迎 建立帳戶,親自體驗實際使用我們產品的成效。新客戶還能獲得價值 $300 美元的免費抵免額,能用於執行、測試及部署工作負載。
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
具備權限的 DaemonSet 安全性影響
在 DaemonSet (或任何 Pod) 中使用 securityContext: privileged: true 設定非常實用,但會帶來重大安全性影響,因為這會為該 Pod 停用大多數的容器隔離界線。請注意以下安全性限制和風險:
- 容器跳脫或主機遭入侵:特殊權限容器應用程式或映像檔中的安全漏洞,可能會直接導致主機節點的根存取權。
- 違反最小權限原則:特權模式會授予「所有」功能,可能遠超過特定工作所需。如果容器遭到入侵,這種廣泛的存取權可能會造成更大的損害。
- 節點不穩定:在具備權限的容器中,可能會執行意外或惡意指令,例如不正確的
sysctl值或rm -rf /host/boot等指令。這類指令可能會導致主機節點作業系統當機或損毀。 - 橫向移動:透過具備特殊權限的 DaemonSet 入侵一個節點,攻擊者就能取得強大的立足點,攻擊其他節點、Kubernetes 控制層或連結的系統。
- 資料曝光:無限制存取主機檔案系統 (
/) 可能會曝光儲存在節點上的機密資料,包括憑證、金鑰,或屬於其他 Pod 的資料 (如果這些 Pod 使用 hostPath 卷宗)。 - 攻擊面擴大:特權模式會公開更多主機核心系統呼叫和功能,讓容器內可能出現安全漏洞。
為避免安全風險,請留意下列最佳做法和緩解措施:
- 避免使用特殊權限模式:最安全的做法是完全避免使用
privileged: true設定。 - 使用 Linux 功能:如需提高權限,您可以在
securityContext.capabilities.add欄位中授予特定 Linux 功能,例如NET_ADMIN、SYS_ADMIN、SYS_MODULE,而非完整權限。這個方法遵循最小權限原則,比授予廣泛權限更為推薦。 - 限制範圍:只在專用 (可能已汙損) 的節點集區上執行具備權限的 DaemonSet,以防容器遭到入侵時造成影響。
- 強制執行政策:使用 Policy Controller 或 Gatekeeper 等工具建立政策,限制、稽核或要求提供部署具備權限的容器的正當理由。
- 掃描並使用受信任的映像檔:使用二進位授權和嚴格的映像檔掃描,確保只有經過審查、受信任的容器映像檔,才能以進階權限執行。
- 減少主機掛接:只掛接必要的特定主機路徑,並盡可能使用
readOnly: true。請避免掛接整個根檔案系統 (/)。 - 定期執行稽核:定期檢查所有以
privileged: true設定執行的工作負載。
啟動環境
在本節中,執行以下操作:
啟用 Cloud API
開啟 Cloud Shell。
選取 Google Cloud 專案:
gcloud config set project project-id
將
project-id替換為您為本教學課程建立或選取的Google Cloud 專案 ID。啟用 Kubernetes Engine API:
gcloud services enable container.googleapis.com
佈建服務帳戶來管理 GKE 叢集
在本節中,您將建立與叢集節點相關聯的服務帳戶。在本教學課程中,GKE 節點會使用這個服務帳戶,而非預設服務帳戶。最佳做法是只授予服務帳戶執行應用程式所需的角色和存取權限。
服務帳戶所需的角色如下:
- Monitoring 檢視者角色 (
roles/monitoring.viewer)。這個角色具備監控資料的唯讀存取權。 - Monitoring 指標寫入者角色 (
roles/monitoring.metricWriter)。這個角色允許寫入監控資料。 - 記錄寫入者角色 (
roles/logging.logWriter):這個角色具備寫入記錄的權限。
如要佈建服務帳戶,請按照下列步驟操作:
在 Cloud Shell 中,初始化儲存服務帳戶名稱的環境變數:
GKE_SERVICE_ACCOUNT_NAME=ds-init-tutorial-gke建立服務帳戶:
gcloud iam service-accounts create "$GKE_SERVICE_ACCOUNT_NAME" \ --display-name="$GKE_SERVICE_ACCOUNT_NAME"初始化環境變數,儲存服務帳戶電子郵件帳戶名稱:
GKE_SERVICE_ACCOUNT_EMAIL="$(gcloud iam service-accounts list \ --format='value(email)' \ --filter=displayName:"$GKE_SERVICE_ACCOUNT_NAME")"將 Identity and Access Management (IAM) 角色繫結至服務帳戶:
gcloud projects add-iam-policy-binding \ "$(gcloud config get-value project 2> /dev/null)" \ --member serviceAccount:"$GKE_SERVICE_ACCOUNT_EMAIL" \ --role roles/monitoring.viewer gcloud projects add-iam-policy-binding \ "$(gcloud config get-value project 2> /dev/null)" \ --member serviceAccount:"$GKE_SERVICE_ACCOUNT_EMAIL" \ --role roles/monitoring.metricWriter gcloud projects add-iam-policy-binding \ "$(gcloud config get-value project 2> /dev/null)" \ --member serviceAccount:"$GKE_SERVICE_ACCOUNT_EMAIL" \ --role roles/logging.logWriter
準備 GKE 叢集
在本節中,您將啟動 GKE 叢集、授予權限並完成叢集設定。
在本教學課程中,只要叢集有相對較少的節點,且節點屬於小型一般用途,就足以說明教學課程的概念。您建立的叢集有一個節點集區 (預設集區)。
在 Cloud Shell 中,建立並啟動區域 GKE 叢集:
gcloud container clusters create ds-init-tutorial \ --enable-ip-alias \ --machine-type=n1-standard-2 \ --metadata disable-legacy-endpoints=true \ --node-labels=app=default-init \ --node-locations us-central1-a,us-central1-b,us-central1-c \ --no-enable-basic-auth \ --no-issue-client-certificate \ --num-nodes=1 \ --location us-central1 \ --service-account="$GKE_SERVICE_ACCOUNT_EMAIL"
使用 DaemonSet 套用節點設定
在本節中,您將對節點集區套用污點,防止工作負載在設定完成前於節點上執行。接著,您會部署 DaemonSet,執行下列作業:
- 使用 taint 的容許條件,在設有 taint 的節點上排程 Pod。
- 執行具特殊權限的 init 容器,先使用
sysctl套用節點設定,再使用kubectl移除節點的污點。移除汙點後,節點就能排定工作負載。 - 排定並執行暫停容器,該容器會保持閒置狀態且不消耗任何資源,防止 DaemonSet 重新排定用於設定的 Pod。
本教學課程會以 vm.max_map_count=262144 核心參數為例,說明如何設定。
將汙點套用至預設節點集區:
gcloud container node-pools update default-pool \ --cluster=ds-init-tutorial \ --node-taints=node.config.status/stage=configuring:NoSchedule \ --region=us-central1有了這個 taint,只有容許該 taint 的 Pod (例如 DaemonSet Pod) 才能排定在這個節點集區中。
確認已套用污點:
kubectl describe nodes -l cloud.google.com/gke-nodepool=default-pool | grep Taints節點狀態應會顯示
node.config.status/stage=configuring:NoSchedule。將下列資訊清單儲存為
auto-untaint-daemonset.yaml:# WARNING: This DaemonSet runs as privileged, which has significant # security implications. Only use this on clusters where you have # strict controls over what is deployed. --- apiVersion: v1 kind: ServiceAccount metadata: name: node-config-sa namespace: default --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: node-patcher-role rules: - apiGroups: [""] resources: ["nodes"] # Permissions needed to read and remove a taint from the node. verbs: ["get", "patch", "update"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: node-config-binding subjects: - kind: ServiceAccount name: node-config-sa namespace: default roleRef: kind: ClusterRole name: node-patcher-role apiGroup: rbac.authorization.k8s.io --- apiVersion: apps/v1 kind: DaemonSet metadata: name: auto-untaint-daemonset labels: app: auto-untaint-configurator spec: selector: matchLabels: app: auto-untaint-configurator updateStrategy: type: RollingUpdate template: metadata: labels: app: auto-untaint-configurator spec: serviceAccountName: node-config-sa hostPID: true # Toleration now matches the taint on your node. tolerations: - key: "node.config.status/stage" operator: "Equal" value: "configuring" effect: "NoSchedule" volumes: - name: host-root-fs hostPath: path: / initContainers: - name: configure-and-untaint image: ubuntu:22.04 # Using a standard container image. securityContext: privileged: true # Required for chroot and sysctl. env: - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName volumeMounts: - name: host-root-fs mountPath: /host command: ["/bin/bash", "-c"] args: - | # Using explicit error checking for each critical command. # Define the configuration and taint details. SYSCTL_PARAM="vm.max_map_count" SYSCTL_VALUE="262144" TAINT_KEY="node.config.status/stage" echo "Running configuration on node: ${NODE_NAME}" # 1. APPLY CONFIGURATION echo "--> Applying ${SYSCTL_PARAM}=${SYSCTL_VALUE}..." if ! chroot /host sysctl -w "${SYSCTL_PARAM}=${SYSCTL_VALUE}"; then echo "ERROR: Failed to apply sysctl parameter." >&2 exit 1 fi echo "--> Configuration applied successfully." # 2. UNTAINT THE NODE # This command removes the taint from the node this Pod is running on. echo "--> Untainting node ${NODE_NAME} by removing taint ${TAINT_KEY}..." if ! /host/home/kubernetes/bin/kubectl taint node "${NODE_NAME}" "${TAINT_KEY}:NoSchedule-"; then echo "ERROR: Failed to untaint the node." >&2 exit 1 fi echo "--> Node has been untainted and is now schedulable." # The main container is minimal; it just keeps the Pod running. containers: - name: pause-container image: registry.k8s.io/pause:3.9這個資訊清單會建立 ServiceAccount、ClusterRole 和 ClusterRoleBinding,授予 DaemonSet 權限,以便從節點移除污點。DaemonSet 會將 Pod 部署至可容許
configuring:NoSchedule污點的每個節點。這個 Pod 會執行特殊權限 init 容器,套用sysctl設定 (vm.max_map_count=262144) 並移除節點污點,讓節點可排程。接著,暫停容器會啟動,讓 Pod 保持運作。init 容器會以特殊權限模式執行,這會影響安全性。詳情請參閱「Privileged DaemonSet tradeoffs and security restrictions」(Privileged DaemonSet 的取捨和安全性限制)。
套用資訊清單:
kubectl apply -f auto-untaint-daemonset.yaml確認 DaemonSet Pod 已建立,並等待 Pod 達到
Running狀態:kubectl get pods -l app=auto-untaint-configurator -o wideRunning狀態表示 init 容器已成功完成。請記下 Pod 名稱,以便在下一節中驗證初始化作業。
驗證及確認初始化程序
節點設定完成後,您可以查看記錄來驗證結果。
檢查其中一個 Pod 的 init 容器記錄,查看輸出內容:
kubectl logs POD_NAME -c configure-and-untaint將
POD_NAME替換為 Pod 名稱。輸出內容應該會指出設定成功,且節點已取消 taint。
確認污點已移除:
kubectl describe nodes -l cloud.google.com/gke-nodepool=default-pool | grep Taints節點狀態應會顯示
Taints: <none>,或顯示具有鍵node.config.status/stage的汙點。
清除所用資源
如要避免系統向您的 Google Cloud 帳戶收取本教學課程所用資源的費用,請刪除您為本教學課程建立的專案。如果您是為了這個教學課程建立專案,可以完全刪除專案。如果您使用的是現有專案,但不想刪除專案,請按照下列步驟清除專案。
清理專案
如要清除專案而不刪除,請移除您在本教學課程中建立的資源。
在 Cloud Shell 中刪除 GKE 叢集:
gcloud container clusters delete ds-init-tutorial --quiet --region us-central1刪除服務帳戶:
gcloud iam service-accounts delete "$GKE_SERVICE_ACCOUNT_EMAIL" --quiet
刪除專案
如要避免系統向您收費,最簡單的方法就是刪除您在教學課程中建立的專案。
- 前往 Google Cloud 控制台的「Manage resources」(管理資源) 頁面。
- 在專案清單中選取要刪除的專案,然後點選「Delete」(刪除)。
- 在對話方塊中輸入專案 ID,然後按一下 [Shut down] (關閉) 以刪除專案。
後續步驟
- 瞭解 GKE。
- 導入安全的軟體供應鏈。
- 瞭解如何強化 GKE 叢集安全防護。
- 查看 Google Cloud 的參考架構、圖表和最佳做法。歡迎瀏覽我們的 Cloud Architecture Center。