概述

你在一家智能制造公司干运维。工厂车间里有 200 台边缘网关,每台跑着数据采集和实时质检的服务。之前用裸 Docker 部署,每次更新都得写脚本逐台 SSH 上去拉镜像、重启容器。200 台机器跑一轮,半小时过去了,中间还经常有几台网络抖动导致更新失败。

你心想:这不就是 Kubernetes 要解决的问题吗?编排、调度、滚动更新、自愈——全都有了。但真去装 K8s 的时候傻眼了:车间网关用的是 ARM 架构的工控机,2 核 CPU、2G 内存,光 etcd 就吃掉 500M,kube-apiserver、kube-scheduler、kube-controller-manager 一堆组件跑起来,系统资源所剩无几。

这时候 K3s 登场了。它是 Rancher 开发的轻量级 Kubernetes 发行版,把所有控制面组件打包成一个 50MB 的二进制文件,内存占用不到 512M,支持 ARM64/x86_64,自带 containerd 运行时、Flannel 网络、CoreDNS、Traefik Ingress——开箱即用。在树莓派上都能跑起来,工控机更不在话下。

这篇文章聊聊 K3s 在边缘计算场景下的实战:从架构原理到集群搭建,从网络方案到边缘自治,从监控告警到故障排查。不是入门教程的复述,而是生产环境踩坑后的经验总结。

K3s 架构:为什么它能在 512M 内存上跑起来

和 K8s 的关键差异

K3s 不是 K8s 的阉割版——这个说法太粗暴了。它是一个为资源受限环境重新设计的 Kubernetes 发行版。核心区别在以下几方面:

特性K8sK3s
二进制大小~300MB(多组件)~50MB(单二进制)
最低内存2GB512MB
存储后端etcd(必须)SQLite(默认)/ etcd / MySQL / PostgreSQL
运行时需单独安装 containerd/Docker内置 containerd
网络 CNI需手动安装内置 Flannel
Ingress需手动安装内置 Traefik
DNS需手动安装内置 CoreDNS
Alpha/Beta 特性全部包含剔除
云厂商专用代码全部包含剔除
架构支持x86_64 / ARM64x86_64 / ARM64 / ARMv7

K3s 的核心设计哲学是:在边缘场景下,你需要的是 K8s 的编排能力,而不是它的全部复杂性。去掉 alpha/beta 特性和云厂商专用代码后,K3s 保留了 K8s 的核心 API 和功能——Pod、Deployment、Service、ConfigMap、HPA、CronJob 这些你日常用的资源全都在,kubectl 命令完全兼容。

单二进制架构

K3s 把以下组件打包到一个二进制文件中:

k3s 二进制
├── kube-apiserver       # API 服务
├── kube-scheduler       # 调度器
├── kube-controller-manager  # 控制器管理器
├── kubelet              # 节点代理
├── kube-proxy           # 网络代理
├── containerd           # 容器运行时
├── flannel              # CNI 网络插件
├── coredns              # DNS 服务
├── traefik              # Ingress 控制器
├── servicelb            # 服务负载均衡器
└── local-path-provisioner  # 本地存储卷分配器

这意味着你不需要像 K8s 那样分别安装和配置十几个组件。一个二进制文件,一条命令启动,全搞定。

存储后端选择

K3s 默认使用 SQLite 作为存储后端,这对单节点集群是完美的——零额外依赖、零资源开销。但 SQLite 不支持多副本写入,所以多节点 Server 集群需要换存储后端:

存储后端适用场景资源开销高可用
SQLite(默认)单节点 Server极低不支持
etcd多节点 Server,生产环境中等支持
MySQL已有 MySQL 基础设施中等支持
PostgreSQL已有 PG 基础设施中等支持

我的建议:边缘场景下如果只需要单节点 Server,用默认的 SQLite 就够了。如果需要高可用多 Server,用嵌入式 etcd(K3s 支持以 --cluster-init 模式启动内置 etcd)。

单节点集群搭建:5 分钟上手

环境准备

以 Ubuntu 22.04 LTS 为例(ARM64 和 x86_64 均可):

# 基础环境准备
sudo apt update && sudo apt upgrade -y

# 安装时间同步(K8s 组件对时间敏感)
sudo apt install chrony -y
sudo systemctl enable --now chrony

