目錄
- 簡介
- 一、創(chuàng)建 Windows HostProcess
- 1.1、HostProcess 的使用限制
- 1.2、HostProcess Pod 配置
- 1.3、配置清單
- 1.4、內(nèi)存資源
- 二、配置 GMSA
- 2.1、創(chuàng)建 GMSA 管理資源
- 2.2、配置集群啟用 GMSA 管理的 RBAC
- 2.3、分配 GMSA 管理服務(wù)賬號
- 2.4、配置 GMSA 管理引用
- 2.5、使用主機(jī)名或 FQDN 對網(wǎng)絡(luò)共享進(jìn)行身份驗(yàn)證
- 2.6、故障排查
- 三、為 Windows 的 Pod 和容器配置 RunAsUserName
- 3.1、設(shè)置 Username
- 3.2、Windows Username 的局限性
- 總結(jié)
簡介
Windows HostProcess 容器讓你能夠在 Windows 主機(jī)上運(yùn)行容器化負(fù)載。 這類容器以普通的進(jìn)程形式運(yùn)行,但能夠在具有合適用戶特權(quán)的情況下, 訪問主機(jī)網(wǎng)絡(luò)名字空間、存儲和設(shè)備。
HostProcess 容器可用來在 Windows 節(jié)點(diǎn)上部署網(wǎng)絡(luò)插件、存儲配置、設(shè)備插件、kube-proxy 以及其他組件, 同時(shí)不需要配置專用的代理或者直接安裝主機(jī)服務(wù)。
一、創(chuàng)建 Windows HostProcess
我何時(shí)該使用 Windows HostProcess 容器?
- 當(dāng)你準(zhǔn)備執(zhí)行需要訪問主機(jī)上網(wǎng)絡(luò)名字空間的任務(wù)時(shí),HostProcess 容器能夠訪問主機(jī)上的網(wǎng)絡(luò)接口和 IP 地址。
- 當(dāng)你需要訪問主機(jī)上的資源,如文件系統(tǒng)、事件日志等等。
- 需要安裝特定的設(shè)備驅(qū)動或者 Windows 服務(wù)時(shí)。
- 需要對管理任務(wù)和安全策略進(jìn)行整合時(shí)。使用 HostProcess 容器能夠縮小 Windows 節(jié)點(diǎn)上所需要的特權(quán)范圍。
HostProcess 容器功能特性默認(rèn)是啟用的。 kubelet 會直接與 containerd 通信,通過 CRI 將主機(jī)進(jìn)程標(biāo)志傳遞過去。 你可以使用 containerd 來運(yùn)行 HostProcess 容器。
想要禁用 HostProcess 容器特性,可以執(zhí)行下面的命令:
$ –feature-gates=WindowsHostProcessContainers=false
1.1、HostProcess 的使用限制
- HostProcess 容器需要 containerd 1.6 或更高版本的 容器運(yùn)行時(shí)。
- HostProcess Pods 只能包含 HostProcess 容器。這是在 Windows 操作系統(tǒng)上的約束; 非特權(quán)的 Windows 容器不能與主機(jī) IP 名字空間共享虛擬網(wǎng)卡(vNIC)。
- HostProcess 在主機(jī)上以一個(gè)進(jìn)程的形式運(yùn)行,除了通過 HostProcess 用戶賬號所實(shí)施的資源約束外,不提供任何形式的隔離。HostProcess 容器不支持文件系統(tǒng)或 Hyper-V 隔離。
- volume 掛載是被支持的,并且要花在到容器卷下。
- 默認(rèn)情況下有一組主機(jī)用戶賬戶可供 HostProcess 容器使用。
- 對資源約束(磁盤、內(nèi)存、CPU 個(gè)數(shù))的支持與主機(jī)上進(jìn)程相同。
- 不支持命名管道或者 UNIX 域套接字形式的掛載,需要使用主機(jī)上的路徑名來訪問 。
1.2、HostProcess Pod 配置
在 Pod 安全標(biāo)準(zhǔn)中所定義的策略中, HostProcess Pod 默認(rèn)是不被 basline 和 restricted 策略支持的。因此建議 HostProcess 運(yùn)行在與 privileged 模式相看齊的規(guī)則下。
當(dāng)運(yùn)行在 privileged 規(guī)則下時(shí),下面是要啟用 HostProcess Pod 創(chuàng)建所需要設(shè)置的選項(xiàng):
控制 | 策略 | 可選值 |
---|---|---|
securityContext.windowsOptions.hostProcess | Windows Pods 提供運(yùn)行 HostProcess 容器的能力,這類容器能夠具有對 Windows 節(jié)點(diǎn)的特權(quán)訪問權(quán)限。 | true |
hostNetwork | 初始時(shí)將默認(rèn)位于主機(jī)網(wǎng)絡(luò)中。在未來可能會希望將網(wǎng)絡(luò)設(shè)置到不同的隔離環(huán)境中。 | true |
securityContext.windowsOptions.runAsUsername | 關(guān)于 HostProcess 容器所要使用的用戶的規(guī)約,需要設(shè)置在 Pod 的規(guī)約中。 | NT AUTHORITY\SYSTEM 、NT AUTHORITY\Local service 、NT AUTHORITY\NetworkService |
runAsNonRoot | 因?yàn)?HostProcess 容器有訪問主機(jī)的特權(quán),runAsNonRoot 字段不可以設(shè)置為 true。 | 未定義/Nil 、false |
1.3、配置清單
這里我們只看部分內(nèi)容:
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 容器支持在容器卷空間中掛載卷的能力。 在容器內(nèi)運(yùn)行的應(yīng)用能夠通過相對或者絕對路徑直接訪問卷掛載。 環(huán)境變量 $CONTAINER_SANDBOX_MOUNT_POINT
在容器創(chuàng)建時(shí)被設(shè)置為指向容器卷的絕對主機(jī)路徑。 相對路徑是基于 .spec.containers.volumeMounts.mountPath
配置來推導(dǎo)的。
1.4、內(nèi)存資源
資源約束(磁盤、內(nèi)存、CPU 個(gè)數(shù))作用到任務(wù)之上,并在整個(gè)任務(wù)上起作用。 例如,如果內(nèi)存限制設(shè)置為 10MB,任何 HostProcess 任務(wù)對象所分配的內(nèi)存不會超過 10MB。 這一行為與其他 Windows 容器類型相同。資源限制的設(shè)置方式與編排系統(tǒng)或容器運(yùn)行時(shí)無關(guān)。 唯一的區(qū)別是用來跟蹤資源所進(jìn)行的磁盤資源用量的計(jì)算,出現(xiàn)差異的原因是因?yàn)?HostProcess 容器啟動引導(dǎo)的方式造成的。
二、配置 GMSA
在 Kubernetes 環(huán)境中,GMSA 憑據(jù)規(guī)約配置為 Kubernetes 集群范圍的自定義資源 (Custom Resources)形式。Windows Pod 以及各 Pod 中的每個(gè)容器可以配置為 使用 GMSA 來完成基于域(Domain)的操作(例如,Kerberos 身份認(rèn)證),以便 與其他 Windows 服務(wù)相交互。
安裝 GMSACredentialSpec CRD:
需要在集群上配置一個(gè)用于 GMSA 憑據(jù)規(guī)約資源的 CustomResourceDefinition(CRD), 以便定義類型為 GMSACredentialSpec 的自定義資源。 下載 GMSA CRD YAML 并將其保存為 gmsa-crd.yaml。然后執(zhí)行 kubectl apply -f gmsa-crd.yaml
命令行安裝 CRD。
安裝 Webhook 來驗(yàn)證 GMSA 用戶
為 Kubernetes 集群配置兩個(gè) Webhook,在 Pod 或容器級別填充和檢查 GMSA 憑據(jù)規(guī)約引用。
- 修改模式(Mutating)的 Webhook,將對 GMSA 的引用(在 Pod 規(guī)約中體現(xiàn)為名字) 展開為完整憑據(jù)規(guī)約的 JSON 形式,并保存回 Pod 規(guī)約中。
- 驗(yàn)證模式(Validating)的 Webhook,確保對 GMSA 的所有引用都是已經(jīng)授權(quán) 給 Pod 的服務(wù)賬號使用的。
安裝以上 Webhook 及其相關(guān)聯(lián)的對象需要執(zhí)行以下步驟:
- 創(chuàng)建一個(gè)證書密鑰對(用于允許 Webhook 容器與集群通信)
- 安裝一個(gè)包含如上證書的 Secret
- 創(chuàng)建一個(gè)包含核心 Webhook 邏輯的 Deployment
- 創(chuàng)建引用該 Deployment 的 Validating Webhook 和 Mutating Webhook 配置
也可以使用這個(gè)腳本來部署和配置上述 GMSA Webhook 及相關(guān)聯(lián)的對象。你還可以在運(yùn)行腳本時(shí)設(shè)置 --dry-run=server
選項(xiàng)以便審查腳本將會對集群做出的變更。
腳本所使用的YAML 模板 也可用于手動部署 Webhook 及相關(guān)聯(lián)的對象,不過需要對其中的參數(shù)作適當(dāng)替換。
2.1、創(chuàng)建 GMSA 管理資源
安裝 GMSACredentialSpec CRD 之后,就可以配置包含 GMSA 約束自定義資源了。GMSA 憑據(jù)規(guī)約中并不包含秘密或敏感數(shù)據(jù)。 其中包含的信息主要用于容器運(yùn)行時(shí),便于后者向 Windows 描述容器所期望的 GMSA。 GMSA 憑據(jù)規(guī)約可以使用 PowerShell 腳本 以 YAML 格式生成。
下面是手動以 JSON 格式生成 GMSA 憑據(jù)規(guī)約并對其進(jìn)行 YAML 轉(zhuǎn)換的步驟:
- 導(dǎo)入 CredentialSpec 模塊: ipmo CredentialSpec.psm1
- 使用 New-CredentialSpec 來創(chuàng)建一個(gè) JSON 格式的憑據(jù)規(guī)約。 要創(chuàng)建名為 WebApp1 的 GMSA 憑據(jù)規(guī)約,調(diào)用 New-CredentialSpec -Name WebApp1 -AccountName WebApp1 -Domain $(Get-ADDomain -Current LocalComputer)。
- 使用 Get-CredentialSpec 來顯示 JSON 文件的路徑。
- 將憑據(jù)規(guī)約從 JSON 格式轉(zhuǎn)換為 YAML 格式,并添加必要的頭部字段 apiVersion、kind、metadata 和 credspec,使其成為一個(gè)可以在 Kubernetes 中配置的 GMSACredentialSpec 自定義資源。
下面的 YAML 配置描述的是一個(gè)名為 gmsa-WebApp1 的 GMSA 憑據(jù)規(guī)約:
apiVersion: windows.k8s.io/v1 kind: GMSACredentialSpec metadata: name: gmsa-WebApp1 # 這是隨意起的一個(gè)名字,將用作引用 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
上面的憑據(jù)規(guī)約資源可以保存為 gmsa-Webapp1-credspec.yaml
,之后使用 kubectl apply -f gmsa-Webapp1-credspec.yml
命令應(yīng)用到集群上。
2.2、配置集群啟用 GMSA 管理的 RBAC
需要為每個(gè) GMSA 憑據(jù)規(guī)約資源定義集群角色。 該集群角色授權(quán)某主體(通常是一個(gè)服務(wù)賬號)對特定的 GMSA 資源執(zhí)行 use 動作。 下面的示例顯示的是一個(gè)集群角色,對前文創(chuàng)建的憑據(jù)規(guī)約 gmsa-WebApp1 執(zhí)行鑒權(quán)。 將此文件保存為 gmsa-webapp1-role.yaml
并執(zhí)行 kubectl apply -f gmsa-webapp1-role.yaml
。
# 創(chuàng)建集群角色讀取憑據(jù)規(guī)約 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 管理服務(wù)賬號
需要將某個(gè)服務(wù)賬號(Pod 配置所對應(yīng)的那個(gè))綁定到前文創(chuàng)建的集群角色上。 這一綁定操作實(shí)際上授予該服務(wù)賬號使用所指定的 GMSA 憑據(jù)規(guī)約資源的訪問權(quán)限。 下面顯示的是一個(gè)綁定到集群角色 webapp1-role
上的 default 服務(wù)賬號,使之 能夠使用前面所創(chuàng)建的 gmsa-WebApp1
憑據(jù)規(guī)約資源。
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 規(guī)約字段 securityContext.windowsOptions.gmsaCredentialSpecName
可用來 設(shè)置對指定 GMSA 憑據(jù)規(guī)約自定義資源的引用。 設(shè)置此引用將會配置 Pod 中的所有容器使用所給的 GMSA。 下面是一個(gè) Pod 規(guī)約示例,其中包含了對 gmsa-WebApp1 憑據(jù)規(guī)約的引用:
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 中的各個(gè)容器也可以使用對應(yīng)容器的 securityContext.windowsOptions.gmsaCredentialSpecName
字段來設(shè)置期望使用的 GMSA 憑據(jù)規(guī)約。
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
當(dāng) Pod 規(guī)約中填充了 GMSA 相關(guān)字段(如上所述),在集群中應(yīng)用 Pod 規(guī)約時(shí)會依次 發(fā)生以下事件:
Mutating Webhook 解析對 GMSA 憑據(jù)規(guī)約資源的引用,并將其全部展開, 得到 GMSA 憑據(jù)規(guī)約的實(shí)際內(nèi)容。Validating Webhook 確保與 Pod 相關(guān)聯(lián)的服務(wù)賬號有權(quán)在所給的 GMSA 憑據(jù)規(guī)約 上執(zhí)行 use 動作。容器運(yùn)行時(shí)為每個(gè) Windows 容器配置所指定的 GMSA 憑據(jù)規(guī)約,這樣容器就可以以 活動目錄中該 GMSA 所代表的身份來執(zhí)行操作,使用該身份來訪問域中的服務(wù)。
2.5、使用主機(jī)名或 FQDN 對網(wǎng)絡(luò)共享進(jìn)行身份驗(yàn)證
如果你在使用主機(jī)名或 FQDN 從 Pod 連接到 SMB 共享時(shí)遇到問題,但能夠通過其 IPv4 地址訪問共享, 請確保在 Windows 節(jié)點(diǎn)上設(shè)置了以下注冊表項(xiàng)。
reg add “HKLM\SYSTEM\CurrentControlSet\Services\hns\State” /v EnableCompartmentNamespace /t REG_DWORD /d 1
2.6、故障排查
當(dāng)我們配置 GMSA 環(huán)境的時(shí)候,不免會遇到一些報(bào)錯(cuò)之類的,那么我們該如何去排查呢?
首先,確保 credspec 已傳遞給 Pod。為此,你需要先運(yùn)行 exec 進(jìn)入到你的一個(gè) Pod 中并檢查 nltest.exe /parentdomain
命令的輸出。 在下面的例子中,Pod 未能正確地獲得憑據(jù)規(guī)約:
$ kubectl exec -it iis-auth-7776966999-n5nzr powershell.exe
nltest.exe /parentdomain
導(dǎo)致以下錯(cuò)誤:
Getting parent domain failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE
如果 Pod 未能正確獲得憑據(jù)規(guī)約,則下一步就要檢查與域之間的通信。 首先,從 Pod 內(nèi)部快速執(zhí)行一個(gè) nslookup 操作,找到域根。
這一操作會告訴我們?nèi)虑椋?/p>
- Pod 能否訪問域控制器(DC)
- DC 能否訪問
- PodDNS 是否正常工作
如果 DNS 和通信測試通過,接下來你需要檢查是否 Pod 已經(jīng)與域之間建立了 安全通信通道。要執(zhí)行這一檢查,你需要再次通過 exec 進(jìn)入到你的 Pod 中 并執(zhí)行 nltest.exe /query
命令。
$ nltest.exe /query
由于某種原因,Pod 無法使用 credspec 中指定的帳戶登錄到域。 你可以嘗試通過運(yùn)行以下命令來修復(fù)安全通道:
$ nltest /sc_reset:domain.example
如果命令成功,你將看到類似以下內(nèi)容的輸出:
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
以上命令修復(fù)了錯(cuò)誤,可以通過將以下生命周期回調(diào)添加到你的 Pod 規(guī)約中來自動執(zhí)行該步驟。 如果這些操作沒有修復(fù)錯(cuò)誤,需要再次檢查的 credspec 并確認(rèn)它是正確和完整的。
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 規(guī)約中添加如上所示的 lifecycle 節(jié),則 Pod 會自動執(zhí)行所 列舉的命令來重啟 netlogon 服務(wù),直到 nltest.exe /query
命令返回時(shí)沒有錯(cuò)誤信息。
三、為 Windows 的 Pod 和容器配置 RunAsUserName
要指定運(yùn)行 Pod 容器時(shí)所使用的用戶名,必須在 Pod 聲明中包含 securityContext (PodSecurityContext)
字段, 并在其內(nèi)部包含 windowsOptions (WindowsSecurityContextOptions)
字段的 runAsUserName
字段。
為 Pod 指定的 Windows SecurityContext 選項(xiàng)適用于該 Pod 中(包括 init 容器)的所有容器。
下面看一個(gè)已經(jīng)設(shè)置了 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
創(chuàng)建 Pod:
$ kubectl apply -f https://k8s.io/examples/windows/run-as-username-pod.yaml
驗(yàn)證 Pod 容器是否在運(yùn)行:
$ kubectl get pod run-as-username-pod-demo
獲取該容器的 shell:
$ kubectl exec -it run-as-username-pod-demo – powershell
檢查運(yùn)行 shell 的用戶的用戶名是否正確:
$ echo $env:USERNAME
輸出結(jié)果
ContainerUser
3.1、設(shè)置 Username
要指定運(yùn)行容器時(shí)所使用的用戶名,請?jiān)谌萜髑鍐沃邪?securityContext (SecurityContext
) 字段,并在其內(nèi)部包含 windowsOptions (WindowsSecurityContextOptions
) 字段的 runAsUserName 字段。
為容器指定的 Windows SecurityContext 選項(xiàng)僅適用于該容器,并且它會覆蓋 Pod 級別設(shè)置。
下面看一個(gè) Pod 的配置文件 windows/run-as-username-container.yaml
,其中只有一個(gè)容器,并且在 Pod 級別和容器級別都設(shè)置了 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
創(chuàng)建 Pod:
$ kubectl apply -f https://k8s.io/examples/windows/run-as-username-container.yaml
驗(yàn)證 Pod 容器是否在運(yùn)行:
$ kubectl get pod run-as-username-container-demo
獲取該容器的 shell:
$ kubectl exec -it run-as-username-container-demo – powershell
檢查運(yùn)行 shell 的用戶的用戶名是否正確(應(yīng)該是容器級別設(shè)置的那個(gè)):
$ echo $env:USERNAME
輸出結(jié)果:
ContainerAdministrator
3.2、Windows Username 的局限性
想要使用此功能,在 runAsUserName 字段中設(shè)置的值必須是有效的用戶名。 它必須是 DOMAIN\USER
這種格式,其中 *DOMAIN* 是可選的。 Windows 用戶名不區(qū)分大小寫。此外,關(guān)于 DOMAIN 和 USER 還有一些限制:
- runAsUserName 字段不能為空,并且不能包含控制字符(ASCII 值:0x00-0x1F、0x7F)
- DOMAIN 必須是 NetBios 名稱或 DNS 名稱,每種名稱都有各自的局限性:
- NetBios 名稱:最多 15 個(gè)字符,不能以 .(點(diǎn))開頭,并且不能包含以下字符:\ / : * ? " < > |
- DNS 名稱:最多 255 個(gè)字符,只能包含字母、數(shù)字、點(diǎn)和中劃線,并且不能以 .(點(diǎn))或 -(中劃線)開頭和結(jié)尾。
- USER 最多不超過 20 個(gè)字符,不能 只 包含點(diǎn)或空格,并且不能包含以下字符:" / \ [ ] : ; | = , + * ? < > @
runAsUserName 字段接受的值的一些示例:ContainerAdministrator、ContainerUser、 NT AUTHORITY\NETWORK SERVICE、NT AUTHORITY\LOCAL SERVICE
。
總結(jié)
本篇內(nèi)容共約一萬字,內(nèi)容還是比較多的,總共包含了 Windows HostProcess的創(chuàng)建、為 Windows Pod 和容器配置 GMSA 和 Windows 的 Pod 和容器配置 RunAsUserName三大功能模塊。全篇文章主要講解了,怎么將運(yùn)行在 Windows 節(jié)點(diǎn)上的 Pod 和容器配置組管理的服務(wù)賬號(Group Managed Service Accounts,GMSA)。 組管理的服務(wù)賬號是活動目錄(Active Directory)的一種特殊類型,提供自動化的 密碼管理、簡化的服務(wù)主體名稱(Service Principal Name,SPN)管理以及跨多個(gè) 服務(wù)器將管理操作委派給其他管理員等能力。