YP.Lam | 斐讯 N1 搭建私有 Kubernetes 集群运行 HomeAssistant

斐讯 N1 搭建私有 Kubernetes 集群运行 HomeAssistant

手上有几台闲置的几台斐讯 N1 刚好达到安装 Kubernetes 的最低硬件要求,于是趁着五一假期在家捣弄个“高可用”斐讯 N1 K8S 集群,用于运行 HomeAssistant

硬件准备

1 台树莓派 CM4+256G SSD,5 台 N1+5 个 32G 迷你 U 盘,两个 cc2652p zigbee dongle, 一个 8 口千兆交换机,明纬 12V5A 电源,1 分 5DC 电源线,短网线若干,厚双面胶。

一顿操作下来,刚好整整齐齐的粘成一块:

k8s-n1

Armbian 准备

得益于 N1 折腾生态比较完善,比较容易找到系统打包脚本,https://github.com/yunsur/phicomm-n1

通过修改 config/boards/arm-64.conf 把不需要的包删除,尽量让操作系统保持简洁

-------------------------- config/boards/arm-64.conf --------------------------
index 9d24069..0a1d99a 100644
@@ -25,5 +25,5 @@ EXTRAWIFI="no"
 WIREGUARD="yes"
 INSTALL_HEADERS="yes"
 INSTALL_DOCKER="yes"
-PACKAGE_LIST_BOARD="bluez bluez-tools bluetooth libubootenv-tool"
-PACKAGE_LIST_FAMILY="autojump avahi-daemon samba samba-common-bin samba-vfs-modules smbclient tcpdump ntpdate python3 python3-pip docker-ce docker-compose"
+PACKAGE_LIST_BOARD=""
+PACKAGE_LIST_FAMILY="avahi-daemon lvm2"

------------------ config/kernel/linux-arm-64-current.config ------------------
index fa4d782..5829e3e 100644
@@ -1783,7 +1783,7 @@ CONFIG_NET_9P=m
 CONFIG_NET_9P_VIRTIO=m
 # CONFIG_NET_9P_DEBUG is not set
 # CONFIG_CAIF is not set
-CONFIG_CEPH_LIB=m
+CONFIG_CEPH_LIB=y
 # CONFIG_CEPH_LIB_PRETTYDEBUG is not set
 # CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set
 CONFIG_NFC=m
@@ -2238,7 +2238,7 @@ CONFIG_ZRAM_WRITEBACK=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
 CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_BLK_DEV_DRBD=m
+CONFIG_BLK_DEV_DRBD=y
 # CONFIG_DRBD_FAULT_INJECTION is not set
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_SX8 is not set
@@ -2248,7 +2248,7 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_CDROM_PKTCDVD is not set
 CONFIG_ATA_OVER_ETH=m
 CONFIG_VIRTIO_BLK=m
-# CONFIG_BLK_DEV_RBD is not set
+CONFIG_BLK_DEV_RBD=y
 # CONFIG_BLK_DEV_RSXX is not set
 
 #
@@ -8152,7 +8152,7 @@ CONFIG_SUNRPC_SWAP=y
 CONFIG_RPCSEC_GSS_KRB5=m
 # CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set
 # CONFIG_SUNRPC_DEBUG is not set
-# CONFIG_CEPH_FS is not set
+CONFIG_CEPH_FS=y
 CONFIG_CIFS=y
 CONFIG_CIFS_STATS2=y
 CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y

集群部署

因为是以实验为目标,集群使用 3 master + 3 worker ,ETCD stacked,keepalived + haproxy 实现 apiserver 的高可用

其中 master[0] 为 raspberry pi 4,其他 5 台为 N1

vip 192.168.2.230
node1 ansible_host=192.168.2.2
node2 ansible_host=192.168.2.231
node3 ansible_host=192.168.2.232
node4 ansible_host=192.168.2.233
node5 ansible_host=192.168.2.234
node6 ansible_host=192.168.2.235

部署脚本基于 ansible,直接 clone 以下项目:https://github.com/TimeBye/kubeadm-ha,然后根据需要修改配置即可,譬如关掉系统资源检查

注意 1:N1 为 arm64 架构,某些较旧的镜像可能不支持(譬如一些过旧的 nginx),因此适当时候要 ‘kubectl get pods -A’ 查看一下, 如果是 CrashLoopBackOff 状态可优先排查一下用到的镜像版本是否支持 arm64

注意 2: armbian 启动默认会开启 swap,需要通过 /etc/default/armbian-zram-config 配置

部署 lb + ingress

使用 metallb 作为二层负载均衡,nginx ingress

helm repo add metallb https://metallb.github.io/metallb
helm upgrade --install metallb metallb/metallb --namespace metallb-system --create-namespace -f metallb.yaml
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace -f ingress.yaml

部署 nfs

尝试了一通 ceph,发现 N1 的渣资源根本跑不起来,于是决定把数据存在局域网一台 zfs 的 nas 上

helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner  --set nfs.server=xxx  --set nfs.path=/data/k8s --set storageClass.provisionerName=k8s-sigs.io/nfs-subdir-external-provisioner --set image.repository=xxx

部署 homeassistant

暂时只想将一些 zigbee 传感器接入,于是部署了以下三个服务:

kubectl apply -f pvc.yaml
helm install mosquitto k8s-at-home/mosquitto -f mosquitto.yaml
helm install home-assistant k8s-at-home/home-assistant -f homeassistant.yaml
helm install zigbee2mqtt k8s-at-home/zigbee2mqtt -f zigbee2mqtt.yaml

其中 config 文件通过 nfs pvc 配置,zigbee2mqtt 绑定到 zigbee dongle 所在的 node

docker 配置代理

整个过程最麻烦的反而是镜像下载被墙问题,如果你使用 docker,需要通过修改 systemd 配置

sudo mkdir -p /etc/systemd/system/docker.service.d
sudo touch /etc/systemd/system/docker.service.d/proxy.conf
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:8080/"
Environment="HTTPS_PROXY=http://proxy.example.com:8080/"
Environment="NO_PROXY=localhost,127.0.0.1,.example.com"