# 关闭 swap(Kubelet 不支持 swap)
sudo swapoff -a
sudo sed -i '/swap/d' /etc/fstab

# 加载必要的内核模块
sudo modprobe overlay
sudo modprobe br_netfilter

# 持久化内核模块
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

# 内核参数调整
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

一键安装

# 安装 K3s Server(国内环境用镜像加速)
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-installation.sh | \
  INSTALL_K3S_MIRROR=cn sh -s - \
  --write-kubeconfig-mode 644 \
  --disable traefik \
  --node-label "node-type=edge"

# 检查安装状态
sudo k3s kubectl get nodes
sudo k3s kubectl get pods -A

解释几个关键参数:

  • --write-kubeconfig-mode 644:让非 root 用户也能读取 kubeconfig
  • --disable traefik:如果你不用 Ingress,可以禁用 Traefik 省资源
  • --node-label:给节点打标签,方便后续调度

安装完成后,K3s 的 kubeconfig 文件在 /etc/rancher/k3s/k3s.yaml,把它复制到 ~/.kube/config 就可以用标准 kubectl 了:

mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config

国内镜像加速

边缘场景的设备通常在国内,拉 Docker Hub 镜像慢得让人抓狂。K3s 用 containerd 而不是 Docker,所以配置方式和 Docker 不一样:

# 创建 containerd 镜像加速配置
sudo mkdir -p /etc/rancher/k3s

cat <<EOF | sudo tee /etc/rancher/k3s/registries.yaml
mirrors:
  docker.io:
    endpoint:
      - "https://registry.cn-hangzhou.aliyuncs.com"
  gcr.io:
    endpoint:
      - "https://registry.cn-hangzhou.aliyuncs.com"
  quay.io:
    endpoint:
      - "https://quay.mirrors.ustc.edu.cn"
configs:
  "registry.cn-hangzhou.aliyuncs.com":
    auth:
      username: "your-aliyun-account"
      password: "your-password"
EOF

# 重启 K3s 使配置生效
sudo systemctl restart k3s

多节点集群:Server + Agent 架构

架构设计

边缘场景下,多节点集群通常是这样设计的:

┌─────────────────────────────────────┐
│          边缘机房 / 工厂车间          │
│                                     │
│  ┌──────────┐    ┌──────────┐      │
│  │ K3s Server│    │ K3s Agent│      │
│  │ (管理节点) │    │ (工作节点)│      │
│  │ 2C/4G    │    │ 2C/2G    │      │
│  └─────┬────┘    └─────┬────┘      │
│        │                │           │
│        │   ┌──────────┐│           │
│        └───┤ K3s Agent ├┘           │
│            │ (工作节点) │           │
│            │ 2C/2G    │            │
│            └──────────┘            │
│                                     │
└─────────────────────────────────────┘

Server 节点跑控制面 + 可以跑工作负载。Agent 节点只跑工作负载。一个 Server 管十几个 Agent,在边缘场景下完全够用。

部署 Server 节点

# 在 Server 节点执行
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-installation.sh | \
  INSTALL_K3S_MIRROR=cn sh -s - \
  --write-kubeconfig-mode 644 \
  --node-label "node-type=server" \
  --node-label "location=edge-room-1"

# 获取 Agent 加入 token
cat /var/lib/rancher/k3s/server/node-token
# 输出类似:K10xxxxxxxxxxxx::server:xxxxxxxxxxxx

部署 Agent 节点

# 在 Agent 节点执行
# 把 <SERVER_IP> 替换为 Server 节点的 IP
# 把 <NODE_TOKEN> 替换为上一步获取的 token
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-installation.sh | \
  INSTALL_K3S_MIRROR=cn sh -s - agent \
  --server https://<SERVER_IP>:6443 \
  --token <NODE_TOKEN> \
  --node-label "node-type=agent" \
  --node-label "location=edge-room-1"

# 验证 Agent 加入
sudo k3s kubectl get nodes

离线安装:边缘场景的刚需

很多边缘设备根本没有外网——工厂车间的网络是封闭的,镜像只能从内网 registry 拉。这时候需要离线安装 K3s。

# 步骤1:在有网络的机器上下载 K3s 二进制文件
# 下载地址:https://github.com/k3s-io/k3s/releases
# 选择对应架构的 binary(amd64 或 arm64)

