CKA考后总结

#k8s #CKA

Table of Contents

在经过两周的集中备考后,我以95分通过了CKA认证考试。这篇文章不是应试技巧的堆砌,而是我在备考过程中对Kubernetes设计理念的一些深层思考,以及实战中踩过的坑。

在深入学习Kubernetes的过程中,我逐渐理解了它的核心设计哲学:

Kubernetes是一个按照Linux “一切皆文件"理念设计的宏观系统,实现了"一切皆资源"的抽象。

这个理解对我后续的学习和实践产生了深远影响。所有的操作本质上都是对API资源的CRUD,理解了这一点,很多概念就能融会贯通。

基础通识

考试内容概览

CKA考试是纯实操的performance-based exam,时长2小时,需要在真实的Kubernetes集群环境中完成15-20道题目。考试涉及的核心知识点如下:

  1. Service与Ingress:创建Service暴露应用,配置Ingress规则实现路由
  2. 存储管理:PV/PVC的创建与绑定,StorageClass的使用
  3. RBAC权限控制:ServiceAccount、ClusterRole、RoleBinding的配置
  4. 集群故障排查:Node健康检查、Pod状态诊断、日志排查
  5. 集群升级:使用kubeadm进行集群版本升级
  6. 数据备份恢复:etcd的backup与restore操作
  7. 工作负载管理:Deployment、Pod的创建与配置
  8. 多容器Pod:Sidecar模式、Init Container的实现
  9. 日志查询:使用kubectl logs过滤容器日志

这里需要强调的是,CKA考试允许查阅Kubernetes官方文档,所以关键不是死记硬背,而是要熟悉文档结构和快速定位能力。

实战技巧与命令速查

在考试中,时间就是分数。这里分享一些我实战中总结的提效技巧。

环境切换

每道题目都会指定特定的集群context,这一步必须做对,否则所有操作都是无效的:

# 切换集群上下文(每道题的第一步)
kubectl config use-context k8s-cluster1

# 验证当前上下文
kubectl config current-context

快速查询与操作

# 获取带标签的资源
kubectl get ns --show-labels
kubectl get pod -o wide --show-labels

# 多资源类型同时查看
kubectl get pod,svc,deploy -n production

# 快速创建Service暴露Pod
kubectl expose pod curl --port=80 --target-port=8000 --name=curl-service

# 导出YAML模板后编辑(避免从零编写)
kubectl create deployment nginx --image=nginx --dry-run=client -o yaml > deploy.yaml

资源类型缩写

熟练使用资源缩写可以大幅提升命令输入速度,这些是考试中最常用的:

缩写完整名称缩写完整名称
popodssvcservices
deploydeploymentsrsreplicasets
stsstatefulsetsdsdaemonsets
cmconfigmapssecretsecrets
nsnamespacesnonodes
pvpersistentvolumespvcpersistentvolumeclaims
saserviceaccountsingingresses
hpahorizontalpodautoscalersependpoints

使用示例:

kubectl get po,svc -n kube-system
kubectl describe deploy nginx
kubectl edit cm nginx-config

关键工具配置

使用 kubectl top 查看资源使用率时,需要预先部署Metrics Server:

# 部署Metrics Server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# 验证部署
kubectl top nodes
kubectl top pods -A

这一步在考试环境中通常已经配置好,但在自己的练习环境中需要手动安装。

API资源的本质

前面提到,Kubernetes的核心理念是"一切皆资源”。所有的操作本质上都是通过API Server对资源进行增删改查。

理解这一点很重要:当你执行 kubectl create deployment 时,实际上是在向API Server提交一个Deployment资源对象的JSON/YAML定义,API Server将其持久化到etcd,然后由各个Controller监听这个资源变化并执行相应的操作。

在编写复杂的资源配置时,Kubernetes API Reference是最权威的文档:

这里可以查到每个资源的完整字段定义、类型、默认值和描述。比如在配置Job的时候,你需要知道 spec.backoffLimit 的默认值是6,这些信息在API文档中都能找到。

Pod的网络与存储共享机制

每个Pod内部都有一个Infra容器(也叫pause容器),这个容器非常小,只有几百KB,但它的作用至关重要:

  1. 网络共享:Infra容器负责创建Network Namespace,Pod内的所有业务容器共享这个网络命名空间,因此它们可以通过localhost互相访问
  2. 存储共享:在Pod级别声明的Volume会挂载到Infra容器,业务容器通过volumeMounts引用这些Volume即可实现文件共享

这种设计使得多容器协作变得自然而优雅,也是Sidecar模式的基础。

RBAC权限控制

