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!
推薦閱讀:
- 自定義資源CRD使用介紹
- Kubernetes安全加固的一些實用建議
- kubernetes之statefulset搭建MySQL集群
- k8s中pod使用詳解(雲原生kubernetes)
- K8S 中 kubectl 命令詳解