wget https://github.com/k3s-io/k3s/releases/download/v1.30.0%2Bk3s1/k3s-arm64
# 注意:ARM64 设选用 k3s-arm64,x86_64 选用 k3s

# 步骤2:下载 K3s 依赖的系统镜像包
wget https://github.com/k3s-io/k3s/releases/download/v1.30.0%2Bk3s1/k3s-airgap-images-arm64.tar.zst

# 步骤3:把文件传到边缘设备
scp k3s-arm64 edge-device:/usr/local/bin/k3s
scp k3s-airgap-images-arm64.tar.zst edge-device:/tmp/

# 步骤4:在边缘设备上执行离线安装
ssh edge-device << 'EOF'
sudo chmod +x /usr/local/bin/k3s

# 导入系统镜像
sudo mkdir -p /var/lib/rancher/k3s/agent/images/
sudo cp /tmp/k3s-airgap-images-arm64.tar.zst /var/lib/rancher/k3s/agent/images/

# 下载 K3s 安装脚本(也需要在有网络的机器上下载后传入)
# 假设安装脚本已经放在 /tmp/k3s-install.sh
sudo chmod +x /tmp/k3s-install.sh
sudo /tmp/k3s-install.sh
EOF

离线安装的关键是把 K3s 二进制文件和 airgap 镜像包提前放到正确的目录。安装脚本会检测到本地已有镜像,不再尝试从网上拉取。

网络方案选型:边缘场景的取舍

K3s 内置网络方案

K3s 默认使用 Flannel(VXLAN 模式)作为 CNI。在大多数边缘场景下这够用了,但有几个需要注意的点:

网络模式适用场景性能复杂度
Flannel VXLAN(默认)通用场景中等
Flannel Host-GW同子网节点
Calico需要网络策略
Cilium需要高级网络功能

边缘场景下我推荐用默认的 Flannel VXLAN。原因很简单:边缘设备的网络拓扑经常变化,VXLAN 对底层网络的要求最低——只要节点之间 IP 可达就行。Host-GW 模式虽然性能更好,但要求所有节点在同一个二层网络,这在跨车间的场景下很难满足。

自定义 Flannel 网段

默认情况下 K3s 使用的 Pod CIDR 是 10.42.0.0/16,Service CIDR 是 10.43.0.0/16。如果你的边缘网络恰好用了这些网段,需要修改:

# 安装时指定自定义网段
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-installation.sh | \
  INSTALL_K3S_MIRROR=cn sh -s - \
  --cluster-cidr 172.20.0.0/16 \
  --service-cidr 172.21.0.0/16 \
  --cluster-dns 172.21.0.10

边缘网络不稳定的问题

边缘场景最大的痛点是网络不稳定——车间网关和 Server 之间的网络可能时断时续。K3s Agent 掉线后会发生什么?

  • Pod 继续运行:Agent 掉线不影响已运行的 Pod,容器还在 containerd 里跑着
  • 无法调度新 Pod:Server 认为 Agent 不可达,不会往上面调度新 Pod
  • 状态上报中断:Pod 状态、节点资源使用情况无法上报到 Server

K3s 有一个边缘场景的关键特性——边缘自治(Edge Autonomy)。当 Agent 和 Server 断连后,Agent 本地的 kubelet 继续管理已有 Pod,不会因为连不上 Server 就把 Pod 杀掉。等网络恢复后,Agent 自动重连,状态同步。

但默认的 Pod 驱逐策略需要调优,否则 Agent 重连后可能触发大规模 Pod 重建:

# 调整 kubelet 驱逐策略,容忍更长的断连时间
# 在 Agent 节点上创建配置
cat <<EOF | sudo tee /etc/rancher/k3s/agent.yaml
kubelet-arg:
  - "node-status-update-frequency=30s"
  - "node-monitor-period=30s"
  - "node-monitor-grace-period=5m"
  - "pod-eviction-timeout=5m"
EOF

# 重启 Agent
sudo systemctl restart k3s-agent

这几个参数的含义:

  • node-status-update-frequency:Agent 每 30 秒上报一次状态(默认 10s,边缘场景可以降低频率省带宽)
  • node-monitor-grace-period:Server 允许 Agent 5 分钟不上报(默认 40s,边缘场景需要拉长)
  • pod-eviction-timeout:超过 5 分钟才标记 Pod 驱逐(默认 5m)

边缘应用部署实战

部署一个数据采集服务

