Kubernetes教程之Windows HostProcess 運行容器化負載

簡介

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.hostProcess Windows Pods 提供運行 HostProcess 容器的能力,這類容器能夠具有對 Windows 節點的特權訪問權限。 true
hostNetwork 初始時將默認位於主機網絡中。在未來可能會希望將網絡設置到不同的隔離環境中。 true
securityContext.windowsOptions.runAsUsername 關於 HostProcess 容器所要使用的用戶的規約,需要設置在 Pod 的規約中。 NT AUTHORITY\SYSTEM 、NT AUTHORITY\Local service 、NT AUTHORITY\NetworkService
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 “HKLM\SYSTEM\CurrentControlSet\Services\hns\State” /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 字段中設置的值必須是有效的用戶名。 它必須是 DOMAIN\USER 這種格式,其中 *DOMAIN* 是可選的。 Windows 用戶名不區分大小寫。此外,關於 DOMAIN 和 USER 還有一些限制:

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

runAsUserName 字段接受的值的一些示例:ContainerAdministrator、ContainerUser、 NT AUTHORITY\NETWORK SERVICE、NT AUTHORITY\LOCAL 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容器內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: