1. 项目概述与设计初衷

几年前,我第一次看到有人用几块树莓派(Raspberry Pi)搭出一个迷你Kubernetes集群时,心里就痒痒的。这玩意儿太酷了——把数据中心的“大脑”塞进一个鞋盒大小的空间,成本还低得惊人。但当时看到的方案大多比较“裸奔”:几块板子用乐高积木或者亚克力架子一摞,电线网线像蜘蛛网一样散在外面,移动起来是个麻烦,更别提在不同网络环境里即插即用了。

所以,当我决定自己动手时,目标就很明确:我要的不是一个实验室里的静态玩具,而是一个真正 一体化、可便携、即插即用 的边缘K3s集群。它应该自带网络路由,让集群拥有独立的IP地址空间,无论插到家里的路由器,还是带到公司、朋友的网络,都能快速上线;它需要内置供电和散热,告别外挂的电源适配器和乱飞的风扇线;最后,所有东西必须严丝合缝地装进一个箱子里,拎起来就能走。

这个想法源于一个实际需求:我曾想部署一个基于IP摄像头的家庭安防系统,所有视频分析、存储服务都容器化,跑在集群上。虽然那个安防项目因为摄像头兼容性暂时搁置了,但构建一个可靠、便携的基础设施平台本身,就充满了挑战和乐趣。下面,我就把从画图、切割、组装到软件部署的完整过程,以及踩过的无数个坑,毫无保留地分享出来。

2. 硬件选型、设计与组装实战

构建一个稳定运行的便携集群,硬件是地基。选型不当,后续的软件部署会步步维艰。我的核心思路是: 计算单元够用就好,网络和供电必须可靠,散热与结构设计要为便携服务

2.1 核心硬件清单与选型逻辑

这是我的最终采购清单,每一件都有其背后的考量:

  • 计算节点(3x Raspberry Pi 4 Model B, 4GB RAM) :为什么是Pi 4且要4GB?Pi 4的CPU性能相比前代大幅提升,且原生支持USB 3.0和千兆以太网,这对节点间通信和存储读写至关重要。4GB内存是甜点,2GB跑K3s略显紧张,8GB对于这个规模又有些浪费。三个节点是构建一个高可用Kubernetes集群的最小要求(一主两从),也能容忍一个节点故障。
  • 网络中枢(TP-Link TL-R605 千兆有线路由器) :这是实现“便携网络”的关键。我需要一个能为集群创建独立子网(如192.168.88.0/24)的路由器。TL-R605体型小巧,纯千兆端口,支持静态DHCP绑定(为每个Pi固定IP),且管理界面简单。它让我的集群在任何地方接入上层网络时,都像一个独立的设备,内部网络结构完全不受外部影响。
  • 集中供电(Anker 60W 6口USB桌面充电站) :树莓派官方推荐5V/3A电源,峰值功耗可能接近。Anker这款充电站单口最大支持12W(5V/2.4A),总输出60W,为三个Pi(约9W*3=27W)和一个小风扇(约2W)供电绰绰有余。集中供电简化了布线,一根主电源线搞定所有设备。
  • 主动散热(Noctua NF-A4x20 5V PWM 风扇) :猫头鹰风扇的静音和可靠性有口皆碑。选择5V版本是为了可以直接从USB充电站取电,无需额外降压模块。40mm尺寸足够为密闭空间内的三块Pi提供气流。PWM功能允许通过Pi的GPIO引脚调速,实现静音与散热的平衡(后续软件部分会讲)。
  • 机箱材料(3mm透明亚克力板) :亚克力易于激光切割,强度足够,且透明材质方便观察内部状态和指示灯。3mm厚度在强度、重量和成本间取得了良好平衡。
  • 连接件
    • M2*6mm螺丝与尼龙柱 :用于固定树莓派。务必使用 尼龙等非导电材质的螺丝和柱 ,防止短路主板背面的焊点,这是新手极易忽略的安全隐患。
    • 优质短款USB-C数据线(3根) :为Pi供电。选择短线(15-20cm)以减少箱内杂乱。务必确认是 数据线 而非仅充电线,因为部分Pi型号需要数据引脚识别快充协议。
    • 六类千兆网线(0.5米,4根) :连接Pi与路由器。短距离无需屏蔽,但千兆线是基础要求。