apiVersion: apps/v1
kind: Deployment
metadata:
  name: data-collector
  namespace: edge-apps
  labels:
    app: data-collector
spec:
  replicas: 3
  selector:
    matchLabels:
      app: data-collector
  template:
    metadata:
      labels:
        app: data-collector
    spec:
      # 只调度到 Agent 节点
      nodeSelector:
        node-type: agent
      # 资源限制(边缘设备资源有限)
      containers:
      - name: collector
        image: registry.cn-hangzhou.aliyuncs.com/edge/data-collector:v1.2.0
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 256Mi
        # 边缘场景必须配存活探针,确保网络抖动时 Pod 能自动重启
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 30
          failureThreshold: 5  # 允许 5 次失败(150s),容忍网络抖动
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 15
        # 边缘场景的配置通过 ConfigMap 注入
        env:
        - name: COLLECT_INTERVAL
          valueFrom:
            configMapKeyRef:
              name: collector-config
              key: interval
        - name: MQTT_BROKER
          valueFrom:
            configMapKeyRef:
              name: collector-config
              key: mqtt-broker
        volumeMounts:
        - name: data-volume
          mountPath: /data
      volumes:
      - name: data-volume
        hostPath:
          path: /var/edge-data
          type: DirectoryOrCreate
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: collector-config
  namespace: edge-apps
data:
  interval: "5s"
  mqtt-broker: "tcp://mqtt.internal:1883"
---
apiVersion: v1
kind: Service
metadata:
  name: data-collector
  namespace: edge-apps
spec:
  selector:
    app: data-collector
  ports:
  - port: 8080
    targetPort: 8080
  # ClusterIP 足够,不需要对外暴露
  type: ClusterIP

滚动更新策略

边缘设备的带宽有限,拉镜像可能比较慢。调整滚动更新参数,避免一次性拉太多镜像把带宽打满:

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1    # 每次只更新 1 个 Pod
      maxSurge: 0          # 不创建额外 Pod,先减后增

镜像预分发

200 台边缘设备同时拉镜像,不管 registry 带多宽都会堵。更好的做法是镜像预分发——在业务低峰期把镜像提前拉到每台设备上:

#!/bin/bash
# 镜像预分发脚本
# 在每台 Agent 节点上执行,提前拉取下一版本镜像

IMAGES=(
  "registry.cn-hangzhou.aliyuncs.com/edge/data-collector:v1.3.0"
  "registry.cn-hangzhou.aliyuncs.com/edge/data-processor:v2.0.0"
)

for image in "${IMAGES[@]}"; do
  echo "[$(date)] 拉取镜像: $image"
  # K3s 使用 containerd,用 crictl 拉镜像
  sudo k3s crictl pull "$image"
  if [ $? -eq 0 ]; then
    echo "[$(date)] ✓ 拉取成功"
  else
    echo "[$(date)] ✗ 拉取失败,稍后重试"
  fi
done

echo "镜像预分发完成。下次部署时将直接使用本地缓存。"

然后通过 Ansible 批量执行:

# ansible playbook: 镜像预分发
- name: Pre-distribute images to edge nodes
  hosts: edge-agents
  become: yes
  tasks:
    - name: Copy pre-pull script
      copy:
        src: pre-pull-images.sh
        dest: /tmp/pre-pull-images.sh
        mode: '0755'

    - name: Run pre-pull script
      shell: /tmp/pre-pull-images.sh
      async: 600          # 最长等待 10 分钟
      poll: 0             # 异步执行,不阻塞

    - name: Check pre-pull status
      async_status:
        jid: "{{ ansible_job_id }}"
      register: job_result
      until: job_result.finished
      retries: 30
      delay: 20

监控与告警:边缘集群的可观测性

资源受限下的监控方案

标准的 Prometheus + Grafana 监控栈在边缘设备上太重了——Prometheus 自己就要吃 500M+ 内存。边缘场景需要更轻量的方案。

推荐方案:K3s 内置 metrics-server + 轻量 Prometheus Agent + 远程存储

边缘集群                          云端
┌─────────────────┐         ┌──────────────────┐
│ K3s 集群         │         │ Prometheus +     │
│                 │         │ Grafana          │
│ metrics-server  │         │                  │
│ (资源指标)       │         │ (集中查询+告警)   │
│                 │         │                  │
│ Prometheus Agent├────────→│ Remote Write     │
│ (采集+转发)      │         │                  │
└─────────────────┘         └──────────────────┘

