K3s 轻量级 Kubernetes 从零到生产实战
K3s 轻量级 Kubernetes 从零到生产实战
主题:在单节点华为云 ECS 上部署 K3s v1.35.5,并通过真实 Demo 应用完成全流程实战
核心理念:轻量不等于功能缩水,K3s 用 512MB 内存跑完整 K8s
实战环境:华为云 ecs-6ce9-0004 (2vCPU/4GiB/Ubuntu 24.04, Docker 29.5.3)
深度踩坑:containerd 双实例、镜像导入、NodePort 503 排查
目录
- 第一部分:K3s 是什么?——轻量级 K8s 的选型之道
- 第二部分:环境准备与 K3s 安装
- 第三部分:K3s 架构深度解析
- 第四部分:K3s 核心组件验证
- 第五部分:部署第一个应用——Node.js Demo App
- 第六部分:containerd 双实例深度踩坑
- 第七部分:NodePort 503 排查全景记录
- 第八部分:K3s 常用运维命令速查
- 第九部分:K3s vs K8s vs MicroK8s 全面对比
- 第十部分:踩坑大全与总结
第一部分:K3s 是什么?——轻量级 K8s 的选型之道
1.1 什么是 K3s?
K3s 是由 Rancher Labs(现属 SUSE)维护的 CNCF 沙箱项目,全称 “Kubernetes minus the fat”(减去臃肿的 K8s)。
┌──────────────────────────────────────────────────────┐
│ K8s 的组成部分 │
├──────────────────────────────────────────────────────┤
│ kube-apiserver │ etcd │ kube-controller-manager │
│ kube-scheduler │ kubelet │ kube-proxy │ CNI │
│ CRI (containerd) │ CoreDNS │ 云提供商插件(CCM) │
│ ... 以及大量 alpha/beta 特性、不再需要的老 API ... │
└──────────────────────────────────────────────────────┘
↓
"减去不必要的部分"
↓
┌──────────────────────────────────────────────────────┐
│ K3s 的组成部分 │
├──────────────────────────────────────────────────────┤
│ ★ 单一二进制(< 100MB)包含所有核心组件 │
│ ★ SQLite 替代 etcd(默认) │
│ ★ 内置 containerd(替代 Docker CRI) │
│ ★ 内置 Flannel CNI + CoreDNS │
│ ★ 内置 Traefik Ingress Controller │
│ ★ 内置 local-path-provisioner(本地存储) │
│ ★ 移除所有 alpha 特性和云提供商插件 │
└──────────────────────────────────────────────────────┘
1.2 为什么选择 K3s?
| 维度 | K3s | 标准 K8s (kubeadm) |
|---|---|---|
| 二进制大小 | < 100MB | 多组件累计 > 1GB |
| 最小内存 | 512MB | 2GB+ |
| 安装方式 | 一条 curl 命令 | kubeadm init + 多步配置 |
| 默认存储 | SQLite(嵌入式) | etcd(强一致分布式) |
| 默认 CNI | Flannel | 无(需自行安装) |
| 默认 Ingress | Traefik | 无(需自行安装) |
| 证书管理 | 自动轮换 | 手动管理 |
| 适用场景 | Edge/IoT/单机开发 | 生产多节点集群 |
| 高可用 | 支持嵌入式 etcd 或外部 DB | 原生支持 |
1.3 K3s 典型应用场景
IoT / 边缘计算 CI/CD 测试环境 开发桌面环境
┌──┐ ┌──┐ ┌──┐
│RPi│ │ECS│ │Mac│
└──┬──┘ └──┬──┘ └──┬──┘
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ K3s │ │ K3s │ │ K3s │
│ Agent │ │ Server │ │ Server │
│ (ARM) │ │ 单节点 │ │ (本地) │
└─────────┘ └─────────┘ └─────────┘
传感器数据采集 快速创建/销毁 本地开发和测试
第二部分:环境准备与 K3s 安装
2.1 服务器规格
| 项目 | 参数 |
|---|---|
| 实例规格 | ac9.large.2(2vCPU / 4GiB) |
| 操作系统 | Ubuntu 24.04.4 LTS |
| 内核版本 | 6.8.0-106-generic |
| 磁盘 | 40GB SSD(已用 6.1G) |
| 公网 IP | 120.46.154.100 |
| 内网 IP | 192.168.0.144 |
| Docker | 29.5.3(overlay2,Cgroup v2) |
2.2 Docker 环境准备
# Step 1:安装 Docker(已配置阿里云镜像加速)
cat > /etc/docker/daemon.json << 'EOF'
{
"registry-mirrors": [
"https://docker.1ms.run",
"https://docker.xuanyuan.me",
"https://mirrors.aliyun.com"
],
"log-driver": "json-file",
"log-opts": {"max-size": "100m", "max-file": "3"}
}
EOF
systemctl restart docker
docker info --format "{{.ServerVersion}}"
# 输出:29.5.3
2.3 K3s 一键安装
这是 K3s 最核心的优势——一条命令完成安装:
# 使用 Rancher 国内镜像加速(国内环境必须!)
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | \
INSTALL_K3S_MIRROR=cn sh -
参数说明:
| 参数 | 含义 |
|---|---|
-sfL |
s=静默, f=失败时输出错误, L=跟随重定向 |
rancher-mirror.rancher.cn |
Rancher 中国镜像站(直连 GitHub 极慢) |
INSTALL_K3S_MIRROR=cn |
告诉安装脚本从国内源下载二进制 |
安装过程做了什么:
curl 下载 install.sh
→ 检测 CPU 架构(amd64/arm64)
→ 从 rancher-mirror.rancher.cn 下载 k3s 二进制(~60MB)
→ 安装到 /usr/local/bin/k3s
→ 创建 systemd unit:k3s.service
→ 生成 kubeconfig:/etc/rancher/k3s/k3s.yaml
→ 自动配置:
- containerd 作为 CRI 运行时
- Flannel 作为 CNI 网络插件
- CoreDNS 作为集群 DNS
- Traefik 作为 Ingress Controller
- local-path-provisioner 作为存储类
→ 启动 k3s-server
→ 完成!
验证安装:
# 1. 检查节点状态
$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP CONTAINER-RUNTIME
ecs-6ce9-0004 Ready control-plane 61m v1.35.5+k3s1 192.168.0.144 containerd://2.2.3-k3s1
输出解读:
| 字段 | 值 | 说明 |
|---|---|---|
| STATUS | Ready | 节点就绪,API Server 可接受请求 |
| ROLES | control-plane | 单节点兼具控制面和数据面角色 |
| VERSION | v1.35.5+k3s1 | K3s 封装版本(2026年6月最新) |
| CONTAINER-RUNTIME | containerd://2.2.3-k3s1 | K3s 内置 containerd |
第三部分:K3s 架构深度解析
3.1 单节点架构全景图
┌────────────────────────────────────────────────────┐
│ ecs-6ce9-0004 (2vCPU/4GiB) │
│ 120.46.154.100 / 192.168.0.144 │
├────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────── K3s Server ───────────────┐ │
│ │ │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │
│ │ │ API │ │Controller │ │ Scheduler │ │ │
│ │ │ Server │ │ Manager │ │ │ │ │
│ │ │ :6443 │ │ │ │ │ │ │
│ │ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │ │
│ │ └──────────────┼──────────────┘ │ │
│ │ │ │ │
│ │ ┌────────▼────────┐ │ │
│ │ │ SQLite (默认) │ │ │
│ │ │ /var/lib/rancher │ │ │
│ │ │ /k3s/server/db/ │ │ │
│ │ └────────┬────────┘ │ │
│ └───────────────────────┼────────────────────────┘ │
│ │ │
│ ┌────────────── K3s Agent ──────────────────────┐ │
│ │ │ │
│ │ ┌───────────┐ │ │
│ │ │ Kubelet │──→ 管理 Pod 生命周期 │ │
│ │ └───────────┘ │ │
│ │ │ │
│ │ ┌───────────┐ │ │
│ │ │Kube-proxy │──→ iptables/ipvs Service 转发 │ │
│ │ └───────────┘ │ │
│ │ │ │
│ │ ┌───────────────────────┐ │ │
│ │ │ K3s containerd │ │ │
│ │ │ /run/k3s/containerd/│ │ │
│ │ │ containerd.sock │ │ │
│ │ └───────────┬───────────┘ │ │
│ │ │ │ │
│ │ ┌───────────▼───────────┐ │ │
│ │ │ K8s Pods │ │ │
│ │ │ ┌──────┐ ┌─────────┐ │ │ │
│ │ │ │Core │ │ Traefik │ │ │ │
│ │ │ │DNS │ │ Ingress │ │ │ │
│ │ │ └──────┘ └─────────┘ │ │ │
│ │ │ ┌──────────────────┐ │ │ │
│ │ │ │ demo-app Pod │ │ │ │
│ │ │ │ 10.42.0.153 │ │ │ │
│ │ │ └──────────────────┘ │ │ │
│ │ └───────────────────────┘ │ │
│ └────────────────────────────────────────────────┘ │
│ │
│ ┌──────────── 系统 Docker ──────────────┐ │
│ │ dockerd + containerd(独立实例) │ │
│ │ /run/containerd/containerd.sock │ │
│ └────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
3.2 K3s 的精简策略
K3s 相比标准 K8s 的精简不是"砍功能",而是"换实现":
| 标准 K8s 组件 | K3s 替代方案 | 优势 |
|---|---|---|
| kube-apiserver | k3s server 内置 | 减少进程数 |
| kube-controller-manager | k3s server 内置 | 内存共享 |
| kube-scheduler | k3s server 内置 | 减少 IPC |
| etcd | SQLite(默认) | 零运维、嵌入式 |
| Docker + dockershim | 内置 containerd | 直接 CRI,无 dockershim 中间层 |
| 云提供商 CCM | 移除 | 减少不必要的 API 调用 |
| kubelet | k3s agent 内置 | 统一升级 |
| kube-proxy | k3s agent 内置 | 统一升级 |
3.3 关键路径与文件
# K3s 目录结构
/etc/rancher/k3s/
├── k3s.yaml # ← kubeconfig(权限 600,root 可读)
└── registries.yaml # ← 镜像仓库配置(需手动创建)
/var/lib/rancher/k3s/
├── server/
│ ├── db/ # ← SQLite 数据文件
│ └── token # ← 集群 Token(用于加节点)
├── agent/
│ ├── containerd/ # ← K3s containerd 数据目录
│ └── etc/containerd/
│ ├── config.toml # ← containerd 配置(K3s 自动生成)
│ └── certs.d/ # ← 私有 Registry 证书
└── data/ # ← K3s 二进制和数据
/run/k3s/containerd/
└── containerd.sock # ← K3s containerd GRPC Socket
第四部分:K3s 核心组件验证
4.1 系统服务状态
$ systemctl status k3s --no-pager
● k3s.service - Lightweight Kubernetes
Loaded: loaded (/etc/systemd/system/k3s.service; enabled; preset: enabled)
Active: active (running)
Docs: https://k3s.io
Main PID: 26125 (k3s-server)
Tasks: 92
Memory: 1.5G (peak: 1.6G)
CPU: 1min 1.607s
内存占用分析:
| 组件 | 内存占用 |
|---|---|
| k3s-server(含 API/Controller/Scheduler) | ~800MB |
| k3s-agent(kubelet + kube-proxy) | ~400MB |
| containerd + Pods 开销 | ~300MB |
| 总计 | ~1.5GB / 4GB(37.5%) |
4.2 Pod 清单与网络模型
$ kubectl get pods -A -o wide
NAMESPACE NAME READY STATUS IP NODE
kube-system coredns-8db54c48d-sv59t 1/1 Running 10.42.0.146 ecs-6ce9-0004
kube-system local-path-provisioner-5d9d9885bc-nftq2 1/1 Running 10.42.0.143 ecs-6ce9-0004
kube-system metrics-server-786d997795-lvp67 1/1 Running 10.42.0.145 ecs-6ce9-0004
kube-system svclb-traefik-38a4f38d-cgkgq 2/2 Running 10.42.0.148 ecs-6ce9-0004
kube-system traefik-9bcdbbd9-sq8mc 1/1 Running 10.42.0.149 ecs-6ce9-0004
default demo-app-6b98c7bf45-bnfqr 1/1 Running 10.42.0.153 ecs-6ce9-0004
Flannel VXLAN 网络模型:
物理网络:192.168.0.0/24(华为云 VPC)
↓
K3s Flannel Overlay:10.42.0.0/16(Pod CIDR)
↓
Service ClusterIP 网络:10.43.0.0/16(自动分配)
┌──────────────────────────────────────────────────────┐
│ 物理网卡 eth0 │
│ 192.168.0.144 │
│ │ │
│ ├── flannel.1 (VTEP 设备) │
│ │ 负责跨节点的 VXLAN 封包/解包 │
│ │ │
│ ├── cni0 (CNI Bridge) │
│ │ 10.42.0.1 — 连接所有 Pod veth │
│ │ ├── veth → Pod: demo-app (10.42.0.153) │
│ │ ├── veth → Pod: coredns (10.42.0.146) │
│ │ └── veth → Pod: traefik (10.42.0.149) │
│ │ │
│ └── kube-ipvs0 (IPVS 接口) │
│ 负责 Service ClusterIP → Pod IP 负载均衡 │
│ iptables-mode: false (K3s 默认使用 IPVS) │
└──────────────────────────────────────────────────────┘
4.3 Service 网络
$ kubectl get svc -A
NAMESPACE NAME TYPE CLUSTER-IP PORT(S) AGE
default kubernetes ClusterIP 10.43.0.1 443/TCP 61m
default demo-app-svc NodePort 10.43.24.186 3000:30300/TCP 13m
kube-system kube-dns ClusterIP 10.43.0.10 53/UDP,53/TCP,9153/TCP 61m
kube-system metrics-server ClusterIP 10.43.248.101 443/TCP 61m
kube-system traefik LoadBalancer 10.43.60.35 80:32443/TCP,443:31350/TCP 32m
Traefik LoadBalancer 的特别之处:K3s 内置的 svclb-traefik DaemonSet 会在每个节点上启动一个负载均衡 Pod,通过 ECMP/iptables 将 LoadBalancer Service 的 External-IP 流量转发到 Traefik Pod,实现单节点环境下的 LoadBalancer 服务。
第五部分:部署第一个应用——Node.js Demo App
5.1 应用源码
demo-app/
├── src/
│ └── server.js # Node.js HTTP 服务
├── Dockerfile # 镜像构建文件
└── deployment.yaml # K8s 部署清单
server.js — 健康检查 + 主页 API:
const http = require('http');
const os = require('os');
const PORT = process.env.PORT || 3000;
const VERSION = process.env.APP_VERSION || '1.0.0';
const server = http.createServer((req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
if (url.pathname === '/health') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
status: 'healthy',
version: VERSION,
hostname: os.hostname(),
uptime: process.uptime(),
timestamp: new Date().toISOString()
}));
return;
}
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(/* HTML 主页 */);
});
server.listen(PORT, () => {
console.log(`Demo App v${VERSION} running on port ${PORT}`);
});
Dockerfile — node:18-alpine 镜像:
FROM node:18-alpine
LABEL maintainer="devops@demo.local"
WORKDIR /app
COPY src/ .
EXPOSE 3000
ENV APP_VERSION=1.0.0
ENV PORT=3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "server.js"]
5.2 Docker 镜像构建
$ cd /root/demo-app
$ docker build -t demo-app:1.0.0 .
# 输出(关键行):
# [+] Building 45.2s (8/8) FINISHED
# => [2/3] COPY src/ . 0.1s
# => [3/3] RUN addgroup -g 1001 -S nodejs ... 2.3s
# => exporting to image 38.4s
验证镜像:
$ docker images demo-app:1.0.0
REPOSITORY TAG IMAGE ID SIZE
demo-app 1.0.0 9ccbdba23821 44.9MB # ← 非常轻量!
5.3 K8s 部署清单
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app
namespace: default
labels:
app: demo-app
spec:
replicas: 1
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
containers:
- name: demo-app
image: docker.io/library/demo-app:1.0.0 # ← 关键:使用完整镜像名
imagePullPolicy: Never # ← 不从 Registry 拉取
ports:
- containerPort: 3000
name: http
env:
- name: APP_VERSION
value: "1.0.0"
- name: PORT
value: "3000"
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 3
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: demo-app-svc
namespace: default
labels:
app: demo-app
spec:
type: NodePort
selector:
app: demo-app
ports:
- port: 3000
targetPort: 3000
nodePort: 30300
name: http
关键配置解读:
| 配置 | 值 | 说明 |
|---|---|---|
imagePullPolicy: Never |
Never | 核心:强制使用本地 containerd 已有的镜像,不从任何 Registry 拉取 |
image: docker.io/library/demo-app:1.0.0 |
完整路径 | 必须与 crictl images 中的名称完全一致 |
nodePort: 30300 |
30300 | NodePort 范围 30000-32767,此处指定 30300 |
readinessProbe |
/health | Pod 就绪后才接收流量 |
resources.requests |
64Mi/100m | 必须设置,避免资源争抢 |
第六部分:containerd 双实例深度踩坑
⚠️ 这是本次实战中最核心、最隐蔽的踩坑,也是新手最容易犯的错误。
6.1 问题现象
Docker build 完镜像后,用 ctr images import 导入,crictl images 却看不到镜像:
$ docker save demo-app:1.0.0 | ctr -n k8s.io images import -
# 命令成功执行
$ crictl images | grep demo-app
# ← 什么都不输出!镜像不存在!
然后又尝试直接 kubectl apply,Pod 报 ErrImageNeverPull。
6.2 根因分析:两个 containerd 实例
在安装了 Docker 的 K3s 节点上,存在两个独立的 containerd 进程:
┌──────────────────────────────────────────────────┐
│ 宿主机 OS │
│ │
│ ┌──────────── docker.service ────────────┐ │
│ │ dockerd │ │
│ │ │ │ │
│ │ └── containerd (PID: 1100) │ │
│ │ Socket: /run/containerd/ │ │
│ │ containerd.sock │ │
│ │ 命名空间: default, moby │ │
│ │ 用途: Docker 镜像构建 & 运行 │ │
│ └──────────────────────────────────────────┘ │
│ │
│ ┌──────────── k3s.service ────────────────┐ │
│ │ k3s-server │ │
│ │ │ │ │
│ │ └── containerd (PID: 24886) │ │
│ │ Socket: /run/k3s/containerd/ │ │
│ │ containerd.sock │ │
│ │ 命名空间: k8s.io │ │
│ │ 用途: K3s CRI 运行时 │ │
│ └──────────────────────────────────────────┘ │
│ │
│ ┌──────────── CRI CLI 工具 ───────────────┐ │
│ │ crictl → 默认连 /run/containerd/ │ │
│ │ ctr → 默认连 /run/containerd/ │ │
│ │ kubectl → 通过 K3s agent 连 K3s 的 │ │
│ │ containerd sock │ │
│ └──────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘
关键区别一览:
| containerd 实例 | Socket 路径 | PID | 命名空间 | 管理方 | 用途 |
|---|---|---|---|---|---|
| 系统 containerd | /run/containerd/containerd.sock |
~1100 | default, moby | Docker daemon | Docker 镜像构建/容器运行 |
| K3s containerd | /run/k3s/containerd/containerd.sock |
~24886 | k8s.io | K3s Agent | K8s Pod 生命周期管理 |
为什么会踩坑:
ctr和crictl默认都连接 系统 containerd(/run/containerd/containerd.sock)- K3s 的 kubelet 只跟 K3s containerd 通信
- 你在系统 containerd 里导入的镜像,K3s 完全看不见!
6.3 正确操作流程
Step 1:Docker build 镜像
$ docker build -t demo-app:1.0.0 .
# 镜存在 Docker 使用的系统 containerd 中
Step 2:导出并导入到 K3s containerd
# 正确命令:必须指定 K3s containerd socket 和 k8s.io 命名空间
$ docker save docker.io/library/demo-app:1.0.0 | \
ctr -a /run/k3s/containerd/containerd.sock -n k8s.io images import -
| 参数 | 值 | 必须性 | 说明 |
|---|---|---|---|
-a |
/run/k3s/containerd/containerd.sock |
⚠️ 必须 | 指定 K3s 的 containerd socket |
-n |
k8s.io |
⚠️ 必须 | K3s 只认这个命名空间 |
Step 3:验证
$ crictl images | grep demo-app
docker.io/library/demo-app 1.0.0 8c25bf4c3e082 44.9MB # ✅ 出现!
Step 4:kubectl apply
$ kubectl apply -f deployment.yaml
deployment.apps/demo-app created
service/demo-app-svc created
$ kubectl get pods -l app=demo-app
NAME READY STATUS RESTARTS AGE
demo-app-6b98c7bf45-bnfqr 1/1 Running 0 10s # ✅ 运行!
6.4 为什么不用 Docker Registry 中转?
你可能想:直接用 docker push 推到 Registry,再让 K3s imagePullPolicy: Always 拉取,不就没这个问题了吗?
在本次实战中行不通,原因如下:
# K3s 节点 (192.168.0.144) → Registry (192.168.0.164)
$ ping -c 2 -W 2 192.168.0.164
2 packets transmitted, 0 received, 100% packet loss # ← 内网不通!
# 华为云不同 ECS 之间默认 VPC 隔离
| 方案 | 可行性 | 说明 |
|---|---|---|
| Docker Registry (内网) | ❌ | 华为云 VPC 默认隔离,不通 |
| Docker Registry (公网) | ⚠️ | 需 5Mbps 带宽传输,且要配置 HTTPS |
| `docker save | ctr import` | ✅ |
第七部分:NodePort 503 排查全景记录
7.1 问题复现
浏览器访问:http://120.46.154.100:30300/
↓
HTTP 503 Service Unavailable
7.2 排查 Step-by-Step
Step 1:检查集群状态
$ kubectl get pods -A
NAMESPACE NAME READY STATUS
kube-system coredns-8db54c48d-sv59t 1/1 Running
kube-system local-path-provisioner-5d9d9885bc-nftq2 1/1 Running
kube-system metrics-server-786d997795-lvp67 1/1 Running
kube-system traefik-9bcdbbd9-sq8mc 1/1 Running
# ⚠️ 没有任何 demo-app Pod!
| 发现 | 结论 |
|---|---|
| 系统 Pod 全部 Running | K3s 集群本身正常 |
| 无 demo-app Pod | 应用从未部署 |
| 无 demo-app Service | NodePort 30300 没有对应后端 |
Step 2:检查 Service
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 61m
# ← 只有默认 kubernetes Service,demo-app-svc 不存在
Step 3:确认根本原因
503 的根本原因:
Kubernetes Service "demo-app-svc" (NodePort 30300) 从未被创建
→ 因为 Deployment 也从未被创建
→ 因为 demo-app 镜像从未被导入 K3s containerd
→ 一切都是从头开始
7.3 修复全流程
Step 1: 创建 demo-app 源码
→ server.js + Dockerfile + deployment.yaml
Step 2: Docker build
→ docker build -t demo-app:1.0.0 . (45s, 44.9MB)
Step 3: 导入 K3s containerd(关键!)
→ docker save | ctr -a /run/k3s/containerd/containerd.sock -n k8s.io images import -
Step 4: kubectl apply
→ deployment.apps/demo-app created
→ service/demo-app-svc created
Step 5: 验证
→ kubectl get pods → Running 1/1 ✅
→ curl localhost:30300/health → {"status":"healthy"} ✅
→ curl http://120.46.154.100:30300/ → HTTP 200 ✅
7.4 验证截图(数据采集)
# 集群范围验证
$ kubectl get pods -A -o wide
NAMESPACE NAME IP NODE
default demo-app-6b98c7bf45-bnfqr 10.42.0.153 ecs-6ce9-0004
kube-system coredns-8db54c48d-sv59t 10.42.0.146 ecs-6ce9-0004
...
$ kubectl describe deployment demo-app
Name: demo-app
Namespace: default
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
$ kubectl describe svc demo-app-svc
Name: demo-app-svc
Type: NodePort
IP: 10.43.24.186
Port: http 3000/TCP
TargetPort: 3000/TCP
NodePort: http 30300/TCP # ← 映射正确
Endpoints: 10.42.0.153:3000 # ← Pod IP 正确
# Pod 日志
$ kubectl logs -l app=demo-app --tail=5
Demo App v1.0.0 running on port 3000
Health check: http://localhost:3000/health
# 最终验证
$ curl -s http://120.46.154.100:30300/health
{"status":"healthy","version":"1.0.0","hostname":"demo-app-6b98c7bf45-bnfqr",
"uptime":156.78,"timestamp":"2026-06-08T04:24:30.123Z"}
7.5 流量链路分析
外部请求
│ http://120.46.154.100:30300/
▼
K3s kube-proxy (IPVS/iptables)
│ NodePort 30300 → Service ClusterIP 10.43.24.186:3000
▼
K3s kube-proxy (IPVS/iptables)
│ 10.43.24.186:3000 → Endpoint 10.42.0.153:3000
▼
Flannel VXLAN
│ 物理网卡 → cni0 bridge → veth pair → Pod netns
▼
demo-app Pod (10.42.0.153:3000)
│ Node.js HTTP Server
▼
HTTP 200: {"status": "healthy", "version": "1.0.0", ...}
第八部分:K3s 常用运维命令速查
8.1 集群管理
# 查看集群信息
kubectl cluster-info # API Server + CoreDNS 地址
kubectl version # Client + Server 版本
kubectl get nodes -o wide # 节点列表 + IP + 运行时
# 查看所有资源
kubectl get all -A # 所有命名空间的所有资源
kubectl get pods -A -o wide # Pod 列表 + IP + 节点
kubectl get svc -A # Service 列表
kubectl get deploy -A # Deployment 列表
# K3s 特有操作
systemctl status k3s # 服务状态
systemctl restart k3s # 重启 K3s(会重启所有 Pod!)
k3s kubectl <command> # 不用配置 kubeconfig 直接操作
8.2 镜像管理(K3s 双 containerd 环境)
# === Docker 端(系统 containerd)===
docker images # 查看 Docker 镜像
docker build -t myapp:v1 . # 构建镜像
docker save myapp:v1 -o /tmp/myapp.tar # 导出镜像
# === K3s containerd 端 ===
crictl images # 查看 K3s 可见的镜像
crictl pull docker.io/library/nginx:latest # 拉取镜像(需网络)
crictl rmi <IMAGE_ID> # 删除镜像
# === 镜像搬运(Docker → K3s)===
docker save docker.io/library/myapp:v1 | \
ctr -a /run/k3s/containerd/containerd.sock -n k8s.io images import -
8.3 Pod 排障
# 查看 Pod 详情
kubectl describe pod <POD_NAME> # 查看 Events(最重要!)
kubectl logs <POD_NAME> # 查看日志
kubectl logs <POD_NAME> --previous # 上一次崩溃的日志
kubectl logs -l app=<LABEL> --tail=50 -f # 按标签查看并跟随
# 进入容器
kubectl exec -it <POD_NAME> -- /bin/sh # 进入容器调试
kubectl port-forward <POD_NAME> 8080:3000 # 端口转发到本地
# 资源使用
kubectl top pods # Pod 资源使用
kubectl top nodes # 节点资源使用
8.4 配置与管理
# configmap/secret
kubectl create configmap app-config --from-file=config.json
kubectl create secret generic db-pass --from-literal=password=123456
# 滚动更新
kubectl set image deploy/demo-app demo-app=demo-app:2.0.0
kubectl rollout status deploy/demo-app # 等待更新完成
kubectl rollout undo deploy/demo-app # 回滚
# 资源伸缩
kubectl scale deploy/demo-app --replicas=3 # 扩容到 3 副本
kubectl autoscale deploy/demo-app --min=1 --max=10 --cpu-percent=80 # HPA
# 清理
kubectl delete -f deployment.yaml # 按文件删除
kubectl delete deploy demo-app # 按名称删除
kubectl delete pods --all # 删除所有 Pod(会被 Deploy 重建)
第九部分:K3s vs K8s vs MicroK8s 全面对比
9.1 整体对比表
| 维度 | K3s | 标准 K8s (kubeadm) | MicroK8s |
|---|---|---|---|
| 开发者 | Rancher / SUSE | CNCF / Google | Canonical |
| 二进制大小 | < 100MB | > 1GB(多组件) | ~200MB(snap 包) |
| 最小内存 | 512MB | 2GB+ | 540MB |
| 安装命令 | curl ... \| sh |
kubeadm init |
snap install microk8s |
| 默认存储 | SQLite | etcd | Dqlite |
| 默认 CNI | Flannel | 无(需手动安装) | Calico(可选) |
| 默认 Ingress | Traefik | 无 | nginx(插件) |
| DNS | CoreDNS | CoreDNS | CoreDNS |
| CRI | 内置 containerd | containerd/CRI-O | 内置 containerd |
| ARM 支持 | ✅ 官方 | ✅ | ✅ |
| 高可用 | 嵌入式 etcd/外部 DB | 原生 etcd 集群 | 多节点集群 |
| GPU 支持 | ✅ | ✅ | ✅(插件) |
| Helm 集成 | 内置 Helm Controller | 需独立安装 Helm | 插件形式 |
| CNCF 认证 | ✅ Certified | ✅ Certified | ✅ Certified |
| 适用场景 | Edge/IoT/单机生产 | 多节点生产集群 | 本地开发/MicroCloud |
9.2 K8s 被 K3s 移除的组件
K3s 的"轻量"来自于对标准 K8s 的策略性精简。以下是移除的组件和替代方案:
| 被移除的组件 | 原因 | 影响 |
|---|---|---|
cloud-controller-manager |
云提供商特定逻辑 | 自建机房/裸金属无影响 |
storage.k8s.io/v1alpha1 |
Alpha API,不稳定 | 生产环境不应使用 |
admissionregistration.k8s.io/v1alpha1 |
Alpha API | 使用 v1 版本 |
apiextensions.k8s.io/v1alpha1 |
旧 CRD API | 使用 v1 版本 |
certificates.k8s.io/v1beta1 |
旧 CSR API | 使用 v1 版本 |
coordination.k8s.io/v1beta1 |
旧 Lease API | 使用 v1 版本 |
| Docker (dockershim) | K8s 1.24+ 已废弃 | containerd 直接替代 |
| 旧版 InTree Volume 驱动 | 大部分云存储 | CSI 驱动替代 |
9.3 选型决策树
你需要 K8s 吗?
│
├── 是 → 需要多节点高可用?
│ ├── 是 → 生产环境?
│ │ ├── 是 → kubeadm K8s(完整生态)
│ │ └── 否 → K3s HA(3 节点 + 外部 DB)
│ │
│ └── 否 → 单机即可?
│ ├── 是 → K3s(本案例实战方案)← ✅
│ └── 否 → ...
│
└── 否 → 用 Docker Compose / Nomad 即可
第十部分:踩坑大全与总结
10.1 踩坑清单(含解决方案)
| # | 踩坑 | 现象 | 根因 | 解决方案 |
|---|---|---|---|---|
| 1 | containerd 双实例 | ctr import 后 crictl 看不到镜像 |
系统 containerd ≠ K3s containerd | ctr -a /run/k3s/containerd/containerd.sock -n k8s.io ... |
| 2 | 镜像名不完整 | ErrImageNeverPull |
K3s containerd 中镜像名带 docker.io/library/ 前缀 |
使用完整名称 docker.io/library/demo-app:1.0.0 |
| 3 | 内网隔离 | no route to host → 192.168.0.164:5000 |
华为云 VPC 默认不同 ECS 内网不通 | 本地构建 + imagePullPolicy: Never |
| 4 | Docker Hub 无法直连 | ImagePullBackOff |
国内网络环境限制 | 配置 K3s registries.yaml 使用镜像加速 |
| 5 | heredoc 引号丢失 | daemon.json JSON 损坏 |
SSH exec 多层转义吞掉引号 | Python json.dumps() + SFTP 上传 |
| 6 | NodePort 503 | http://IP:30300/ → 503 |
应用从未部署 | 创建 Deployment + Service 全流程 |
| 7 | K3s 内存占用偏高 | 1.5GB / 4GB | k3s-server 单进程多角色 | 正常现象,生产建议 8GB+ |
| 8 | kubectl version --short 报错 | unknown flag: --short |
K8s 1.29+ 移除了此 flag | 使用 kubectl version |
10.2 K3s 单节点配置建议
# /etc/rancher/k3s/registries.yaml
mirrors:
docker.io:
endpoint:
- "https://docker.1ms.run"
- "https://docker.xuanyuan.me"
- "https://mirrors.aliyun.com"
# 如有私有 Registry:
# "your-registry.com:5000":
# endpoint:
# - "http://your-registry.com:5000"
10.3 总结金句
K3s 不是 K8s 的"阉割版",而是 K8s 的"精简重构"——用更少的资源做同样的事。
| 本次实战收获 | 说明 |
|---|---|
| K3s 安装 | 一条 curl 命令,国内用 rancher-mirror.rancher.cn |
| 架构理解 | K3s 是单二进制封装所有核心组件 |
| containerd 双实例 | 最核心的踩坑:系统 Docker 和 K3s 各有一个 containerd |
| 镜像搬运 | `docker save |
| NodePort 排查 | 503 = 应用未部署 → 从镜像构建到 kubectl apply 全流程 |
| Flannel 网络 | VXLAN 10.42.0.0/16 Overlay,IPVS Service 转发 |
| 运维命令 | 涵盖 Pod/镜像/网络/日志全套命令速查 |
10.4 下一步学习路线
K3s 单节点掌握了 →
│
├── K3s 多节点 HA(3 Server + N Agent)
├── K3s + 外部 MySQL/PostgreSQL 存储
├── K3s Helm Controller 自动化 Chart 部署
├── K3s + Longhorn 分布式存储
├── K3s + Istio/Linkerd Service Mesh
└── K3s 边缘场景(ARM/树莓派集群)
博客完成时间:2026-06-08
实战环境:华为云 ecs-6ce9-0004 (2vCPU/4GiB, Ubuntu 24.04, K3s v1.35.5+k3s1)
在线验证:http://120.46.154.100:30300/
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)