Files
Qiniu/technical/xinfra-preview/k8s-rke2-fundamentals.md
T

14 KiB
Raw Blame History

tags, create time
tags create time
k8s
rke2
preview
infra
2026-07-04 12:00

K8s + RKE2 基础

概述

Kubernetes(K8s)是容器编排的事实标准,Rancher RKE2 是 CNCF 认证的轻量级、安全优先的 K8s 发行版,专为边缘和混合云场景设计。xinfra 平台的容器调度底层基于 RKE2,后续所有服务部署都建立在对这个知识栈的理解之上。

核心概念

Kubernetes 核心对象关系

graph TD
    Node[Node / 节点] --> Pod[Pod / 最小部署单元]
    Pod --> C[Containers / 容器]
    Deployment[Deployment / 副本控制] --> Pod
    Service[Service / 网络暴露] --> Pod
    Namespace[Namespace / 资源隔离] --> Deployment
    Namespace --> Service
    PV[PersistentVolume / 持久存储] --> PVC[PVC / 申请存储]
    PvcRef[PVC ref by Pod] --> Pod
对象 职责 类比
Node 运行 Pod 的物理机或虚拟机 服务器
Pod 一个或多个容器的打包体 应用实例
Deployment 管理 Pod 的副本数、滚动更新策略 发布控制器
Service 为一组 Pod 提供稳定的访问入口(负载均衡) 反向代理
Namespace 逻辑隔离的资源分组 多租户文件夹
ConfigMap / Secret 将配置注入 Pod(非敏感/敏感数据分离) .env 文件
Ingress 七层路由,HTTP/HTTPS 域名到 Service 的映射 Nginx 规则

RKE2 vs 原生 K8s

RKE2(Rancher Kubernetes Engine v2)的核心特点:

  1. 单二进制部署:不需要单独安装 etcd、containerd 等依赖,一条命令拉起整集群
  2. **SST(Simple System Tray)**内置 SQLite,etcd 作为可选而非必须
  3. FIPS 140-2 合规:内置加密要求,适合企业对安全审计的需要
  4. 自动注册与拉取:可配合 Rancher Server 实现节点无感加入

[!info] 为什么选 RKE2? xinfra 需要管理七机房多套集群,RKE2 的"一键部署 + 低运维成本"特性正好契合——减少环境差异导致的兼容问题,让平台专注于上层抽象而非底层排障。

RKE2 安装方式对比

方式 命令特点 适用场景 是否支持 Rancher 集成
单二进制直接运行 curl → sh(安装脚本直出,无需额外依赖) 开发测试、小规模集群(≤3 节点) ✅ — 自动发现并注册
Systemd 服务管理 systemctl enable --now rke2-server 生产环境标准化部署 ✅
Air-gap(离线) 预下载 .tar.gz 包 + INSTALL_DIR=/opt/rke2 指向本地文件 内网无外网环境的机房 ❌ — 需手动同步镜像

[!warning] Air-gap 是常见坑点 RKE2 Server/Agent 首次启动时会从官方 registry 拉取 K8s 组件 OCI 镜像。如果机房无法访问外网,必须提前准备 image bundle tarball,并通过 --image-volume-mount /var/lib/rancher/rke2/agent/image-store 指定本地缓存路径。

节点注册机制详解

Worker 节点加入集群有两种认证方式:

# 方式 1:静态 Token(最简单,适合小集群)
# 服务端会在 /etc/rancher/rke2/rke2.yaml 旁生成 token
export TOKEN="K10xxx...from server node"
rke2 agent --server https://master-ip:6443 --token $TOKEN

# 方式 2:Bootstrap 证书签名(推荐,支持 TLS 双向认证)
# Agent 首次连接时发送 CSR(Certificate Signing Request),
# kube-controller-manager 审批后颁发客户端证书

关键文件分布:

路径 内容 说明
/etc/rancher/rke2/rke2.yaml kubeconfig(含 admin 权限证书) ⚠️ 等同于集群 master key,务必备份保护
/var/lib/rancher/rke2/agent/ 容器镜像、kubelet 证书 Agent 工作目录
/var/lib/rancher/rke2/server/ etcd 数据、控制平面组件 Server 工作目录
/var/lib/rancher/rke2/bin/ rke2、kubectl、crictl 等 可执行文件软链到原位置

RKE2 配置管理

RKE2 支持多种配置来源,优先级从低到高:

# 1. 系统级配置(最低优先级)
# /etc/rancher/rke2/config.yaml
tls-san:
  - "k8s.company.com"
cluster-cidr: 10.42.0.0/16
service-cidr: 10.43.0.0/16

# 2. Systemd Override(覆盖默认 service 参数)
# /etc/systemd/system/rke2-server.service.d/override.conf
[Service]
Environment="RKE2_TOKEN=${TOKEN}"
Environment="NODE_LABEL=node-role=true,datacenter=bj"

# 3. CLI 参数(最高优先级,覆盖 config.yaml)
# systemctl start rke2-server --token=TOKEN --cluster-cidr=10.42.0.0/16