Prometheus Agent 模式只负责采集和转发,不做本地存储,资源占用极低(~50M 内存)。所有指标通过 remote_write 发送到云端的 Prometheus 做集中存储和查询。

# Prometheus Agent 配置(边缘节点)
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-agent-config
  namespace: monitoring
data:
  prometheus.yml: |
    global:
      scrape_interval: 30s      # 边缘场景降低采集频率
      evaluation_interval: 30s

    # Agent 模式:只采集和转发,不做本地存储
    remote_write:
      - url: "https://cloud-prometheus.example.com/api/v1/write"
        # 边缘网络不稳定,配置重试
        queue_config:
          capacity: 500
          max_shards: 2
          min_shards: 1
          max_samples_per_send: 100
          batch_send_deadline: 30s

    scrape_configs:
      # 采集 K3s 节点指标
      - job_name: 'k3s-node'
        static_configs:
          - targets: ['localhost:10250']
        scheme: https
        tls_config:
          ca_file: /var/lib/rancher/k3s/agent/client-ca.crt
          cert_file: /var/lib/rancher/k3s/agent/client-kubelet.crt
          key_file: /var/lib/rancher/k3s/agent/client-kubelet.key
        bearer_token_file: /var/lib/rancher/k3s/agent/client-kubelet.token

      # 采集容器指标
      - job_name: 'k3s-containers'
        static_configs:
          - targets: ['localhost:10250']
        scheme: https
        tls_config:
          ca_file: /var/lib/rancher/k3s/agent/client-ca.crt
          cert_file: /var/lib/rancher/k3s/agent/client-kubelet.crt
          key_file: /var/lib/rancher/k3s/agent/client-kubelet.key
        bearer_token_file: /var/lib/rancher/k3s/agent/client-kubelet.token
        metrics_path: /metrics/cadvisor    

关键告警规则

边缘场景的告警规则和云端不同,需要特别关注网络断连和资源耗尽:

# 边缘集群关键告警规则
groups:
  - name: edge-cluster-alerts
    rules:
      # Agent 节点离线
      - alert: EdgeNodeOffline
        expr: up{job="k3s-node"} == 0
        for: 5m
        labels:
          severity: P1
        annotations:
          summary: "边缘节点 {{ $labels.instance }} 离线超过 5 分钟"
          description: "检查节点网络连通性和 K3s Agent 进程状态"

      # 节点内存使用率过高
      - alert: EdgeNodeMemoryHigh
        expr: |
          (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 > 85          
        for: 10m
        labels:
          severity: P2
        annotations:
          summary: "节点 {{ $labels.instance }} 内存使用率超过 85%"
          description: "边缘设备内存有限,需要检查是否有异常 Pod 占用过多内存"

      # 磁盘空间不足
      - alert: EdgeNodeDiskSpaceLow
        expr: |
          (1 - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} /
                node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}) * 100 > 80          
        for: 15m
        labels:
          severity: P2
        annotations:
          summary: "节点 {{ $labels.instance }} 磁盘使用率超过 80%"
          description: "检查容器日志和镜像是否需要清理"

      # Pod 重启次数过多
      - alert: EdgePodRestartLoop
        expr: increase(kube_pod_container_status_restarts_total[1h]) > 5
        for: 5m
        labels:
          severity: P2
        annotations:
          summary: "Pod {{ $labels.pod }} 在 1 小时内重启超过 5 次"
          description: "可能是应用崩溃或 OOM,检查容器日志"

      # K3s Server 不可达
      - alert: K3sServerDown
        expr: up{job="k3s-apiserver"} == 0
        for: 2m
        labels:
          severity: P0
        annotations:
          summary: "K3s API Server 不可达"
          description: "检查 K3s Server 进程和 etcd/SQLite 存储"

故障排查:边缘场景常见问题

问题一:Agent 节点加入失败

现象:Agent 安装后,kubectl get nodes 看不到节点。

排查步骤

# 1. 检查 Agent 日志
sudo journalctl -u k3s-agent -f --no-pager | tail -50

# 2. 常见原因:token 不对
# 确认 Server 上的 token 和 Agent 使用的一致
cat /var/lib/rancher/k3s/server/node-token

# 3. 常见原因:网络不通
# 从 Agent 节点测试到 Server 的连通性
curl -k https://<SERVER_IP>:6443/readyz

# 4. 常见原因:防火墙拦截
# K3s Server 需要开放以下端口:
# 6443/tcp - K8s API
# 8472/udp - Flannel VXLAN
# 51820/udp - Flannel WireGuard(如果启用)
# 10250/tcp - Kubelet

# 5. 常见原因:时间不同步
# K8s 组件对时间敏感,时间差超过 30 秒会导致 TLS 证书验证失败
timedatectl status

问题二:Pod 一直处于 ContainerCreating

现象:部署 Pod 后一直卡在 ContainerCreating 状态。

# 查看 Pod 事件
kubectl describe pod <pod-name> -n <namespace>

# 常见原因1:镜像拉不下来
# 检查 containerd 镜像拉取日志
sudo crictl logs $(sudo crictl ps -a --name <container-name> -q)

# 常见原因2:CNI 网络插件没就绪
# 检查 Flannel Pod
kubectl get pods -n kube-system | grep flannel

# 常见原因3:磁盘满了
df -h
# 清理无用镜像
sudo k3s crictl rmi --prune

问题三:边缘节点频繁掉线

现象:节点频繁在 Ready 和 NotReady 之间切换。

# 1. 检查网络稳定性
ping -c 100 <SERVER_IP>
# 如果丢包率 > 5%,说明网络质量差

# 2. 调整 K3s Agent 的重连参数
# 编辑 /etc/rancher/k3s/agent.yaml
cat <<EOF | sudo tee /etc/rancher/k3s/agent.yaml
server: https://<SERVER_IP>:6443
token: <NODE_TOKEN>
kubelet-arg:
  - "node-status-update-frequency=30s"
EOF

sudo systemctl restart k3s-agent

# 3. 检查节点资源是否耗尽
# 如果内存不足,kubelet 可能无法正常上报
free -h

问题四:SQLite 数据库锁死

单节点 K3s 用 SQLite 存储时,偶发数据库锁死导致 API Server 无响应:

# 检查 K3s Server 状态
sudo systemctl status k3s

# 如果卡住,查看日志
sudo journalctl -u k3s --no-pager | tail -100

# 典型的锁死日志:
# "database is locked" 或 "SQLITE_BUSY"

# 紧急恢复:重启 K3s
sudo systemctl restart k3s

# 长期方案:迁移到嵌入式 etcd
# 停止当前 K3s
sudo /usr/local/bin/k3s-uninstall.sh

# 用 etcd 模式重新安装
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-installation.sh | \
  INSTALL_K3S_MIRROR=cn sh -s - \
  --cluster-init \
  --cluster-cidr 10.42.0.0/16 \
  --service-cidr 10.43.0.0/16

多集群管理:云端统管边缘集群

边缘场景通常有几十上百个 K3s 集群分布在不同的机房和车间。手动管理每个集群的 kubectl context 根本不现实。这时候需要多集群管理工具。

方案对比

工具维护方适用规模资源开销功能
RancherSUSE中大型较高全功能多集群管理
kubecm开源小型仅 context 切换
Cluster APICNCF大型集群生命周期管理
FleetSUSE大型GitOps + 多集群

小型部署用 kubecm 够了——它就是一个帮你管理 kubeconfig context 的 CLI 工具:

# 安装 kubecm
curl -sLo kubecm.tar.gz https://github.com/sunny0826/kubecm/releases/latest/download/kubecm_Linux_x86_64.tar.gz
tar -zxvf kubecm.tar.gz kubecm
sudo mv kubecm /usr/local/bin/

# 添加集群 context
kubecm add edge-factory-1 --kubeconfig /path/to/factory-1-kubeconfig

# 切换集群
kubecm switch edge-factory-1

# 查看所有集群
kubecm list

如果集群数量超过 20 个,建议上 Rancher。Rancher 可以统一管理 K3s 和 K8s 集群,提供 Web 界面和 RBAC:

# 在云端安装 Rancher(用 Docker 快速部署)
docker run -d --restart=unless-stopped \
  -p 80:80 -p 443:443 \
  --name rancher \
  rancher/rancher:v2.9.0

# 然后在每个 K3s 集群中注册 Agent
# Rancher 会生成一条 kubectl apply 命令
# 在 K3s Server 上执行即可