注意:供电是集群稳定的生命线 。切勿使用劣质或功率不足的电源。我曾因一个电源接口接触不良,导致一个节点随机重启,排查了整整一天。建议为充电站单独配一个可靠的12V/5A以上电源适配器。

2.2 机箱结构设计与激光切割

机箱设计我使用了Fusion 360进行建模,核心目标是模块化、易组装、强散热。

  1. 分层结构设计 :机箱内部共分四层,从上到下依次是:

    • 顶板 :开有路由器网口、电源接口的引出孔,以及风扇出风口。
    • 路由器固定层 :专门为TL-R605设计卡槽,将其悬空固定,利于散热。
    • 树莓派安装层 :该层板子设计有多个安装孔位,对应不同Pi的型号。我设计了两种方向的安装卡板( pi card.dxf pi card mirror.dxf ),让用户可以根据喜好决定以太网口朝上还是朝下。
    • 底板与支柱 :底板封闭,四角有高的支柱,既作为支撑,也留出了底部进风的空间,与顶部的风扇形成垂直风道。
  2. 风道设计 :散热是密闭空间的大敌。设计原则是 强制对流,冷进热出 。底部支柱抬升机体,留出进风缝隙;顶部安装排风扇,将内部热空气抽出。空气自然从底部吸入,流经Pi和路由器主板,从顶部排出,形成有效风道。

  3. 激光切割要点

    • 将设计好的零件导出为DXF格式文件。
    • 寻找本地或线上的激光切割服务,材料选择3mm亚克力。
    • 关键参数 :功率、速度和切割次数需要根据机器和材料厚度调整。通常3mm亚克力需要较低速度(如15-20mm/s)和较高功率(如80%)进行多次切割(2-3次),才能切透且边缘光滑无融化。务必先让服务商打样测试。
    • 切割完成后,用酒精湿巾仔细清洁每一块亚克力板边缘的烟尘,否则会影响粘合强度和美观。

2.3 实战组装步骤与避坑指南

组装过程像拼一个精细的模型,顺序很重要。

  1. 粘合主箱体

    • 使用专用的 亚克力胶水 (如氯仿或丙烯酸粘合剂),而不是普通万能胶。这类胶水通过溶解亚克力表面使其熔合,强度极高。
    • 在通风良好的环境下操作。用注射器或细针头点胶,用量宜少不宜多,否则会溢出影响美观。
    • 按照设计顺序,将四块侧板与底板粘合。用直角夹或重物辅助固定,保持90度垂直,静置至少24小时确保完全固化。 这是我犯的第一个错误 :第一次没等胶水干透就进行下一步,导致侧板受力开裂。
  2. 安装内部组件

    • 先装风扇 :在顶板内侧用螺丝固定好40mm风扇,风扇方向确认是 向外抽风 。电线预留足够长度连接到未来的供电口。
    • 安装路由器卡板 :将切割好的路由器固定层放入箱内相应卡槽,无需粘死,方便日后维护。将TL-R605路由器放入。
    • 准备Pi安装卡板 :将 pi card 卡板与3D打印的 绝缘垫高柱 spacer.3mf )用M2螺丝组装好。垫高柱是关键,它确保了Pi主板背面与金属螺丝/卡板之间有安全距离。
    • 暂勿安装Pi :此时只安装空的卡板到箱体内。因为接下来需要先对Pi进行“无头模式”预配置。
  3. 布线理线艺术

    • 电源线 :将三根USB-C短线从Anker充电站引出,沿着箱体边缘走线,用扎带或线缆固定扣整理,预留出连接Pi的接口。
    • 网线 :准备四根短网线(路由器WAN口1根,连接三个Pi各1根)。同样沿着边缘走线,避免缠绕。
    • 风扇电源线 :将其连接到充电站的一个USB-A口上。
    • 核心技巧 :所有线缆尽量做到“横平竖直”,在转角处留有余量,不要绷得太紧。良好的理线不仅能提升内部空气流通效率,更重要的是便于日后故障排查和硬件更换。

3. 系统与网络基础配置

