前言
在本搭建指南的第一部分中,我们从零开始,详细介绍了两种主流的 Kubernetes 集群搭建方法。首先,我们探讨了如何使用 kubeadm 工具快速部署一个功能完备的集群,
这个过程涵盖了从环境准备、容器运行时安装到集群初始化的每一个步骤。随后,我们深入到手动二进制部署的细节,构建了一个高可用的生产级集群。
这包括:手动签发所有 TLS 证书,搭建高可用 etcd 集群,配置 keepalived 和 haproxy 实现 API Server 的负载均衡,
并逐一部署了 kube-apiserver、kube-controller-manager、kube-scheduler、kubelet 和 kube-proxy 等核心组件。
最后,我们成功安装了 Calico CNI 插件和 CoreDNS 服务,完成了一个健壮的底层平台搭建。
在第一部分完成集群基础建设之后,本篇(第二部分)将聚焦于集群的上层应用和管理。我们将从安装 Kubernetes Dashboard 开始,为您提供一个直观的 Web UI 来管理集群资源。
本文也已经假定你熟悉 k8s的各种资源,概念和含义。
下面来回顾以下机器的分配:
配置hosts文件
1 2 3 4 5 6 7 8 9 10 192.168.3.120 k8smaster (VIP) 192.168.3.121 k8snode1 k8smaster1 etcd1 192.168.3.122 k8snode2 k8smaster2 etcd2 192.168.3.123 k8snode3 k8smaster3 etcd3 192.168.3.124 k8snode4 k8worker1 192.168.3.125 k8snode5 k8worker2 192.168.3.126 k8snode6 k8worker3 192.168.3.127 k8snode7 k8worker4 ...
搭建 dashboard
dashboard 对比
工具
类型
核心优势
主要缺点
适合场景
Kubernetes Dashboard
Web UI
官方支持,基础功能全面
权限配置复杂,功能单一
快速搭建一个基础的、用于资源增删改查的 Web 界面。
Lens
桌面客户端
功能强大的一站式 IDE,多集群管理体验好
资源消耗大,需要本地安装,商业模式有争议
开发者和管理员日常工作的主力工具,尤其适合管理多个集群。
K9s
终端 TUI
极致轻量和高效,键盘驱动
学习曲线陡峭,无图形化界面
追求效率的命令行重度用户,用于快速排障和日常巡检。
Grafana
监控仪表盘
无与伦比的监控数据可视化能力
部署复杂,非资源管理工具
深入的性能分析、故障定位和集群健康状况的长期监控。
下面我的搭建 dashboard 用于管理k8s 集群
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 apiVersion: v1 kind: Namespace metadata: name: kubernetes-dashboard --- apiVersion: v1 kind: ServiceAccount metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard --- kind: Service apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: type: NodePort ports: - port: 443 targetPort: 8443 nodePort: 32443 selector: k8s-app: kubernetes-dashboard --- apiVersion: v1 kind: Secret metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-certs namespace: kubernetes-dashboard type: Opaque --- apiVersion: v1 kind: Secret metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-csrf namespace: kubernetes-dashboard type: Opaque data: csrf: "" --- apiVersion: v1 kind: Secret metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-key-holder namespace: kubernetes-dashboard type: Opaque --- kind: ConfigMap apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-settings namespace: kubernetes-dashboard --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard rules: - apiGroups: ["" ] resources: ["secrets" ] resourceNames: ["kubernetes-dashboard-key-holder" , "kubernetes-dashboard-certs" , "kubernetes-dashboard-csrf" ] verbs: ["get" , "update" , "delete" ] - apiGroups: ["" ] resources: ["configmaps" ] resourceNames: ["kubernetes-dashboard-settings" ] verbs: ["get" , "update" ] - apiGroups: ["" ] resources: ["services" ] resourceNames: ["heapster" , "dashboard-metrics-scraper" ] verbs: ["proxy" ] - apiGroups: ["" ] resources: ["services/proxy" ] resourceNames: ["heapster" , "http:heapster:" , "https:heapster:" , "dashboard-metrics-scraper" , "http:dashboard-metrics-scraper" ] verbs: ["get" ] --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard rules: - apiGroups: ["metrics.k8s.io" ] resources: ["pods" , "nodes" ] verbs: ["get" , "list" , "watch" ] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: kubernetes-dashboard subjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kubernetes-dashboard --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kubernetes-dashboard roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kubernetes-dashboard subjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kubernetes-dashboard --- kind: Deployment apiVersion: apps/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: replicas: 3 revisionHistoryLimit: 10 selector: matchLabels: k8s-app: kubernetes-dashboard template: metadata: labels: k8s-app: kubernetes-dashboard spec: tolerations: - key: "node-role.kubernetes.io/master" operator: "Exists" effect: "NoSchedule" - key: "node-role.kubernetes.io/control-plane" operator: "Exists" effect: "NoSchedule" affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - k8snode1 - k8snode2 - k8snode3 securityContext: seccompProfile: type: RuntimeDefault containers: - name: kubernetes-dashboard image: kubernetesui/dashboard:v2.7.0 imagePullPolicy: Always ports: - containerPort: 8443 protocol: TCP args: - --auto-generate-certificates - --namespace=kubernetes-dashboard volumeMounts: - name: kubernetes-dashboard-certs mountPath: /certs - mountPath: /tmp name: tmp-volume livenessProbe: httpGet: scheme: HTTPS path: / port: 8443 initialDelaySeconds: 30 timeoutSeconds: 30 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsUser: 1001 runAsGroup: 2001 volumes: - name: kubernetes-dashboard-certs secret: secretName: kubernetes-dashboard-certs - name: tmp-volume emptyDir: {} serviceAccountName: kubernetes-dashboard nodeSelector: "kubernetes.io/os": linux tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule --- kind: Service apiVersion: v1 metadata: labels: k8s-app: dashboard-metrics-scraper name: dashboard-metrics-scraper namespace: kubernetes-dashboard spec: ports: - port: 8000 targetPort: 8000 selector: k8s-app: dashboard-metrics-scraper --- kind: Deployment apiVersion: apps/v1 metadata: labels: k8s-app: dashboard-metrics-scraper name: dashboard-metrics-scraper namespace: kubernetes-dashboard spec: replicas: 3 revisionHistoryLimit: 10 selector: matchLabels: k8s-app: dashboard-metrics-scraper template: metadata: labels: k8s-app: dashboard-metrics-scraper spec: tolerations: - key: "node-role.kubernetes.io/master" operator: "Exists" effect: "NoSchedule" - key: "node-role.kubernetes.io/control-plane" operator: "Exists" effect: "NoSchedule" affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - k8snode1 - k8snode2 - k8snode3 securityContext: seccompProfile: type: RuntimeDefault containers: - name: dashboard-metrics-scraper image: kubernetesui/metrics-scraper:v1.0.8 ports: - containerPort: 8000 protocol: TCP livenessProbe: httpGet: scheme: HTTP path: / port: 8000 initialDelaySeconds: 30 timeoutSeconds: 30 volumeMounts: - mountPath: /tmp name: tmp-volume securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsUser: 1001 runAsGroup: 2001 serviceAccountName: kubernetes-dashboard nodeSelector: "kubernetes.io/os": linux tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule volumes: - name: tmp-volume emptyDir: {}
部署如下
1 2 3 kubectl apply -f dashborad.yaml
我们在 master 节点执行 kubectl get pods -A -o wide 得到以下数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES kube-system calico-kube-controllers-c57dfffd6-9sbjs 1/1 Running 1 (178m ago) 62d 10.244.98.192 k8snode3 <none> <none> kube-system calico-node-52fnv 1/1 Running 0 62d 192.168.3.123 k8snode3 <none> <none> kube-system calico-node-5ndpq 1/1 Running 1 (59d ago) 62d 192.168.3.121 k8snode1 <none> <none> kube-system calico-node-77bst 1/1 Running 0 62d 192.168.3.125 k8snode5 <none> <none> kube-system calico-node-8wpgl 1/1 Running 0 62d 192.168.3.122 k8snode2 <none> <none> kube-system calico-node-bgk6r 1/1 Running 0 62d 192.168.3.124 k8snode4 <none> <none> kube-system coredns-6dcb4b89d5-2crlk 1/1 Running 0 60d 10.244.249.3 k8snode1 <none> <none> kube-system coredns-6dcb4b89d5-c2cb9 1/1 Running 7 (61d ago) 61d 10.244.98.194 k8snode3 <none> <none> kube-system coredns-6dcb4b89d5-vvpp5 1/1 Running 7 (61d ago) 61d 10.244.185.193 k8snode2 <none> <none> kubernetes-dashboard dashboard-metrics-scraper-59d6dd7d8-7vshq 1/1 Running 0 57d 10.244.185.198 k8snode2 <none> <none> kubernetes-dashboard dashboard-metrics-scraper-59d6dd7d8-g6v9k 1/1 Running 0 57d 10.244.185.197 k8snode2 <none> <none> kubernetes-dashboard dashboard-metrics-scraper-59d6dd7d8-t6cw6 1/1 Running 0 57d 10.244.98.197 k8snode3 <none> <none> kubernetes-dashboard kubernetes-dashboard-955db9b78-5pz4z 1/1 Running 0 57d 10.244.185.196 k8snode2 <none> <none> kubernetes-dashboard kubernetes-dashboard-955db9b78-j2pmw 1/1 Running 0 57d 10.244.185.199 k8snode2 <none> <none> kubernetes-dashboard kubernetes-dashboard-955db9b78-krlpf 1/1 Running 0 57d 10.244.98.198 k8snode3 <none> <none>
可以看到,在kubernetes-dashboard 中创建 dashboard-metrics-scraper 和 kubernetes-dashboard 两个类型的组件,每个组件为 3 pod。
对于 deployment 和 service 我们可以指定 namespace 的空间
1 2 3 4 5 6 7 8 9 [root@k8snode1 ~]# kubectl get deployments --namespace=kubernetes-dashboard -o wide NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR dashboard-metrics-scraper 3/3 3 3 57d dashboard-metrics-scraper kubernetesui/metrics-scraper:v1.0.8 k8s-app=dashboard-metrics-scraper kubernetes-dashboard 3/3 3 3 57d kubernetes-dashboard kubernetesui/dashboard:v2.7.0 k8s-app=kubernetes-dashboard``` [root@k8snode1 ~]# kubectl get svc --namespace=kubernetes-dashboard -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR dashboard-metrics-scraper ClusterIP 10.96.144.232 <none> 8000/TCP 57d k8s-app=dashboard-metrics-scraper kubernetes-dashboard NodePort 10.96.152.197 <none> 443:32443/TCP 57d k8s-app=kubernetes-dashboard
dashboard-metrics-scraper, kubernetes-dashboard 的功能如下
kubernetes-dashboard:核心前端界面这是 Kubernetes 官方提供的 Web 用户界面,是您与集群进行可视化交互的核心入口。可以将其视为 kubectl 命令行的图形化版本。•
核心功能:•资源可视化:以图形化方式展示集群中的各种资源,如节点(Nodes)、命名空间(Namespaces)、工作负载(Deployments, Pods, StatefulSets 等)、服务(Services)、存储(PersistentVolumeClaims)和配置(ConfigMaps, Secrets)等。•
资源管理:允许您通过浏览器直接创建、编辑、更新和删除资源。例如,您可以上传 YAML 文件来部署应用,或者在 UI 上直接修改 Deployment 的副本数来实现扩缩容。•
基本监控与排障:提供对 Pod 日志的实时查看功能,可以进入 Pod 的 Shell 执行命令,并展示资源的基本状态和事件,帮助快速定位问题。在下面的配置中,它被部署为一个 Deployment,拥有3个副本以确保高可用,并通过一个 NodePort 类型的 Service 将其 8443 端口映射到节点的 32443 端口,从而允许从集群外部访问。
dashboard-metrics-scraper:指标数据抓取器可以将其理解为 Dashboard 的一个辅助组件或“数据探针”。它本身不提供用户界面,而是默默地在后台工作,为 kubernetes-dashboard 提供关键的性能指标数据。•
核心功能:•指标采集:它的唯一职责是从 Kubernetes 的核心监控管道——指标服务器(Metrics Server)——中抓取各个 Pod 和节点的资源使用情况,主要是 CPU 和内存的实时数据。•
数据供给:它将采集到的数据通过一个内部 API 暴露给 kubernetes-dashboard 前端。Dashboard UI 在展示 Pod 列表或节点列表时,会调用 metrics-scraper 的接口来获取并展示那些迷你的 CPU 和内存使用图表(Sparkline charts)。简单来说:如果没有 metrics-scraper,你的 Dashboard 只能看到资源“长什么样”(例如,Pod 的名字和状态),但无法看到它“活得怎么样”(例如,它消耗了多少 CPU 和内存)。那些直观的性能曲线将无法显示。
总结一下:kubernetes-dashboard 是提供操作界面的“大脑”和“躯干”,而 dashboard-metrics-scraper 则是为其提供实时性能数据的“眼睛”。两者结合,才能提供一个功能完整的可视化体验。
NameSpace 和 ServiceAccount
Namespace (命名空间):集群中的逻辑隔离区您可以把 Namespace 想象成在一台计算机上创建的不同文件夹,或者在一栋办公楼里划分出的不同独立办公室。
核心作用:
1.资源隔离与组织:Namespace 将一个物理的 Kubernetes 集群划分为多个逻辑上的“虚拟集群”。这使得不同的团队、项目或环境(如“开发环境”、“测试环境”、“生产环境”)可以共享同一个 K8s 集群,但各自的资源(如 Pods, Deployments, Services)却互不干扰,仿佛在自己的独立空间里。
2.命名范围:在不同的 Namespace 中,你可以拥有同名的资源。例如,namespace-a 里的 Service my-db 和 namespace-b 里的 Service my-db 是两个完全不同的资源,避免了命名冲突。
3.访问控制:Namespace 是实现基于角色的访问控制(RBAC)的基本单位。你可以精细地为某个用户或用户组设置权限,例如“A 团队的用户只能访问 team-a 命名空间内的所有资源”。
在我们的配置中: 我们创建了一个名为 kubernetes-dashboard 的 Namespace 。这样做的好处是,所有与 Dashboard 相关的组件(包括它的 Deployment、Service、Secret 等)都会被整齐地放在这个专属的“文件夹”里,与您业务应用完全隔离,便于管理和后续的清理(例如,不再需要时,只需一条命令 kubectl delete namespace kubernetes-dashboard 即可删除所有相关资源)。
ServiceAccount (服务账户):Pod 的身份标识如果说普通的用户账户(UserAccount)是给人类(比如管理员您)登录集群使用的,那么 ServiceAccount 就是专门给程序(运行在 Pod 里的进程)使用的“身份证”。•
核心作用:
提供身份:ServiceAccount 为 Pod 中的进程提供了一个可以在集群内部被识别的身份。当 Pod 需要与 Kubernetes API 服务器进行通信时(例如,查询其他 Pod 的信息),它就会亮出这个“身份证”来证明自己是谁。
权限认证:单有身份是不够的,还需要有权限。ServiceAccount 本身不包含任何权限,但它是权限绑定的目标。通过创建 RoleBinding 或 ClusterRoleBinding,你可以将特定的权限(定义在 Role 或 ClusterRole 中)授予某个 ServiceAccount。这样,使用了该 ServiceAccount 的 Pod 就拥有了相应的操作权限。
在我们的配置中: 我们创建了一个名为 kubernetes-dashboard 的 ServiceAccount 。这个服务账户会被 Dashboard 的 Pod 使用。后续的 RoleBinding 和 ClusterRoleBinding 配置,就是将“读取集群节点和 Pod 指标”以及“管理自身配置”等权限,精确地授予给了这个 kubernetes-dashboard 的“身份”。这样,Dashboard 程序才能合法地从 API Server 获取信息并在前端页面上展示出来。
Role 和 RoleBinding
K8s 的授权方式为RBAC(基于角色的访问控制)的四个关键组件:Role、ClusterRole、RoleBinding 和 ClusterRoleBinding。 RBAC 的核心逻辑可以概括为一句话:“把 (Bind) [什么权限] 授予 (to) [谁]”。•
[什么权限]:这就是 Role 和 ClusterRole 定义的内容。它们是一份“权限清单”。
[谁]:这就是主体(Subject),通常是 User(用户)、Group(用户组)或 ServiceAccount(服务账户)。
把…授予… (Bind):这个“授权”的动作,就是 RoleBinding 和 ClusterRoleBinding 完成的工作。
Role:命名空间内的权限清单
功能:Role 定义了一系列在特定命名空间内允许执行的操作。它只对它所在的那个命名空间生效。•在配置中
1 2 3 4 5 6 7 8 9 10 11 12 13 kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard rules: - apiGroups: ["" ] resources: ["secrets" , "configmaps" ] resourceNames: ["kubernetes-dashboard-key-holder" , "kubernetes-dashboard-certs" , "kubernetes-dashboard-csrf" , "kubernetes-dashboard-settings" ] verbs: ["get" , "update" , "delete" ]
这个 Role 定义了这样一条规则:
“在 kubernetes-dashboard 这个命名空间内,允许对名为 kubernetes-dashboard-key-holder 等特定的 secrets 和 configmaps 资源进行 get(获取)、update(更新)和 delete(删除)操作”。
这个权限是有范围限制的。拥有这个 Role 的用户,无法操作其他命名空间(比如 default)里的 secrets。
ClusterRole:整个集群的权限清单
功能:ClusterRole 定义了一系列在整个集群范围内允许执行的操作。它不受命名空间限制。它有两种主要用途:
1.授权操作集群级别的资源(例如 Nodes、PersistentVolumes,这些资源不属于任何命名空间)。
2.授权操作所有命名空间中的同类资源(例如,允许“查看所有命名空间中的 Pods”)。•在配置中:
1 2 3 4 5 6 7 8 9 10 11 kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard rules: - apiGroups: ["metrics.k8s.io" ] resources: ["pods" , "nodes" ] verbs: ["get" , "list" , "watch" ]
这个 ClusterRole 定义了这样一条规则:“在整个集群的任何地方,允许对 metrics.k8s.io API 组下的 pods 和 nodes 资源进行 get(获取)、list(列出)和 watch(监听)操作”。
这个权限是全局的。这是 dashboard-metrics-scraper 需要的,因为它必须能够从集群的所有节点和 Pod 中抓取监控指标,而不能只局限于某一个命名空间。
RoleBinding:在命名空间内进行授权
功能:RoleBinding 的作用就是执行“授权”这个动作。它把一个 Role 所定义的权限,授予给一个或多个主体(ServiceAccount 等),但这个授权行为仅在 RoleBinding 所在的命名空间内有效。•在配置中:YAML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: kubernetes-dashboard namespace: kubernetes-dashboard roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: kubernetes-dashboard subjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kubernetes-dashboard
解释: 这部分配置的意思是:“在 kubernetes-dashboard 命名空间内,将我们上面定义的那个名为 kubernetes-dashboard 的 Role(权限清单),授予给 kubernetes-dashboard 这个 ServiceAccount”。
ClusterRoleBinding:在整个集群进行授权
功能:ClusterRoleBinding 同样是执行“授权”动作,但它授予的是全局范围的权限。它将一个 ClusterRole 授予给一个或多个主体,使其在整个集群都拥有该权限。
1 2 3 4 5 6 7 8 9 10 11 12 13 apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kubernetes-dashboard roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kubernetes-dashboard subjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kubernetes-dashboard
解释: 这部分配置的意思是:“在整个集群范围内,将我们上面定义的那个名为 kubernetes-dashboard 的 ClusterRole(全局权限清单),授予给 kubernetes-dashboard 这个 ServiceAccount”。正是因为有了这个 ClusterRoleBinding,Dashboard 的 Pod(通过其 ServiceAccount)才获得了在所有命名空间中查看节点和 Pod 指标的能力。
查看内置的 Role
查看 ServiceAccount (服务账户)这些命令用于查看和检查赋予 Pod 身份的 ServiceAccount。Shell Script# 1. 列出 ‘kubernetes-dashboard’ 命名空间中所有的 ServiceAccount
1 2 3 4 5 6 7 8 9 10 kubectl get serviceaccount -n kubernetes-dashboard kubectl describe serviceaccount kubernetes-dashboard -n kubernetes-dashboard kubectl get serviceaccount --all-namespaces
查看 Role 和 RoleBinding (命名空间级别)这些命令用于检查在特定命名空间内定义的权限和授权关系。Shell Script# 1. 列出 ‘kubernetes-dashboard’ 命名空间中所有的 Role
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 kubectl get role -n kubernetes-dashboard kubectl describe role kubernetes-dashboard -n kubernetes-dashboard kubectl get rolebinding -n kubernetes-dashboard kubectl describe rolebinding kubernetes-dashboard -n kubernetes-dashboard
查看 ClusterRole 和 ClusterRoleBinding (集群级别)这些命令用于检查整个集群范围的权限和授权关系。Shell Script# 1. 列出集群中所有的 ClusterRole (因为列表很长,用 grep 过滤)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 kubectl get clusterrole | grep dashboard kubectl describe clusterrole kubernetes-dashboard kubectl get clusterrolebinding | grep dashboard kubectl describe clusterrolebinding kubernetes-dashboard kubectl get clusterrole -l kubernetes.io/bootstrapping=rbac-defaults kubectl get clusterrole -l '!kubernetes.io/bootstrapping'
权限验证与检查 (auth can-i)这是最强大、最直接的验证工具。它能准确地回答“某某某到底能不能做某某事?”Shell Script# 1. 检查当前用户(你自己)是否可以在 ‘default’ 命名空间中列出 Pods
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 kubectl auth can-i list pods -n default kubectl auth can-i get secrets -n kubernetes-dashboard --as=system:serviceaccount:kubernetes-dashboard:kubernetes-dashboard kubectl auth can-i update configmaps -n kubernetes-dashboard --as=system:serviceaccount:kubernetes-dashboard:kubernetes-dashboard kubectl auth can-i list nodes --as=system:serviceaccount:kubernetes-dashboard:kubernetes-dashboard kubectl auth can-i list pods.metrics.k8s.io -n default --as=system:serviceaccount:kubernetes-dashboard:kubernetes-dashboard
auth can-i 命令的返回结果非常直观:
如果返回 yes,代表有权限。
+如果返回 no,代表没有权限。
通过运行以上这些命令,特别是第 4 部分的 auth can-i,您就可以非常精确地验证您在 YAML 文件中定义的每一条 RBAC 规则是否都已在集群中正确生效。
创建自己的 namespace
下面我们要创建自己的 namespace 和 service account
创建 namespace
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 kubectl create namespace zhipeng-space cat > zhipeng1.yaml << 'EOF' --- apiVersion: v1 kind: ServiceAccount metadata: name: zhipeng1 namespace: zhipeng-space --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: zhipeng1-admin namespace: zhipeng-space roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: admin subjects: - kind: ServiceAccount name: zhipeng1 namespace: zhipeng-space EOF kubectl apply -f zhipeng1.yaml
创建超级用户
由于我们需要使用 ui-admin 来操作集群,因此我们需要一个超级用户 ui-amdin 来管理集群,因此我们需要班定 cluster-admin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 cat > ui-admin.yaml << 'EOF' --- apiVersion: v1 kind: ServiceAccount metadata: name: ui-admin namespace: kubernetes-dashboard --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: ui-admin roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: ui-admin namespace: kubernetes-dashboard EOF kubectl apply -f ui-admin.yaml
token 登录dashboard
1 2 3 4 5 6 7 kubectl -n kubernetes-dashboard create token ui-admin [root@k8snode1 ~]# kubectl get svc --namespace=kubernetes-dashboard NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE dashboard-metrics-scraper ClusterIP 10.96.144.232 <none> 8000/TCP 57d kubernetes-dashboard NodePort 10.96.152.197 <none> 443:32443/TCP 57d
我们配置是 nodePort 因此我们需要 存在 kubernetes-dashboard node ip + 32443 来访问kubernetes-dashboard
我们使用 token 登录
1 2 3 kubectl -n kubernetes-dashboard create token ui-admin
之后使用 打印出来的 token 来登录即可
配置 kubectl
早在第一章节,我们已经在 配置合了 kubectl 这个是负责和 api-server 交互的,我们使用了内嵌证书的方式进行,内嵌证书在创建的时候已经将用户名写进证书体里,因此我们可以通过 kubectl 对 api 进行操作
现在我们在 k8snode1中执行
1 2 3 [root@k8snode1 .kube]# kubectl config get-contexts --kubeconfig=/root/.kube/config CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes kubernetes kubernetes
可以看到我们现在 kubectl config 使用的是 kubernetes,在上一个章节中,我们使用了以下命令来生成证书
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 openssl genrsa -out admin.key 2048 openssl req -new -key admin.key \ -out admin.csr \ -subj "/C=CN/ST=Beijing/L=Beijing/O=system:masters/CN=kubernetes" ... kubectl config set-context kubernetes \ --cluster=kubernetes \ --user=kubernetes \ --kubeconfig=/root/.kube/config
这里我们使用了system:masters 组别,因为一个名为 cluster-admin 的 ClusterRole 永久地绑定到了一个名为 system:masters 的用户组上。这是有 k8s集群隐式完成的
我们可以看一下所有用户组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 kubectl get clusterrolebindings -o jsonpath='{.items[*].subjects[?(@.kind=="Group")].name}' | tr " " "\n" | sort | uniq system:authenticated system:masters system:monitoring system:serviceaccounts system:unauthenticated [root@k8snode1 .kube]# kubectl describe clusterrolebinding cluster-admin Name: cluster-admin Labels: kubernetes.io/bootstrapping=rbac-defaults Annotations: rbac.authorization.kubernetes.io/autoupdate: true Role: Kind: ClusterRole Name: cluster-admin Subjects: Kind Name Namespace ---- ---- --------- Group system:masters
特别说明的是,这里的组并不是k8s集群中的实体概念,对于 k8s 来说在赋权的时候可以将某个权限赋予某个人或者某个组。对于技术上来说,用户是一个 k8s实体存在的东西
而组别并不存在,也就无法查询组下究竟有多少人,组可以理解为一个用户的 tag,那么我们在服务端不会维护这个 tag实际依赖关系
那么在生成用户凭凭证的时候 可以设置 O=(证书方式) 也可以是 jwt 的 group 方式来给用户打 “tag”, 这样以来就可以实现灵活分配用户权限。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 [root@k8snode1 certs]# cat /etc/kubernetes/cfg/kubelet.kubeconfig apiVersion: v1 clusters: - cluster: certificate-authority-data: ... server: https://k8smaster:9443 name: default-cluster contexts: - context: cluster: default-cluster namespace: default user: default-auth name: default-context current-context: default-context kind: Config users :- name: default-auth user: client-certificate: /etc/kubernetes/certs/kubelet-client-current.pem client-key: /etc/kubernetes/certs/kubelet-client-current.pem [root@k8snode1 certs]# openssl x509 -in /etc/kubernetes/certs/kubelet-client-current.pem -noout -subject subject=O=system:nodes, CN=system:node:k8snode1 [root@k8snode1 certs]# openssl x509 -in kube-apiserver.crt -noout -subject subject=CN=kubernetes
从上面的内容当中,我们是使用了 kubelet-client-current.pem 为 kebuctl 的身份,而kubelet-client-current.pem
步骤
技术术语
您的操作
Kubelet 的行为
1
使用 Bootstrap Token
启动 kubelet 服务
读取 bootstrap.kubeconfig,用临时 Token 连接 API Server。
2
提交 CSR
(无)
自动生成密钥对,并向 API Server 提交一个证书签名请求。
3
批准 CSR
kubectl certificate approve …
等待 CSR 的状态变为 Approved。
4
签发证书
(无)
kube-controller-manager 自动用 CA 签署证书。
5
获取并使用新证书
(无)
下载新证书,保存到本地,并创建 kubelet-client-current.pem 链接。从此改用新证书进行所有通信。
所以,您没有创建过 kubelet-client-current.pem 的记忆是完全正确的。它是 Kubelet 在您批准了它的“入职申请”后,自己“领取”并开始使用的正式身份证明。
这个自动化过程是 Kubernetes 安全性和可扩展性的基石。
了解上述背景之后,我们就可以着手创建 kubectl 的上线问,让我们可以在非 master 机器上操作我们自己的空间,注意,这里是非 master 节点!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ```bash cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Secret metadata: name: zhipeng1-perm-token namespace: zhipeng-space annotations: kubernetes.io/service-account.name: "zhipeng1" type: kubernetes.io/service-account-token EOF PERM_TOKEN=$(kubectl -n zhipeng-space get secret zhipeng1-perm-token -o jsonpath={.data.token} | base64 -d) echo $PERM_TOKEN KUBE_CONFIG="zhipeng-worker.kubeconfig" SERVER_URL="https://k8smaster:9443" kubectl config set-cluster kubernetes \ --certificate-authority=/etc/kubernetes/ssl/ca.crt \ --embed-certs=true \ --server=${SERVER_URL} \ --kubeconfig=${KUBE_CONFIG} kubectl config set-credentials zhipeng1-user \ --token=${PERM_TOKEN} \ --kubeconfig=${KUBE_CONFIG} kubectl config set-context zhipeng-context \ --cluster=kubernetes \ --user=zhipeng1 \ --namespace=zhipeng-space \ --kubeconfig=${KUBE_CONFIG} kubectl config use-context zhipeng-context --kubeconfig=${KUBE_CONFIG} scp zhipeng-worker.kubeconfig root@k8snode4:/root/.kube/ [root@k8snode4 ~]# kubectl config current-context zhipeng-context [root@k8snode4 ~]# kubectl get pods -A -o wide Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:zhipeng-space:zhipeng1" cannot list resource "pods" in API group "" at the cluster scope
命令总结
kubectl 命令
作用
常用场景
Example
kubectl get nodes
查看 Kubernetes 集群中的 Node
判断节点是否加入、是否 Ready
kubectl get nodes
kubectl get nodes -o wide
查看 Node 的详细信息,包括 IP、OS、内核、容器运行时等
检查节点状态、IP、版本
kubectl get nodes -o wide
kubectl get node <node>
查看指定 Node 的基本状态
检查某个节点
kubectl get node k8snode5
kubectl describe node <node>
查看 Node 的详细信息、Conditions、Taints、Events 等
排查节点为什么 NotReady
kubectl describe node k8snode5
kubectl delete node <node>
从 Kubernetes API 中删除 Node 对象
Worker 节点重新加入前清理旧 Node 记录
kubectl delete node k8snode5
kubectl get csr
查看 Kubernetes CertificateSigningRequest
检查 kubelet 证书申请是否成功/是否等待批准
kubectl get csr
kubectl describe csr <name>
查看某个 CSR 的详细信息
排查 kubelet 证书申请问题
kubectl describe csr node-csr-xxxxx
kubectl get sa -A
查看所有 Namespace 中的 ServiceAccount
查找 zhipeng1-user 是否是 SA
kubectl get sa -A
kubectl get sa -A | grep zhipeng
从所有 SA 中搜索指定名称
快速确认 ServiceAccount 是否存在
kubectl get sa -A | grep zhipeng
kubectl get sa <name> -n <namespace> -o yaml
查看 ServiceAccount 完整 YAML
检查 SA 配置
kubectl get sa zhipeng1-user -n zhipeng-space -o yaml
kubectl create token <sa>
为 ServiceAccount 创建 Token
重新生成用户/程序访问 API Server 的 Token
kubectl create token zhipeng1-user -n zhipeng-space
kubectl auth whoami
查看当前 kubeconfig 对应的 Kubernetes 身份
判断当前认证用户是谁
kubectl auth whoami
kubectl auth can-i <verb> <resource>
判断当前身份是否有某个权限
排查 RBAC
kubectl auth can-i get pods
kubectl auth can-i --list
列出当前身份所有可执行权限
全面检查 RBAC
kubectl auth can-i --list
kubectl config view
查看当前 kubeconfig 配置
检查 cluster/context/user
kubectl config view
kubectl config view --minify
只查看当前 Context 使用的配置
快速确认当前连接哪个集群/用户
kubectl config view --minify
kubectl config view --raw --minify
查看当前 Context 的完整敏感配置
检查 Token、证书等认证信息
kubectl config view --raw --minify
kubectl config current-context
查看当前使用的 Context
判断 kubectl 当前使用哪套配置
kubectl config current-context
kubectl config get-contexts
列出所有 Context
多集群/多用户环境下排查配置
kubectl config get-contexts
kubectl config get-users
查看 kubeconfig 中定义的 User
检查当前有哪些认证身份
kubectl config get-users
kubectl config set-credentials
创建/修改 kubeconfig 中的 User 凭据
更新 Token、客户端证书等
kubectl config set-credentials zhipeng1-user --token='<TOKEN>'
kubectl config set-context
创建/修改 Context
指定 cluster、user、namespace 的组合
kubectl config set-context zhipeng-context --cluster=kubernetes --user=zhipeng1-user --namespace=zhipeng-space
kubectl get pods -A
查看所有 Namespace 的 Pod
检查整个集群 Pod 状态
kubectl get pods -A
kubectl get pods -n <namespace>
查看指定 Namespace 的 Pod
检查某个业务 Namespace
kubectl get pods -n zhipeng-space
kubectl get pods -o wide
查看 Pod 所在 Node、IP 等
排查 Pod 调度和网络
kubectl get pods -A -o wide
kubectl get --raw=/version
直接请求 API Server 的版本接口
检查 API Server 是否能访问
kubectl get --raw=/version
kubectl get --raw=/api
直接请求 Kubernetes Core API
检查 API Server/API 认证链路
kubectl get --raw=/api
部署一个应用到 自己的空间
下面我们部署一个 nginx 到 自己的空间,注意这里需要在 非 master 节点执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-zhipeng spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: serviceAccountName: zhipeng1 nodeSelector: node-role.kubernetes.io/worker: "" containers: - name: nginx image: nginx:1.21.6 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-service namespace: zhipeng-space spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 nodePort: 30080 type : NodePort
部署我够用们第一个应用
以 zhipeng 的身份 deploy nginx-service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-zhipeng spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: serviceAccountName: zhipeng1 nodeSelector: node-role.kubernetes.io/worker: "" containers: - name: nginx image: nginx:1.21.6 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-service namespace: zhipeng-space spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 nodePort: 30080 type : NodePort [root@k8snode4 yaml]# kubectl get deployment [root@k8snode4 yaml]# kubectl get deployment -o wide NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR nginx-zhipeng 1/2 2 1 29s nginx nginx:1.21.6 app=nginx [root@k8snode4 yaml]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-service NodePort 10.96.94.231 <none> 80:30080/TCP 66s springboot-svc ClusterIP 10.96.105.20 <none> 80/TCP 58d
部署好之后,我们检查一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 [root@k8snode4 yaml]# curl http://10.96.94.231 <!DOCTYPE html> <html> <head > <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/" >nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/" >nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> [root@k8snode4 yaml]# curl http://k8snode4:30080 <!DOCTYPE html> <html> <head > <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/" >nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/" >nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> [root@k8snode4 yaml]#
我们在检验一下,是否是一 zhipeng1 的身份运行
1 2 3 4 5 6 7 8 9 10 kubectl exec -it <Pod名字> -n zhipeng-space -- cat /var/run/secrets/kubernetes.io/serviceaccount/namespace 检查重点:输出应该是 zhipeng-space。 深度验证(查看具体 ServiceAccount): Bash kubectl get pod <Pod名字> -n zhipeng-space -o jsonpath='{.spec.serviceAccountName}' 输出必须是 zhipeng1。
结束语
好了,搭建一个建议的集群到此就基本结束了,但是本系列并没有结束,接下来我将讲解更为高级的应用,以及如何部署自己的应用到 k8s集群中。