14 KiB
tags, create time
| tags | create time | ||||
|---|---|---|---|---|---|
|
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)的核心特点:
- 单二进制部署:不需要单独安装 etcd、containerd 等依赖,一条命令拉起整集群
- **SST(Simple System Tray)**内置 SQLite,etcd 作为可选而非必须
- FIPS 140-2 合规:内置加密要求,适合企业对安全审计的需要
- 自动注册与拉取:可配合 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
关键流程说明:
- RKE2 Server 启动后会自动拉取对应 K8s 版本的组件包(kube-apiserver、controller-manager 等),解压到
/var/lib/rancher/rke2/,通过 systemd 管理运行 - Agent 节点只需传入
--token(静态认证令牌)和--serverURL,即可自动完成 TLS 证书握手并加入集群 - 默认使用 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 时非常有用。但正式脚本中不建议滥用,容易造成误操作。
常见陷阱与最佳实践
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 存在但外部打不通"的问题,排查清单:
- Nginx Ingress Controller Pod 是否 Running →
kubectl get pods -n ingress-nginx - Ingress 资源是否有
loadBalancer.ip→kubectl get ingress -n <ns>(若无 IP,可能云厂商 LB 未就绪) - Endpoint 是否有地址 →
kubectl get endpoints <service-name> -n <ns>(为空说明没有 Ready 的 Pod 匹配) - DNS 解析是否正确 → 内网环境可能需要手动配置 hosts 或使用 CoreDNS
关联笔记
以下文档构成了 xinfra 容器化部署的知识链:
- technical/xinfra-preview/wayne-overview — Wayne 上层的 YAML 模板就是基于这些 K8s 对象
- technical/xinfra-preview/cachecloud-overview — CacheCloud 管理 Redis,其宿主机未来可能迁移至 K8s 部署
- technical/xinfra-preview/cloud-dm-overview — K8s 内的 MySQL 实例由 CloudDM 做 SQL 审核
- technical/xinfra-preview/ansible-playbook-basics — Ansible Playbook 负责 RKE2 集群的底层裸机/VMAutomation