硬件组装完毕,相当于有了躯干。接下来要注入灵魂——操作系统和网络。这一步的目标是让三台Pi在无需连接显示器、键盘鼠标(即“无头模式”)的情况下,以固定的身份(IP地址)接入我们准备好的独立网络。

3.1 树莓派无头启动配置

所谓“无头启动”,就是让Pi在第一次开机前,就通过SD卡上的配置文件,完成语言、时区、Wi-Fi(如果需要)、SSH等基础设置。

  1. 烧录系统镜像

    • 从树莓派官网下载最新版的 Raspberry Pi OS Lite (64-bit) 。对于服务器集群,我们不需要图形桌面,Lite版本更轻量、更安全。
    • 使用官方推荐的 Raspberry Pi Imager 工具进行烧录。插入SD卡后,在Imager中先选择操作系统,再选择存储卡。
    • 关键步骤 :在点击“烧录”前,按下 Ctrl+Shift+X 打开 高级选项菜单 。这里是我们进行无头配置的核心:
      • 设置主机名:例如 k3s-master , k3s-node-1 , k3s-node-2 。这有助于在网络上区分它们。
      • 启用SSH:勾选“启用SSH”,并选择“使用密码认证”或“使用公钥认证”。 强烈建议使用公钥认证 ,安全性更高。你可以提前在个人电脑上生成SSH密钥对( ssh-keygen ),并将公钥内容粘贴在这里。
      • 设置用户名和密码:配置一个非默认的用户(如 pi 用户已不被推荐)和强密码。
      • 配置无线网络(可选):如果你的环境需要Wi-Fi,在此填入SSID和密码。但为了稳定和性能, 强烈建议且本方案全程使用有线网络
      • 设置区域选项:正确设置时区(如Asia/Shanghai)和键盘布局。
    • 配置完成后,再执行烧录。Imager会自动将这些设置写入SD卡的首个分区(FAT32格式的 boot 分区)。
  2. 启用容器特性与内存配置

    • 烧录完成后,不要急着弹出SD卡。在电脑上再次打开SD卡的 boot 分区。
    • 新建一个名为 ssh 的空文件(如果Imager没创建的话),这是启用SSH服务的传统信号。
    • 新建或编辑 config.txt 文件,在末尾添加两行:
      cgroup_memory=1
      cgroup_enable=memory
      
      这是 运行K3s/Kubernetes必须的配置 ,它启用了Linux的cgroup内存管理功能,否则K3s安装会失败。
    • 弹出SD卡,插入对应的树莓派。

3.2 路由器网络规划与静态IP绑定

现在,将组装好的机箱通电。路由器、充电站、风扇开始工作。

  1. 访问路由器管理界面

    • 用一根网线将你的笔记本电脑与TL-R605的任意一个LAN口连接。
    • 将笔记本的以太网适配器设置为自动获取IP(DHCP)。
    • 打开浏览器,输入路由器的默认管理地址(通常是 192.168.1.1 192.168.0.1 ,请查看路由器底部标签)。
    • 登录后,首先修改LAN口设置。我将LAN口IP地址改为 192.168.88.1 ,子网掩码 255.255.255.0 。这样,我的集群就拥有了一个独立的 192.168.88.0/24 网段。修改后,路由器可能会重启,之后你需要用新的IP( 192.168.88.1 )重新登录。
  2. 配置静态DHCP绑定

    • 这是确保每台Pi每次都能获得相同IP的关键。在路由器的DHCP服务器设置中,找到“静态地址分配”或“地址保留”功能。
    • 此时,将三张预配置好的SD卡分别插入三个树莓派,并用网线将它们连接到路由器的LAN口,然后给Pi上电。
    • 稍等片刻,在路由器的“客户端列表”或“DHCP分配列表”中,你应该能看到三个主机名(如 k3s-master , k3s-node-1 等)及其自动获取的IP(如 192.168.88.101 , .102 , .103 )。
    • 将每个主机名和其对应的MAC地址,绑定到一个你指定的固定IP上。我这样分配:
      • k3s-master -> 192.168.88.10
      • k3s-node-1 -> 192.168.88.11
      • k3s-node-2 -> 192.168.88.12
    • 保存设置。之后,无论路由器重启还是Pi重启,它们都会获得这些固定的IP。
  3. 验证与初始登录

    • 从你的笔记本电脑,尝试ping这些固定IP(如 ping 192.168.88.10 )。如果能通,说明网络配置成功。
    • 使用SSH连接主节点: ssh your_username@192.168.88.10 。如果配置了公钥,会直接登录;如果是密码,则输入你预设的密码。
    • 登录后,第一件事是更新系统: sudo apt update && sudo apt upgrade -y 。升级后最好重启一次。