性能调优:榨干边缘设备的每一滴资源

资源分配策略

边缘设备的资源有限,必须精打细算。以下是典型的资源分配建议(以 2C/4G 的工控机为例):

总资源:2 vCPU / 4GB RAM / 32GB Disk
─────────────────────────────────────
系统保留:       0.3 vCPU / 512MB
K3s 系统组件:   0.3 vCPU / 512MB
  - kubelet
  - containerd
  - Flannel
  - CoreDNS
  - metrics-server
应用可用:       1.4 vCPU / 3GB
─────────────────────────────────────

K3s Server 调优

# K3s Server 启动参数调优
# 编辑 /etc/systemd/system/k3s.service

# 在 ExecStart 行添加以下参数:
# --kube-apiserver-arg="default-watch-cache-size=100"  # 降低 watch cache 内存
# --kube-apiserver-arg="max-requests-inflight=200"     # 限制并发请求
# --kube-controller-manager-arg="node-sync-period=30s" # 降低同步频率
# --kube-controller-manager-arg="concurrent-deployments=2"  # 降低并发
# --etcd-arg="quota-backend-bytes=17179869184"         # 限制 etcd 存储 16GB

# 示例配置
ExecStart=/usr/local/bin/k3s server \
  --kube-apiserver-arg="default-watch-cache-size=100" \
  --kube-apiserver-arg="max-requests-inflight=200" \
  --kube-controller-manager-arg="node-sync-period=30s" \
  --kube-controller-manager-arg="concurrent-deployments=2" \
  --write-kubeconfig-mode 644

容器运行时调优

# containerd 配置调优
# 编辑 /var/lib/rancher/k3s/agent/etc/containerd/config.toml.tmpl

# 关键调优项:
# - 限制日志大小
# - 降低垃圾回收频率
# - 限制并发下载

[plugins."io.containerd.grpc.v1.cri"]
  # 限制容器日志大小
  max_container_log_line_size = 16384
  # 降低镜像拉取并发
  [plugins."io.containerd.grpc.v1.cri".image_decryption]
    key_model = "node"

# 日志限制
[plugins."io.containerd.runtime.v1.linux"]
  # 每个容器最多保留 3 个日志文件
  # 每个日志文件最大 10MB
  log_rotation = true
  log_max_size = "10MB"
  log_max_files = 3

磁盘清理自动化

边缘设备磁盘空间有限,容器日志和镜像会逐渐占满磁盘。需要定期清理:

#!/bin/bash
# K3s 边缘节点磁盘清理脚本
# 建议用 cron 每天执行一次

set -euo pipefail

LOG_FILE="/var/log/k3s-disk-cleanup.log"
THRESHOLD=75  # 磁盘使用率超过 75% 时触发清理

echo "[$(date)] 开始磁盘清理..." >> "$LOG_FILE"

# 检查磁盘使用率
DISK_USAGE=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
echo "[$(date)] 当前磁盘使用率: ${DISK_USAGE}%" >> "$LOG_FILE"

if [ "$DISK_USAGE" -lt "$THRESHOLD" ]; then
  echo "[$(date)] 磁盘使用率未超阈值,跳过清理" >> "$LOG_FILE"
  exit 0
fi

# 1. 清理未使用的容器镜像
echo "[$(date)] 清理未使用镜像..." >> "$LOG_FILE"
sudo k3s crictl rmi --prune >> "$LOG_FILE" 2>&1

# 2. 清理容器日志(保留最近 3 天)
echo "[$(date)] 清理容器日志..." >> "$LOG_FILE"
find /var/lib/rancher/k3s/agent/containerd/logs -name "*.log" -mtime +3 -delete >> "$LOG_FILE" 2>&1

# 3. 清理 K3s 日志
echo "[$(date)] 清理 K3s 日志..." >> "$LOG_FILE"
sudo journalctl --vacuum-time=3d >> "$LOG_FILE" 2>&1

# 4. 清理临时文件
echo "[$(date)] 清理临时文件..." >> "$LOG_FILE"
find /tmp -type f -mtime +7 -delete >> "$LOG_FILE" 2>&1

# 检查清理后的磁盘使用率
DISK_USAGE_AFTER=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
echo "[$(date)] 清理后磁盘使用率: ${DISK_USAGE_AFTER}%" >> "$LOG_FILE"
echo "[$(date)] 磁盘清理完成" >> "$LOG_FILE"

