让看板读取集群

KubernetesBeginner
立即练习

介绍

Orchard Market 需要一个小型状态看板,用来查看摊位和配送应用。看板程序已经准备好,但当前 Kubernetes 身份无法读取这些应用的 Deployment。为看板创建专用身份,只授予显示真实期望副本数、可用副本数和模板镜像所需的权限。员工命名空间、Secret 和工作负载修改必须保持在其权限范围之外。

你将得到可用的看板和 CSV 下载文件,以及四份保存的清单,分别描述身份、两个命名空间的授权和工作负载身份选择。看板向准备好的集群发起真实 HTTPS 请求,访问失败时不会用静态的成功数据替代。

你应当已经了解基本终端路径、简单的 YAML、命名空间、Pod、Deployment、Service 和标签。本实验会在使用 ServiceAccount、Role、RoleBinding 和提供的客户端之前解释它们。真实单节点 Kubernetes 集群、看板、合成应用数据和诊断工具均已准备就绪。你无需安装集群、构建镜像、编写客户端或复制令牌。时长由作者估计,包括阅读和处理普通错误的时间,并非对初学者完成过程实际计时所得。

创建看板专用身份

在这一步中,你将读取看板实际的初始身份,并保存一个专用 ServiceAccount,暂不授予它应用访问权限。

从 Board Tab 开始。Orchard Market 应显示 A clear view of the working day.、Market stalls 和 Market delivery 两组,以及两组各自的 Access denied · API 403。这是预期的初始问题。完整结果将显示:catalogue 有 2 个期望副本和 2 个可用副本,checkout 为 1 和 1,pickup 为 1 和 1,receipts 为 0 和 0。四者都使用准备好的 python:3.12-alpine 模板镜像。收据归档是有意缩减到零副本的。

三个主要字段回答不同的问题。Desired replicas 是 Deployment 中声明的数量。Available replicas 是副本通过就绪检查并满足最短就绪时间后,由控制器统计的数量。Template image 是 Deployment 模板请求的镜像;在更新期间,它不能证明所有已有 Pod 都已使用该镜像。展开 What these fields mean,阅读后再次折叠。这些是控制器观测,不是顾客网站的持续可用性检查。

选择 Access details。Read as 的值来自 API,初始值以 market-board:default 结尾。表格说明预期的权限范围,并不表示访问权限已经授予。使用 Back to status board,再切换到 Workspace。

终端起始目录为 /home/labex/project/status-board。pwd 打印工作目录,ls 列出目录条目;如果你切换了目录,可以使用带绝对路径的 cd 返回:

pwd
ls
cd /home/labex/project/status-board

预期看到 scope.json、starter 和 tools。cat 显示准备好的操作范围文件。它使用 JSON(JavaScript Object Notation),一种由命名值和列表组成的文本格式,记录实际命名空间、身份和应用名称:

cat scope.json

看板运行在 market-board,获准读取的应用数据则位于 market-stalls 和 market-delivery。market-office 被排除在外。--context=labex-v135 选择准备好的集群;-n 选择命名空间。Workspace 现有的操作者凭据可以检查和配置这些课程对象,但并非看板凭据。以该操作者身份检查实际目标 Deployment:

kubectl --context=labex-v135 get deployments -n market-stalls
kubectl --context=labex-v135 get deployments -n market-delivery

读取名称和期望/可用副本结果,包括期望副本数为零的收据归档。底层对象确实存在,即使看板还无法读取它们。操作者终端中的成功结果,不能证明看板 Pod 内的进程具有访问权限。

ServiceAccount 是工作负载在某个命名空间中的 Kubernetes API 身份,不是 Linux 用户或浏览器访问者。准备好的看板 Deployment 最初选择 default ServiceAccount。describe 以易读的分节显示对象配置:

kubectl --context=labex-v135 describe deployment status-board -n market-board

在 Pod 模板中查找所选的 ServiceAccount。Pod 会收到为该账户投射的凭据。准备好的客户端在内部读取该凭据,并使用提供的证书颁发机构证书验证 API 服务器证书;它不会打印凭据,也不会使用你的操作者 kubeconfig。你只需配置身份和权限,不必实现凭据处理。

提供的 ./tools/board-test 在当前看板 Pod 内运行该客户端。开头的 ./ 表示工具位于当前工作目录。第一个参数选择已教过的诊断操作。identity 询问 API 如何认证这个实际凭据:

./tools/board-test identity

预期 username 为 system:serviceaccount:market-board:default,并包含当前的 pod_uid。http_status 值 201 表示 API 已回答此次自身身份审查。该审查不是持久化的集群对象,不会修改权限,也不会创建 Deployment。不会显示令牌。看板进程就绪、身份得到确认,仍不代表它能访问应用数据。

