378 lines
14 KiB
Markdown
378 lines
14 KiB
Markdown
---
|
||
tags: [k8s, rke2, preview, infra]
|
||
create time: 2026-07-04 12:00
|
||
---
|
||
|
||
# K8s + RKE2 基础
|
||
|
||
## 概述
|
||
|
||
Kubernetes(K8s)是容器编排的事实标准,Rancher RKE2 是 CNCF 认证的轻量级、安全优先的 K8s 发行版,专为边缘和混合云场景设计。xinfra 平台的容器调度底层基于 RKE2,后续所有服务部署都建立在对这个知识栈的理解之上。
|
||
|
||
## 核心概念
|
||
|
||
### Kubernetes 核心对象关系
|
||
|
||
```mermaid
|
||
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 节点加入集群有两种认证方式:
|
||
|
||
```bash
|
||
# 方式 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 支持多种配置来源,优先级从低到高:
|
||
|
||
```yaml
|
||
# 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` 中添加:
|
||
> ```yaml
|
||
> cni: cilium
|
||
> ```
|
||
> 重新拉起 Server 即可自动替换网络方案——这是 RKE2 比原生 K8s 更省心的地方:**网络方案可以配置驱动,而不是代码依赖**。
|
||
|
||
### RKE2 集群架构
|
||
|
||
```mermaid
|
||
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 从创建到运行的完整链路:
|
||
|
||
```mermaid
|
||
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 在本机完成。这体现了**控制面与数据面的职责分离**。
|
||
|
||
### 典型部署流程
|
||
|
||
```bash
|
||
# 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 骨架:**
|
||
|
||
```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 示例:**
|
||
|
||
```yaml
|
||
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 速查手册
|
||
|
||
日常运维最高频的命令组合:
|
||
|
||
```bash
|
||
# ── 查看 ──
|
||
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 资源,导致雪崩:
|
||
|
||
```yaml
|
||
# 推荐:每个容器都要设请求值和上限
|
||
containers:
|
||
- name: app
|
||
resources:
|
||
requests: { cpu: "100m", memory: "128Mi" } # 调度依据
|
||
limits: { cpu: "500m", memory: "512Mi" } # 硬上限
|
||
```
|
||
|
||
### 2. Liveness vs Readiness 混淆
|
||
|
||
- **livenessProbe**:判断容器是否"活着",失败则重启 Pod
|
||
- **readinessProbe**:判断容器能否接收流量,失败则从 Service 后端摘除
|
||
|
||
```yaml
|
||
# 正确姿势:两个都设,readiness 更激进(快判快入),liveness 更保守
|
||
readinessProbe:
|
||
httpGet: { path: /healthz, port: 8080 }
|
||
initialDelaySeconds: 3
|
||
periodSeconds: 5
|
||
livenessProbe:
|
||
httpGet: { path: /healthz, port: 8080 }
|
||
initialDelaySeconds: 15
|
||
periodSeconds: 10
|
||
```
|
||
|
||
### 3. 频繁查看日志的习惯
|
||
|
||
```bash
|
||
# 实时跟踪单个 Pod 日志
|
||
kubectl logs -f <pod-name> -n <namespace>
|
||
|
||
# 如果是重启过的 Pod,看上一次容器的日志
|
||
kubectl logs -f <pod-name> -n <namespace> --previous
|
||
```
|
||
|
||
### 4. CrashLoopBackOff — 最常见的 Pod 异常状态
|
||
|
||
Pod 反复崩溃重启时,排查顺序如下:
|
||
|
||
```mermaid
|
||
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 容器化部署的知识链:
|
||
|
||
- [[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
|