集群管理
1 - 以独立模式运行 kubelet
本教程将向你展示如何运行一个独立的 kubelet 实例。
你可能会有不同的动机来运行一个独立的 kubelet。 本教程旨在向你介绍 Kubernetes,即使你对此并没有太多经验也没有关系。 你可以跟随本教程学习节点设置、基本(静态)Pod 以及 Kubernetes 如何管理容器。
你学习完本教程后,就可以尝试使用带一个控制平面的集群来管理 Pod、节点和其他类别的对象。例如,你好,Minikube。
你还可以以独立模式运行 kubelet 来满足生产场景要求,例如为高可用、弹性部署的集群运行控制平面。 本教程不涵盖运行弹性控制平面所需的细节。
教程目标
- 在 Linux 系统上安装
cri-o和kubelet,并将其作为systemd服务运行。 - 启动一个运行
nginx的 Pod,监听针对此 Pod 的 IP 地址的 TCP 80 端口的请求。 - 学习此方案中不同组件之间如何交互。
Caution
本教程中所使用的 kubelet 配置在设计上是不安全的,不得用于生产环境中。
准备开始
- 对使用
systemd和iptables(或使用iptables仿真的nftables)的 Linux 系统具有管理员(root)访问权限。 - 有权限访问互联网以下载本教程所需的组件,例如:
- 实现 Kubernetes CRI 的容器运行时。
- 网络插件(通常称为 容器网络接口(CNI))。
- 必需的 CLI 工具:
curl、tar、jq。
准备好系统
配置内存交换
默认情况下,如果在节点上检测到内存交换,kubelet 将启动失败。 这意味着内存交换应该被禁用或被 kubelet 容忍。
Note
如果你配置 kubelet 为容忍内存交换,则 kubelet 仍会配置 Pod(以及这些 Pod 中的容器)不使用交换空间。 要了解 Pod 实际上可以如何使用可用的交换,你可以进一步阅读 Linux 节点上交换内存管理。
如果你启用了交换内存,则禁用它或在 kubelet 配置文件中添加 failSwapOn: false。
要检查交换内存是否被启用:
sudo swapon --show
如果此命令没有输出,则交换内存已被禁用。
临时禁用交换内存:
sudo swapoff -a
要使此变更持续到重启之后:
确保在 /etc/fstab 或 systemd.swap 中禁用交换内存,具体取决于它在你的系统上是如何配置的。
启用 IPv4 数据包转发
检查 IPv4 数据包转发是否被启用:
cat /proc/sys/net/ipv4/ip_forward
如果输出为 1,则 IPv4 数据包转发已被启用。如果输出为 0,按照以下步骤操作。
要启用 IPv4 数据包转发,创建一个配置文件,将 net.ipv4.ip_forward
参数设置为 1:
sudo tee /etc/sysctl.d/k8s.conf <<EOF
net.ipv4.ip_forward = 1
EOF
将变更应用到系统:
sudo sysctl --system
输出类似于:
...
* Applying /etc/sysctl.d/k8s.conf ...
net.ipv4.ip_forward = 1
* Applying /etc/sysctl.conf ...
下载、安装和配置组件
安装容器运行时
下载所需软件包的最新可用版本(推荐)。
本教程建议安装 CRI-O 容器运行时(外部链接)。
根据你安装的特定 Linux 发行版,有几种安装容器运行时的方式。
尽管 CRI-O 推荐使用 deb 或 rpm 包,但本教程使用
CRI-O Packaging 项目中的静态二进制包脚本,
以简化整个安装过程,并保持与 Linux 发行版无关。
此脚本安装并配置更多必需的软件,例如容器联网所用的
cni-plugins
以及运行容器所用的 crun 和
runc。
此脚本将自动检测系统的处理器架构(amd64 或 arm64),并选择和安装最新版本的软件包。
设置 CRI-O
查阅发布版本页面(外部链接)。
下载静态二进制包脚本:
curl https://raw.githubusercontent.com/cri-o/packaging/main/get > crio-install
运行安装器脚本:
sudo bash crio-install
启用并启动 crio 服务:
sudo systemctl daemon-reload
sudo systemctl enable --now crio.service
快速测试:
sudo systemctl is-active crio.service
输出类似于:
active
详细的服务检查:
sudo journalctl -f -u crio.service
安装网络插件
cri-o 安装器安装并配置 cni-plugins 包。你可以通过运行以下命令来验证安装包:
/opt/cni/bin/bridge --version
输出类似于:
CNI bridge plugin v1.5.1
CNI protocol versions supported: 0.1.0, 0.2.0, 0.3.0, 0.3.1, 0.4.0, 1.0.0
检查默认配置:
cat /etc/cni/net.d/11-crio-ipv4-bridge.conflist
输出类似于:
{
"cniVersion": "1.0.0",
"name": "crio",
"plugins": [
{
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"hairpinMode": true,
"ipam": {
"type": "host-local",
"routes": [
{ "dst": "0.0.0.0/0" }
],
"ranges": [
[{ "subnet": "10.85.0.0/16" }]
]
}
}
]
}
Note
确保默认的 subnet 范围(10.85.0.0/16)不会与你已经在使用的任一网络地址重叠。
如果出现重叠,你可以编辑此文件并进行相应的更改。更改后重启服务。
下载并设置 kubelet
下载 kubelet 的最新稳定版本。
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubelet"
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/arm64/kubelet"
配置:
sudo mkdir -p /etc/kubernetes/manifests
sudo tee /etc/kubernetes/kubelet.yaml <<EOF
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
authentication:
webhook:
enabled: false # 请勿在生产集群中使用!
authorization:
mode: AlwaysAllow # 请勿在生产集群中使用!
enableServer: false
logging:
format: text
address: 127.0.0.1 # 限制对 localhost 的访问
readOnlyPort: 10255 # 请勿在生产集群中使用!
staticPodPath: /etc/kubernetes/manifests
containerRuntimeEndpoint: unix:///var/run/crio/crio.sock
EOF
Note
由于你搭建的不是一个生产集群,所以你可以使用明文
HTTP(readOnlyPort: 10255)对 kubelet API 进行不做身份认证的查询。
为了顺利完成本次教学,身份认证 Webhook 被禁用,鉴权模式被设置为 AlwaysAllow。
你可以进一步了解鉴权模式和
Webhook 身份认证,
以正确地配置 kubelet 在你的环境中以独立模式运行。
参阅端口和协议以了解 Kubernetes 组件使用的端口。
安装:
chmod +x kubelet
sudo cp kubelet /usr/bin/
创建 systemd 服务单元文件:
sudo tee /etc/systemd/system/kubelet.service <<EOF
[Unit]
Description=Kubelet
[Service]
ExecStart=/usr/bin/kubelet \
--config=/etc/kubernetes/kubelet.yaml
Restart=always
[Install]
WantedBy=multi-user.target
EOF
服务配置文件中故意省略了命令行参数 --kubeconfig。此参数设置
kubeconfig
文件的路径,指定如何连接到 API 服务器,以启用 API 服务器模式。省略此参数将启用独立模式。
启用并启动 kubelet 服务:
sudo systemctl daemon-reload
sudo systemctl enable --now kubelet.service
快速测试:
sudo systemctl is-active kubelet.service
输出类似于:
active
详细的服务检查:
sudo journalctl -u kubelet.service
检查 kubelet 的 API /healthz 端点:
curl http://localhost:10255/healthz?verbose
输出类似于:
[+]ping ok
[+]log ok
[+]syncloop ok
healthz check passed
查询 kubelet 的 API /pods 端点:
curl http://localhost:10255/pods | jq '.'
输出类似于:
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {},
"items": null
}
在 kubelet 中运行 Pod
在独立模式下,你可以使用 Pod 清单运行 Pod。这些清单可以放在本地文件系统上, 或通过 HTTP 从配置源获取。
为 Pod 创建一个清单:
cat <<EOF > static-web.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-web
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
EOF
将 static-web.yaml 清单文件复制到 /etc/kubernetes/manifests 目录。
sudo cp static-web.yaml /etc/kubernetes/manifests/
查找 kubelet 和 Pod 的信息
Pod 网络插件为每个 Pod 创建一个网络桥(cni0)和一对 veth 接口
(这对接口的其中一个接口在新创建的 Pod 内,另一个接口在主机层面)。
查询 kubelet 的 API 端点 http://localhost:10255/pods:
curl http://localhost:10255/pods | jq '.'
要获取 static-web Pod 的 IP 地址:
curl http://localhost:10255/pods | jq '.items[].status.podIP'
输出类似于:
"10.85.0.4"
连接到 nginx 服务器 Pod,地址为 http://<IP>:<Port>(端口 80
是默认端口),在本例中为:
curl http://10.85.0.4
输出类似于:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
了解更多细节
如果你需要排查在学习本教程时遇到的问题,你可以在以下目录中查找监控和故障排查资料:
/var/lib/cni
/var/lib/containers
/var/lib/kubelet
/var/log/containers
/var/log/pods
清理
kubelet
sudo systemctl disable --now kubelet.service
sudo systemctl daemon-reload
sudo rm /etc/systemd/system/kubelet.service
sudo rm /usr/bin/kubelet
sudo rm -rf /etc/kubernetes
sudo rm -rf /var/lib/kubelet
sudo rm -rf /var/log/containers
sudo rm -rf /var/log/pods
容器运行时
sudo systemctl disable --now crio.service
sudo systemctl daemon-reload
sudo rm -rf /usr/local/bin
sudo rm -rf /usr/local/lib
sudo rm -rf /usr/local/share
sudo rm -rf /usr/libexec/crio
sudo rm -rf /etc/crio
sudo rm -rf /etc/containers
网络插件
sudo rm -rf /opt/cni
sudo rm -rf /etc/cni
sudo rm -rf /var/lib/cni
结论
本页涵盖了以独立模式部署 kubelet 的各个基本方面。你现在可以部署 Pod 并测试更多功能。
请注意,在独立模式下,kubelet 不支持从控制平面获取 Pod 配置(因为没有控制平面连接)。
你还不能使用 ConfigMap 或 Secret 来配置静态 Pod 中的容器。
接下来
- 跟随你好,Minikube 学习如何在有控制平面的情况下运行 Kubernetes。minikube 工具帮助你在自己的计算机上搭建一个练习集群。
- 进一步了解网络插件
- 进一步了解容器运行时
- 进一步了解 kubelet
- 进一步了解静态 Pod
2 - 在 Kubernetes 节点上配置交换内存
本文演示了如何使用 kubeadm 在 Kubernetes 节点上制备和启用交换内存。
教程目标
- 使用 kubeadm 在 Kubernetes 节点上制备交换内存。
- 学习配置加密和未加密的交换内存。
- 学习如何在系统启动时启用交换内存。
准备开始
你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:
你的 Kubernetes 服务器版本必须不低于版本 1.33.要获知版本信息,请输入 kubectl version.
你需要在集群中至少有一个运行 Linux 操作系统的工作节点。 本次演示需要先安装 kubeadm 工具,安装步骤请参考 kubeadm 安装指南。
在每个需要配置交换内存的工作节点上,你需要以下工具:
fallocatemkswapswapon
对于加密的交换空间(推荐),你还需要:
cryptsetup
使用 kubeadm 安装支持交换内存的集群
创建交换文件并启用交换内存
如果当前节点未启用交换内存,则需要先制备交换空间。 本节将展示如何以加密和未加密的方式创建 4GiB 的交换文件。
你可以使用如下命令设置加密的交换文件。
请注意,此示例使用的是 cryptsetup 工具(在大多数 Linux 发行版中都可用):
# 分配存储空间并限制访问权限
fallocate --length 4GiB /swapfile
chmod 600 /swapfile
# 基于已分配的存储空间创建加密设备
cryptsetup --type plain --cipher aes-xts-plain64 --key-size 256 -d /dev/urandom open /swapfile cryptswap
# 格式化此交换空间
mkswap /dev/mapper/cryptswap
# 为换页激活交换空间
swapon /dev/mapper/cryptswap
未加密的交换文件可以按以下方式配置:
# 分配存储空间并限制访问权限
fallocate --length 4GiB /swapfile
chmod 600 /swapfile
# 格式化此交换空间
mkswap /swapfile
# 为换页激活交换空间
swapon /swapfile
验证交换内存是否启用
你可以使用 swapon -s 命令或 free 命令来验证交换内存是否启用。
使用 swapon -s:
Filename Type Size Used Priority
/dev/dm-0 partition 4194300 0 -2
使用 free -h:
total used free shared buff/cache available
Mem: 3.8Gi 1.3Gi 249Mi 25Mi 2.5Gi 2.5Gi
Swap: 4.0Gi 0B 4.0Gi
引导时启用交换内存
在设置好交换内存后,若要在系统引导时启动交换文件,通常有两种做法:
你可以设置一个 systemd 单元来激活(加密的)交换内存,或者在
/etc/fstab 文件中添加类似于 /swapfile swap swap defaults 0 0 的行。
使用 systemd 激活交换内存,可以确保在交换内存可用之前延迟启动 kubelet(如果你有这个需求)。 同样,使用 systemd 还可以让服务器在 kubelet(以及通常的容器运行时)关闭之前保持交换内存处于启用状态。
配置 kubelet
在节点上启用交换内存后,需要按如下方式配置 kubelet。 你需要为此节点选择一种交换内存行为。 在本教程中,你将配置 LimitedSwap 行为。
找到并编辑 kubelet 配置文件,然后:
- 将
failSwapOn设置为 false - 将
memorySwap.swapBehavior设置为 LimitedSwap
# 此代码片段应添加到 kubelet 的配置文件中
failSwapOn: false
memorySwap:
swapBehavior: LimitedSwap
为了使这些配置生效,需重启 kubelet。 通常你需要为此运行以下命令:
systemctl restart kubelet.service
你应该会发现 kubelet 现在处于健康状态,并且你可以根据需要运行使用交换内存的 Pod。
3 - 使用 Pod 级资源与 kubelet 资源管理器
More information about this feature
To use this feature, you (or a cluster administrator) will need to enable the PodLevelResourceManagers feature gate for all relevant components in your cluster.
See Enable Or Disable Feature Gates for more information.
本教程演示如何配置 kubelet 的资源管理器(拓扑、CPU 和内存)
以支持 Pod 级资源规约。你可以定义混合分配模型:
其中一些容器获得独占的、NUMA 对齐的基础设施资源,
而另一些容器则共享 Pod 级共享池中的剩余资源。
要了解该特性背后的概念,请阅读 Pod 级资源管理器概念页面。
教程目标
- 配置
kubelet资源管理器(CPU、内存和拓扑)以支持 Pod 级资源。 - 使用
pod拓扑管理器作用域部署工作负载,以实现混合的独占容器和共享容器,并达到单 NUMA 对齐。 - 查看并验证 CPU 和内存资源如何在独占容器与 Pod 共享池之间划分。
- 了解当 Pod 级共享池将为空时的准入拒绝规则。
- 使用
container拓扑管理器作用域和混合的容器分配部署工作负载。
准备开始
你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:
你的 Kubernetes 服务器版本必须不低于版本 v1.36.要获知版本信息,请输入 kubectl version.
要完成本教程,你需要:
- 一个带有 Linux 工作节点的 Kubernetes 集群 (Pod 级资源管理器在 Windows 节点上不受支持)。
- 至少一个具有 NUMA 拓扑的工作节点 (最好有多个 NUMA 节点,以便观察对齐情况)。
- 在工作节点上拥有管理权限(root 或
sudo), 以修改kubelet配置并重启kubelet服务。 - 拥有
kubectl访问权限,且具备创建名字空间和 Pod 的权限。
确保为控制平面和工作节点启用了以下特性门控:
PodLevelResourcesPodLevelResourceManagers
创建一个名字空间
创建一个名字空间,使本教程中创建的资源与集群的其余部分隔离开来:
kubectl create namespace plrm-tutorial
在混合分配场景中使用 Pod 作用域
当拓扑管理器的作用域设置为 pod 时,kubelet 会基于 .spec.resources
为整个 Pod 执行一次 NUMA 对齐。得到的资源预算随后被划分:
请求 Guaranteed 资源的容器获得独占切片,
而未获得独占分配的容器则在 Pod 级共享池中共享剩余的预算。
第 1 步:针对 Pod 作用域配置 kubelet
若要启用此行为,请在希望以所需策略运行这些工作负载的目标工作节点上配置 kubelet。
你可以按如下方式更新这些节点的
kubelet 配置:
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cpuManagerPolicy: "static"
memoryManagerPolicy: "Static"
topologyManagerScope: "pod"
topologyManagerPolicy: "single-numa-node"
- 对于
topologyManagerPolicy,有效值为single-numa-node、restricted或best-effort。 使用 Pod 级资源管理时,你不能指定其他任何值。
重启 kubelet 以应用该配置。例如,在使用 systemd 的 Linux 上:
systemctl restart kubelet.service。
第 2 步:部署混合分配的 Pod
请考虑以下示例 Pod 清单。该 Pod 在 Pod 级别(.spec.resources)
请求总计 4 个 CPU 的预算。在该 Pod 内部:
main-app容器请求 2 个完整 CPU 核心的独占分配 (requests=limits= 2 CPU)。- 由于
metrics-sidecar和logging-sidecar未指定容器级别的 requests, 这两个边车容器共享 Pod 级共享池中剩余的 CPU 核心:2 个 CPU 核心。
apiVersion: v1
kind: Pod
metadata:
name: pod-scope-mixed
annotations:
kubernetes.io/description: "A pod demonstrating pod-level scope where one container gets exclusive resources and others share the remaining pod resources in a shared pool."
spec:
# 在 Pod 级别,该 Pod 的 CPU request 等于 limits,内存 request 也等于内存 limits。
# main-app 容器在容器级别满足 Guaranteed QoS 类的要求,而各边车容器未指定任何资源 request。
# 在 pod 范围下,这意味着 kubelet 可以静态地为整个 Pod 分配
# 4 个 CPU,其中 2 个独占分配给 main-app 容器,剩余的 2 个由边车在该 Pod 的共享池中共享。
resources:
requests:
cpu: "4"
memory: "4Gi"
limits:
cpu: "4"
memory: "4Gi"
initContainers:
- name: metrics-sidecar
# 注意:这是仅用于演示的占位镜像,并不是真正的 metrics 助手。
image: registry.k8s.io/pause:3.9
restartPolicy: Always
- name: logging-sidecar
# 注意:这是仅用于演示的占位镜像,并不是真正的日志代理。
image: registry.k8s.io/pause:3.9
restartPolicy: Always
containers:
- name: main-app
# 注意:这是仅用于演示的占位镜像。
image: registry.k8s.io/pause:3.9
resources:
requests:
cpu: "2"
memory: "2Gi"
limits:
cpu: "2"
memory: "2Gi"
将清单应用到你的集群:
kubectl apply -f https://k8s.io/examples/pods/resource/pod-level-resource-managers-pod-scope-mixed.yaml --namespace=plrm-tutorial
第 3 步:验证和检查资源划分
检查 Pod 是否成功运行:
kubectl get pod pod-scope-mixed --namespace=plrm-tutorial
了解背后发生了什么:
flowchart TD subgraph Pod["Pod-Level Budget: 4 CPUs, 4Gi Memory"] direction TB C1["main-app<br/>(Exclusive: 2 CPUs, 2Gi Memory)"] subgraph Pool["Pod Shared Pool: 2 CPUs, 2Gi Memory"] C2["metrics-sidecar"] C3["logging-sidecar"] end end- Pod 对齐: 拓扑管理器评估了 4 个 CPU 的 Pod 请求
(
spec.resources),并将整个 Pod 分配到单个 NUMA 节点。 - 独占分配: CPU 管理器为
main-app分配了一个专属的 2 个 CPU 切片。main-app的 CPU CFS 配额节流被禁用,使其能够不受节流地访问这些独占核心。
- Pod 共享池: 剩余的 2 个 CPU 构成一个 Pod 级共享池。
metrics-sidecar和logging-sidecar未指定任何容器级资源 (resources: {}),因此它们在这个 Pod 隔离的共享池中运行, 并启用了 CFS 配额强制执行。虽然该池由这两个边车共享, 但它与节点上的外部工作负载隔离开来,为这些边车提供专属的 NUMA 局部性,并防止节点级资源争用。
- Pod 对齐: 拓扑管理器评估了 4 个 CPU 的 Pod 请求
(
观察空共享池的准入限制
使用 pod 作用域时,如果存在需要共享池的容器,而某些 Pod 规约会导致 Pod 共享池为空,
则 kubelet 的准入控制会拒绝这些 Pod 规约。
如果来自 Guaranteed 容器的独占资源请求之和等于 Pod 级总预算,
并且至少还有一个容器需要共享池,那么 kubelet 将拒绝该 Pod。
第 4 步:检查无效的 Pod 清单
请考虑以下清单。该 Pod 请求总计 4 个 CPU 的预算。
container-a 请求独占的 1 个 CPU,container-b 请求独占的 3 个 CPU
(合计 4 个 CPU)。container-c 未请求独占资源且需要共享池,但已剩下 0 个 CPU:
第 5 步:尝试部署并观察拒绝
应用此清单:
kubectl apply -f https://k8s.io/examples/pods/resource/pod-level-resource-managers-empty-shared-pool.yaml --namespace=plrm-tutorial
查看 Pod 事件以观察准入错误:
kubectl describe pod empty-shared-pool --namespace=plrm-tutorial请注意事件消息,它说明
kubelet拒绝该 Pod 的原因是: 对于需要共享资源的容器而言,Pod 级共享池将为空:Status: Failed Reason: TopologyAffinityError Message: Pod was rejected: Pod Scope pod with pod-level resources failed admission under pod-scope topology managerflowchart TD subgraph Pod["Pod-Level Budget: 4 CPUs, 4Gi Memory"] direction TB C1["container-a<br/>(Exclusive: 1 CPU, 1Gi Memory)"] C2["container-b<br/>(Exclusive: 3 CPUs, 3Gi Memory)"] subgraph Pool["Pod Shared Pool: 0 CPUs, 0Gi Memory"] C3["container-c<br/>(Requires shared pool)"] end end Pool --> Rejection["Admission Error: Pod Rejected!"] style Rejection fill:#ffcccc,stroke:#ff0000,stroke-width:2px
在混合分配场景下使用 container 作用域
你也可以将拓扑管理器的作用域配置为 container。在此模式下,kubelet 会逐个评估每个容器以进行独占分配,
而 .spec.resources 中的 Pod 总体预算仍会强制执行 QoS 和 cgroup 限额边界。
第 6 步:为 container 作用域配置 kubelet
在目标工作节点上更新你的
kubelet 配置,以使用 container 作用域:
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cpuManagerPolicy: "static"
memoryManagerPolicy: "Static"
topologyManagerScope: "container"
topologyManagerPolicy: "single-numa-node"
重启 kubelet 以应用该配置。例如,在使用 systemd 的 Linux 上:
systemctl restart kubelet.service。
第 7 步:部署容器作用域的混合工作负载
请考虑以下示例 Pod 清单。该 Pod 的总预算为 4 个 CPU:
infrastructure-sidecar请求独占的 2 个 CPU 切片(requests=limits= 2 CPU)。worker-1和worker-2未指定容器级别的 requests,而是在常规的节点级共享池中运行。
apiVersion: v1
kind: Pod
metadata:
name: container-scope-mixed
annotations:
kubernetes.io/description: "A pod demonstrating container-level scope where one container gets exclusive resources and others run in the node's shared pool."
spec:
# 在 Pod 级别,该 Pod 的 CPU request 等于 limits,内存 request 也等于内存 limits。
# infrastructure-sidecar 容器在容器级别满足 Guaranteed QoS 类的要求,而各 worker
# 容器未指定任何资源 request。在 container 范围下,kubelet 会逐个评估容器以进行独占分配。
# 这意味着 infrastructure-sidecar 获得独占的 2 个 CPU 切片,
# 而 worker 容器在节点的常规共享池中运行,同时所有容器的总量仍受 Pod 级限额约束。
resources:
requests:
cpu: "4"
memory: "4Gi"
limits:
cpu: "4"
memory: "4Gi"
initContainers:
- name: infrastructure-sidecar
# 注意:这是仅用于演示的占位镜像,并不是真正的基础设施助手。
image: registry.k8s.io/pause:3.9
restartPolicy: Always
resources:
requests:
cpu: "2"
memory: "2Gi"
limits:
cpu: "2"
memory: "2Gi"
containers:
- name: worker-1
# 注意:这是仅用于演示的占位镜像。
image: registry.k8s.io/pause:3.9
- name: worker-2
# 注意:这是仅用于演示的占位镜像。
image: registry.k8s.io/pause:3.9
应用该清单:
kubectl apply -f https://k8s.io/examples/pods/resource/pod-level-resource-managers-container-scope-mixed.yaml --namespace=plrm-tutorial
第 8 步:验证部署
检查 Pod 是否正在运行:
kubectl get pod container-scope-mixed --namespace=plrm-tutorial
了解背后发生了什么:
flowchart TD subgraph Pod["Pod-Level Budget: 4 CPUs, 4Gi Memory"] direction TB C1["infrastructure-sidecar<br/>(Exclusive NUMA Slice: 2 CPUs, 2Gi Memory)"] subgraph NodePool["Node Shared Pool: Pod-level limit"] C3["worker-2"] C2["worker-1"] end end- 容器作用域对齐: 在
container作用域下,kubelet会逐个评估容器。infrastructure-sidecar直接从节点的可分配池中获得一个独占的、NUMA 对齐的 2 个 CPU 切片。 - 节点共享池:
worker-1和worker-2未指定任何容器级资源请求 (resources: {}),因此在container作用域下,它们在节点的常规共享池中运行(而不是在 Pod 隔离的池中)。 - Pod 限额强制执行: 所有容器的 CPU 消耗总量仍由 Pod 级限额(
spec.resources.limits)限制在 4 个 CPU 以内。
- 容器作用域对齐: 在
清理现场
删除本教程中创建的名字空间和所有示例 Pod:
kubectl delete namespace plrm-tutorial
接下来
- 阅读概念文档:
- 了解如何配置节点级资源管理器:
- 了解如何分配资源:
4 - 探索验证与变更准入策略
本页面让你试用声明式准入策略,这类策略允许你使用通用表达式语言(CEL)验证或变更资源。
Kubernetes 1.37 支持两种准入策略:
本教程介绍这两种准入策略。
准备开始
你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:
要定义准入策略,你必须是集群管理员。请确保你对用于学习的集群具有管理员访问权限。
对于 ValidatingAdmissionPolicy,你需要:
- 运行 1.30 或更高版本的集群。
对于 MutatingAdmissionPolicy,你需要:
- 运行 1.36 或更高版本的集群。
要检查版本,请运行 kubectl version。如果你运行的是较旧版本的 Kubernetes,请查阅对应版本的文档。
什么是声明式准入策略?
声明式准入策略为准入 Webhook 提供了一种声明式的、进程内的替代方案。
通过使用通用表达式语言(CEL)来声明策略规则,这些策略直接在 API 服务器内部进行评估。
这些策略高度可配置,使策略作者能够定义可参数化的逻辑,并根据集群管理员的需要限定到特定资源。
准入策略的 API 类型
这两种策略的用途不同。
ValidatingAdmissionPolicy 用于强制执行约束。
MutatingAdmissionPolicy 用于在准入时修改资源。
策略要素
每个被应用的策略都有一个策略对象(ValidatingAdmissionPolicy 或 MutatingAdmissionPolicy) 和一个独立的绑定对象(ValidatingAdmissionPolicyBinding 或 MutatingAdmissionPolicyBinding)。
你还可以使用参数,参数是可选的。要了解更多信息, 请参阅参数资源(ValidatingAdmissionPolicy 或参数资源(MutatingAdmissionPolicy)。
策略对象使用通用表达式语言(CEL)描述策略的抽象逻辑。 例如,ValidatingAdmissionPolicy 可以强制副本数量限制或确保存在特定的标签, 而 MutatingAdmissionPolicy 可以修改资源,例如为命名空间添加默认标签。
绑定对象将策略与你的集群关联并提供作用域。
ValidatingAdmissionPolicyBinding 或 MutatingAdmissionPolicyBinding 将策略连接到特定资源。
如果你只想对特定子集的资源强制执行策略,
那么绑定就是你缩小策略作用域的地方(使用 matchResources)。
参数允许将策略行为的配置与其定义分离。参数资源是指 API 中可用的 Kubernetes 资源。
它们可以是内置的 API 类型(例如 ConfigMap),
也可以是定制资源。
然后,策略绑定使用 spec.paramRef 引用实际的参数资源。
如果策略不需要参数,则不设置 spec.paramKind。
CEL 表达式
这两种策略都依赖一种称为通用表达式语言(CEL)的表达式语言。 阅读 Kubernetes 中的通用表达式语言以了解更多。
如果你刚接触 CEL,可以先练习编写一个非常简单的表达式,例如 false || true。
你可以在 CEL Playground 中测试 CEL 表达式。
策略操作
每个准入策略绑定必须指定一个或多个操作,以声明策略如何被执行。
ValidatingAdmissionPolicyBinding
对于 ValidatingAdmissionPolicyBinding,支持的 validationActions 包括:
- Audit
- 验证失败会记录在 API 请求的审计事件中。
- Warn
- 验证失败会作为警告报告给请求客户端。
- Deny
- 验证失败会导致请求被拒绝。
策略检查失败或发生错误时,会按这些操作执行。
只有当 failurePolicy 设为 Fail(或未指定)时,
由 failurePolicy 定义的失败才会按这些操作执行。
有关策略审计日志的更多细节, 请参见审计注解:验证失败。
不能同时使用 Deny 和 Warn,因为这种组合会在 API 响应体和 HTTP Warning: 头中重复验证失败信息。
MutatingAdmissionPolicyBinding
对于 MutatingAdmissionPolicyBinding,操作始终是变更对象。
你可以使用 JSON Patch 或 Kubernetes 的应用配置(apply configuration)。
通过验证强制执行
现在,试着定义一个 ValidatingAdmissionPolicy。
下面是一个 ValidatingAdmissionPolicy 示例,它要求任何 Deployment 都有多个副本。
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: "enforce-multiple-replicas-deployments"
annotations:
kubernetes.io/description: "Require that matching Deployments have multiple replicas"
spec:
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
resources: ["deployments"] # Deployment API
operations: ["CREATE", "UPDATE"] # API 动词,会被转换为大写
validations:
- expression: "object.spec.replicas >= 2"
spec.validations 包含 CEL 表达式,
这些表达式使用通用表达式语言(CEL)验证请求。
如果某个表达式求值为 false,则根据 spec.failurePolicy 字段执行验证检查。
编写一个这样的策略并应用它。
或者,如果你想应用一个现成的清单:
kubectl apply --server-side -f https://k8s.io/examples/access/manifest-admission-control/vap-min-replicas.yaml
单独来看,这个策略不会起任何作用。
你可以试着创建一个 0 个或 1 个副本的 Deployment;这会成功(除非有其他策略阻止)。
要让它生效,你需要定义一个 ValidatingAdmissionPolicyBinding。
选择一个你要在其中执行新策略的命名空间。
下面是你所创建策略的一个示例 ValidatingAdmissionPolicyBinding:
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: enforce-multiple-replicas-deployments-binding
spec:
policyName: "enforce-multiple-replicas-deployments"
validationActions: [Deny]
matchResources:
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: default # 改成你正在使用的命名空间
注意:
任何对命名空间有完全/管理员访问权限的人都可以写入其标签。这包括删除命名空间中的标签。
kubernetes.io/metadata.name 标签是受保护的,但如果你使用其他标签,
请注意确保只有可信用户能够删除或编辑你所选的标签。
基于该示例 YAML 编写一个清单(如果你使用的是 default 命名空间,可以直接使用而无需任何改动)。
使用 kubectl apply 应用该清单。
测试策略
现在测试该策略。
试着创建一个 Deployment,
然后用 kubectl scale 将其缩容到 0 个副本。会发生什么?
你可以把 ValidatingAdmissionPolicyBinding 的验证操作改为 Deny 之外的其他操作。 如果你选择 Warning 验证操作,然后试着把 Deployment 缩容到 0 个副本,会发生什么?
说明:
如果你确实把 ValidatingAdmissionPolicyBinding 改成只警告用户,就会有一个问题 …
名字不对!如果你修改 ValidatingAdmissionPolicyBinding 或关联的 ValidatingAdmissionPolicy, 使其只警告用户,你应该检查是否也需要修改策略的名称。 你需要修改名称,以确保命名不会误导他人。
现有资源不受影响
如果你有一个 0 个或 1 个副本的 Deployment, 并把 ValidatingAdmissionPolicyBinding 改回 Deny 模式,它不会影响任何现有资源。
(如果你想尝试把 Deployment 扩容到至少 2 个副本,可以用其他方式实现 —— 例如使用 控制器)。
ValidatingAdmissionPolicy 就介绍到这里。接下来你将了解 MutatingAdmissionPolicy。
在资源创建或变更时修改资源
在这个例子中,假设你想使用 Pod 安全性准入, 确保除系统命名空间之外的命名空间都执行某一 Pod 安全性标准。
与验证类似,你可以创建 MutatingAdmissionPolicy 在准入时修改资源。 你需要修改的 API 类型是 Namespace。
下面是一个实现其中部分功能的 MutatingAdmissionPolicy:
---
# 注意:在应用 default-pod-security-baseline 策略之前,请阅读相关说明,
# 以便理解该策略在信息安全方面的影响。
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata:
name: "default-pod-security-baseline"
annotations:
kubernetes.io/description: "Default new namespaces to enforce the Baseline pod security standard"
spec:
reinvocationPolicy: IfNeeded
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["namespaces"]
matchConditions:
- name: "exclude-system-namespaces"
# 如果名称以 "kube-" 开头,它就是系统命名空间。
# 假定 API 服务器或集群管理工具会应用相关默认值。
expression: "!object.metadata.name.startsWith('kube-')"
- name: "no-existing-pod-security-label"
expression: "!('pod-security.kubernetes.io/enforce' in object.metadata.labels)"
mutations:
- patchType: "ApplyConfiguration"
applyConfiguration:
expression: "Object{metadata: Object.metadata{labels: {'pod-security.kubernetes.io/enforce': 'baseline'}}}"
注意:
此策略设置的是默认值。
有能力更新命名空间的人可以移除命名空间上的 pod-security.kubernetes.io/enforce 标签。
如果你不确定这意味着什么,请阅读安全文档, 或征求外部的信息安全建议。
要应用该策略:
kubectl apply --server-side -f https://k8s.io/examples/access/manifest-admission-control/default-pod-security-baseline.yaml
需要 MutatingAdmissionPolicyBinding 来激活此策略;例如:
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicyBinding
metadata:
name: default-pod-security-baseline
spec:
# 要应用的 MutatingAdmissionPolicy 名称
policyName: default-pod-security-baseline
测试策略
试着创建一个名为 example 的新命名空间:
kubectl create ns example
检查它的标签:
kubectl describe ns example
尽管你没有指定 Pod 安全性准入的执行级别,该标签已被设置。
接下来,看看你能否找到绕过这些安全设置的办法。 为另一个 Namespace 创建一个 YAML 清单:
apiVersion: v1
kind: Namespace
metadata:
name: another-example
labels:
pod-security.kubernetes.io/enforce: privileged
你可以使用 kubectl apply --server-side 从本地清单创建该命名空间。这样能行吗?
可以,而且新命名空间允许运行特权 Pod。
这个准入策略并未设置为验证或限制。它提供默认值,但你可以设置自己的值。 不过,你可以把变更准入与验证准入策略结合起来,这样既能强制执行某些要求,又能让人容易遵守。 (本教程不解释这一点,但你可以这样做)。
提供一个有用的默认值意味着,当人们什么都没设置时, 他们得到的结果比只看到一条错误消息要好。 设想你确实有一条验证规则,确保所有命名空间都必须至少执行 baseline 标准。 不知道这条规则的人可能会尝试部署某些东西, 然后在创建命名空间时立刻看到一条错误消息。
使用参数资源
参数资源允许策略配置与其定义分离。
策略可以定义 paramKind,它概述参数资源的组、版本和类别(也称为 GVK)。
然后,策略绑定将该策略关联到其绑定的作用域,并由特定的参数资源配置。
---
# 注意:在应用 default-pod-security-configurable 策略之前,请阅读相关说明,
# 以便理解该策略在信息安全方面的影响。
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata:
name: "default-pod-security-configurable"
annotations:
kubernetes.io/description: "Default new namespaces to enforce the chosen pod security standard"
spec:
reinvocationPolicy: IfNeeded
paramKind:
apiVersion: v1
kind: ConfigMap
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["namespaces"]
matchConditions:
- name: "exclude-system-namespaces"
# 如果名称以 "kube-" 开头,它就是系统命名空间。
# 假定 API 服务器或集群管理工具会应用相关默认值。
expression: "!object.metadata.name.startsWith('kube-')"
- name: "no-existing-pod-security-label"
expression: "!('pod-security.kubernetes.io/enforce' in object.metadata.labels)"
mutations:
- patchType: "ApplyConfiguration"
applyConfiguration:
expression: "Object{metadata: Object.metadata{labels: {'pod-security.kubernetes.io/enforce': params.data.default}}}"
下面是一个 MutatingAdmissionPolicyBinding 示例:
---
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicyBinding
metadata:
name: default-pod-security-configurable
spec:
# 要应用的 MutatingAdmissionPolicy 名称
policyName: default-pod-security-configurable
# 要使用的参数
paramRef:
# 如果 ConfigMap 不存在或为空,则不设置默认值
# (但允许创建命名空间)
parameterNotFoundAction: Allow
# 参数所在的位置
namespace: kube-system
name: default-pod-security-standard
下面是放入 kube-system 命名空间的一个示例 ConfigMap:
---
apiVersion: v1
kind: ConfigMap
metadata:
namespace: kube-system
name: default-pod-security-standard
data:
default: baseline # 也可以是 "restricted"
定义这两个对象。你应先创建 ConfigMap; 绑定要求参数资源已经存在(即使你计划之后修改它)。
现在,删除之前的 MutatingAdmissionPolicyBinding:
kubectl delete mutatingadmissionpolicybindings/default-pod-security-baseline
并创建一个新的命名空间:
kubectl create ns yet-another-example
kubectl describe ns yet-another-example
标签是否被设为默认值了?
修改参数
# 这会启动一个编辑器,让你修改该参数的 .data.default
kubectl --namespace kube-system edit configmap default-pod-security-standard
修改之后,再试着创建一个命名空间。会发生什么?
清理
要删除所创建的资源,请运行以下命令:
kubectl delete validatingadmissionpolices/enforce-multiple-replicas-deployments \
validatingadmissionpolicybindings/enforce-multiple-replicas-deployments
kubectl delete mutatingadmissionpolicies/default-pod-security-baseline \
mutatingadmissionpolicybindings/default-pod-security-baseline
kubectl delete mutatingadmissionpolicies/default-pod-security-configurable \
mutatingadmissionpolicybindings/default-pod-security-configurable
kubectl --namespace kube-system delete configmaps/default-pod-security-standard
kubectl delete namespaces/example namespaces/another-example namespaces/yet-another-example
如果你创建了任何测试 Pod 或测试 Namespace,也请一并清理。
5 - 名字空间演练
Kubernetes 名字空间有助于不同的项目、团队或客户去共享 Kubernetes 集群。
名字空间通过以下方式实现这点:
- 为名字设置作用域.
- 为集群中的部分资源关联鉴权和策略的机制。
使用多个名字空间是可选的。
此示例演示了如何使用 Kubernetes 名字空间细分集群。
准备开始
你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:
要获知版本信息,请输入 kubectl version.
环境准备
此示例作如下假设:
- 你已拥有一个配置好的 Kubernetes 集群。
- 你已对 Kubernetes 的 Pod、 服务 和 Deployment 有基本理解。
理解默认名字空间
默认情况下,Kubernetes 集群会在配置集群时实例化一个默认名字空间,用以存放集群所使用的默认 Pod、Service 和 Deployment 集合。
假设你有一个新的集群,你可以通过执行以下操作来检查可用的名字空间:
kubectl get namespaces
NAME STATUS AGE
default Active 13m
创建新的名字空间
在本练习中,我们将创建两个额外的 Kubernetes 名字空间来保存我们的内容。
我们假设一个场景,某组织正在使用共享的 Kubernetes 集群来支持开发和生产:
开发团队希望在集群中维护一个空间,以便他们可以查看用于构建和运行其应用程序的 Pod、Service 和 Deployment 列表。在这个空间里,Kubernetes 资源被自由地加入或移除, 对谁能够或不能修改资源的限制被放宽,以实现敏捷开发。
运维团队希望在集群中维护一个空间,以便他们可以强制实施一些严格的规程, 对谁可以或谁不可以操作运行生产站点的 Pod、Service 和 Deployment 集合进行控制。
该组织可以遵循的一种模式是将 Kubernetes 集群划分为两个名字空间:development 和 production。
让我们创建两个新的名字空间来保存我们的工作。
文件 namespace-dev.yaml 描述了 development 名字空间:
apiVersion: v1
kind: Namespace
metadata:
name: development
labels:
name: development
使用 kubectl 创建 development 名字空间。
kubectl create -f https://k8s.io/examples/admin/namespace-dev.yaml
将下列的内容保存到文件 namespace-prod.yaml 中,
这些内容是对 production 名字空间的描述:
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
name: production
让我们使用 kubectl 创建 production 名字空间。
kubectl create -f https://k8s.io/examples/admin/namespace-prod.yaml
为了确保一切正常,我们列出集群中的所有名字空间。
kubectl get namespaces --show-labels
NAME STATUS AGE LABELS
default Active 32m <none>
development Active 29s name=development
production Active 23s name=production
在每个名字空间中创建 Pod
Kubernetes 名字空间为集群中的 Pod、Service 和 Deployment 提供了作用域。
与一个名字空间交互的用户不会看到另一个名字空间中的内容。
为了演示这一点,让我们在 development 名字空间中启动一个简单的 Deployment 和 Pod。
我们首先检查一下当前的上下文:
kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: REDACTED
server: https://130.211.122.180
name: lithe-cocoa-92103_kubernetes
contexts:
- context:
cluster: lithe-cocoa-92103_kubernetes
user: lithe-cocoa-92103_kubernetes
name: lithe-cocoa-92103_kubernetes
current-context: lithe-cocoa-92103_kubernetes
kind: Config
preferences: {}
users:
- name: lithe-cocoa-92103_kubernetes
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
token: 65rZW78y8HbwXXtSXuUw9DbP4FLjHi4b
- name: lithe-cocoa-92103_kubernetes-basic-auth
user:
password: h5M0FtUUIflBSdI7
username: admin
kubectl config current-context
lithe-cocoa-92103_kubernetes
下一步是为 kubectl 客户端定义一个上下文,以便在每个名字空间中工作。 "cluster" 和 "user" 字段的值将从当前上下文中复制。
kubectl config set-context dev --namespace=development \
--cluster=lithe-cocoa-92103_kubernetes \
--user=lithe-cocoa-92103_kubernetes
kubectl config set-context prod --namespace=production \
--cluster=lithe-cocoa-92103_kubernetes \
--user=lithe-cocoa-92103_kubernetes
默认情况下,上述命令会添加两个上下文到 .kube/config 文件中。
你现在可以查看上下文并根据你希望使用的名字空间并在这两个新的请求上下文之间切换。
查看新的上下文:
kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: REDACTED
server: https://130.211.122.180
name: lithe-cocoa-92103_kubernetes
contexts:
- context:
cluster: lithe-cocoa-92103_kubernetes
user: lithe-cocoa-92103_kubernetes
name: lithe-cocoa-92103_kubernetes
- context:
cluster: lithe-cocoa-92103_kubernetes
namespace: development
user: lithe-cocoa-92103_kubernetes
name: dev
- context:
cluster: lithe-cocoa-92103_kubernetes
namespace: production
user: lithe-cocoa-92103_kubernetes
name: prod
current-context: lithe-cocoa-92103_kubernetes
kind: Config
preferences: {}
users:
- name: lithe-cocoa-92103_kubernetes
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
token: 65rZW78y8HbwXXtSXuUw9DbP4FLjHi4b
- name: lithe-cocoa-92103_kubernetes-basic-auth
user:
password: h5M0FtUUIflBSdI7
username: admin
让我们切换到 development 名字空间进行操作。
kubectl config use-context dev
你可以使用下列命令验证当前上下文:
kubectl config current-context
dev
此时,我们从命令行向 Kubernetes 集群发出的所有请求都限定在 development 名字空间中。
让我们创建一些内容。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: snowflake
name: snowflake
spec:
replicas: 2
selector:
matchLabels:
app: snowflake
template:
metadata:
labels:
app: snowflake
spec:
containers:
- image: registry.k8s.io/serve_hostname
imagePullPolicy: Always
name: snowflake
应用清单文件来创建 Deployment。
kubectl apply -f https://k8s.io/examples/admin/snowflake-deployment.yaml
我们创建了一个副本大小为 2 的 Deployment,该 Deployment 运行名为 snowflake 的 Pod,
其中包含一个仅提供主机名服务的基本容器。
kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
snowflake 2/2 2 2 2m
kubectl get pods -l app=snowflake
NAME READY STATUS RESTARTS AGE
snowflake-3968820950-9dgr8 1/1 Running 0 2m
snowflake-3968820950-vgc4n 1/1 Running 0 2m
这很棒,开发人员可以做他们想要的事情,而不必担心影响 production 名字空间中的内容。
让我们切换到 production 名字空间,展示一个名字空间中的资源如何对另一个名字空间不可见。
kubectl config use-context prod
production 名字空间应该是空的,下列命令应该返回的内容为空。
kubectl get deployment
kubectl get pods
生产环境需要以放牛的方式运维,让我们创建一些名为 cattle 的 Pod。
kubectl create deployment cattle --image=registry.k8s.io/serve_hostname --replicas=5
kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
cattle 5/5 5 5 10s
kubectl get pods -l run=cattle
NAME READY STATUS RESTARTS AGE
cattle-2263376956-41xy6 1/1 Running 0 34s
cattle-2263376956-kw466 1/1 Running 0 34s
cattle-2263376956-n4v97 1/1 Running 0 34s
cattle-2263376956-p5p3i 1/1 Running 0 34s
cattle-2263376956-sxpth 1/1 Running 0 34s
此时,应该很清楚地展示了用户在一个名字空间中创建的资源对另一个名字空间是不可见的。
随着 Kubernetes 中的策略支持的发展,我们将扩展此场景,以展示如何为每个名字空间提供不同的授权规则。