4. K3s集群部署与优化

核心来了——部署K3s。K3s是Rancher Labs专为边缘和资源受限环境打造的轻量级Kubernetes发行版,去掉了很多传统K8s的组件,用单个二进制文件替代,安装和管理都极其简单。

4.1 主节点(Master)安装与关键配置

在主节点( 192.168.88.10 )上执行安装。

  1. 一键安装主节点

    curl -sfL https://get.k3s.io | sh -
    

    这个命令会下载并安装K3s server(即Master角色)。安装完成后,K3s服务会自动启动。

  2. 获取节点令牌(Token) : 节点加入集群时需要验证令牌。令牌存储在 /var/lib/rancher/k3s/server/node-token 文件中。

    sudo cat /var/lib/rancher/k3s/server/node-token
    

    复制输出的一长串字符,这就是你的 K3S_TOKEN 。妥善保存。

  3. 获取Kubeconfig文件 : 为了能在本地使用 kubectl 命令管理集群,需要将主节点的配置文件复制到本地。

    sudo cat /etc/rancher/k3s/k3s.yaml
    

    复制输出的内容。在你的笔记本电脑上,将其保存为 ~/.kube/config 但需要修改其中 server: 的地址 ,从 https://127.0.0.1:6443 改为 https://192.168.88.10:6443 (你的主节点IP)。

  4. 主节点关键优化

    • 禁用默认的Traefik Ingress Controller :K3s默认安装Traefik,如果你计划使用其他Ingress(如Nginx),可以在安装时禁用。或者安装后卸载:
      # 安装时禁用
      curl -sfL https://get.k3s.io | sh -s - --disable traefik
      # 或者安装后,通过helm卸载
      sudo k3s kubectl delete helmchart traefik -n kube-system
      
    • 禁用默认的Local-Storage :同样,如果不需要本地存储类,可以禁用。
      curl -sfL https://get.k3s.io | sh -s - --disable local-storage
      

4.2 工作节点(Worker Node)加入集群

在工作节点( 192.168.88.11 , 192.168.88.12 )上分别执行。

  1. 加入集群命令 : 使用从主节点获取的 K3S_TOKEN 和主节点的IP地址。

    curl -sfL https://get.k3s.io | K3S_URL=https://192.168.88.10:6443 K3S_TOKEN=你的主节点令牌 sh -
    

    这个命令会安装K3s agent,并将其注册到主节点。

  2. 验证节点状态 : 回到你的笔记本电脑(已配置好kubeconfig),执行:

    kubectl get nodes -o wide
    

    稍等片刻,你应该能看到三个节点,状态都是 Ready -o wide 参数可以显示节点的内网IP,确认它们是否正确识别。

4.3 集群基础组件与优化部署

