首頁 > 軟體

Kubernetes教學之Windows HostProcess 執行容器化負載

2022-07-23 14:01:05

簡介

Windows HostProcess 容器讓你能夠在 Windows 主機上執行容器化負載。 這類容器以普通的程序形式執行,但能夠在具有合適使用者特權的情況下, 存取主機網路名稱空間、儲存和裝置。

HostProcess 容器可用來在 Windows 節點上部署網路外掛、儲存設定、裝置外掛、kube-proxy 以及其他元件, 同時不需要設定專用的代理或者直接安裝主機服務。

一、建立 Windows HostProcess

我何時該使用 Windows HostProcess 容器?

  • 當你準備執行需要存取主機上網路名稱空間的任務時,HostProcess 容器能夠存取主機上的網路介面和 IP 地址。
  • 當你需要存取主機上的資源,如檔案系統、事件紀錄檔等等。
  • 需要安裝特定的裝置驅動或者 Windows 服務時。
  • 需要對管理任務和安全策略進行整合時。使用 HostProcess 容器能夠縮小 Windows 節點上所需要的特權範圍。

HostProcess 容器功能特性預設是啟用的。 kubelet 會直接與 containerd 通訊,通過 CRI 將主機程序標誌傳遞過去。 你可以使用 containerd 來執行 HostProcess 容器。

想要禁用 HostProcess 容器特性,可以執行下面的命令:

$ --feature-gates=WindowsHostProcessContainers=false

1.1、HostProcess 的使用限制

  • HostProcess 容器需要 containerd 1.6 或更高版本的 容器執行時。
  • HostProcess Pods 只能包含 HostProcess 容器。這是在 Windows 作業系統上的約束; 非特權的 Windows 容器不能與主機 IP 名稱空間共用虛擬網路卡(vNIC)。
  • HostProcess 在主機上以一個程序的形式執行,除了通過 HostProcess 使用者賬號所實施的資源約束外,不提供任何形式的隔離。HostProcess 容器不支援檔案系統或 Hyper-V 隔離。
  • volume 掛載是被支援的,並且要花在到容器卷下。
  • 預設情況下有一組主機使用者賬戶可供 HostProcess 容器使用。
  • 對資源約束(磁碟、記憶體、CPU 個數)的支援與主機上程序相同。
  • 不支援命名管道或者 UNIX 域通訊端形式的掛載,需要使用主機上的路徑名來存取 。

1.2、HostProcess Pod 設定

在 Pod 安全標準中所定義的策略中, HostProcess Pod 預設是不被 basline 和 restricted 策略支援的。因此建議 HostProcess 執行在與 privileged 模式相看齊的規則下。

當執行在 privileged 規則下時,下面是要啟用 HostProcess Pod 建立所需要設定的選項:

控制策略可選值
securityContext.windowsOptions.hostProcessWindows Pods 提供執行 HostProcess 容器的能力,這類容器能夠具有對 Windows 節點的特權存取許可權。true
hostNetwork初始時將預設位於主機網路中。在未來可能會希望將網路設定到不同的隔離環境中。true
securityContext.windowsOptions.runAsUsername關於 HostProcess 容器所要使用的使用者的規約,需要設定在 Pod 的規約中。NT AUTHORITYSYSTEM 、NT AUTHORITYLocal service 、NT AUTHORITYNetworkService
runAsNonRoot因為 HostProcess 容器有存取主機的特權,runAsNonRoot 欄位不可以設定為 true。未定義/Nil 、false

1.3、設定清單

這裡我們只看部分內容:

spec:
  securityContext:
    windowsOptions:
      hostProcess: true
      runAsUserName: "NT AUTHORITY\Local service"
  hostNetwork: true
  containers:
  - name: test
    image: image1:latest
    command:
      - ping
      - -t
      - 127.0.0.1
  nodeSelector:
    "kubernetes.io/os": windows

HostProcess 容器支援在容器卷空間中掛載卷的能力。 在容器內執行的應用能夠通過相對或者絕對路徑直接存取卷掛載。 環境變數 $CONTAINER_SANDBOX_MOUNT_POINT 在容器建立時被設定為指向容器卷的絕對主機路徑。 相對路徑是基於 .spec.containers.volumeMounts.mountPath 設定來推導的。