RBAC(Role-Based Access Control)是Kubernetes中最重要的安全机制之一,也是CKA考试的必考点。在我备考过程中,RBAC是最容易混淆的部分,需要理清楚几个核心概念。

RBAC的四大对象

Kubernetes的RBAC由四种资源对象组成:

  1. Role:定义命名空间级别的权限规则
  2. ClusterRole:定义集群级别的权限规则
  3. RoleBinding:将Role绑定到用户/组/ServiceAccount(命名空间级别)
  4. ClusterRoleBinding:将ClusterRole绑定到用户/组/ServiceAccount(集群级别)

关键理解:

  • Role和RoleBinding都是命名空间级别的资源
  • ClusterRole和ClusterRoleBinding是集群级别的资源
  • 但是,RoleBinding也可以引用ClusterRole,这时ClusterRole的权限会被限制在RoleBinding所在的命名空间

权限绑定的四种组合

角色类型绑定类型作用范围使用场景
RoleRoleBinding单个命名空间授予命名空间内的资源权限
ClusterRoleClusterRoleBinding整个集群授予集群级别的资源权限
ClusterRoleRoleBindingRoleBinding所在的命名空间复用集群角色但限制在某命名空间
ClusterRole多个RoleBinding多个命名空间(每个RoleBinding一个)在多个命名空间授予相同权限

ServiceAccount vs User Account

在实际使用中,需要区分两种账号类型:

  • User Account:真实用户的账号,由外部认证系统管理(如证书、OIDC等)
  • ServiceAccount:Pod内应用程序的身份标识,由Kubernetes管理

考试中几乎都是在配置ServiceAccount的权限。每个Pod默认会使用所在命名空间的default ServiceAccount,但在实际生产环境中,应该为不同的应用创建专用的ServiceAccount并授予最小权限。

实战示例

创建一个只能读取Pod信息的ServiceAccount:

# 创建ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: pod-reader
  namespace: default
---
# 创建Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader-role
  namespace: default
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
---
# 创建RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: ServiceAccount
  name: pod-reader
  namespace: default
roleRef:
  kind: Role
  name: pod-reader-role
  apiGroup: rbac.authorization.k8s.io

在Pod中使用这个ServiceAccount:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  serviceAccountName: pod-reader
  containers:
  - name: app
    image: nginx

这里需要注意的是,roleRef字段在创建后不能修改,如果需要更换角色,必须删除RoleBinding重新创建。

Service网络暴露

Service是Kubernetes中实现服务发现和负载均衡的核心抽象。在我的理解中,Service本质上是一个稳定的网络端点,它通过label selector动态关联一组Pod,并为这组Pod提供统一的访问入口。

Service的四种类型

  1. ClusterIP(默认):在集群内部分配一个虚拟IP,只能在集群内部访问
  2. NodePort:在每个Node上开放一个端口(30000-32767),可以从集群外部访问
  3. LoadBalancer:在云环境中创建外部负载均衡器
  4. ExternalName:通过CNAME记录映射到外部服务

快速创建Service

在考试中,使用命令行快速创建Service比手写YAML效率更高:

# 为Deployment创建ClusterIP Service
kubectl expose deployment nginx --port=80 --target-port=8080

# 创建NodePort Service
kubectl expose deployment nginx --type=NodePort --port=80

# 为已存在的Pod创建Service
kubectl expose pod nginx --port=80 --name=nginx-service

Service与Endpoints的关系

Service通过label selector找到匹配的Pod后,会自动创建对应的Endpoints对象。可以通过以下命令查看:

kubectl get endpoints nginx-service

如果Service没有正常工作,检查Endpoints是否为空是一个重要的排查步骤。

Ingress路由规则

Ingress是Kubernetes提供的HTTP/HTTPS路由规则,它工作在七层(应用层),可以根据域名和路径将流量分发到不同的Service。

Ingress的工作原理

Ingress资源本身只是一组路由规则的定义,真正执行路由的是Ingress Controller(如Nginx Ingress Controller、Traefik等)。这是很多初学者容易混淆的地方。

部署流程:

  1. 首先在集群中安装Ingress Controller
  2. 创建Ingress资源定义路由规则
  3. Ingress Controller监听Ingress资源变化并更新配置

Ingress配置示例

基于域名和路径的路由:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080
      - path: /web
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
  - host: admin.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-service
            port:
              number: 3000

配置TLS证书:

spec:
  tls:
  - hosts:
    - app.example.com
    secretName: app-tls-secret
  rules:
  - host: app.example.com
    # ...