一个生产可用的集群,还需要一些“装修”。

  1. 安装Helm :Helm是Kubernetes的包管理器,极大简化了复杂应用的部署。

    # 在主节点或已配置kubectl的机器上
    curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
    
  2. 部署网络插件(CNI) :K3s默认使用Flannel作为容器网络接口。通常安装时已自带,但需要确认。如果使用其他CNI(如Calico,功能更强大),需先禁用Flannel再安装。

    # 安装时指定
    curl -sfL https://get.k3s.io | sh -s - --flannel-backend=none --disable-network-policy
    # 然后安装Calico
    kubectl create -f https://docs.projectcalico.org/manifests/tigera-operator.yaml
    kubectl create -f https://docs.projectcalico.org/manifests/custom-resources.yaml
    
  3. 部署存储类(StorageClass) :在边缘场景,常用NFS或本地存储。这里以部署一个简单的NFS客户端存储类为例(假设你有一个NFS服务器在 192.168.88.100 ):

    # 安装NFS客户端工具
    sudo apt install nfs-common -y
    # 创建PersistentVolume (PV) 和 StorageClass (SC)
    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: nfs-pv
    spec:
      capacity:
        storage: 100Gi
      volumeMode: Filesystem
      accessModes:
        - ReadWriteMany
      persistentVolumeReclaimPolicy: Retain
      storageClassName: nfs-client
      nfs:
        path: /path/to/nfs/share
        server: 192.168.88.100
    ---
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: nfs-client
    provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
    parameters:
      archiveOnDelete: "false"
    EOF
    
  4. 部署监控与可视化(可选但推荐)

    • MetalLB :为集群提供LoadBalancer类型的服务,在裸金属环境下非常有用。
    • Prometheus + Grafana :监控集群和应用的黄金组合。可以通过Helm一键部署。
    # 添加Prometheus社区仓库
    helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
    helm repo update
    # 安装kube-prometheus-stack(包含Prometheus, Grafana, AlertManager等)
    helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring --create-namespace
    

    安装后,通过 kubectl get svc -n monitoring 查看Grafana服务,使用端口转发( kubectl port-forward svc/prometheus-grafana -n monitoring 8080:80 )即可在本地浏览器用 admin/prom-operator 登录查看仪表盘。

5. 集群运维、问题排查与实战心得

集群跑起来只是开始,稳定运行和高效排错才是真正的挑战。下面是我在运维这个便携集群过程中积累的实战经验。

5.1 日常运维命令速查

这些命令能帮你快速了解集群健康状况:

# 查看所有节点状态
kubectl get nodes -o wide

# 查看所有Pod(跨所有命名空间)
kubectl get pods -A

# 查看系统组件(如CoreDNS, Metrics-server)状态
kubectl get pods -n kube-system

# 查看Pod的详细事件,常用于排错
kubectl describe pod <pod-name> -n <namespace>

# 查看Pod的实时日志
kubectl logs -f <pod-name> -n <namespace>

# 查看集群资源使用情况(需安装metrics-server)
kubectl top nodes
kubectl top pods -A

# 进入Pod内部执行命令(调试神器)
kubectl exec -it <pod-name> -n <namespace> -- /bin/bash

5.2 常见问题与解决方案实录

以下是我踩过的坑和解决方案,希望能帮你节省时间。

问题现象 可能原因 排查步骤与解决方案
节点状态为 NotReady 1. 网络插件(Flannel/Calico)异常
2. 节点kubelet进程异常
3. 节点资源(内存/磁盘)不足
1. kubectl get pods -n kube-system 查看 coredns , flannel 等Pod是否运行。
2. 登录问题节点,执行 sudo systemctl status k3s-agent (worker) 或 sudo systemctl status k3s (master) 查看服务状态。
3. 在节点上执行 df -h free -m 检查磁盘和内存。清理Docker/K3s无用镜像: sudo k3s crictl rmi --prune
Pod一直处于 Pending 状态 1. 没有满足资源需求的节点
2. 没有可用的PV(持久卷)
3. NodeSelector/Affinity规则不匹配
1. kubectl describe pod <pod-name> 查看 Events 部分,通常有明确提示。
2. kubectl get pv kubectl get pvc 检查存储卷状态。
3. 检查Pod的配置,看是否有节点选择器限制。
Pod处于 CrashLoopBackOff 1. 应用本身启动失败(配置错误、端口冲突等)
2. 依赖的服务(如数据库)未就绪
3. 镜像拉取失败或权限问题
1. kubectl logs <pod-name> --previous 查看上一次崩溃的日志。
2. kubectl describe pod 查看详细事件和状态。
3. 检查 livenessProbe readinessProbe 配置是否过于严格。
无法从集群外访问服务 1. Service类型为ClusterIP(默认)
2. NodePort端口被防火墙阻挡
3. Ingress控制器未正确配置
1. 将Service类型改为 NodePort LoadBalancer (如果安装了MetalLB)。
2. 检查节点防火墙( sudo ufw status ),开放对应端口。
3. 检查Ingress资源定义和Ingress Controller的Pod日志。
磁盘空间不足导致集群异常 K3s/容器日志、未清理的镜像占满空间 1. 定期清理: sudo journalctl --vacuum-time=7d (系统日志), sudo k3s crictl rmi --prune (镜像)。
2. 为 /var/lib/rancher/k3s 挂载更大容量磁盘。