# 添加 cron 任务
# echo "0 3 * * * /usr/local/bin/k3s-disk-cleanup.sh" | sudo tee /etc/cron.d/k3s-cleanup

安全加固:边缘设备的特殊风险

边缘设备部署在物理上不可控的环境中(车间、户外机柜),安全风险比机房服务器更高。需要特别注意以下几点:

1. K3s API Server 认证

# 不要在生产环境使用 --write-kubeconfig-mode 644
# 应该使用更严格的权限
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-installation.sh | \
  INSTALL_K3S_MIRROR=cn sh -s - \
  --write-kubeconfig-mode 600

2. 网络隔离

# 用 iptables 限制 K3s API 只允许管理网段访问
sudo iptables -A INPUT -p tcp --dport 6443 -s 10.0.0.0/8 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 6443 -j DROP

# 持久化 iptables 规则
sudo apt install iptables-persistent -y
sudo netfilter-persistent save

3. 镜像签名验证

边缘设备容易被物理接触,攻击者可能替换镜像。启用镜像签名验证:

# K3s containerd 配置镜像验证
# /var/lib/rancher/k3s/agent/etc/containerd/config.toml.tmpl

[plugins."io.containerd.grpc.v1.cri".containerd]
  # 启用镜像拉取验证
  default_runtime_name = "runc"
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
    runtime_type = "io.containerd.runc.v2"

# 配置只信任私有 registry
[plugins."io.containerd.grpc.v1.cri".registry]
  config_path = "/etc/containerd/certs.d"

总结

K3s 在边缘计算场景下的价值不是说它"轻"——而是它在保持 K8s API 完全兼容的前提下,把部署和运维的复杂度降了一个数量级。你用 kubectl 管理边缘集群和管理云端 K8s 集群的操作完全一样,但资源开销只有后者的四分之一。

实际生产中需要关注的几个关键点:

架构选型上,单节点 Server + SQLite 适合小规模边缘部署(≤20 个 Agent)。大规模场景用嵌入式 etcd 多 Server 集群。如果已有 MySQL/PG 基础设施也可以复用。

网络方案上,默认的 Flannel VXLAN 对边缘场景最友好——对底层网络要求低,容忍跨子网。但要注意调整 kubelet 的断连容忍参数,否则网络抖动会导致 Pod 频繁重建。

应用部署上,边缘场景的核心约束是带宽和资源。镜像预分发比实时拉取更靠谱。资源 limit 必须设置——一台 2G 内存的设备上跑一个不设 limit 的 Pod,分分钟 OOM。

监控告警上,别在边缘设备上跑完整的 Prometheus。用 Agent 模式只采集转发,集中存储放到云端。告警规则重点关注节点离线、磁盘空间和 Pod 重启。

安全加固上,边缘设备的物理安全不可控,网络隔离和镜像验证是必修课。K3s API 端口不要暴露到公网。

最后说一句实践层面的体会:K3s 的安装确实是一行命令的事,但生产环境的边缘集群运维远不止安装。网络不稳定、资源受限、设备分散、镜像分发——这些才是真正的挑战。把这些问题都解决了,你的边缘 K3s 集群才算真正能上生产。

参考资料与致谢

本文在撰写过程中参考了以下资料,感谢原作者的贡献:

  1. K3s - 轻量级 Kubernetes(官方文档) — Rancher 官方,提供了 K3s 架构设计、安装配置和功能特性的权威说明
  2. 云原生环境中的边缘计算:从K3s到边缘节点的全栈部署 — CSDN,提供了 K3s 与 KubeEdge、OpenYurt 的对比分析和边缘应用部署实践
  3. 如何在 Ubuntu 22.04 LTS 上配置并调优 K3s 轻量级 Kubernetes 集群 — 腾讯云开发者社区,提供了边缘场景下的硬件选型、系统优化和 K3s 调优参数
  4. 轻量级k8s:适配边缘计算场景的轻量级的k8s-k3s入门与实战 — CSDN,提供了 K3s 与 K8s 的详细特性对比和资源占用数据
  5. 2026年Edge AI全面爆发:端侧小模型推理与K3s边缘部署实战全解析 — 51CTO博客,提供了 K3s 在 Edge AI 场景下的部署实践和容器化模型部署方案