1.4、記憶體資源

資源約束(磁碟、記憶體、CPU 個數)作用到任務之上,並在整個任務上起作用。 例如,如果記憶體限制設定為 10MB,任何 HostProcess 任務物件所分配的記憶體不會超過 10MB。 這一行為與其他 Windows 容器型別相同。資源限制的設定方式與編排系統或容器執行時無關。 唯一的區別是用來跟蹤資源所進行的磁碟資源用量的計算,出現差異的原因是因為 HostProcess 容器啟動引導的方式造成的。

二、設定 GMSA

在 Kubernetes 環境中,GMSA 憑據規約設定為 Kubernetes 叢集範圍的自定義資源 (Custom Resources)形式。Windows Pod 以及各 Pod 中的每個容器可以設定為 使用 GMSA 來完成基於域(Domain)的操作(例如,Kerberos 身份認證),以便 與其他 Windows 服務相互動。

安裝 GMSACredentialSpec CRD

需要在叢集上設定一個用於 GMSA 憑據規約資源的 CustomResourceDefinition(CRD), 以便定義型別為 GMSACredentialSpec 的自定義資源。 下載 GMSA CRD YAML 並將其儲存為 gmsa-crd.yaml。然後執行 kubectl apply -f gmsa-crd.yaml命令列安裝 CRD。

安裝 Webhook 來驗證 GMSA 使用者

為 Kubernetes 叢集設定兩個 Webhook,在 Pod 或容器級別填充和檢查 GMSA 憑據規約參照。

  • 修改模式(Mutating)的 Webhook,將對 GMSA 的參照(在 Pod 規約中體現為名字) 展開為完整憑據規約的 JSON 形式,並儲存回 Pod 規約中。
  • 驗證模式(Validating)的 Webhook,確保對 GMSA 的所有參照都是已經授權 給 Pod 的服務賬號使用的。

安裝以上 Webhook 及其相關聯的物件需要執行以下步驟:

  • 建立一個證書金鑰對(用於允許 Webhook 容器與叢集通訊)
  • 安裝一個包含如上證書的 Secret
  • 建立一個包含核心 Webhook 邏輯的 Deployment
  • 建立參照該 Deployment 的 Validating Webhook 和 Mutating Webhook 設定

也可以使用這個指令碼來部署和設定上述 GMSA Webhook 及相關聯的物件。你還可以在執行指令碼時設定 --dry-run=server 選項以便審查指令碼將會對叢集做出的變更。

指令碼所使用的YAML 模板 也可用於手動部署 Webhook 及相關聯的物件,不過需要對其中的引數作適當替換。

2.1、建立 GMSA 管理資源

安裝 GMSACredentialSpec CRD 之後,就可以設定包含 GMSA 約束自定義資源了。GMSA 憑據規約中並不包含祕密或敏感資料。 其中包含的資訊主要用於容器執行時,便於後者向 Windows 描述容器所期望的 GMSA。 GMSA 憑據規約可以使用 PowerShell 指令碼 以 YAML 格式生成。

下面是手動以 JSON 格式生成 GMSA 憑據規約並對其進行 YAML 轉換的步驟:

  • 匯入 CredentialSpec 模組: ipmo CredentialSpec.psm1
  • 使用 New-CredentialSpec 來建立一個 JSON 格式的憑據規約。 要建立名為 WebApp1 的 GMSA 憑據規約,呼叫 New-CredentialSpec -Name WebApp1 -AccountName WebApp1 -Domain $(Get-ADDomain -Current LocalComputer)。
  • 使用 Get-CredentialSpec 來顯示 JSON 檔案的路徑。
  • 將憑據規約從 JSON 格式轉換為 YAML 格式,並新增必要的頭部欄位 apiVersion、kind、metadata 和 credspec,使其成為一個可以在 Kubernetes 中設定的 GMSACredentialSpec 自定義資源。

下面的 YAML 設定描述的是一個名為 gmsa-WebApp1 的 GMSA 憑據規約:

apiVersion: windows.k8s.io/v1
kind: GMSACredentialSpec
metadata:
  name: gmsa-WebApp1  # 這是隨意起的一個名字,將用作參照
credspec:
  ActiveDirectoryConfig:
    GroupManagedServiceAccounts:
    - Name: WebApp1   # GMSA 賬號的使用者名稱
      Scope: CONTOSO  # NETBIOS 域名
    - Name: WebApp1   # GMSA 賬號的使用者名稱
      Scope: contoso.com # DNS 域名
  CmsPlugins:
  - ActiveDirectory
  DomainJoinConfig:
    DnsName: contoso.com  # DNS 域名
    DnsTreeName: contoso.com # DNS 域名根
    Guid: 244818ae-87ac-4fcd-92ec-e79e5252348a  # GUID
    MachineAccountName: WebApp1 # GMSA 賬號的使用者名稱
    NetBiosName: CONTOSO  # NETBIOS 域名
    Sid: S-1-5-21-2126449477-2524075714-3094792973 # GMSA 的 SID

上面的憑據規約資源可以儲存為 gmsa-Webapp1-credspec.yaml,之後使用 kubectl apply -f gmsa-Webapp1-credspec.yml 命令應用到叢集上。

2.2、設定叢集啟用 GMSA 管理的 RBAC

需要為每個 GMSA 憑據規約資源定義叢集角色。 該叢集角色授權某主體(通常是一個服務賬號)對特定的 GMSA 資源執行 use 動作。 下面的範例顯示的是一個叢集角色,對前文建立的憑據規約 gmsa-WebApp1 執行鑑權。 將此檔案儲存為 gmsa-webapp1-role.yaml 並執行 kubectl apply -f gmsa-webapp1-role.yaml

# 建立叢集角色讀取憑據規約
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: webapp1-role
rules:
- apiGroups: ["windows.k8s.io"]
  resources: ["gmsacredentialspecs"]
  verbs: ["use"]
  resourceNames: ["gmsa-WebApp1"]

2.3、分配 GMSA 管理服務賬號

需要將某個服務賬號(Pod 設定所對應的那個)繫結到前文建立的叢集角色上。 這一系結操作實際上授予該服務賬號使用所指定的 GMSA 憑據規約資源的存取許可權。 下面顯示的是一個繫結到叢集角色 webapp1-role 上的 default 服務賬號,使之 能夠使用前面所建立的 gmsa-WebApp1 憑據規約資源。

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: allow-default-svc-account-read-on-gmsa-WebApp1
  namespace: default
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
roleRef:
  kind: ClusterRole
  name: webapp1-role
  apiGroup: rbac.authorization.k8s.io

2.4、設定 GMSA 管理參照

Pod 規約欄位 securityContext.windowsOptions.gmsaCredentialSpecName 可用來 設定對指定 GMSA 憑據規約自定義資源的參照。 設定此參照將會設定 Pod 中的所有容器使用所給的 GMSA。 下面是一個 Pod 規約範例,其中包含了對 gmsa-WebApp1 憑據規約的參照:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: with-creds
  name: with-creds
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      run: with-creds
  template:
    metadata:
      labels:
        run: with-creds
    spec:
      securityContext:
        windowsOptions:
          gmsaCredentialSpecName: gmsa-webapp1
      containers:
      - image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
        imagePullPolicy: Always
        name: iis
      nodeSelector:
        kubernetes.io/os: windows

Pod 中的各個容器也可以使用對應容器的 securityContext.windowsOptions.gmsaCredentialSpecName 欄位來設定期望使用的 GMSA 憑據規約。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: with-creds
  name: with-creds
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      run: with-creds
  template:
    metadata:
      labels:
        run: with-creds
    spec:
      containers:
      - image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
        imagePullPolicy: Always
        name: iis
        securityContext:
          windowsOptions:
            gmsaCredentialSpecName: gmsa-Webapp1
      nodeSelector:
        kubernetes.io/os: windows

當 Pod 規約中填充了 GMSA 相關欄位(如上所述),在叢集中應用 Pod 規約時會依次 發生以下事件:

Mutating Webhook 解析對 GMSA 憑據規約資源的參照,並將其全部展開, 得到 GMSA 憑據規約的實際內容。Validating Webhook 確保與 Pod 相關聯的服務賬號有權在所給的 GMSA 憑據規約 上執行 use 動作。容器執行時為每個 Windows 容器設定所指定的 GMSA 憑據規約,這樣容器就可以以 活動目錄中該 GMSA 所代表的身份來執行操作,使用該身份來存取域中的服務。

2.5、使用主機名或 FQDN 對網路共用進行身份驗證

如果你在使用主機名或 FQDN 從 Pod 連線到 SMB 共用時遇到問題,但能夠通過其 IPv4 地址存取共用, 請確保在 Windows 節點上設定了以下登入檔項。

reg add “HKLMSYSTEMCurrentControlSetServiceshnsState” /v EnableCompartmentNamespace /t REG_DWORD /d 1

2.6、故障排查

當我們設定 GMSA 環境的時候,不免會遇到一些報錯之類的,那麼我們該如何去排查呢?

首先,確保 credspec 已傳遞給 Pod。為此,你需要先執行 exec 進入到你的一個 Pod 中並檢查 nltest.exe /parentdomain 命令的輸出。 在下面的例子中,Pod 未能正確地獲得憑據規約:

$ kubectl exec -it iis-auth-7776966999-n5nzr powershell.exe

nltest.exe /parentdomain 導致以下錯誤:

Getting parent domain failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE

如果 Pod 未能正確獲得憑據規約,則下一步就要檢查與域之間的通訊。 首先,從 Pod 內部快速執行一個 nslookup 操作,找到域根。

這一操作會告訴我們三件事情:

  • Pod 能否存取域控制器(DC)
  • DC 能否存取
  • PodDNS 是否正常工作

如果 DNS 和通訊測試通過,接下來你需要檢查是否 Pod 已經與域之間建立了 安全通訊通道。要執行這一檢查,你需要再次通過 exec 進入到你的 Pod 中 並執行 nltest.exe /query 命令。

$ nltest.exe /query

由於某種原因,Pod 無法使用 credspec 中指定的帳戶登入到域。 你可以嘗試通過執行以下命令來修復安全通道:

$ nltest /sc_reset:domain.example

如果命令成功,你將看到類似以下內容的輸出:

Flags: 30 HAS_IP HAS_TIMESERV
Trusted DC Name dc10.domain.example
Trusted DC Connection Status Status = 0 0x0 NERR_Success
The command completed successfully

以上命令修復了錯誤,可以通過將以下生命週期回撥新增到你的 Pod 規約中來自動執行該步驟。 如果這些操作沒有修復錯誤,需要再次檢查的 credspec 並確認它是正確和完整的。

        image: registry.domain.example/iis-auth:1809v1
        lifecycle:
          postStart:
            exec:
              command: ["powershell.exe","-command","do { Restart-Service -Name netlogon } while ( $($Result = (nltest.exe /query); if ($Result -like '*0x0 NERR_Success*') {return $true} else {return $false}) -eq $false)"]
        imagePullPolicy: IfNotPresent

如果向你的 Pod 規約中新增如上所示的 lifecycle 節,則 Pod 會自動執行所 列舉的命令來重啟 netlogon 服務,直到 nltest.exe /query 命令返回時沒有錯誤資訊。

三、為 Windows 的 Pod 和容器設定 RunAsUserName

要指定執行 Pod 容器時所使用的使用者名稱,必須在 Pod 宣告中包含 securityContext (PodSecurityContext) 欄位, 並在其內部包含 windowsOptions (WindowsSecurityContextOptions) 欄位的 runAsUserName 欄位。

為 Pod 指定的 Windows SecurityContext 選項適用於該 Pod 中(包括 init 容器)的所有容器。

下面看一個已經設定了 runAsUserName 欄位的 Windows Pod 的組態檔windows/run-as-username-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: run-as-username-pod-demo
spec:
  securityContext:
    windowsOptions:
      runAsUserName: "ContainerUser"
  containers:
  - name: run-as-username-demo
    image: mcr.microsoft.com/windows/servercore:ltsc2019
    command: ["ping", "-t", "localhost"]
  nodeSelector:
    kubernetes.io/os: windows