5.3 风扇智能调速与电源管理

为了让集群在安静与凉爽间取得平衡,我通过一个简单的Python脚本实现了风扇的PWM调速。

  1. 硬件连接 :将Noctua风扇的PWM线(通常是蓝色)连接到主节点树莓派的某个GPIO引脚(如GPIO18,物理引脚12),红线接5V,黑线接地。
  2. 安装依赖
    sudo apt install python3-pip python3-rpi.gpio -y
    pip3 install psutil
    
  3. 创建调速脚本 ( /usr/local/bin/fan_control.py ):
    #!/usr/bin/env python3
    import RPi.GPIO as GPIO
    import psutil
    import time
    
    FAN_PIN = 18  # 使用的GPIO引脚
    TEMP_THRESHOLD_LOW = 45  # 低温阈值(摄氏度)
    TEMP_THRESHOLD_HIGH = 60 # 高温阈值
    PWM_FREQ = 25  # PWM频率,对于风扇通常25Hz即可
    
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(FAN_PIN, GPIO.OUT)
    fan = GPIO.PWM(FAN_PIN, PWM_FREQ)
    fan.start(0)  # 初始速度0%
    
    try:
        while True:
            cpu_temp = psutil.sensors_temperatures()['cpu_thermal'][0].current
            if cpu_temp < TEMP_THRESHOLD_LOW:
                duty_cycle = 0  # 低温停转
            elif cpu_temp > TEMP_THRESHOLD_HIGH:
                duty_cycle = 100  # 高温全速
            else:
                # 在阈值间线性调速
                duty_cycle = (cpu_temp - TEMP_THRESHOLD_LOW) / (TEMP_THRESHOLD_HIGH - TEMP_THRESHOLD_LOW) * 100
            fan.ChangeDutyCycle(duty_cycle)
            time.sleep(10)  # 每10秒检查一次
    except KeyboardInterrupt:
        pass
    finally:
        fan.stop()
        GPIO.cleanup()
    
  4. 设置为系统服务 :创建systemd服务文件,让脚本开机自启,并赋予访问硬件和温度传感器的权限。

经过这番调优,在集群低负载时,风扇几乎无声;运行压力测试时,风扇会平滑提速,将CPU温度稳稳压在65度以下。

5.4 数据备份与灾难恢复

便携意味着移动,移动意味着风险。定期备份集群状态至关重要。

  1. 备份K3s配置与数据
    # 在主节点上,备份K3s的配置文件和数据目录
    sudo tar czf k3s-backup-$(date +%Y%m%d).tar.gz /etc/rancher/k3s /var/lib/rancher/k3s
    # 将备份文件拷贝到安全的地方(如你的笔记本电脑或NAS)
    
  2. 备份集群资源声明
    # 使用kubectl导出所有重要资源(排除掉系统级和临时资源)
    kubectl get all --all-namespaces -o yaml > cluster-state-$(date +%Y%m%d).yaml
    
  3. 恢复演练 :定期在新SD卡上恢复系统,练习从零开始重建集群。这能确保你的备份是有效的,也让你对整个过程烂熟于心。

构建并运维这个便携式Raspberry Pi K3s集群的整个过程,就像在微观世界里实践了一遍数据中心运维。从硬件选型的权衡,到激光切割的精度,从网络规划的缜密,到Kubernetes编排的抽象,每一个环节都充满了动手的乐趣和解决问题的成就感。

这个盒子现在安静地放在我的书架上,它不再是一个概念验证的玩具。我已在上面稳定运行了个人Git服务器、家庭自动化控制中心、一个轻量级的CI/CD流水线,以及各种临时起意的测试项目。它的存在让我能随时随地拥有一个私有的、云原生的开发测试环境,成本极低,却收获无穷。

如果你也心动了,我最大的建议是: 立刻开始,从第一块亚克力板切割做起 。过程中遇到的每一个报错,都是你深入理解容器、网络和分布式系统的绝佳机会。这个亲手打造的“便携云”,将成为你技术栈中最特别、也最坚实的一块拼图。

更多推荐