创建发布目录。mkdir -p 在需要时创建目录,并保留已有目录。下一条命令中的 > 将输出重定向到可编辑文件。带引号的 YAML 标记让文本保持字面值,直到最后单独占一行的结束标记。重复命令只会覆盖该发布文件:

mkdir -p release
cat > release/identity.yaml <<'YAML'
apiVersion: v1
kind: ServiceAccount
metadata:
  name: market-reader
  namespace: market-board
YAML

读取文件后应用它。apply -f 读取指定清单,创建或更新其中的对象:

cat release/identity.yaml
kubectl --context=labex-v135 apply -f release/identity.yaml
kubectl --context=labex-v135 get serviceaccount market-reader -n market-board

专用身份现在已存在,无需因此创建长期有效的令牌 Secret:当 Pod 使用该身份时,Kubernetes 会将绑定到 Pod 的凭据投射进去。仅创建这个 ServiceAccount,既不会授予 Deployment 访问权限,也不会改变运行中看板的身份。保持原始 default 账户不变。

如果路径拼写有误,先使用已展示的 pwd、ls 和绝对路径 cd,再重复失败操作。如果出现 YAML 错误,请读取可编辑文件,与完整示例比较缩进,重写后再次应用。保持 scope.json、起始文件、工具、原始命名空间、应用和数据不变。你只会编辑指定的发布清单及其具名身份/RBAC 对象,以及看板 Deployment 所选的 ServiceAccount。

接通第一个命名空间

在这一步中,你将在摊位命名空间授予两种读取操作,再让新的看板 Pod 实际使用专用身份。

从 Workspace 开始,位于 /home/labex/project/status-board。Kubernetes RBAC 指基于角色的访问控制。Role 定义一个命名空间内的权限。RoleBinding 将该命名空间的 Role 连接到某个身份。仅有名称相同,并不能建立这种连接。

看板需要 list 读取 Deployment 集合,需要 get 打开单个 Deployment。Deployment 属于 apps API 组;规则使用 apps,不带 /v1。watch 会请求变更流,但本看板不使用它。不需要写入动词或 Secret 访问。两种读取动词都应覆盖每个获准命名空间中的全部 Deployment。省略 resourceNames,这个可选规则字段会将权限限制到指定名称的资源。绑定中的 roleRef.apiGroup 标识 RBAC API,即 rbac.authorization.k8s.io;它不同于 Role 所允许的 Deployment 所属的 apps 组。

将 Role 及其绑定保存在同一份清单中。--- 分隔符开始第二份 YAML 文档。绑定的 metadata.namespace 是权限适用的位置,subjects.namespace 则是 ServiceAccount 所在的位置。这里刻意让两者不同:

cat > release/first-access.yaml <<'YAML'
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployment-reader
  namespace: market-stalls
rules:
- apiGroups: [apps]
  resources: [deployments]
  verbs: [get, list]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: board-reader
  namespace: market-stalls
subjects:
- kind: ServiceAccount
  name: market-reader
  namespace: market-board
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: deployment-reader
YAML

读取并应用两个对象,再检查 API 解释后的连接关系:

cat release/first-access.yaml
kubectl --context=labex-v135 apply -f release/first-access.yaml
kubectl --context=labex-v135 describe role deployment-reader -n market-stalls
kubectl --context=labex-v135 describe rolebinding board-reader -n market-stalls

预期只包含针对 Deployment 的 get 和 list。沿 roleRef 找到 market-stalls 中的 Role,再沿主体找到 market-board 中的 market-reader。该绑定不会在目标命名空间中创建第二个 ServiceAccount。

运行中的看板仍使用 default。诊断工具的 list 操作用该 Pod 的当前凭据请求实际 Deployment 集合。被禁止的读取返回 http_status: 403,且命令以非零状态退出;切换工作负载身份之前,这是预期结果:

./tools/board-test list market-stalls

新权限属于 market-reader,不属于 default。不要通过给 default 账户授权来修复。应在准备好的看板 Deployment 的已保存副本中选择专用账户。

先读取完整起始文件。它包含需要保留的现有镜像、挂载源文件、健康检查、副本数和其他设置:

cat starter/board.yaml

kubectl set serviceaccount 修改所选身份。--local 转换这个输入文件,不会将其应用到集群。-f 指定输入,-o yaml 将 YAML 清单写到标准输出,已学过的 > 再将其保存为可编辑发布文件:

kubectl --context=labex-v135 set serviceaccount --local -f starter/board.yaml market-reader -o yaml > release/board.yaml

读取结果,确认 spec.template.spec.serviceAccountName 为 market-reader。保留全部其他应用设置:

cat release/board.yaml
kubectl --context=labex-v135 apply -f release/board.yaml

现有 Pod 的 ServiceAccount 不能原位修改。更新 Deployment 的 Pod 模板会创建新 Pod。rollout status 等待新工作负载;--timeout=120s 限制等待时间:

kubectl --context=labex-v135 rollout status deployment/status-board -n market-board --timeout=120s
kubectl --context=labex-v135 get pods -n market-board

预期有一个就绪的当前看板 Pod。替换这个看板 Pod 是必要的;目标应用 Pod 不会被修改。再次读取其实际认证身份:

./tools/board-test identity

预期为 system:serviceaccount:market-board:market-reader,pod_uid 与原先使用 default 身份的 Pod 不同。这确认的是进程凭据,而非仅评估一个模拟身份。

Deployment 集合和详情结果还包含 generation,即 Deployment 期望状态的版本,以及 observed_generation,即其控制器最后处理的版本。详情页将它们标为 Deployment generation 和 Observed generation。控制器可能短暂落后于期望变更。这些字段不统计顾客请求,也不能证明网站可用性。

读取摊位集合和单个 Deployment。get 的参数依次是命名空间和 Deployment 名称:

./tools/board-test list market-stalls
./tools/board-test get market-stalls catalogue

预期 http_status: 200,集合中有两个原始摊位 Deployment,单项结果中的 catalogue 有 2 个期望副本和 2 个可用副本。uid 标识原始对象;模板镜像仍为 python:3.12-alpine。命名空间 Role 不会延伸到配送命名空间:

./tools/board-test list market-delivery

最后这条命令预期返回 API 403 和非零命令状态。切换到 Board,使用 Refresh view,打开 Inspect catalogue,读取期望/可用副本数和 Template image。使用 Back to status board 返回。摊位卡片应正常工作,配送组仍显示 Access denied · API 403。这个部分完成的结果,是命名空间边界的有用证据。

如果滚动更新后 Read as 暂时仍显示旧身份,再使用一次 Refresh view。要确认当前 Pod,切换到 Workspace,重复 ./tools/board-test identity,然后返回 Board 并刷新。Service 路由可能需要短暂时间才能跟上滚动更新;不要给旧身份授权来掩盖这个过渡过程。

将实际读取身份、成功的摊位卡片和仍被拒绝的配送组,与这个运行中的示例比较:

仅接通第一个命名空间的 Orchard Market

如果滚动更新超时,请返回 Workspace,使用已展示的 describe 和 get 命令检查同一个 Deployment 和 Pod。如果读取意外被拒绝,请比较 Role、RoleBinding 主体命名空间和选定的工作负载身份。只修正发布文件,应用它,再重复对应的滚动更新或请求。不要复制操作者凭据、修改应用或重启 VM。

RoleBinding 的 roleRef 不可变。如果之前的拼写错误导致本课新建的 board-reader 绑定引用了错误的 Role,Kubernetes 会拒绝原位修改该引用。检查并修正 release/first-access.yaml 后,只重建你自己的具名绑定,再应用修正后的保存文件:

kubectl --context=labex-v135 delete rolebinding board-reader -n market-stalls
kubectl --context=labex-v135 apply -f release/first-access.yaml

这些是条件恢复命令,不是正常成功流程中必需的删除操作。不要删除 default 或平台绑定,也不要删除原始看板 Deployment 或目标工作负载。

扩展看板而不扩大其职责

在这一步中,你将为同一身份授予配送命名空间中的相同两种读取操作,再验证有用的输出和受保护边界。

从 Workspace 开始,位于 /home/labex/project/status-board。第二个命名空间需要自己的 Role 和 RoleBinding。可以在其中复用 Role 名称,但主体仍位于 market-board;身份并没有移动:

cat > release/second-access.yaml <<'YAML'
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployment-reader
  namespace: market-delivery
rules:
- apiGroups: [apps]
  resources: [deployments]
  verbs: [get, list]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: board-reader
  namespace: market-delivery
subjects:
- kind: ServiceAccount
  name: market-reader
  namespace: market-board
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: deployment-reader
YAML
cat release/second-access.yaml
kubectl --context=labex-v135 apply -f release/second-access.yaml
kubectl --context=labex-v135 describe rolebinding board-reader -n market-delivery

该绑定将目标 Role 授予已有的看板身份。当前 Pod 已使用该身份,因此不需要额外的看板滚动更新。RBAC 授权会相加;改变文件顺序不会引入拒绝规则,也不会移除无关授权。

通过实际看板凭据读取两个获准集合和一个配送详情:

./tools/board-test list market-stalls
./tools/board-test list market-delivery
./tools/board-test get market-delivery pickup

预期返回 API 200,包含原始对象和镜像。配送集合包含 pickup,其期望/可用副本数为 1/1,以及 receipts,副本数为 0/0。即使没有运行中的 Pod,期望副本数为零的 Deployment 仍是真实对象。保留这一声明设置。

现在检查被排除的数据。Kubernetes Secret 存储命名数据值。准备好的 staff-note 是合成测试数据;看板没有理由读取它。操作者可以在不显示数据值的情况下确认该对象存在:

kubectl --context=labex-v135 get secret staff-note -n market-stalls

看板自己的凭据访问第三个命名空间和这个 Secret 时,必须仍收到 API 403。下面两条命令预期都以非零状态结束:

./tools/board-test list market-office
./tools/board-test secret market-stalls staff-note

对象缺失、连接失败或一张错误截图,都不等同于这个实际授权拒绝。同一个客户端可以成功读取获准目标,而现有被排除对象保持完整。其投射凭据文件并不会赋予它 Secret API 的访问权限。

工具的 permission 操作询问 API,这个实际凭据是否能执行某项操作,但不会执行该操作。参数是命名空间、动词,以及适用时的 Deployment 名称。对于每个禁止操作,非持久化审查返回 http_status: 201 和 allowed: false;工具针对该拒绝返回非零状态:

./tools/board-test permission market-stalls patch catalogue
./tools/board-test permission market-delivery delete pickup
./tools/board-test permission market-stalls create

看板只需要 get 和 list;不会获准使用 watch 流或修改工作负载。保持 default 身份和原始平台 RBAC 不变。不要添加 ClusterRole、ClusterRoleBinding、通配符、额外主体或其他资源授权。

切换到 Board,使用 Refresh view。两组现在都显示原始 Deployment。打开 Inspect pickup,读取副本数和镜像,再使用 Back to status board。读取 receipts 卡片:Scaled to zero,可用数 0,期望数 0。这不是替代失败请求的空结果。

将实际读取身份、全部四张 Deployment 卡片以及可见的零期望副本归档,与这个完成后的示例比较:

两个获准命名空间均已接通的 Orchard Market

选择 Download CSV,打开实际下载的 orchard-market-deployments.csv。它有四行数据,每个原始 Deployment 对应一行,包括收据归档。将命名空间、Deployment 名称、期望/可用值、模板镜像和 API 状态与页面比较。这是新的 API 导出,不是保存的成功样本。浏览器下载位置和终端工作区不同;无需将下载文件复制到工作区。

选择 Access details,确认实际 Read as 值和两个预期命名空间范围,再使用 Back to status board。保留每个原始目标 Deployment、Pod/容器身份、源文件、镜像、数据和命名空间标签。保留原始看板 Deployment 和 Service;只改变其所选的 ServiceAccount。可复用发布配置包含 identity.yaml、first-access.yaml、second-access.yaml 和 board.yaml,与实际身份和生效权限一致。

如果第二个命名空间仍被拒绝,返回 Workspace,使用已展示的 describe 命令检查其绑定,比较主体命名空间和 Role 引用,修正保存的文件后再次应用。对于错误且不可变的 roleRef,使用之前教过的相同窄范围恢复方法,此处仅针对你新建的配送绑定:

kubectl --context=labex-v135 delete rolebinding board-reader -n market-delivery
kubectl --context=labex-v135 apply -f release/second-access.yaml

只在这个特定恢复情形下执行。如果被排除的访问意外成功,请检查你保存的两个 Role 及其绑定,从这些对象中移除非预期权限并再次应用。宽泛授权不会被另一个更窄的 Role 覆盖。不要编辑平台权限或应用来掩盖错误。路径和 YAML 错误使用之前教过的恢复方法,无需重置 VM。

完成的工具读取这个准备好的单节点集群中控制器报告的 Deployment 状态。它不验证看板访问者身份、不读取 Pod 日志或指标,也不证明生产环境持续可用。其就绪端点只确认看板进程能够提供服务;实际 API 结果才能确认是否能访问应用数据。

总结

你为真实的集群内使用方创建了专用 ServiceAccount,连接了命名空间范围的 Role 和 RoleBinding,并让新 Pod 实际使用该身份。随后,你将相同的读取职责扩展到第二个获准命名空间,没有授予被排除数据或工作负载修改权限。

可用的看板、当前 CSV 和保存的清单,将身份、权限与实际 API 输出联系起来。期望副本数、控制器报告的可用副本数和模板镜像仍是不同的观测结果。API 拒绝仍显示为数据不可用,而有意设置零期望副本的 Deployment 仍作为真实对象显示。