从零搭建 Kubernetes 集群并部署 Kuboard v3 管理面板 ------ 国内环境完整实战教程
作者 :实战运维团队 | 环境 :ecs-2c98 四节点集群 | 软件版本 :K8s v1.32.13 + Kuboard v3 + containerd 2.2.1 + Flannel v0.28.5
更新日期 :2025年
阅读时长 :约 60 分钟 | 实战时长:约 90 分钟
📋 目录 (Table of Contents)
| 章节 | 标题 | 内容概览 |
|---|---|---|
| 第一篇 | Kuboard 与 Kubernetes 入门 | 概念、对比、架构设计 |
| 第1章 | Kuboard 概述 | 产品定位、与 K8s Dashboard 对比、功能特点 |
| 第2章 | 环境准备与架构设计 | 集群规划、端口规划、ASCII 架构图 |
| 第二篇 | Kubernetes 集群搭建 | 从裸机到 Ready 集群 |
| 第3章 | 系统环境初始化 | hosts、swap、内核模块、sysctl |
| 第4章 | 容器运行时 containerd 安装配置 | 安装、配置、SystemdCgroup |
| 第5章 | kubeadm/kubelet/kubectl 安装 | 版本锁定、组件说明 |
| 第6章 | Master 节点初始化与 kubeadm init | 阿里云镜像加速、初始化输出解读 |
| 第7章 | CNI 网络插件 Flannel 部署 | 国内镜像拉取踩坑、Flannel 原理 |
| 第8章 | Worker 节点加入集群 | token 管理、join 命令复用 |
| 第三篇 | Kuboard 部署与使用 | 管理面板实战 |
| 第9章 | Kuboard v3 部署 | 华为云 SWR 镜像、K8s Deployment + NodePort |
| 第10章 | Kuboard 界面实战 | 集群导入、工作负载管理、监控 |
| 第四篇 | 踩坑与最佳实践 | 血泪经验总结 |
| 第11章 | 国内镜像加速方案汇总 | registry.aliyuncs.com、hub.rat.dev、中科大镜像 |
| 第12章 | 常见问题排查指南 | Pod 排错、网络排错、kubeadm 排错 |
| 附录 | 速查表与配置详解 | 命令速查、containerd 配置、YAML 模板 |
第一篇:Kuboard 与 Kubernetes 入门
第1章:Kuboard 概述
1.1 什么是 Kuboard?(What is Kuboard?)
Kuboard 是一款国产的 Kubernetes 多集群管理面板,提供了比官方 Kubernetes Dashboard 更贴近国内用户使用习惯的图形化界面。它基于 Kubernetes 的 kubectl proxy 模式工作,通过读取 K8s API Server 的数据进行可视化展示和管理。
核心定位:
- 🎯 多集群管理:一个 Kuboard 实例可管理多个 K8s 集群
- 🎯 审计与权限:内置 RBAC 可视化管理,支持 LDAP/AD 集成
- 🎯 国产化适配:中文界面、华为云 SWR 镜像加速、国内网络友好
小知识 :Kuboard 的作者是中国开发者,官网
kuboard.cn在国内访问速度极快,文档也是全中文的,对国内运维工程师非常友好。
1.2 Kuboard v3 核心功能
| 功能模块 | 功能描述 | 对应 K8s 对象 |
|---|---|---|
| 集群概览 | 节点状态、Pod 运行数、资源使用率仪表盘 | Node, Pod, Metrics |
| 工作负载 | Deployment / StatefulSet / DaemonSet / Job / CronJob 管理 | Workload API |
| 服务与路由 | Service / Ingress 可视化配置 | Service, Ingress |
| 配置管理 | ConfigMap / Secret 创建与编辑 | ConfigMap, Secret |
| 存储管理 | PV / PVC / StorageClass 管理 | Storage API |
| 命名空间 | Namespace 资源配额 (ResourceQuota) 管理 | Namespace, ResourceQuota |
| 集群导入 | 通过 kubeconfig 或 Token 导入外部集群 | -- |
| 审计日志 | 操作记录与变更追踪 | Event + Audit Log |
1.3 Kuboard vs Kubernetes Dashboard 对比
| 对比维度 | Kubernetes Dashboard | Kuboard v3 |
|---|---|---|
| 界面语言 | 英文为主,中文非官方翻译 | ✅ 全中文原生支持 |
| 多集群管理 | ❌ 每个集群需独立部署 | ✅ 一个实例管理多集群 |
| 权限管理 (RBAC) | 基础支持,配置复杂 | ✅ 图形化 RBAC 管理 |
| 审计日志 | ❌ 无内置审计 | ✅ 内置操作审计 |
| LDAP/AD 集成 | 需额外配置 | ✅ 原生支持 |
| 微服务视图 | ❌ 无 | ✅ 支持以应用为中心视图 |
| 部署方式 | YAML 手动部署 | ✅ 支持 K8s YAML / Docker Compose |
| 镜像来源 | registry.k8s.io (国外) | ✅ SWR 华为云镜像 (国内加速) |
| 文档 | 英文官方文档 | ✅ 中文详细文档 + 视频教程 |
| 活跃度 | CNCF 官方维护 | 社区活跃,更新频繁 |
| 适合人群 | K8s 资深用户 | 国内运维、DevOps 团队 |
结论 :如果你在国内生产环境使用 K8s,Kuboard 的中文界面 + 国内镜像加速 + 多集群管理是显著优势;如果你在国际环境或需要 CNCF 官方认证工具,Dashboard 更合适。
1.4 Kuboard 架构原理
┌─────────────────────────────────────────────────────────────┐
│ Browser (浏览器) │
│ http://<NodeIP>:30080 │
└──────────────────────────┬──────────────────────────────────┘
│ HTTP
▼
┌─────────────────────────────────────────────────────────────┐
│ Kuboard Pod (Deployment) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ kuboard (Go Backend + Vue Frontend) │ │
│ │ - 读取 kubeconfig 访问 API Server │ │
│ │ - 提供 Web UI 服务 (端口 80) │ │
│ │ - 管理多个集群的连接信息 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Service: kuboard (NodePort 30080) │
└──────────────────────────┬──────────────────────────────────┘
│ kubeconfig / Token
▼
┌─────────────────────────────────────────────────────────────┐
│ Kubernetes API Server │
│ (https://:6443) │
└─────────────────────────────────────────────────────────────┘
关键点:
- Kuboard 本身以 Pod 形式运行在 K8s 集群内(也可以跑在集群外)
- 通过 kubeconfig 文件 或 ServiceAccount Token 连接目标集群的 API Server
- Kuboard 的 Go 后端 代理所有 kubectl 操作,Vue 前端 提供 UI
- NodePort
30080是访问入口,默认账号admin,密码Kuboard123
第2章:环境准备与架构设计
2.1 集群规划 (Cluster Planning)
本次实战使用 4 台华为云 ECS 弹性云服务器 (实例类型 ecs-2c98),具体规划如下:
| 节点主机名 | 节点别名 | 角色 (Role) | 公网 IP (Public IP) | 私网 IP (Private IP) | 配置 |
|---|---|---|---|---|---|
kuboard-01 |
ecs-2c98-0001 | Master + Kuboard | 120.46.195.39 |
192.168.0.85 |
2vCPU / 4GiB (ac9.large.2) |
kuboard-02 |
ecs-2c98-0002 | Worker-1 | 120.46.32.153 |
192.168.0.28 |
同上 |
kuboard-03 |
ecs-2c98-0003 | Worker-2 | 1.94.204.169 |
192.168.0.153 |
同上 |
kuboard-04 |
ecs-2c98-0004 | Worker-3 | 120.46.129.80 |
192.168.0.51 |
同上 |
为什么只有 1 个 Master? 生产环境推荐 3 Master 节点做高可用(etcd 奇数节点),但本次为实战教程,单 Master 足以演示完整流程。后续可扩展为多 Master。
2.2 整体架构 ASCII 图
┌──────────────────────────────────┐
│ Internet (公网访问) │
│ │
│ 访问 Kuboard: │
│ http://120.46.195.39:30080 │
└──────────────┬───────────────────┘
│
│ NodePort 30080
▼
┌──────────────────────────────────────────────────────────────────────────────┐
│ Kubernetes Cluster (ecs-2c98) │
│ │
│ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────┐ │
│ │ Master Node │ │ Worker Node 1 │ │ Worker Node 2 │ │
│ │ kuboard-01 │ │ kuboard-02 │ │ kuboard-03 │ │
│ │ │ │ │ │ │ │
│ │ ┌───────────────┐ │ │ ┌───────────────┐ │ │ ┌───────────┐ │ │
│ │ │ Control Plane │ │ │ │ kubelet │ │ │ │ kubelet │ │ │
│ │ │ │ │ │ │ kube-proxy │ │ │ │ kube-proxy│ │ │
│ │ │ - API Server │◄─┼────┼──┤ (Pod Net) │ │ │ │ (Pod Net) │ │ │
│ │ │ - etcd │ │ │ │ │ │ │ │ │ │ │
│ │ │ - Scheduler │ │ │ │ [User Pods] │ │ │ │ [User Pods]│ │ │
│ │ │ - Controller │ │ │ └───────────────┘ │ │ └───────────┘ │ │
│ │ └───────────────┘ │ └─────────────────────┘ └─────────────────┘ │
│ │ ┌───────────────┐ │ │
│ │ │ Kuboard │ │ ┌─────────────────────┐ │
│ │ │ (Pod) │ │ │ Worker Node 3 │ │
│ │ │ Port: 80 │ │ │ kuboard-04 │ │
│ │ └───────────────┘ │ │ │ │
│ └─────────────────────┘ │ ┌───────────────┐ │ │
│ ▲ │ │ kubelet │ │ │
│ │ kubeconfig │ │ kube-proxy │ │ │
│ │ │ │ (Pod Net) │ │ │
│ │ │ └───────────────┘ │ │
│ │ └─────────────────────┘ │
│ ┌─────┴─────────────┐ │
│ │ Admin Laptop │ │
│ │ (运维工程师电脑) │ │
│ │ kubectl + SSH │ │
│ └───────────────────┘ │
│ │
│ Flannel CNI: Pod CIDR 10.244.0.0/16 (每个 Node 分配一个 /24 子网) │
│ Service CIDR: 10.96.0.0/12 (kubeadm 默认) │
└──────────────────────────────────────────────────────────────────────────────┘
Legend (图例):
█ Control Plane 组件 (Master 专属)
░ Worker 组件 (工作节点)
↔ Pod 网络 (Flannel Overlay Network)
2.3 网络规划 (Network Planning)
Kubernetes 网络模型有三层:
| 网络层 | CIDR | 说明 |
|---|---|---|
| Node Network (节点网络) | 192.168.0.0/24 |
华为云 VPC 私网,节点间通信 |
| Pod Network (容器网络) | 10.244.0.0/16 |
Flannel CNI 分配,每个 Node 一个 /24 子网 |
| Service Network (服务网络) | 10.96.0.0/12 |
kubeadm 默认,ClusterIP 分配范围 |
Flannel 子网分配示例(实际分配取决于 Flannel 的 hostgw/VXLAN 模式):
kuboard-01 (Master): Pod CIDR = 10.244.0.0/24
kuboard-02 (Worker): Pod CIDR = 10.244.1.0/24
kuboard-03 (Worker): Pod CIDR = 10.244.2.0/24
kuboard-04 (Worker): Pod CIDR = 10.244.3.0/24
2.4 端口规划与防火墙规则 (Port Planning & Firewall)
2.4.1 Master 节点必需端口
| 协议 | 端口 | 服务 | 说明 |
|---|---|---|---|
| TCP | 6443 |
Kubernetes API Server | 所有节点 和 kubectl 访问 |
| TCP | 2379-2380 |
etcd server/client | 仅 Master 节点间通信(多 Master 时需要) |
| TCP | 10250 |
kubelet API | 所有节点 kubelet 与 API Server 通信 |
| TCP | 10259 |
kube-scheduler | 健康检查(可选外部访问) |
| TCP | 10257 |
kube-controller-manager | 健康检查(可选外部访问) |
| TCP | 30080 |
Kuboard NodePort | 浏览器访问 Kuboard |
| UDP | 8472 |
Flannel VXLAN | Pod 跨节点通信(Overlay 网络) |
2.4.2 Worker 节点必需端口
| 协议 | 端口 | 服务 | 说明 |
|---|---|---|---|
| TCP | 10250 |
kubelet API | API Server → kubelet |
| TCP | 30000-32767 |
NodePort Services | 外部访问 Service |
| UDP | 8472 |
Flannel VXLAN | Pod 跨节点通信 |
| TCP | 30080 |
Kuboard (NodePort) | 所有节点开放,便于高可用访问 |
2.4.3 华为云安全组配置
在华为云控制台,为 ecs-2c98 安全组添加以下入方向规则:
# Master 节点 (kuboard-01)
TCP 6443 0.0.0.0/0 # API Server (建议限制为管理IP)
TCP 30080 0.0.0.0/0 # Kuboard Web UI
TCP 10250 192.168.0.0/24 # kubelet API (仅内网)
UDP 8472 192.168.0.0/24 # Flannel VXLAN (仅内网)
# 所有节点
TCP 10250 192.168.0.0/24
UDP 8472 192.168.0.0/24
TCP 30000-32767 0.0.0.0/0 # NodePort 范围
⚠️ 安全提示 :生产环境请将 API Server (
6443) 的源 IP 限制为运维人员 IP,不要对0.0.0.0/0开放。
2.5 软件版本一览 (Software Versions)
本次实战使用的真实版本数据:
| 组件 | 版本 | 镜像/包来源 | 说明 |
|---|---|---|---|
| OS | Ubuntu 24.04.4 LTS | 华为云公共镜像 | Kernel 6.8.0-106-generic |
| containerd | v2.2.1 | Docker CE 仓库 | SystemdCgroup = true |
| runc | v1.2.4 | 随 containerd 安装 | OCI 运行时 |
| Kubernetes | v1.32.13 | 阿里云 k8s 镜像站 | kubeadm + kubelet + kubectl |
| CNI Plugins | v1.6.2 | GitHub Release | bridge, host-local, lo |
| Flannel | v0.28.5 | ghcr.io/flannel-io/flannel |
Pod CIDR 10.244.0.0/16 |
| Kuboard | v3 | swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard:v3 |
华为云 SWR,约 132MB |
| kubectl | v1.32.13 | 与 K8s 组件版本一致 | 客户端命令行工具 |
为什么选择这些版本?
- K8s v1.32:最新的稳定版(写作时),包含最新安全补丁
- containerd v2 :v2.x 系列配置格式有变化(
config.tomlv2 格式),本章会详细说明- Flannel v0.28.5:与 K8s 1.32 兼容的最新版本
- Kuboard v3:最新稳定版,支持 K8s 1.20+
2.6 准备工作检查清单 (Pre-flight Checklist)
在开始安装前,请确认以下事项:
- 所有节点已创建并可通过 SSH 登录
- 所有节点已配置 root 或 sudo NOPASSWD 权限
- 节点间私网互通(在华为云同 VPC 下默认互通)
- 节点可访问互联网(用于拉取镜像,或已准备离线镜像)
-
swap已关闭(K8s 1.22+ 强制要求,第3章详述) - 防火墙规则已按 2.4 节配置
- 所有节点时间同步 (推荐安装
chrony或ntp) - 准备一个用于保存 kubeconfig 的本地机器(运行 kubectl)
第3章:系统环境初始化
目标:对 4 台服务器进行统一的系统级初始化,为 K8s 安装做好准备。
3.1 设置主机名 (Set Hostnames)
在每台对应节点上执行:
bash
# 在 120.46.195.39 (Master) 上执行
sudo hostnamectl set-hostname kuboard-01
# 在 120.46.32.153 (Worker-1) 上执行
sudo hostnamectl set-hostname kuboard-02
# 在 1.94.204.169 (Worker-2) 上执行
sudo hostnamectl set-hostname kuboard-03
# 在 120.46.129.80 (Worker-3) 上执行
sudo hostnamectl set-hostname kuboard-04
验证:
bash
$ hostname
kuboard-01 # 在 Master 节点上
3.2 配置 /etc/hosts (Configure Hosts File)
在所有节点上执行,确保节点间可以通过主机名互相解析:
bash
cat << 'EOF' | sudo tee -a /etc/hosts
# Kubernetes Cluster Nodes (ecs-2c98)
192.168.0.85 kuboard-01
192.168.0.28 kuboard-02
192.168.0.153 kuboard-03
192.168.0.51 kuboard-04
EOF
验证(在任意节点上):
bash
$ ping -c 2 kuboard-02
PING kuboard-02 (192.168.0.28) 56(84) bytes of data.
64 bytes from kuboard-02 (192.168.0.28): icmp_seq=1 ttl=64 time=0.523 ms
64 bytes from kuboard-02 (192.168.0.28): icmp_seq=2 ttl=64 time=0.341 ms
为什么需要配置 hosts? kubeadm 在某些检查中会使用主机名,且 Flannel 的某些模式(如
host-gw)依赖主机名解析。
3.3 关闭 swap (Disable Swap)
Kubernetes 1.22+ 强制要求关闭 swap,因为 swap 会导致 Pod 的性能不稳定(内存换入换出)。
在所有节点上执行:
bash
# 1. 临时关闭 swap (立即生效)
sudo swapoff -a
# 2. 永久关闭 swap (注释 /etc/fstab 中的 swap 行)
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
验证:
bash
$ free -h
total used free shared buff/cache available
Mem: 3.8Gi 285Mi 3.2Gi 0.0Ki 328Mi 3.3Gi
Swap: 0B 0B 0B # <-- Swap 为 0 表示已关闭
⚠️ 踩坑提示 :如果忘记关闭 swap,
kubeadm init会报错:[ERROR Swap]: running with swap on is not supported. Please disable swap。虽然可以通过--ignore-preflight-errors=Swap跳过,但强烈不推荐在生产环境开启 swap。
3.4 加载内核模块 (Load Kernel Modules)
Kubernetes 需要以下内核模块支持:
br_netfilter:允许 bridged 流量经过 iptables 链(K8s 网络依赖)overlay:Overlay filesystem 支持(容器分层文件系统)ip_vs系列:Kube-proxy IPVS 模式所需(性能优于 iptables 模式)
在所有节点上执行:
bash
# 1. 加载当前所需模块
sudo modprobe overlay
sudo modprobe br_netfilter
sudo modprobe ip_vs
sudo modprobe ip_vs_rr
sudo modprobe ip_vs_wrr
sudo modprobe ip_vs_sh
sudo modprobe nf_conntrack
# 2. 验证模块已加载
lsmod | grep -E 'overlay|br_netfilter|ip_vs'
输出示例:
br_netfilter 32768 0
ip_vs_rr 16384 0
ip_vs 180224 6 ip_vs_rr,ip_vs_sh,ip_vs_wrr
3.4.1 持久化内核模块
确保重启后模块自动加载:
bash
cat << 'EOF' | sudo tee /etc/modules-load.d/k8s.conf
# Kubernetes required kernel modules
overlay
br_netfilter
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
EOF
3.5 配置内核参数 (Configure Kernel Parameters)
K8s 网络需要以下 sysctl 参数:
在所有节点上执行:
bash
cat << 'EOF' | sudo tee /etc/sysctl.d/k8s.conf
# Kubernetes networking requirements
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
# Optional: 优化 TCP 连接
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_tw_reuse = 1
EOF
# 立即生效
sudo sysctl --system
参数说明:
| 参数 | 值 | 说明 |
|---|---|---|
net.bridge.bridge-nf-call-iptables |
1 |
允许 bridge 流量经过 iptables,Kube-proxy 依赖此参数 |
net.bridge.bridge-nf-call-ip6tables |
1 |
同上,针对 IPv6 |
net.ipv4.ip_forward |
1 |
开启 IP 转发,Pod 跨节点通信必须 |
验证:
bash
$ sysctl net.bridge.bridge-nf-call-iptables
net.bridge.bridge-nf-call-iptables = 1
$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
3.6 安装基础工具包 (Install Essential Packages)
在所有节点上执行:
bash
sudo apt-get update
sudo apt-get install -y \
curl \
wget \
apt-transport-https \
ca-certificates \
software-properties-common \
gnupg \
lsb-release \
net-tools \
iproute2 \
ethtool \
conntrack \
ipset \
jq \
vim \
bash-completion
各工具包用途说明:
| 包名 | 用途 |
|---|---|
curl / wget |
下载工具,拉取 GPG 密钥和 YAML 文件 |
apt-transport-https |
允许 apt 通过 HTTPS 下载包 |
ca-certificates |
HTTPS 证书验证 |
gnupg |
GPG 密钥管理,添加 Docker/K8s 仓库时需要 |
iproute2 |
ip 命令,网络管理 |
ethtool |
网卡工具,Flannel 安装时可能用到 |
conntrack |
连接跟踪工具,kube-proxy 依赖 |
ipset |
IP set 工具,kube-proxy IPVS 模式依赖 |
jq |
JSON 解析工具,调试 K8s API 响应 |
3.7 时间同步 (Time Synchronization)
Kubernetes 集群各节点时间必须同步,否则 etcd 会出现问题。
在所有节点上执行:
bash
# 安装 chrony (比 ntp 更现代)
sudo apt-get install -y chrony
# 启动并设置开机自启
sudo systemctl enable chronyd
sudo systemctl start chronyd
# 验证时间同步状态
chronyc sources -v
输出示例:
.-- Source mode '^' = server, '=' = peer, '#' = local clock.
/ .- Source state '*' = current synced, '+' = combined , '-' = not combined,
| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.
|| .- xxxx [ yyyy ] +/- zzzz
|| Reachability flag (Octal) -. | xxxx = adjusted offset,
|| Log2(Polling interval) --. | | yyyy = measured offset,
|| \ | | zzzz = estimated error.
|| | \
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* time.google.com 1 6 17 12 +123us[ +456us] +/- 15ms
3.8 系统初始化验证
完成以上步骤后,在所有节点上执行以下验证脚本:
bash
echo "=== Hostname ==="
hostname
echo -e "\n=== Swap Status ==="
free -h | grep Swap
echo -e "\n=== Kernel Modules ==="
lsmod | grep -E 'overlay|br_netfilter|ip_vs' | wc -l
echo -e "\n=== Sysctl Parameters ==="
sysctl net.bridge.bridge-nf-call-iptables
sysctl net.ipv4.ip_forward
echo -e "\n=== /etc/hosts ==="
grep kuboard /etc/hosts
echo -e "\n=== Time Sync ==="
timedatectl status | grep "System clock synchronized"
预期输出(所有节点应通过):
=== Hostname ===
kuboard-01 (各节点不同)
=== Swap Status ===
Swap: 0B 0B 0B
=== Kernel Modules ===
7 (或更多)
=== Sysctl Parameters ===
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
=== /etc/hosts ===
192.168.0.85 kuboard-01
192.168.0.28 kuboard-02
...
=== Time Sync ===
System clock synchronized: yes
第4章:容器运行时 containerd 安装配置
Kubernetes 自 v1.24 起已移除
dockershim,推荐使用 containerd 或 CRI-O 作为容器运行时 (Container Runtime Interface, CRI)。本次实战选择 containerd。
4.1 什么是 containerd?
┌─────────────────────────────────────────────────────────────┐
│ Kubernetes │
│ (kubelet) │
└──────────────────────┬──────────────────────────────────────┘
│ CRI (Container Runtime Interface)
│ gRPC, unix:///run/containerd/containerd.sock
▼
┌─────────────────────────────────────────────────────────────┐
│ containerd │
│ (符合 CRI 标准的容器运行时,负责: │
│ - 镜像拉取 (Image Pull) │
│ - 容器生命周期管理 (Create/Start/Stop) │
│ - 容器网络接口 (CNI) 调用 │
│ - 容器存储接口 (CSI) 调用 │
│ ) │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ runc (OCI 运行时) │ │
│ │ - 实际创建和运行容器进程 │ │
│ │ - 设置 Linux namespace 和 cgroup │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
containerd vs Docker:
| 对比 | Docker | containerd |
|---|---|---|
| 架构 | Docker Engine → containerd → runc | containerd → runc (更简洁) |
| CLI 工具 | docker |
ctr (底层) / nerdctl (用户友好) |
| CRI 支持 | 需要 dockershim (已废弃) | 原生支持 |
| 资源占用 | 较高 (包含 build/push 等额外功能) | 较低 (专注运行时) |
| K8s 推荐 | ❌ v1.24+ 不推荐 | ✅ 官方推荐 |
4.2 安装 containerd
在所有节点上执行:
4.2.1 添加 Docker CE 仓库 (containerd 包含在 Docker CE 仓库中)
bash
# 1. 添加 Docker 官方 GPG 密钥
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 2. 添加 Docker CE 仓库 (阿里云镜像加速)
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 3. 更新包索引
sudo apt-get update
为什么用阿里云镜像? Docker 官方仓库
download.docker.com在国内访问极慢,阿里云镜像站提供高速访问。
4.2.2 安装 containerd
bash
# 安装 containerd (会同时安装 runc 和 CNI plugins)
sudo apt-get install -y containerd.io
# 验证安装版本
containerd --version
真实输出 (ecs-2c98 环境):
containerd containerd.io 2.2.1-1 # <-- v2.2.1
验证 runc 版本:
bash
runc --version
# runc version 1.2.4
# commit: v1.2.4-0-g6c0748e2
# spec: 1.2.0
4.3 配置 containerd (关键!)
4.3.1 生成默认配置文件
bash
# 生成默认配置到 /etc/containerd/config.toml
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
踩坑记录 #3 :
containerd config default在 v2.x 版本输出的配置格式与 v1.x 不同。v2.x 使用 TOML v2 格式 ,且SystemdCgroup的路径有所变化。
4.3.2 修改关键配置参数
需要修改两个关键配置:
① 开启 SystemdCgroup (K8s 要求使用 systemd 作为 cgroup 驱动)
bash
# 方法:使用 sed 替换(推荐,避免手动编辑错误)
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
② 配置国内镜像加速 (可选,加速镜像拉取)
在 /etc/containerd/config.toml 的 [plugins."io.containerd.grpc.v1.cri".registry.mirrors] 部分添加:
toml
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://mirrors.aliyun.com"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
endpoint = ["https://registry.aliyuncs.com"]
注意 :containerd v2 的配置路径与 v1 不同,v2 使用
plugins."io.containerd.grpc.v1.cri"而不是plugins."io.containerd.grpc.v1.cri".registry。
4.3.3 完整的关键配置项说明
toml
# /etc/containerd/config.toml 关键配置解读
# --- 1. 运行时配置 ---
[plugins."io.containerd.grpc.v1.cri".containerd]
# snapshotter 使用 overlayfs (性能最好)
snapshotter = "overlayfs"
# 禁用容器内系统 swap (K8s 要求)
disable_snapshot_annotations = false
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
# 使用 systemd cgroup 驱动 (与 K8s 保持一致)
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true # <-- 关键!必须为 true
# --- 2. 镜像仓库加速 (Mirrors) ---
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
# 阿里云镜像加速
endpoint = ["https://mirrors.aliyun.com"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
# 阿里云 K8s 镜像
endpoint = ["https://registry.aliyuncs.com"]
# --- 3. 沙箱镜像 (Pause Image) ---
[plugins."io.containerd.grpc.v1.cri"]
# K8s Pod 基础设施镜像 (每个 Pod 的 pause 容器)
sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.10"
4.4 重启 containerd 并验证
bash
# 1. 重启 containerd 使配置生效
sudo systemctl restart containerd
# 2. 设置开机自启
sudo systemctl enable containerd
# 3. 查看状态
sudo systemctl status containerd
预期输出:
● containerd.service - containerd container runtime
Loaded: loaded (/lib/systemd/system/containerd.service; enabled; preset: enabled)
Active: active (running) since Thu 2025-xx-xx 10:00:00 CST; 10s ago
Docs: https://containerd.io
Main PID: 12345 (containerd)
Tasks: 11
Memory: 15.3M
CPU: 100ms
CGroup: /system.slice/containerd.service
└─12345 /usr/bin/containerd
4.4.1 使用 ctr 验证 containerd 工作正常
bash
# 查看 containerd 信息
sudo ctr --namespace k8s.io version
# 列出已拉取的镜像 (此时应为空)
sudo ctr --namespace k8s.io images ls
输出示例:
Client:
Version: 2.2.1
Revision:
Server:
Version: 2.2.1
Revision:
4.5 (可选) 安装 nerdctl ------ containerd 的 docker 风格 CLI
ctr 是 containerd 的底层 CLI,参数复杂。nerdctl 提供了与 docker 命令兼容的用户体验。
bash
# 下载 nerdctl (选择最新版本)
NERDCTL_VERSION="2.1.3"
wget https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-amd64.tar.gz
# 解压并安装
sudo tar -C /usr/local/bin -xzf nerdctl-${NERDCTL_VERSION}-linux-amd64.tar.gz
# 验证
nerdctl --version
nerdctl 常用命令(与 docker 几乎一致):
bash
nerdctl ps # 列出容器
nerdctl images # 列出镜像
nerdctl pull nginx # 拉取镜像
nerdctl run -it --rm nginx bash
4.6 containerd 排错指南
| 问题 | 原因 | 解决方案 |
|---|---|---|
containerd: command not found |
未安装 | apt-get install containerd.io |
Failed to connect to containerd |
containerd 未启动 | systemctl start containerd |
SystemdCgroup = false 导致 kubelet 启动失败 |
配置未修改 | 修改 config.toml 并重启 |
| 镜像拉取超时 | 国内网络问题 | 配置 mirrors 或使用代理 |
ctr images ls 看不到镜像 |
namespace 不对 | 使用 ctr -n k8s.io images ls |
第5章:kubeadm / kubelet / kubectl 安装
kubeadm :K8s 集群引导工具,负责初始化 Master 和将 Worker 加入集群
kubelet :运行在每个节点上的 "节点代理",管理 Pod 生命周期
kubectl:K8s 命令行工具,用于与 API Server 交互
5.1 添加 Kubernetes 阿里云镜像仓库
在所有节点上执行:
bash
# 1. 添加阿里云 K8s 仓库 GPG 密钥
curl -fsSL https://mirrors.aliyun.com/kubernetes-new/core:/stable:/v1.32/deb/Release.key | \
sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# 2. 添加 K8s 仓库 (阿里云镜像)
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] \
https://mirrors.aliyun.com/kubernetes-new/core:/stable:/v1.32/deb/ /" | \
sudo tee /etc/apt/sources.list.d/kubernetes.list
# 3. 更新包索引
sudo apt-get update
踩坑记录 #1 (扩展) :K8s 官方仓库
pkgs.k8s.io在国内访问不稳定。阿里云镜像站同步了官方仓库,速度极快且稳定。
5.2 安装指定版本 kubeadm / kubelet / kubectl
在所有节点上执行:
bash
# 安装指定版本 (与实战环境一致: v1.32.13)
sudo apt-get install -y \
kubelet=1.32.13-1.1 \
kubeadm=1.32.13-1.1 \
kubectl=1.32.13-1.1 \
--allow-downgrades
# 锁定版本,防止 apt upgrade 时自动升级
sudo apt-mark hold kubelet kubeadm kubectl
验证安装:
bash
$ kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"32", GitVersion:"v1.32.13", ...}
$ kubelet --version
Kubernetes v1.32.13
$ kubectl version --client
Client Version: v1.32.13
5.2.1 关于版本锁定
bash
# 查看 hold 状态
sudo apt-mark showhold
# 输出: kubelet kubeadm kubectl
# 如果需要升级,先取消 hold
sudo apt-mark unhold kubelet kubeadm kubectl
⚠️ 重要 :K8s 集群的所有节点必须使用相同版本的 kubelet/kubeadm,否则会出现兼容性问题。
5.3 配置 kubelet 的 cgroup 驱动
kubelet 的 cgroup 驱动必须与 containerd 的 SystemdCgroup 设置一致 (都使用 systemd)。
创建 kubelet 配置文件:
bash
cat << 'EOF' | sudo tee /etc/systemd/system/kubelet.service.d/20-kubeadm.conf
# 此文件由 kubeadm 自动生成,此处为手动创建示例
# 通常不需要手动创建,kubeadm init 会自动配置
EOF
# 更推荐的方式:通过 kubeadm 配置
# 见第6章的 kubeadm-config.yaml
实际上,kubeadm 会在 init 时自动配置 kubelet,只需确保 containerd 的 SystemdCgroup = true 即可。
5.4 启用 kubelet (但不要启动)
bash
# 重新加载 systemd 配置
sudo systemctl daemon-reload
# 启用 kubelet (开机自启,但此时不要启动,kubeadm init 会启动它)
sudo systemctl enable kubelet
为什么不要手动启动 kubelet? 在
kubeadm init之前,kubelet 会因为缺少配置文件而启动失败(这是正常的)。kubeadm 会在初始化过程中生成 kubelet 配置。
5.5 安装 CNI 插件 (CNI Plugins)
CNI (Container Network Interface) 插件是 K8s 网络的基础。Flannel 依赖 CNI 插件的可执行文件。
在所有节点上执行:
bash
# 下载 CNI plugins v1.6.2
CNI_VERSION="v1.6.2"
wget https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/cni-plugins-linux-amd64-${CNI_VERSION}.tgz
# 解压到 /opt/cni/bin
sudo mkdir -p /opt/cni/bin
sudo tar -C /opt/cni/bin -xzf cni-plugins-linux-amd64-${CNI_VERSION}.tgz
# 验证 CNI 插件
ls /opt/cni/bin/
输出:
bandwidth bridge dhcp dummy firewall ... host-local ipvlan loopback macvlan portmap ptp sbr static tuning vlan vrf
关键 CNI 插件说明:
| 插件 | 用途 |
|---|---|
bridge |
创建桥接设备,Flannel 默认使用 |
host-local |
IP 地址分配 (IPAM),Flannel 使用 |
loopback |
配置 lo 网卡 |
portmap |
端口映射 (NodePort 实现依赖) |
5.6 验证:所有节点环境检查
在执行 kubeadm init 之前,运行 kubeadm 自带的预检:
bash
sudo kubeadm init --dry-run 2>&1 | head -30
如果一切正常 ,会看到 preflight 阶段检查通过。如果有错误,根据错误提示修复(通常是 swap 未关闭、内核模块缺失等)。
第6章:Master 节点初始化与 kubeadm init
本章实战在 Master 节点 (kuboard-01, 192.168.0.85) 上执行
6.1 创建 kubeadm 配置文件
使用配置文件(而不是命令行参数)初始化集群,便于版本控制和重复部署。
在 Master 节点 上创建 /tmp/kubeadm-config.yaml:
yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
bootstrapTokens:
- token: "abcdef.0123456789abcdef"
description: "default bootstrap token"
ttl: "24h"
nodeRegistration:
criSocket: "unix:///run/containerd/containerd.sock"
imagePullPolicy: IfNotPresent
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: "v1.32.13"
clusterName: "kuboard-cluster"
networking:
serviceSubnet: "10.96.0.0/12"
podSubnet: "10.244.0.0/16" # <-- 必须与 Flannel 的 --pod-network-cidr 一致
dnsDomain: "cluster.local"
controlPlaneEndpoint: "" # 单 Master 不需要指定
apiServer:
extraArgs:
ServiceAccount-issuer: "https://kubernetes.default.svc.cluster.local"
ServiceAccount-signing-key-file: "/etc/kubernetes/pki/sa.key"
controllerManager:
extraArgs:
bind-address: "0.0.0.0"
scheduler:
extraArgs:
bind-address: "0.0.0.0"
imageRepository: "registry.aliyuncs.com/google_containers" # <-- 关键!国内镜像加速
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: "systemd" # <-- 与 containerd 的 SystemdCgroup 一致
failSwapOn: false
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs" # 使用 IPVS 模式 (性能优于 iptables)
ipvs:
scheduler: "rr"
配置参数详细解释:
| 配置项 | 值 | 说明 |
|---|---|---|
imageRepository |
registry.aliyuncs.com/google_containers |
从阿里云拉取 K8s 组件镜像,避免 registry.k8s.io 访问超时 |
podSubnet |
10.244.0.0/16 |
Pod IP 分配范围,必须与 CNI 插件的配置匹配 |
serviceSubnet |
10.96.0.0/12 |
Service ClusterIP 分配范围 |
cgroupDriver |
systemd |
kubelet 使用 systemd cgroup 驱动 |
KubeProxyConfiguration.mode |
ipvs |
Kube-proxy 使用 IPVS 模式 |
criSocket |
unix:///run/containerd/containerd.sock |
指定 containerd 的 CRI socket 路径 |
6.2 执行 kubeadm init
在 Master 节点 上执行:
bash
sudo kubeadm init \
--config=/tmp/kubeadm-config.yaml \
--upload-certs \
--v=5
参数说明:
--config:指定配置文件路径--upload-certs:将 CA 证书上传到集群 Secret(多 Master 时需要)--v=5:输出详细日志(排错时有用)
踩坑记录 #1 详情 :如果未指定
imageRepository,kubeadm 默认从registry.k8s.io拉取镜像。国内服务器访问该地址会超时,报错:[ERROR ImagePull]: failed to pull image registry.k8s.io/kube-apiserver:v1.32.x。解决方案就是在配置文件中指定imageRepository: "registry.aliyuncs.com/google_containers"。
6.3 kubeadm init 输出解读
成功的初始化输出 (关键部分):
[init] Using Kubernetes version: v1.32.13
[preflight] Running pre-flight checks
[WARNING Hostname]: hostname "kuboard-01" could not be reached via DNS
# ^ 可以忽略,因为我们配置了 /etc/hosts
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take up to a minute or so in case of network slowness
# ^ 使用阿里云镜像,通常 1-2 分钟完成
[kubelet-start] Writing kubelet configuration to file
[certs] Generating certificates...
# ^ 生成 CA、API Server、etcd 等证书 (位于 /etc/kubernetes/pki/)
[kubeconfig] Writing kubeconfig files...
# ^ 生成 admin.conf, kubelet.conf, controller-manager.conf, scheduler.conf
[control-plane] Creating static pod manifests...
# ^ 创建 API Server, Controller Manager, Scheduler 的静态 Pod 清单
[etcd] Creating static pod manifest for local etcd
# ^ 创建 etcd 静态 Pod 清单
[upload-config] Storing the configuration...
[mark-control-plane] Marking the node kuboard-01 as control-plane
[kubelet-check] Waiting for the kubelet to boot up the control plane
# ^ 等待 kubelet 启动控制平面 Pod
[patch-node] Uploading the CRI endpoint...
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a CNI network addon (like Flannel):
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.0.85:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
6.4 配置 kubectl (管理员用)
在 Master 节点 上执行:
bash
# 方法1:非 root 用户
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 方法2:root 用户 (简单直接)
export KUBECONFIG=/etc/kubernetes/admin.conf
echo 'export KUBECONFIG=/etc/kubernetes/admin.conf' >> ~/.bashrc
验证 kubectl 可以连接集群:
bash
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
kuboard-01 NotReady control-plane 2m v1.32.13
为什么 STATUS 是 NotReady? 因为还没有安装 CNI 网络插件。安装 Flannel 后,状态会变成
Ready。
6.5 查看集群组件状态
bash
# 查看所有组件状态
kubectl get componentstatuses
# 查看控制平面 Pod
kubectl get pods -n kube-system
输出示例:
NAME READY STATUS RESTARTS AGE
etcd-kuboard-01 1/1 Running 0 3m
kube-apiserver-kuboard-01 1/1 Running 0 3m
kube-controller-manager-kuboard-01 1/1 Running 0 3m
kube-scheduler-kuboard-01 1/1 Running 0 3m
coredns-xxxx-yyyy 0/1 Pending 0 3m # 等待网络插件
kube-proxy-zzzz 1/1 Running 0 3m
注意 :CoreDNS Pod 处于
Pending状态是正常的,因为 Flannel 尚未安装,Pod 网络未就绪。
6.6 保存 kubeadm join 命令
将 kubeadm init 输出的 kubeadm join 命令保存到文件,后续 Worker 节点加入时需要:
bash
# 在 Master 节点上保存 join 命令
kubeadm token create --print-join-command > /tmp/kubeadm-join.sh
chmod +x /tmp/kubeadm-join.sh
cat /tmp/kubeadm-join.sh
如果忘记了 join 命令,可以在 Master 上重新生成:
bash
# 创建新的 bootstrap token 并打印 join 命令
sudo kubeadm token create --print-join-command --ttl=24h
6.7 kubeadm init 排错指南
| 错误 | 原因 | 解决方案 |
|---|---|---|
[ERROR Swap] |
swap 未关闭 | swapoff -a + 注释 fstab |
[ERROR ImagePull] |
无法拉取镜像 | 使用 --image-repository=registry.aliyuncs.com/google_containers |
[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables] |
sysctl 参数未设置 | 执行第3章的 sysctl 配置 |
context deadline exceeded |
镜像拉取超时 | 检查网络、配置 containerd mirrors |
Port 6443 is in use |
API Server 已在运行 | kubeadm reset 后重试 |
重置集群 (排错时使用):
bash
sudo kubeadm reset --force
sudo rm -rf /etc/kubernetes /var/lib/etcd ~/.kube
第7章:CNI 网络插件 Flannel 部署
Flannel 是最简单的 K8s CNI 插件之一,适合入门和中小规模集群。它为每个 Node 分配一个子网,通过 VXLAN 或 host-gw 实现跨节点 Pod 通信。
7.1 Flannel 工作原理
┌──────────────────────────────────────────────────────────────────┐
│ Flannel 网络模型 │
│ │
│ Node-1 (kuboard-01) Node-2 (kuboard-02) │
│ Pod CIDR: 10.244.0.0/24 Pod CIDR: 10.244.1.0/24 │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Pod-A │ 10.244.0.2 │ Pod-C │ 10.244.1.2 │
│ │(eth0) │──────┐ │(eth0) │ │
│ └──────────┘ │ └──────────┘ │
│ │ flannel.1 (VXLAN) │
│ ┌──────────┐ │ ┌──────────┐ │
│ │ Pod-B │ 10.244.0.3 │ Pod-D │ 10.244.1.3 │
│ │(eth0) │ │ │(eth0) │ │
│ └──────────┘ │ └──────────┘ │
│ │ ▼ ▲ │
│ │ ┌──────────────┐ │ │
│ └────►│ flanneld │────────┘ │
│ │ (Agent) │ VXLAN tunnel (UDP 8472) │
│ └──────┬───────┘ │
│ │ │
│ ┌──────▼───────┐ │
│ │ host eth0 │ 192.168.0.85 │
│ └──────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
Flannel 核心组件:
| 组件 | 运行方式 | 功能 |
|---|---|---|
flanneld |
DaemonSet Pod | 为每个 Node 分配 Pod CIDR 子网,维护路由表 |
cni0 / veth |
网络接口 | 将 Pod 连接到 Node 的网络命名空间 |
flannel.1 |
VXLAN 接口 | 跨节点 Pod 通信的 Overlay 隧道 (UDP 8472) |
host-gw 模式 |
直连路由 | 无需 Overlay,性能更好(要求 Node 同二层网络) |
7.2 下载 Flannel YAML 清单
在 Master 节点 上执行:
bash
# 下载最新版 Flannel 安装清单
wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
# 查看文件内容
ls -lh kube-flannel.yml
head -50 kube-flannel.yml
kube-flannel.yml 结构解读:
kube-flannel.yml 包含以下 K8s 资源:
1. ServiceAccount: flannel (RBAC 权限)
2. ClusterRole + ClusterRoleBinding: flannel 权限绑定
3. ConfigMap: kube-flannel-cfg (NetConf 配置)
4. DaemonSet: kube-flannel-ds (核心,每个 Node 运行一个 Pod)
5. NetworkPolicy: 可选的网络策略
7.3 修改 Flannel 配置 (Pod CIDR 匹配)
关键 :Flannel 的 net-conf.json 中的 Network 必须与 kubeadm init 时指定的 podSubnet 完全一致 (10.244.0.0/16)。
bash
# 验证当前 kube-flannel.yml 中的 Network 配置
grep -A 5 "net-conf.json" kube-flannel.yml
预期输出 (应显示 "Network": "10.244.0.0/16"):
json
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
如果不一致 ,需要修改
kube-flannel.yml中的net-conf.json的Network字段,使其与kubeadm-config.yaml中的podSubnet一致。
7.4 部署 Flannel (踩坑记录 #2 详解)
⚠️ 踩坑记录 #2:Flannel ghcr.io 镜像拉取失败
现象 :在国内服务器执行 kubectl apply -f kube-flannel.yml 后,Flannel Pod 一直 ImagePullBackOff,查看 Pod 详情:
Failed to pull image "ghcr.io/flannel-io/flannel:v0.28.5": rpc error: code = DeadlineExceeded desc = failed to pull and unpack image: failed to resolve reference "ghcr.io/flannel-io/flannel:v0.28.5": failed to do request: Head "https://ghcr.io/v2/flannel-io/flannel/manifests/v0.28.5": dial tcp 20.205.243.166:443: i/o timeout
原因 :ghcr.io (GitHub Container Registry) 在国内访问极不稳定,经常超时。
解决方案 (二选一):
方案A:使用 hub.rat.dev 代理 (推荐)
bash
# 1. 编辑 kube-flannel.yml,替换镜像地址
sed -i 's|ghcr.io/flannel-io/flannel|docker.rainbond.cc/flannel-io/flannel|g' kube-flannel.yml
# 验证替换结果
grep "image:" kube-flannel.yml
# 应显示: image: docker.rainbond.cc/flannel-io/flannel:v0.28.5
方案B:手动拉取 + 导出 + 导入 (离线方案)
在 Master 节点 (有外网代理或能访问 ghcr.io 的机器上):
bash
# 1. 拉取 Flannel 镜像 (在有外网访问的机器上)
sudo ctr -n k8s.io images pull ghcr.io/flannel-io/flannel:v0.28.5
# 2. 导出为 tar 包
sudo ctr -n k8s.io images export flannel-v0.28.5.tar \
ghcr.io/flannel-io/flannel:v0.28.5
# 3. 通过 sftp/scp 传到所有 Worker 节点
scp flannel-v0.28.5.tar root@192.168.0.28:/tmp/
scp flannel-v0.28.5.tar root@192.168.0.153:/tmp/
scp flannel-v0.28.5.tar root@192.168.0.51:/tmp/
# 4. 在所有节点 (包括 Master) 上导入
sudo ctr -n k8s.io images import /tmp/flannel-v0.28.5.tar
# 5. 验证镜像已导入
sudo ctr -n k8s.io images ls | grep flannel
然后修改 kube-flannel.yml ,将 imagePullPolicy 改为 IfNotPresent:
yaml
# 在 kube-flannel.yml 中,找到 imagePullPolicy
imagePullPolicy: IfNotPresent # 改为 IfNotPresent (而不是 Always)
7.5 应用 Flannel YAML
bash
# 部署 Flannel
kubectl apply -f kube-flannel.yml
输出:
namespace/kube-flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created
7.6 验证 Flannel 部署成功
bash
# 1. 查看 Flannel Pod 状态 (等待所有节点 Ready)
kubectl get pods -n kube-flannel -o wide --watch
预期输出 (等待 1-2 分钟):
NAMESPACE NAME READY STATUS RESTARTS AGE NODE
kube-flannel kube-flannel-ds-abcde 1/1 Running 0 1m kuboard-01
bash
# 2. 查看 Node 状态 (应从 NotReady 变为 Ready)
kubectl get nodes -o wide
预期输出:
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
kuboard-01 Ready control-plane 5m v1.32.13 192.168.0.85 <none> Ubuntu 24.04.4 LTS 6.8.0-106-generic containerd://2.2.1
STATUS = Ready 表示 Flannel 工作正常,节点网络已就绪!
bash
# 3. 验证 CNI 接口已创建
ip link show | grep flannel
# 或
ip link show | grep cni
输出示例:
6: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 ...
7: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 ...
7.7 Flannel 排错指南
| 问题 | 诊断命令 | 解决方案 |
|---|---|---|
Flannel Pod Init:0/1 |
kubectl logs -n kube-flannel ds/kube-flannel-ds |
检查 CNI 插件是否已安装 (/opt/cni/bin/bridge) |
Flannel Pod ImagePullBackOff |
kubectl describe pod -n kube-flannel <pod> |
参考踩坑#2,使用镜像代理或离线导入 |
Node 一直是 NotReady |
kubectl describe node kuboard-01 |
检查 Conditions 中的 NetworkUnavailable |
| Pod 跨节点无法通信 | kubectl exec -it <pod> -- ping <another-pod-ip> |
检查防火墙 UDP 8472 是否开放 |
cni0 接口不存在 |
ip link show cni0 |
重启 Flannel Pod 或检查 bridge CNI 插件 |
第8章:Worker 节点加入集群
目标:将 kuboard-02、kuboard-03、kuboard-04 三个 Worker 节点加入集群。
8.1 在 Master 节点上准备 join 命令
如果之前保存了 kubeadm init 输出的 join 命令,可以直接使用。否则,在 Master 节点 上重新生成:
bash
# 创建新的 token 并打印 join 命令
sudo kubeadm token create --print-join-command
输出示例:
kubeadm join 192.168.0.85:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1a2b3c4d5e6f...
Token 说明 :
kubeadm token默认 24 小时过期。如果 token 过期,需要重新创建。
8.2 在所有 Worker 节点上执行 join
将上一步得到的 kubeadm join 命令,分别在 kuboard-02、kuboard-03、kuboard-04 上执行:
bash
# 在 kuboard-02 (120.46.32.153) 上执行
sudo kubeadm join 192.168.0.85:6443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1a2b3c4d5e6f...
# 在 kuboard-03 (1.94.204.169) 上执行
sudo kubeadm join 192.168.0.85:6443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1a2b3c4d5e6f...
# 在 kuboard-04 (120.46.129.80) 上执行
sudo kubeadm join 192.168.0.85:6443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1a2b3c4d5e6f...
成功输出 (每个 Worker 节点):
[preflight] Running pre-flight checks
[WARNING Hostname]: hostname "kuboard-02" could not be reached via DNS
[join] Reading configuration from the cluster...
[join] 2025-xx-xx ... [kubelet-start] Starting the kubelet
[join] 2025-xx-xx ... [control-plane] Adding node "kuboard-02" to the cluster
This node has joined the cluster!
8.3 在 Master 节点上验证所有节点已加入
bash
kubectl get nodes -o wide
预期输出 (4 个节点全部 Ready):
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION
kuboard-01 Ready control-plane 15m v1.32.13 192.168.0.85 <none> Ubuntu 24.04.4 LTS 6.8.0-106-generic
kuboard-02 Ready <none> 3m v1.32.13 192.168.0.28 <none> Ubuntu 24.04.4 LTS 6.8.0-106-generic
kuboard-03 Ready <none> 2m v1.32.13 192.168.0.153 <none> Ubuntu 24.04.4 LTS 6.8.0-106-generic
kuboard-04 Ready <none> 2m v1.32.13 192.168.0.51 <none> Ubuntu 24.04.4 LTS 6.8.0-106-generic
注意 :Worker 节点的
ROLES列是<none>,这是正常的。如需添加角色标签,可以执行:
bashkubectl label node kuboard-02 node-role.kubernetes.io/worker=worker
8.4 查看所有系统 Pod 状态
bash
kubectl get pods -A -o wide
完整输出示例 (所有 Pod Running):
NAMESPACE NAME READY STATUS RESTARTS AGE NODE
kube-flannel kube-flannel-ds-abcde 1/1 Running 0 10m kuboard-01
kube-flannel kube-flannel-ds-bcdef 1/1 Running 0 5m kuboard-02
kube-flannel kube-flannel-ds-cdefg 1/1 Running 0 5m kuboard-03
kube-flannel kube-flannel-ds-defgh 1/1 Running 0 5m kuboard-04
kube-system coredns-668d6bf9b5-xyzab 1/1 Running 0 15m kuboard-01
kube-system coredns-668d6bf9b5-wxyza 1/1 Running 0 15m kuboard-01
kube-system etcd-kuboard-01 1/1 Running 0 15m kuboard-01
kube-system kube-apiserver-kuboard-01 1/1 Running 0 15m kuboard-01
kube-system kube-controller-manager-kuboard-01 1/1 Running 0 15m kuboard-01
kube-system kube-proxy-aaaaa 1/1 Running 0 15m kuboard-01
kube-system kube-proxy-bbbbb 1/1 Running 0 5m kuboard-02
kube-system kube-proxy-ccccc 1/1 Running 0 5m kuboard-03
kube-system kube-proxy-ddddd 1/1 Running 0 5m kuboard-04
kube-system kube-scheduler-kuboard-01 1/1 Running 0 15m kuboard-01
🎉 恭喜!Kubernetes 集群已成功搭建! 接下来部署 Kuboard v3 管理面板。
8.5 Worker 节点加入失败排错
| 错误 | 原因 | 解决方案 |
|---|---|---|
token is expired |
token 超过 24 小时 | 在 Master 上 kubeadm token create 重新生成 |
connection refused |
Master API Server 不可达 | 检查 Master 防火墙、安全组规则 |
certificate signed by unknown authority |
CA 证书 hash 不匹配 | 重新获取正确的 --discovery-token-ca-cert-hash |
Preflight checks failed |
swap 未关闭等 | 执行第3章的系统初始化步骤 |
Worker 节点 NotReady |
Flannel 未正常运行 | 检查 Worker 节点上的 Flannel Pod 日志 |
重置 Worker 节点 (排错时用):
bash
sudo kubeadm reset --force
sudo rm -rf /etc/kubernetes /var/lib/kubelet
第9章:Kuboard v3 部署
目标 :在 K8s 集群中部署 Kuboard v3,并通过 NodePort
30080访问。
9.1 Kuboard 部署架构
┌──────────────────────────────────────────────────────────────────┐
│ Kuboard v3 on Kubernetes │
│ │
│ kuboard Namespace: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Deployment: kuboard (replicas: 1) │ │
│ │ Pod: kuboard-xxxxxxxxxx-yyyyy │ │
│ │ Container: kuboard │ │
│ │ Image: swr.cn-east-2.myhuaweicloud.com/... │ │
│ │ Port: 80 (HTTP) │ │
│ │ Env: KUBOARD_AGENT_KEY=... │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ Service: kuboard (NodePort, port 80 → NodePort 30080) │
│ → 访问: http://任意节点IP:30080 │
│ │
│ ConfigMap: kuboard-config (配置文件) │
│ ServiceAccount: kuboard (RBAC 权限) │
└──────────────────────────────────────────────────────────────────┘
9.2 创建 Kuboard 部署 YAML
在 Master 节点 上创建 /tmp/kuboard-v3.yaml:
yaml
---
apiVersion: v1
kind: Namespace
metadata:
name: kuboard
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kuboard
namespace: kuboard
labels:
app: kuboard
spec:
replicas: 1
selector:
matchLabels:
app: kuboard
template:
metadata:
labels:
app: kuboard
spec:
# 允许调度到 Master 节点 (control-plane 有 taint)
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
# 优先调度到 Master 节点 (Kuboard 管理面板通常放 Master)
nodeSelector:
kubernetes.io/hostname: "kuboard-01"
containers:
- name: kuboard
image: swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard:v3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
protocol: TCP
env:
- name: KUBOARD_AGENT_KEY
value: "kuboard-register-key-2025"
- name: KUBOARD_AGENT_PORT
value: "30080"
- name: KUBOARD_SERVER_NODE_PORT
value: "30080"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 5
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
---
apiVersion: v1
kind: Service
metadata:
name: kuboard
namespace: kuboard
labels:
app: kuboard
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080
name: http
protocol: TCP
selector:
app: kuboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kuboard-cluster-admin
subjects:
- kind: ServiceAccount
name: default
namespace: kuboard
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
踩坑记录 #5 详解 :Control-plane 节点默认有
node-role.kubernetes.io/control-plane:NoSchedule污点 (taint),普通 Pod 无法调度上去。需要在PodSpec中添加对应的toleration。
9.3 部署 Kuboard
bash
# 应用 Kuboard YAML
kubectl apply -f /tmp/kuboard-v3.yaml
输出:
namespace/kuboard created
deployment.apps/kuboard created
service/kuboard created
clusterrolebinding.rbac.authorization.k8s.io/kuboard-cluster-admin created
9.4 验证 Kuboard 部署
bash
# 1. 查看 Kuboard Pod 状态
kubectl get pods -n kuboard -o wide --watch
等待约 30 秒,预期输出:
NAME READY STATUS RESTARTS AGE NODE
kuboard-xxxxxxxxxx-yyyyy 1/1 Running 0 30s kuboard-01
bash
# 2. 查看 Kuboard Service
kubectl get svc -n kuboard
输出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kuboard NodePort 10.96.xx.xx <none> 80:30080/TCP 1m
bash
# 3. 查看 Pod 日志 (确认启动正常)
kubectl logs -n kuboard deployment/kuboard --tail=20
关键日志:
2025/xx/xx ...
Kuboard v3 started successfully!
Access Kuboard at http://<NodeIP>:30080
Default username: admin
Default password: Kuboard123
9.5 访问 Kuboard Web UI
打开浏览器,访问:
http://120.46.195.39:30080
注意 :如果使用华为云,确保安全组已开放 TCP 30080 入方向规则。
登录信息 (默认):
- 用户名:
admin - 密码:
Kuboard123
⚠️ 安全提示:登录后请立即修改默认密码!
9.6 Kuboard 端口名踩坑 (踩坑记录 #6)
踩坑记录 #6:Service 端口名超过 15 字符
现象 :在创建 Service 时,如果 name 字段超过 15 个字符,K8s 会报错:
metadata.annotations: Too long: must be no more than 15 characters
解决方案 :端口名使用简短名称,如 http 而非 kuboard-http-server-port。
在上面的 YAML 中,端口名已设置为 http(5个字符),符合 K8s 要求。
第10章:Kuboard 界面实战
10.1 首次登录与修改密码
- 访问
http://120.46.195.39:30080 - 输入用户名
admin,密码Kuboard123 - 系统会强制要求修改密码 → 设置新密码
- 进入 Kuboard 主页
10.2 导入当前集群
Kuboard 需要导入 K8s 集群才能管理。由于我们是在集群内部署的 Kuboard,它可以自动发现当前集群。
步骤:
- 点击左侧导航 集群 → 导入集群
- 选择 KubeConfig 方式
- 将 Master 节点上的
/etc/kubernetes/admin.conf内容粘贴到输入框 - 点击 导入
或者,使用 ServiceAccount Token 方式 (推荐,更安全):
bash
# 获取 default ServiceAccount 的 token
kubectl -n kuboard get secret \
$(kubectl -n kuboard get sa default -o jsonpath='{.secrets[0].name}') \
-o jsonpath='{.data.token}' | base64 --decode
将输出的 token 粘贴到 Kuboard 导入界面。
10.3 Kuboard 主要功能导航
Kuboard v3 界面结构:
┌─────────────────────────────────────────────────────────────┐
│ Logo Kuboard v3 [集群: kuboard-cluster] admin ▼ │
├──────────┬──────────────────────────────────────────────────┤
│ │ │
│ 集群概览 │ 节点状态、Pod 数量、资源使用率仪表盘 │
│ │ │
│ 工作负载 │ ┌────────┬────────┬────────┬────────┐ │
│ │ │ 部署 │ 有状态集 │ DaemonSet│ 任务 │ │
│ │ └────────┴────────┴────────┴────────┘ │
│ 配置管理 │ ConfigMap / Secret │
│ │ │
│ 网络 │ Service / Ingress │
│ │ │
│ 存储 │ PV / PVC / StorageClass │
│ │ │
│ 集群管理 │ 节点管理 / 命名空间 / 审计日志 │
│ │ │
└──────────┴──────────────────────────────────────────────────┘
10.4 通过 Kuboard 创建第一个 Nginx 部署
步骤 (通过 Kuboard Web UI):
- 左侧导航 → 工作负载 → 部署 → 创建
- 填写表单:
- 名称:
nginx-demo - 命名空间:
default - 容器:
- 名称:
nginx - 镜像:
nginx:1.27 - 端口:
80
- 名称:
- 副本数:
2
- 点击 完成
- 查看部署状态
验证 (通过 kubectl):
bash
kubectl get deployments
kubectl get pods -l app=nginx-demo
10.5 Kuboard 监控功能
Kuboard 集成了 Metrics Server(需先安装)来显示资源使用率:
bash
# 安装 Metrics Server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 如果 Metrics Server 启动失败,可能需要添加 --kubelet-insecure-tls 参数
# 修改 metrics-server deployment:
kubectl patch deployment metrics-server -n kube-system --type='json' \
-p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}]'
安装完成后,Kuboard 界面即可显示 CPU/内存使用率图表。
第11章:国内镜像加速方案汇总
11.1 常用国内镜像加速地址
| 镜像仓库 | 加速地址 | 用途 |
|---|---|---|
| 阿里云容器镜像服务 | registry.aliyuncs.com |
K8s 官方镜像 (k8s.gcr.io / registry.k8s.io) |
| 阿里云 Docker Hub 加速 | mirrors.aliyun.com |
Docker Hub 镜像 |
| 中科大 USTC | docker.mirrors.ustc.edu.cn |
Docker Hub 镜像 |
| 网易 | hub-mirror.c.163.com |
Docker Hub 镜像 |
| 百度 | mirror.baidubce.com |
Docker Hub 镜像 |
| Rainbond (hub.rat.dev) | docker.rainbond.cc |
GitHub Packages / ghcr.io 镜像 |
| 华为云 SWR | swr.cn-east-2.myhuaweicloud.com |
华为云容器镜像 (Kuboard 官方镜像) |
11.2 containerd 镜像加速完整配置
编辑 /etc/containerd/config.toml,添加以下配置:
toml
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://mirrors.aliyun.com", "https://docker.mirrors.ustc.edu.cn"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
endpoint = ["https://registry.aliyuncs.com"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."ghcr.io"]
endpoint = ["https://docker.rainbond.cc"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]
endpoint = ["https://quay.mirrors.ustc.edu.cn"]
修改后重启 containerd:
bash
sudo systemctl restart containerd
11.3 kubeadm 使用国内镜像
kubeadm init 时指定 --image-repository 参数:
bash
sudo kubeadm init \
--image-repository=registry.aliyuncs.com/google_containers \
--pod-network-cidr=10.244.0.0/16
或在配置文件 (kubeadm-config.yaml) 中指定:
yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
imageRepository: "registry.aliyuncs.com/google_containers"
第12章:常见问题排查指南
12.1 Pod 排错命令速查
bash
# 1. 查看 Pod 状态
kubectl get pods -A
# 2. 查看 Pod 详情 (事件日志)
kubectl describe pod <pod-name> -n <namespace>
# 3. 查看 Pod 日志
kubectl logs <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace> --previous # 上一次重启前的日志
# 4. 查看多容器 Pod 中指定容器的日志
kubectl logs <pod-name> -n <namespace> -c <container-name>
# 5. 进入 Pod 容器调试
kubectl exec -it <pod-name> -n <namespace> -- /bin/bash
kubectl exec -it <pod-name> -n <namespace> -- /bin/sh # Alpine 镜像
# 6. 查看 Pod 的资源使用率 (需要 Metrics Server)
kubectl top pod <pod-name> -n <namespace>
12.2 Node 排错
bash
# 1. 查看 Node 状态
kubectl get nodes
# 2. 查看 Node 详情 (Conditions, 资源, 事件)
kubectl describe node <node-name>
# 3. 查看 Node 资源使用率
kubectl top node
# 4. 临时标记 Node 为不可调度 (维护前)
kubectl cordon <node-name>
# 5. 驱逐 Node 上的 Pod (维护前)
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
# 6. 恢复 Node 可调度
kubectl uncordon <node-name>
12.3 网络排错
bash
# 1. 从 Pod 内部测试 DNS 解析
kubectl exec -it <pod-name> -- nslookup kubernetes.default
# 2. 测试 Pod 间通信
kubectl exec -it <pod-a> -- ping <pod-b-ip>
# 3. 测试 Service 连通性
kubectl exec -it <pod-name> -- curl http://<service-name>.<namespace>:port
# 4. 查看 Service 和 Endpoints
kubectl get svc,endpoints -n <namespace>
# 5. 查看 iptables 规则 (kube-proxy iptables 模式)
sudo iptables -t nat -L | grep <service-name>
# 6. 查看 IPVS 规则 (kube-proxy ipvs 模式)
sudo ipvsadm -ln
12.4 kubeadm 和集群排错
bash
# 1. 查看 kubelet 日志
sudo journalctl -u kubelet -f
# 2. 查看 kubelet 状态
sudo systemctl status kubelet
# 3. 查看容器运行时日志
sudo journalctl -u containerd -f
# 4. 查看 etcd 日志
kubectl logs -n kube-system etcd-kuboard-01
# 5. 查看 API Server 日志
kubectl logs -n kube-system kube-apiserver-kuboard-01
# 6. 验证集群健康状态
kubectl get componentstatuses
kubectl get --raw '/healthz'
12.5 常用调试工具 Pod
创建一个包含常用网络工具的调试 Pod:
yaml
apiVersion: v1
kind: Pod
metadata:
name: netshoot
spec:
containers:
- name: netshoot
image: nicolaka/netshoot:latest
command: ["/bin/bash", "-c", "sleep 3600"]
imagePullPolicy: IfNotPresent
restartPolicy: Always
bash
kubectl apply -f netshoot.yaml
kubectl exec -it netshoot -- bash
# 在 netshoot 容器中可以使用: curl, wget, nslookup, dig, ping, traceroute, etc.
附录A:完整部署命令速查表
A.1 系统初始化 (所有节点)
bash
# 设置主机名
sudo hostnamectl set-hostname <hostname>
# 配置 /etc/hosts
cat << 'EOF' | sudo tee -a /etc/hosts
192.168.0.85 kuboard-01
192.168.0.28 kuboard-02
192.168.0.153 kuboard-03
192.168.0.51 kuboard-04
EOF
# 关闭 swap
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
# 加载内核模块
sudo modprobe overlay
sudo modprobe br_netfilter
# 配置 sysctl
cat << 'EOF' | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
A.2 安装 containerd (所有节点)
bash
# 添加 Docker CE 仓库
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装 containerd
sudo apt-get update && sudo apt-get install -y containerd.io
# 生成并修改配置
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
# 重启
sudo systemctl restart containerd
sudo systemctl enable containerd
A.3 安装 K8s 组件 (所有节点)
bash
# 添加阿里云 K8s 仓库
curl -fsSL https://mirrors.aliyun.com/kubernetes-new/core:/stable:/v1.32/deb/Release.key | \
sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] \
https://mirrors.aliyun.com/kubernetes-new/core:/stable:/v1.32/deb/ /" | \
sudo tee /etc/apt/sources.list.d/kubernetes.list
# 安装指定版本
sudo apt-get update && sudo apt-get install -y \
kubelet=1.32.13-1.1 \
kubeadm=1.32.13-1.1 \
kubectl=1.32.13-1.1
sudo apt-mark hold kubelet kubeadm kubectl
A.4 Master 初始化
bash
# 创建配置文件
cat << 'EOF' > /tmp/kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
nodeRegistration:
criSocket: "unix:///run/containerd/containerd.sock"
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: "v1.32.13"
networking:
podSubnet: "10.244.0.0/16"
imageRepository: "registry.aliyuncs.com/google_containers"
EOF
# 执行初始化
sudo kubeadm init --config=/tmp/kubeadm-config.yaml
# 配置 kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
A.5 安装 Flannel
bash
# 下载 Flannel YAML
wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
# 替换镜像 (解决国内网络问题)
sed -i 's|ghcr.io/flannel-io/flannel|docker.rainbond.cc/flannel-io/flannel|g' kube-flannel.yml
# 部署
kubectl apply -f kube-flannel.yml
# 验证
kubectl get nodes # 等待所有节点 Ready
A.6 Worker 加入集群
bash
# 在 Master 上生成 join 命令
sudo kubeadm token create --print-join-command
# 在 Worker 节点上执行输出的命令
sudo kubeadm join 192.168.0.85:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash>
A.7 部署 Kuboard v3
bash
# 创建 Kuboard YAML (见第9章完整 YAML)
# 应用
kubectl apply -f /tmp/kuboard-v3.yaml
# 验证
kubectl get pods -n kuboard
kubectl get svc -n kuboard
# 访问
# http://<NodeIP>:30080
# 默认账号: admin / Kuboard123
附录B:containerd 配置详解
B.1 containerd v2 完整配置参考
/etc/containerd/config.toml 关键配置项详解:
toml
# ============================================================
# containerd v2 配置详解
# 生成方式: containerd config default > /etc/containerd/config.toml
# ============================================================
# --- 全局配置 ---
version = 2 # <-- TOML 配置版本 (v2)
# --- gRPC 监听地址 ---
[grpc]
address = "/run/containerd/containerd.sock" # <-- kubelet 连接的 CRI socket
# kubeadm 配置中的 criSocket 必须与此一致
# --- CRI 插件配置 (最关键) ---
[plugins."io.containerd.grpc.v1.cri"]
# 沙箱镜像 (Pause 容器)
# K8s 每个 Pod 的第一个容器,负责创建网络命名空间
sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.10"
# 禁止将容器内 /etc/hosts 文件挂载为 tmpfs (K8s 1.28+ 可设为 true)
disable_hosts_mount = false
# --- 容器运行时配置 ---
[plugins."io.containerd.grpc.v1.cri".containerd]
# 快照器 (snapshotter): overlayfs 性能最好
snapshotter = "overlayfs"
# --- runc 运行时配置 ---
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
# runtime_type: 使用 OCI 运行时 (runc)
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
# SystemdCgroup: 必须使用 systemd cgroup 驱动 (K8s 要求)
SystemdCgroup = true # <-- 必须为 true!
# --- 镜像仓库加速配置 ---
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://mirrors.aliyun.com"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
endpoint = ["https://registry.aliyuncs.com"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."ghcr.io"]
endpoint = ["https://docker.rainbond.cc"]
B.2 containerd 常用 ctr 命令
bash
# 列出镜像
sudo ctr -n k8s.io images ls
# 拉取镜像
sudo ctr -n k8s.io images pull registry.aliyuncs.com/google_containers/pause:3.10
# 导出镜像
sudo ctr -n k8s.io images export pause.tar \
registry.aliyuncs.com/google_containers/pause:3.10
# 导入镜像
sudo ctr -n k8s.io images import pause.tar
# 删除镜像
sudo ctr -n k8s.io images rm registry.aliyuncs.com/google_containers/pause:3.10
# 查看容器
sudo ctr -n k8s.io containers ls
# 查看任务 (运行的容器)
sudo ctr -n k8s.io tasks ls
附录C:Kuboard YAML 完整模板
C.1 Kuboard v3 完整部署 YAML
yaml
# ============================================================
# Kuboard v3 完整部署 YAML
# 适用:Kubernetes v1.20+
# 镜像:华为云 SWR (国内加速)
# 访问:http://<NodeIP>:30080
# 默认账号:admin / Kuboard123
# ============================================================
---
apiVersion: v1
kind: Namespace
metadata:
name: kuboard
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kuboard
namespace: kuboard
labels:
app: kuboard
spec:
replicas: 1
selector:
matchLabels:
app: kuboard
template:
metadata:
labels:
app: kuboard
spec:
# 容忍 Master 节点污点 (允许调度到 control-plane)
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "NoSchedule"
# 节点选择器 (可选,指定运行在 kuboard-01)
# nodeSelector:
# kubernetes.io/hostname: "kuboard-01"
containers:
- name: kuboard
image: swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard:v3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
protocol: TCP
env:
- name: KUBOARD_AGENT_KEY
value: "kuboard-register-key-2025"
- name: KUBOARD_AGENT_PORT
value: "30080"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
volumeMounts:
- name: kuboard-data
mountPath: /data
volumes:
- name: kuboard-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: kuboard
namespace: kuboard
labels:
app: kuboard
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080
name: http
protocol: TCP
selector:
app: kuboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kuboard-cluster-admin
subjects:
- kind: ServiceAccount
name: default
namespace: kuboard
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
C.2 Flannel v0.28.5 国内镜像版 YAML (节选)
yaml
# ============================================================
# kube-flannel.yml 修改版 (使用国内镜像)
# 修改点:将 ghcr.io/flannel-io/flannel 替换为国内可访问的镜像
# ============================================================
# ... (省略 ServiceAccount, ClusterRole 等,与官方相同)
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-flannel-ds
namespace: kube-flannel
spec:
selector:
matchLabels:
app: flannel
template:
metadata:
labels:
app: flannel
spec:
containers:
- name: kube-flannel
# 原始: image: ghcr.io/flannel-io/flannel:v0.28.5
# 修改为国内可访问的镜像:
image: docker.rainbond.cc/flannel-io/flannel:v0.28.5
imagePullPolicy: IfNotPresent
# ... (其余配置与官方相同)
第13章:集群运维实战
本章介绍 K8s 集群日常运维操作,包括健康检查、备份恢复、版本升级、资源管理等实战技巧。
13.1 集群健康检查 (Cluster Health Check)
bash
# === 1. 检查所有节点状态 ===
kubectl get nodes -o wide
# 预期输出:
# NAME STATUS ROLES AGE VERSION INTERNAL-IP
# kuboard-01 Ready control-plane 1d v1.32.13 192.168.0.85
# kuboard-02 Ready <none> 1d v1.32.13 192.168.0.28
# kuboard-03 Ready <none> 1d v1.32.13 192.168.0.153
# kuboard-04 Ready <none> 1d v1.32.13 192.168.0.51
# === 2. 检查所有命名空间中的 Pod ===
kubectl get pods -A
# === 3. 检查组件状态 ===
kubectl get componentstatuses
# === 4. 检查 API Server 健康状态 ===
kubectl get --raw '/healthz' # 输出: ok
# === 5. 检查节点资源使用率 (需要 Metrics Server) ===
kubectl top nodes
# 预期输出:
# NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
# kuboard-01 128m 6% 1892Mi 49%
# kuboard-02 45m 2% 856Mi 22%
# kuboard-03 52m 2% 923Mi 24%
# kuboard-04 48m 2% 879Mi 23%
13.2 使用 Kuboard 进行集群监控
登录 Kuboard (http://120.46.195.39:30080) 后:
┌──────────────────────────────────────────────────────────────────┐
│ Kuboard 集群概览页面 │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 节点状态 │ │ Pod 运行数 │ │ 异常告警 │ │
│ │ 4 / 4 Ready │ │ 28 Running │ │ 0 个 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ 节点资源使用率 (实时图表): │
│ kuboard-01: CPU 6% MEM 49% ████████░░░░░░░░░░ │
│ kuboard-02: CPU 2% MEM 22% ████░░░░░░░░░░░░░░ │
│ kuboard-03: CPU 2% MEM 24% ████░░░░░░░░░░░░░░ │
│ kuboard-04: CPU 2% MEM 23% ████░░░░░░░░░░░░░░ │
│ │
│ 工作负载状态: │
│ Deployments: 5/5 Ready ReplicaSets: 5/5 Ready │
│ StatefulSets: 0/0 Ready DaemonSets: 4/4 Ready │
└──────────────────────────────────────────────────────────────────┘
Kuboard 监控功能详解:
| 功能 | 说明 | 访问路径 |
|---|---|---|
| 节点监控 | 查看节点 CPU/内存/磁盘使用率 | 集群 → 节点 → 选择节点 |
| Pod 监控 | 查看 Pod 资源使用率和日志 | 工作负载 → Pod → 选择 Pod |
| 容器日志 | 查看容器标准输出/错误日志 | Pod 详情 → 容器 → 日志 |
| 事件查看 | 查看 K8s Events (排错关键) | 任意资源详情 → 事件标签页 |
| YAML 编辑 | 在线编辑 K8s 资源 YAML | 任意资源详情 → YAML 标签页 |
13.3 备份 etcd 数据 (生产环境必做)
etcd 是 K8s 的唯一数据存储,必须定期备份!
bash
# === 方法1: 使用 etcdctl 备份 (推荐) ===
# 1. 安装 etcd-client
sudo apt-get install -y etcd-client
# 2. 执行备份
sudo ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot-$(date +%Y%m%d-%H%M%S).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# 3. 验证备份文件
sudo ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-snapshot-*.db
# 预期输出:
# Deprecated: A future release will stop checking for this flag. Please use --write-out/-w
# 2025-xx-xx ...
# Snapshot status as of 2025-xx-xx ...
# Hash: xxxxxxxxxxxxxxxx
# Revision: xxxxx
# Total Keys: xxxxx
# Total Size: x.x MiB
自动化备份脚本 (/usr/local/bin/etcd-backup.sh):
bash
#!/bin/bash
# etcd 自动备份脚本
BACKUP_DIR="/backup/etcd"
mkdir -p $BACKUP_DIR
DATE=$(date +%Y%m%d-%H%M%S)
SNAPSHOT="${BACKUP_DIR}/etcd-snapshot-${DATE}.db"
echo "[$(date)] Starting etcd backup..."
sudo ETCDCTL_API=3 etcdctl snapshot save $SNAPSHOT \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
if [ $? -eq 0 ]; then
echo "[$(date)] Backup successful: $SNAPSHOT"
# 保留最近 7 天的备份
find $BACKUP_DIR -name "etcd-snapshot-*.db" -mtime +7 -delete
else
echo "[$(date)] Backup FAILED!"
exit 1
fi
设置定时备份 (每天凌晨 2 点):
bash
# 添加 cron 任务
echo "0 2 * * * /usr/local/bin/etcd-backup.sh >> /var/log/etcd-backup.log 2>&1" \
| sudo crontab -
13.4 Kubernetes 版本升级实战
⚠️ 升级前必须备份 etcd! 升级有风险,操作需谨慎。
升级策略 :逐版本升级,例如 v1.32.13 → v1.33.x (不能跨次要版本升级)。
13.4.1 升级 Master 节点
bash
# 1. 查看当前版本
kubectl version --short
# 2. 查看可用版本
sudo apt-get update
apt-cache madison kubeadm | head -10
# 3. 升级 kubeadm (在所有 Master 节点上)
sudo apt-get install -y kubeadm=1.33.0-1.1 kubelet=1.33.0-1.1 kubectl=1.33.0-1.1
sudo apt-mark hold kubelet kubeadm kubectl
# 4. 验证 kubeadm 版本
kubeadm version
# 5. 检查升级计划
sudo kubeadm upgrade plan
# 预期输出:
# [upgrade/config] Making sure the configuration is correct
# [upgrade] Running pre-flight checks
# [upgrade] Making sure the cluster is healthy
# [upgrade] Fetching available versions to upgrade to
# [upgrade/versions] Target version: v1.33.0
# [upgrade/versions] Latest version in the v1.32 series: v1.32.13
# ...
# Components with upgrade available:
# COMPONENT CURRENT AVAILABLE
# kube-apiserver v1.32.13 v1.33.0
# ...
# 6. 执行控制平面升级
sudo kubeadm upgrade apply v1.33.0
# 7. 手动升级 kubelet 配置
sudo systemctl daemon-reload
sudo systemctl restart kubelet
# 8. 取消 Master 节点的调度保护 (以便升级时排空 Pod)
kubectl uncordon kuboard-01
13.4.2 升级 Worker 节点
bash
# 在**每个 Worker 节点**上执行:
# 1. 标记节点为不可调度并驱逐 Pod
kubectl drain kuboard-02 --ignore-daemonsets --delete-emptydir-data
# 2. 升级 kubeadm/kubelet/kubectl
sudo apt-get install -y kubeadm=1.33.0-1.1 kubelet=1.33.0-1.1 kubectl=1.33.0-1.1
sudo apt-mark hold kubelet kubeadm kubectl
# 3. 升级 kubelet 配置
sudo systemctl daemon-reload
sudo systemctl restart kubelet
# 4. 恢复节点可调度
kubectl uncordon kuboard-02
# 5. 验证节点版本
kubectl get nodes -o wide
13.5 资源管理:ResourceQuota 和 LimitRange
13.5.1 设置命名空间资源配额 (ResourceQuota)
yaml
# resource-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: production
spec:
hard:
requests.cpu: "4" # CPU 请求总量上限
requests.memory: 8Gi # 内存请求总量上限
limits.cpu: "8" # CPU 限制总量上限
limits.memory: 16Gi # 内存限制总量上限
pods: "20" # Pod 数量上限
services: "10" # Service 数量上限
secrets: "20" # Secret 数量上限
configmaps: "20" # ConfigMap 数量上限
bash
kubectl apply -f resource-quota.yaml
kubectl describe resourcequota -n production
13.5.2 设置默认资源限制 (LimitRange)
yaml
# limit-range.yaml
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: production
spec:
limits:
- default: # 默认限制 (Limit)
cpu: "500m"
memory: "512Mi"
defaultRequest: # 默认请求 (Request)
cpu: "100m"
memory: "128Mi"
type: Container
bash
kubectl apply -f limit-range.yaml
kubectl describe limitrange -n production
13.6 通过 Kuboard 管理应用 (实战演示)
13.6.1 创建 Nginx 部署 (通过 Kuboard Web UI)
步骤详解:
1. 登录 Kuboard → 点击左侧 "工作负载" → "部署" → "创建"
2. 填写基本信息:
- 名称 (Name): nginx-deployment
- 命名空间 (Namespace): default
- 副本数 (Replicas): 3
3. 添加容器:
- 容器名称: nginx
- 镜像: nginx:1.27
- 拉取策略: IfNotPresent
- 容器端口: 80 (HTTP)
4. 配置资源限制:
- CPU 请求: 100m
- CPU 限制: 500m
- 内存请求: 128Mi
- 内存限制: 512Mi
5. 配置健康检查:
- 存活探针 (LivenessProbe): HTTP GET / 端口 80, 初始延迟 30s
- 就绪探针 (ReadinessProbe): HTTP GET / 端口 80, 初始延迟 5s
6. 点击 "完成",等待部署完成
7. 验证:
kubectl get deployment nginx-deployment
kubectl get pods -l app=nginx-deployment
13.6.2 创建 Service 暴露服务
1. 在 Kuboard 中,点击左侧 "网络" → "服务" → "创建"
2. 填写基本信息:
- 名称: nginx-service
- 命名空间: default
- 类型: NodePort
3. 配置端口映射:
- 端口名称: http
- 协议: TCP
- 服务端口: 80
- 目标端口: 80
- NodePort: 30001
4. 选择 Pod 选择器 (Selector):
- app: nginx-deployment
5. 点击 "完成"
6. 验证访问:
curl http://192.168.0.85:30001
# 应返回 Nginx 默认页面
13.7 实用 kubectl 别名配置 (提升效率)
编辑 ~/.bashrc 或 ~/.zshrc,添加以下别名:
bash
# kubectl 别名 (k = kubectl)
alias k='kubectl'
alias kgp='kubectl get pods'
alias kgpa='kubectl get pods -A'
alias kgs='kubectl get svc'
alias kgn='kubectl get nodes'
alias kd='kubectl describe'
alias kl='kubectl logs'
alias kex='kubectl exec -it'
alias kdelf='kubectl delete -f'
alias kaf='kubectl apply -f'
# 自动补全 (bash)
source <(kubectl completion bash)
complete -F __start_kubectl k
# 自动补全 (zsh)
# source <(kubectl completion zsh)
使用示例:
bash
k get pods # = kubectl get pods
k describe pod nginx-xxxx # = kubectl describe pod nginx-xxxx
k logs -f nginx-xxxx # = kubectl logs -f nginx-xxxx
k exec -it nginx-xxxx -- bash # = kubectl exec -it nginx-xxxx -- bash
13.8 集群安全加固建议
| 安全项 | 措施 | 命令/配置 |
|---|---|---|
| API Server 访问控制 | 限制 API Server 6443 端口仅对管理 IP 开放 | 华为云安全组配置 |
| etcd 加密 | 启用 etcd 静态加密 (Secret 数据加密) | kubeadm init 时配置 EncryptionConfiguration |
| Pod 安全策略 | 使用 Pod Security Admission (PSA) | 命名空间标签 pod-security.kubernetes.io/enforce=restricted |
| 网络策略 | 配置 NetworkPolicy 限制 Pod 间通信 | 见下方 YAML 示例 |
| 镜像安全 | 使用私有镜像仓库 + 镜像签名验证 | 配置 ImagePolicyWebhook |
| RBAC 最小权限 | 避免使用 cluster-admin,按需授权 | 创建专属 Role/ClusterRole |
NetworkPolicy 示例 (限制只允许特定 Pod 访问数据库):
yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-access-policy
namespace: production
spec:
podSelector:
matchLabels:
app: mysql
ingress:
- from:
- podSelector:
matchLabels:
app: app-frontend
ports:
- protocol: TCP
port: 3306
总结
本文从零开始,在 4 台华为云 ECS 服务器上完成了:
- ✅ 系统环境初始化 (hostname, swap, 内核模块, sysctl)
- ✅ containerd 安装与配置 (SystemdCgroup, 国内镜像加速)
- ✅ Kubernetes v1.32.13 集群搭建 (kubeadm init + Flannel + Worker join)
- ✅ Kuboard v3 部署 (华为云 SWR 镜像, NodePort 30080)
- ✅ 踩坑记录与解决方案 (6 个真实踩坑记录)
集群访问信息:
- Kubernetes API Server :
https://120.46.195.39:6443 - Kuboard Web UI :
http://120.46.195.39:30080 - 默认账号 :
admin/Kuboard123
后续学习方向:
- 部署 Ingress Controller (Nginx Ingress / Traefik)
- 配置 StorageClass (持久化存储)
- 部署监控栈 (Prometheus + Grafana + AlertManager)
- 配置 CI/CD (Jenkins / GitLab Runner)
- 多 Master 高可用部署
文档版本 : v1.0 | 最后更新 : 2025年 | 适用 K8s 版本 : v1.32.x
反馈与问题: 请在 Kuboard 官方社区或 GitHub Issues 反馈
常见问题 FAQ (Frequently Asked Questions)
Q1: kubeadm init 时镜像拉取超时怎么办?
A : 这是国内服务器访问 registry.k8s.io 不通导致的。解决方案:
- 使用阿里云镜像:
--image-repository=registry.aliyuncs.com/google_containers - 如果使用配置文件,设置
imageRepository: "registry.aliyuncs.com/google_containers" - 确保 containerd 的 mirror 配置正确(见第 11 章)
Q2: Flannel Pod 一直 Init:0/1 或 ImagePullBackOff?
A : 通常是 ghcr.io 镜像拉取失败(国内网络问题)。解决方案:
- 修改
kube-flannel.yml,将ghcr.io/flannel-io/flannel替换为docker.rainbond.cc/flannel-io/flannel - 或者手动拉取镜像后导出,再通过
ctr import导入到所有节点 - 检查
/opt/cni/bin/下是否存在bridge和host-localCNI 插件
Q3: Worker 节点加入集群后一直是 NotReady?
A: 可能原因:
- Flannel DaemonSet 没有调度到该 Worker 节点 → 检查
kubectl get pods -n kube-flannel -o wide - containerd
SystemdCgroup未设置为true→ 检查/etc/containerd/config.toml - 防火墙 UDP 8472 (VXLAN) 未开放 → 放行 VXLAN 端口
Q4: Kuboard Pod 无法调度到 Master 节点?
A : Master 节点默认有 node-role.kubernetes.io/control-plane:NoSchedule 污点。解决方案:
在 Kuboard 的 Deployment YAML 中添加 tolerations:
yaml
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
Q5: 如何彻底卸载 K8s 集群?
A: 在所有节点上执行:
bash
sudo kubeadm reset --force
sudo rm -rf /etc/kubernetes /var/lib/etcd /var/lib/kubelet ~/.kube
sudo apt-get purge -y kubelet kubeadm kubectl
sudo apt-get autoremove -y
sudo systemctl restart containerd
Q6: 生产环境有哪些必须做的安全加固?
A:
- API Server 6443 端口仅对管理 IP 开放(安全组规则)
- 立即修改 Kuboard 默认密码 (
Kuboard123) - 为不同团队创建专属 RBAC 账号,避免使用
cluster-admin - 启用 etcd 静态加密(加密 Secret 数据)
- 配置 Pod Security Admission (PSA),限制特权容器
- 定期备份 etcd 数据(见第 13 章)
本文档持续更新,欢迎提交 PR 或 Issue 反馈问题。