这里需要注意pathType字段,Kubernetes 1.18+引入了三种类型:

  • Prefix:前缀匹配
  • Exact:精确匹配
  • ImplementationSpecific:由Ingress Controller决定

Deployment工作负载管理

Deployment是Kubernetes中最常用的工作负载资源,它提供了声明式的Pod更新和回滚能力。在我的实践中,几乎所有的无状态应用都应该使用Deployment来管理。

核心功能

  1. 副本管理:维护指定数量的Pod副本
  2. 滚动更新:零停机更新应用版本
  3. 版本回滚:快速回退到之前的版本
  4. 扩缩容:动态调整Pod数量

常用操作命令

# 创建Deployment
kubectl create deployment nginx --image=nginx:1.21 --replicas=3

# 扩缩容
kubectl scale deployment nginx --replicas=5

# 查看滚动更新状态
kubectl rollout status deployment nginx

# 更新镜像(触发滚动更新)
kubectl set image deployment nginx nginx=nginx:1.22

# 查看历史版本
kubectl rollout history deployment nginx

# 回滚到上一个版本
kubectl rollout undo deployment nginx

# 回滚到指定版本
kubectl rollout undo deployment nginx --to-revision=2

# 暂停/恢复滚动更新
kubectl rollout pause deployment nginx
kubectl rollout resume deployment nginx

更新策略配置

Deployment支持两种更新策略,考试中经常需要配置这些参数:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # 滚动更新时最多可以超出replicas的Pod数量
      maxUnavailable: 0  # 滚动更新时最多允许多少个Pod不可用
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.21
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"

这里的maxSurgemaxUnavailable是控制滚动更新速度的关键参数,在生产环境中需要根据实际情况调优。

Pod调度与配置

Pod是Kubernetes中最小的调度单元。在备考过程中,我发现Pod调度是一个既实用又容易出题的知识点,需要掌握三种主要的调度方式。

Pod调度的三种机制

1. NodeSelector(标签选择)

最简单的调度方式,通过Node标签来指定Pod运行的节点:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeSelector:
    disktype: ssd
    env: production
  containers:
  - name: nginx
    image: nginx

Node标签管理命令:

# 添加标签
kubectl label nodes k8s-node01 disktype=ssd

# 查看所有节点标签
kubectl get nodes --show-labels

# 查看指定节点标签
kubectl get node k8s-node01 --show-labels

# 删除标签(注意label key后面的减号)
kubectl label nodes k8s-node01 disktype-

# 修改标签(需要--overwrite参数)
kubectl label nodes k8s-node01 disktype=hdd --overwrite

2. Taint与Toleration(污点与容忍)

Taint是给Node打上"污点",只有能容忍这个污点的Pod才能被调度到该Node上。这是一种"排斥"机制:

# 给Node添加污点
kubectl taint nodes k8s-node01 key=value:NoSchedule

# 查看Node的污点
kubectl describe node k8s-node01 | grep Taint

# 删除污点
kubectl taint nodes k8s-node01 key:NoSchedule-

污点的三种效果:

  • NoSchedule:不会调度新Pod到该Node
  • PreferNoSchedule:尽量不调度,但不是强制
  • NoExecute:不仅不调度新Pod,还会驱逐已有的Pod

在Pod中容忍污点:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  tolerations:
  - key: "key"
    operator: "Equal"
    value: "value"
    effect: "NoSchedule"
  containers:
  - name: nginx
    image: nginx

3. Affinity(亲和性)

Affinity提供了更灵活的调度规则,支持硬性要求(required)和软性偏好(preferred):

NodeAffinity示例

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd
            - nvme
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: zone
            operator: In
            values:
            - zone-a
  containers:
  - name: nginx
    image: nginx

PodAffinity示例(将相关Pod调度到同一节点):

apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - cache
        topologyKey: kubernetes.io/hostname
  containers:
  - name: web
    image: nginx

这个配置会将web Pod调度到已经运行了app=cache标签的Pod所在的节点上。

Pod配置要点

在考试中经常需要快速编写Pod YAML,这些是关键字段:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
  namespace: default
  labels:
    app: my-app
    tier: frontend
spec:
  # 调度相关
  nodeSelector:
    disktype: ssd
  # 资源限制
  containers:
  - name: app
    image: nginx:1.21
    ports:
    - containerPort: 80
    resources:
      requests:
        memory: "128Mi"
        cpu: "100m"
      limits:
        memory: "256Mi"
        cpu: "200m"
    # 环境变量
    env:
    - name: ENV_VAR
      value: "production"
    # 存储挂载
    volumeMounts:
    - name: data
      mountPath: /data
  # 存储卷定义
  volumes:
  - name: data
    emptyDir: {}
  # 重启策略
  restartPolicy: Always

持久化存储PV/PVC

存储管理是Kubernetes中相对复杂的部分,涉及PV、PVC、StorageClass三个层次的抽象。在我的理解中,这是一个典型的"解耦"设计。

存储抽象层次

  1. PV(PersistentVolume):集群级别的存储资源,由管理员创建或通过StorageClass动态创建
  2. PVC(PersistentVolumeClaim):用户对存储的请求,描述需要的容量和访问模式
  3. StorageClass:存储类,用于动态创建PV的模板

静态PV创建流程

创建PV

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-data
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  hostPath:
    path: /data/pv-data

访问模式说明:

  • ReadWriteOnce (RWO):单节点读写
  • ReadOnlyMany (ROX):多节点只读
  • ReadWriteMany (RWX):多节点读写

回收策略:

  • Retain:保留数据,需要手动清理
  • Delete:删除PVC时自动删除PV和底层存储
  • Recycle:已废弃,不推荐使用

创建PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-data
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: manual

在Pod中使用PVC

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: nginx
    volumeMounts:
    - name: data
      mountPath: /usr/share/nginx/html
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: pvc-data

动态存储配置

在生产环境中,更常用的是通过StorageClass动态创建PV:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-storage
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp3
  iopsPerGB: "10"

用户创建PVC时指定storageClassName,系统会自动创建对应的PV。

容量扩展

Kubernetes 1.11+支持在线扩容PVC(前提是StorageClass的allowVolumeExpansion设置为true):

# 编辑PVC,修改storage容量
kubectl edit pvc pvc-data

# 查看扩容状态
kubectl describe pvc pvc-data

这里需要注意的是,不是所有存储后端都支持在线扩容,hostPath类型就不支持。

多容器Pod与Sidecar模式

Sidecar模式是Kubernetes中一种常见的设计模式,通过在Pod中运行辅助容器来增强主容器的功能。考试中经常会考察多容器Pod的配置。

Sidecar典型应用场景

  1. 日志收集:Sidecar容器收集主容器的日志并发送到日志系统
  2. 代理网关:如Service Mesh中的Envoy Sidecar
  3. 配置热更新:监听配置变化并通知主容器
  4. 数据同步:定期同步外部数据到共享存储

多容器Pod示例

一个带日志收集Sidecar的Pod配置:

apiVersion: v1
kind: Pod
metadata:
  name: app-with-sidecar
spec:
  containers:
  # 主应用容器
  - name: app
    image: nginx
    volumeMounts:
    - name: logs
      mountPath: /var/log/nginx
  # Sidecar日志收集容器
  - name: log-collector
    image: busybox
    command: ['sh', '-c', 'tail -f /var/log/nginx/access.log']
    volumeMounts:
    - name: logs
      mountPath: /var/log/nginx
  # 共享存储卷
  volumes:
  - name: logs
    emptyDir: {}

从运行中的Pod提取配置

在考试中,如果需要基于已有Pod创建Sidecar配置,可以先导出YAML再编辑:

# 导出Pod配置
kubectl get pod app -o yaml > app.yaml

# 编辑文件,添加Sidecar容器
vim app.yaml

# 删除旧Pod并创建新Pod
kubectl delete pod app
kubectl apply -f app.yaml

这里需要注意删除导出YAML中的status、resourceVersion等运行时字段。

经过CKA考试的备考和实战,我对Kubernetes的理解上了一个台阶。考试本身不难,但它确实是一个很好的学习驱动力,强迫你系统化地掌握Kubernetes的核心概念。

备考建议

  1. 动手实践优先:理论知识要通过实操来巩固,搭建一个本地集群(kubeadm、k3s或minikube都可以)反复练习
  2. 熟悉文档结构:考试允许查文档,但你需要知道去哪里查,提前整理好常用页面的书签
  3. 时间管理:2小时15-20道题,平均每题6-8分钟,遇到难题先跳过,确保简单题不失分
  4. 验证结果:每做完一题都要验证,检查Pod状态、Service Endpoints、日志输出等

核心收获

通过这次学习,我最大的收获不是通过了考试,而是真正理解了Kubernetes的设计哲学:

通过声明式API和控制器模式,实现了复杂分布式系统的自动化管理。

这种理念可以应用到很多其他系统的设计中。在后续的Homelab实践中,我会继续深入Kubernetes的网络、存储、安全等高级主题。

就这样!希望这篇文章能够帮助到正在备考CKA或学习Kubernetes的朋友。