建立 Pod:

$ kubectl apply -f https://k8s.io/examples/windows/run-as-username-pod.yaml

驗證 Pod 容器是否在執行:

$ kubectl get pod run-as-username-pod-demo

獲取該容器的 shell:

$ kubectl exec -it run-as-username-pod-demo – powershell

檢查執行 shell 的使用者的使用者名稱是否正確:

$ echo $env:USERNAME

輸出結果

ContainerUser

3.1、設定 Username

要指定執行容器時所使用的使用者名稱,請在容器清單中包含 securityContext (SecurityContext) 欄位,並在其內部包含 windowsOptions (WindowsSecurityContextOptions) 欄位的 runAsUserName 欄位。

為容器指定的 Windows SecurityContext 選項僅適用於該容器,並且它會覆蓋 Pod 級別設定。

下面看一個 Pod 的組態檔 windows/run-as-username-container.yaml,其中只有一個容器,並且在 Pod 級別和容器級別都設定了 runAsUserName:

apiVersion: v1
kind: Pod
metadata:
  name: run-as-username-container-demo
spec:
  securityContext:
    windowsOptions:
      runAsUserName: "ContainerUser"
  containers:
  - name: run-as-username-demo
    image: mcr.microsoft.com/windows/servercore:ltsc2019
    command: ["ping", "-t", "localhost"]
    securityContext:
        windowsOptions:
            runAsUserName: "ContainerAdministrator"
  nodeSelector:
    kubernetes.io/os: windows

建立 Pod:

$ kubectl apply -f https://k8s.io/examples/windows/run-as-username-container.yaml

驗證 Pod 容器是否在執行:

$ kubectl get pod run-as-username-container-demo

獲取該容器的 shell:

$ kubectl exec -it run-as-username-container-demo – powershell

檢查執行 shell 的使用者的使用者名稱是否正確(應該是容器級別設定的那個):

$ echo $env:USERNAME

輸出結果:

ContainerAdministrator

3.2、Windows Username 的侷限性

想要使用此功能,在 runAsUserName 欄位中設定的值必須是有效的使用者名稱。 它必須是 DOMAINUSER 這種格式,其中 *DOMAIN* 是可選的。 Windows 使用者名稱不區分大小寫。此外,關於 DOMAIN 和 USER 還有一些限制:

  • runAsUserName 欄位不能為空,並且不能包含控制字元(ASCII 值:0x00-0x1F、0x7F)
  • DOMAIN 必須是 NetBios 名稱或 DNS 名稱,每種名稱都有各自的侷限性:
  • NetBios 名稱:最多 15 個字元,不能以 .(點)開頭,並且不能包含以下字元: / : * ? " < > |
  • DNS 名稱:最多 255 個字元,只能包含字母、數位、點和中劃線,並且不能以 .(點)或 -(中劃線)開頭和結尾。
  • USER 最多不超過 20 個字元,不能 只 包含點或空格,並且不能包含以下字元:" / [ ] : ; | = , + * ? < > @

runAsUserName 欄位接受的值的一些範例:ContainerAdministrator、ContainerUser、 NT AUTHORITYNETWORK SERVICE、NT AUTHORITYLOCAL SERVICE

總結

本篇內容共約一萬字,內容還是比較多的,總共包含了 Windows HostProcess的建立、為 Windows Pod 和容器設定 GMSA 和 Windows 的 Pod 和容器設定 RunAsUserName三大功能模組。全篇文章主要講解了,怎麼將執行在 Windows 節點上的 Pod 和容器設定組管理的服務賬號(Group Managed Service Accounts,GMSA)。 組管理的服務賬號是活動目錄(Active Directory)的一種特殊型別,提供自動化的 密碼管理、簡化的服務主體名稱(Service Principal Name,SPN)管理以及跨多個 伺服器將管理操作委派給其他管理員等能力。

到此這篇關於Kubernetes教學之Windows HostProcess 執行容器化負載的文章就介紹到這了,更多相關Windows HostProcess容器內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com