欢迎光临
我们一直在努力

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: demoapp
namespace: default
labels:
app: demoapp
spec:
replicas: 1
selector:
matchLabels:
app: demoapp
template:
metadata:
labels:
app: demoapp
spec:
containers:
name: demoapp
image: docker.io/library/demoapp: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: demoappsvc
namespace: default
labels:
app: demoapp
spec:
type: NodePort
selector:
app: demoapp
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/

赞(0)
未经允许不得转载:171主机测评 » K3s 轻量级 Kubernetes 从零到生产实战
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址