[!tip] 自定义 CNI 插件 RKE2 默认使用 Canal(Calico + Flannel 组合)。如果需要更换为 Cilium,只需在 config.yaml 中添加:

cni: cilium

重新拉起 Server 即可自动替换网络方案——这是 RKE2 比原生 K8s 更省心的地方:网络方案可以配置驱动,而不是代码依赖。

RKE2 集群架构

graph TB
    subgraph "Master Node(控制平面)"
        RKE2[RKE2 Server<br/>rke2 server --token=TOKEN]
        APIServer[Kube-apiserver]
        ControllerMgr[Kube-controller-manager]
        Scheduler[Kube-scheduler]
        ETCD[(etcd DB)]
        CCM[Cloud Controller Manager]
        APIServer --> ControllerMgr
        APIServer --> Scheduler
        APIServer <--> ETCD
        RKE2 --> APIServer
        RKE2 --> ControllerMgr
        RKE2 --> Scheduler
        RKE2 --> ETCD
        RKE2 --> CCM
    end

    subgraph "Worker Node(工作节点)"
        RKE2W[RKE2 Agent<br/>rke2 agent --server=https://MASTER_IP:6443 --token=TOKEN]
        Kubelet1[Kubelet]
        KubeProxy1[Kube-proxy]
        Containerd1[containerd]
        RKE2W --> Kubelet1
        RKE2W --> KubeProxy1
        RKE2W --> Containerd1
    end

    Dev[kubectl / Wayne API] --> APIServer
    APIServer -. kubeconfig .-> RKE2W
    Kubelet1 -. etcd sync .-> ETCD

关键流程说明:

  1. RKE2 Server 启动后会自动拉取对应 K8s 版本的组件包(kube-apiserver、controller-manager 等),解压到 /var/lib/rancher/rke2/,通过 systemd 管理运行
  2. Agent 节点只需传入 --token(静态认证令牌)和 --server URL,即可自动完成 TLS 证书握手并加入集群
  3. 默认使用 containerd 作为容器运行时——无需单独安装 Docker,这也是 RKE2 比 k3s 更"正规"的原因之一

Pod 生命周期与调度流程

Pod 从创建到运行的完整链路:

sequenceDiagram
    participant user as 开发者 (kubectl/Wayne)
    participant apiserver as kube-apiserver
    participant scheduler as kube-scheduler
    participant node as Node Kubelet
    participant containerd as containerd

    user->>apiserver: POST /api/v1/namespaces/default/pods
    apiserver->>apiserver: 验证 RBAC + 持久化到 etcd
    Note over apiserver: Pod 状态 = Pending
    apiserver-->>user: 201 Created

    scheduler->>apiserver: LIST pods (unassigned)
    scheduler->>scheduler: 预选 (Fit) → 优先级排序 (Score)
    scheduler->>apiserver: PATCH pod -> set nodeName
    Note over apiserver: Pod 状态仍为 Pending(等待 Kubelet 响应)

    apiserver-->>node: WATCH pod assigned to this node
    node->>containerd: Pull image (if not cached)
    node->>containerd: Create container
    node->>node: Set readinessProbe
    Note over node: Pod 状态 = Running
    node->>apiserver: UPDATE pod status

启发问题:为什么调度器选中节点后,Pod 不会立即变成 Running,而还需要 Kubelet 配合?——因为调度器只负责"选地址",真正的镜像拉取、容器创建、网络挂载都由 Kubelet 在本机完成。这体现了控制面与数据面的职责分离。

典型部署流程

# 1. 编写 Deployment YAML
kubectl apply -f deployment.yaml

# 2. 编写 Service YAML
kubectl apply -f service.yaml

# 3. 查看状态
kubectl get pods -n <namespace>
kubectl describe pod <pod-name> -n <namespace>

# 4. 滚动更新(改镜像版本)
kubectl set image deployment/<name> app=<new-image> -n <namespace>
kubectl rollout status deployment/<name> -n <namespace>

Deployment YAML 骨架:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-service
  namespace: default
spec:
  replicas: 3                    # 期望副本数
  strategy:
    type: RollingUpdate          # 滚动更新策略
    rollingUpdate:
      maxSurge: 1                # 更新时最多比期望多 1 个 Pod
      maxUnavailable: 0          # 更新时不允许不可用
  selector:
    matchLabels:
      app: my-service
  template:                      # Pod 模板
    metadata:
      labels:
        app: my-service
    spec:
      containers:
      - name: app
        image: registry/my-service:v1.2.0
        ports:
        - containerPort: 8080

Service 类型详解

Service 是 Pod 的"稳定门面",不同 type 决定了流量如何到达 Pod:

type 工作原理 适用场景
ClusterIP(默认) K8s 内部虚拟 IP,仅集群内可访问 服务间调用,不对外暴露
NodePort 在每个节点上开放一个端口,外部可通过 <NodeIP>:<port> 访问 快速测试、开发环境验证
LoadBalancer 对接云厂商 LB 自动创建公网 IP 云上生产环境
Ingress 七层路由,基于域名/路径分发到不同 Service 多服务共享入口,HTTPS 终结

[!warning] NodePort vs Ingress NodePort 只做到四层 TCP/UDP 负载均衡——无法按域名路由。如果你的应用需要 api.example.com → Service-A、web.example.com → Service-B 这种能力,必须用 Ingress。xinfra 中通常配合 Nginx Ingress Controller 使用。

Ingress 示例:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-service-ingress
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"   # 强制 HTTPS
spec:
  rules:
  - host: api.myapp.company.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-service       # 对应 ClusterIP Service
            port:
              number: 80

kubectl 速查手册

日常运维最高频的命令组合:

# ── 查看 ──
kubectl get pods -A                                          # 所有 namespace 的 Pod
kubectl get svc,ingress -n prod                              # 查看 Service + Ingress
kubectl top pod -n staging --containers                      # 容器级 CPU/Memory 用量

# ── 调试 ──
kubectl exec -it <pod> -- /bin/sh                            # 进入容器 Shell
kubectl logs -f <pod> -c <sidecar-name> -n ns                # 查看指定 Sidecar 日志
kubectl describe pod <pod> -n ns                             # 查看详细事件(调度失败原因等)

# ── 资源操作 ──
kubectl rollout undo deployment/<name> -n ns                 # 回滚到上一版本
kubectl scale deployment/<name> --replicas=5 -n ns           # 手动扩缩容
kubectl patch deployment/<name> -p '{"spec":{"template":{"spec":{"containers":[{"name":"app","image":"new:v2"}]}}}}' -n ns  # 热更新镜像

[!tip] -A 标志 = --all-namespaces,当你不确定资源在哪个 namespace 时非常有用。但正式脚本中不建议滥用,容易造成误操作。

详见 k8s-rke2-fundamentals/core-objects-quiz — 覆盖 Pod 生命周期、Service 类型、探针机制等核心考点的 10 道选择题自测。


常见陷阱与最佳实践

1. Resource Limit 缺失

不设置 resources.limits 的 Pod 在节点资源紧张时会抢占其他 Pod 资源,导致雪崩:

# 推荐:每个容器都要设请求值和上限
containers:
- name: app
  resources:
    requests: { cpu: "100m", memory: "128Mi" }   # 调度依据
    limits:     { cpu: "500m", memory: "512Mi" }   # 硬上限

2. Liveness vs Readiness 混淆

  • livenessProbe:判断容器是否"活着",失败则重启 Pod
  • readinessProbe:判断容器能否接收流量,失败则从 Service 后端摘除
# 正确姿势:两个都设,readiness 更激进(快判快入),liveness 更保守
readinessProbe:
  httpGet: { path: /healthz, port: 8080 }
  initialDelaySeconds: 3
  periodSeconds: 5
livenessProbe:
  httpGet: { path: /healthz, port: 8080 }
  initialDelaySeconds: 15
  periodSeconds: 10

3. 频繁查看日志的习惯

# 实时跟踪单个 Pod 日志
kubectl logs -f <pod-name> -n <namespace>

# 如果是重启过的 Pod,看上一次容器的日志
kubectl logs -f <pod-name> -n <namespace> --previous

4. CrashLoopBackOff — 最常见的 Pod 异常状态

Pod 反复崩溃重启时,排查顺序如下:

flowchart TD
    S[CrashLoopBackOff] --> C1{kubectl describe pod<br/>看 REASON}
    C1 -->|ImagePullBackOff| I1[检查镜像仓库可达性 + ImagePullSecrets]
    C1 -->|OOMKilled| M1[调大 memory limit / 排查内存泄漏]
    C1 -->|CreateContainerConfigError| CM1[检查 ConfigMap/Secret 是否存在]
    C1 -->|ErrImagePull| E1[镜像 tag 错误或 registry 认证失败]

    C1 -->|Initialized/Ready/-/Running| LOGS[kubectl logs -p]
    LOGS --> APP[应用自身启动失败?]
    APP -->|Yes| FIX[检查启动参数 + 依赖服务连接性]
    APP -->|No| DEEP[深入 containerd/containerd-shim 日志]

5. Ingress 404 或无法访问

开发环境常见"Service 存在但外部打不通"的问题,排查清单:

  1. Nginx Ingress Controller Pod 是否 Running → kubectl get pods -n ingress-nginx
  2. Ingress 资源是否有 loadBalancer.ip → kubectl get ingress -n <ns>(若无 IP,可能云厂商 LB 未就绪)
  3. Endpoint 是否有地址 → kubectl get endpoints <service-name> -n <ns>(为空说明没有 Ready 的 Pod 匹配)
  4. DNS 解析是否正确 → 内网环境可能需要手动配置 hosts 或使用 CoreDNS

关联笔记

以下文档构成了 xinfra 容器化部署的知识链: