在树莓派上点亮你的 Kubernetes 集群

提到 raspberry pi 相信大家都不陌生, 简单来说它就是一台名片大小基于 ARM 架构的计算机. 经过几代的发展 raspberry pi 的硬件配置有了长足的进步. 在目前最新的 4b 版本上, raspberry pi 可以提供 4 核, 8GB RAM 的配置. 这也使得它的可玩性大大提高. 最近恰好在学习 Kubernetes, 所以就想到用 raspberry pi 来组一台 Kubernetes 集群. 对于这台集群我希望它拥有低功耗, 安静, 但最主要是可以稳定地运行多个服务. 这篇文章是这个系列的第一篇, 先来介绍如何在一台由4块 raspberry pi 4b 组成的硬件集群上搭建 kubernetes cluster.

硬件准备

我这次选择了 4 台 raspberry pi 4b 8GB 版本. 其中一台 master, 另外三台 node 节点. 树莓派默认需要一个 5V 3A 的 type c 电源以及一个千兆有线网口, 这样如果要部署一个 4 节点的集群就要准备 8 根线 ( 4 根电源线 + 4 根网线). 考虑到布线的简洁清爽, 我为树莓派加装了一个 POE 模块, 有了 POE 模块就可以用一根网线同时提供网络和供电功能, 这样只需要 4 根网线以及一台 POE 交换机/路由器即可解决所有的供电和网络需求. 另外每台树莓派配有一块 64GB 的 sdcard 用来安装系统.

具体使用到的清单如下:

软件准备

操作系统方面我们选择目前最新的 LTS 版本, Ubuntu 20.04 版. 我们使用 usbimager 将ubuntu 镜像刷入 sdcard. Kubernetes 安装最新的稳定版本 1.22.2. 需要用到的软件下载地址如下:

安装步骤

初步准备

  1. usbimager 使用非常简单, 在界面中选择下载的20.04镜像并指定目标 sdcard 设备进行写入. 如果 sdcard 上存在其他系统或者分区, 建议可以将这些分区先删除后再进行系统刷入.

  2. 完成 4 台设备的系统刷入后, 将 sdcard 插入树莓派并连接到POE进行初步测试. 树莓派默认通过 DHCP 获取 IP 地址. 因此如果顺利的话, 可以在路由器的管理界面中看到树莓派分配的 IP 地址. 为了方便今后的使用, 我们可以在此时绑定 MAC 与 IP 地址的分配. 这样 4 台树莓派都获得了固定的 IP 地址. 在我的环境中 4 台树莓派的地址分配如下:

  • master01: 172.16.0.1
  • node01: 172.16.0.11
  • node02: 172.16.0.12
  • node03: 172.16.0.13

系统准备

所有的树莓派上完成以下准备工作:

  1. 更新系统: sudo apt update && sudo apt dist-upgrade && apt-get install -y apt-transport-https

  2. 创建自定义用户: sudo adduser manfred

  3. 给予该用户 sudo 权限: sudo usermod -aG sudo manfred

  4. 设置主机名(注意每个node 的名字不同): echo master01 | sudo tee /etc/hostname

  5. 为集群内所有节点添加 hosts 文件映射:

    1
    2
    3
    4
    5
    6
    # cat /etc/hosts
    127.0.0.1 localhost
    172.16.0.1 master01
    172.16.0.11 node01
    172.16.0.12 node02
    172.16.0.13 node03
  6. 编辑 /boot/firmware/cmdline.txt 并在行末添加:

    1
    cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1 swapaccount=1
  7. 重启: sudo reboot

  8. 安装 docker: curl -sSL get.docker.com | sudo sh

  9. 将自己的账号加入 docker 组: sudo usermod -aG docker manfred

  10. 编辑 docker 配置文件并指定中文源: sudo vi /etc/docker/daemon.json

    1
    2
    3
    4
    5
    6
    7
    8
    9
    {
    "exec-opts": ["native.cgroupdriver=systemd"],
    "log-driver": "json-file",
    "log-opts": {
    "max-size": "100m"
    },
    "storage-driver": "overlay2",
    "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"]
    }
  11. 应用上述配置: sudo systemctl daemon-reload && sudo systemctl restart docker

  12. 开启路由: sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf

  13. 重启系统: sudo reboot

  14. 重启后确定 docker 工作正常: docker run hello-world

完成以上步骤后, 下面开始进入 kubernetes 的安装过程.

Kubernetes 安装准备

在所有树莓派上执行以下步骤:

  1. 为Kubernetes 设置国内源:
    1
    2
    3
    4
    5
    curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - 
    cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
    deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
    EOF
    sudo apt-get update
  2. 由于我们安装的版本 1.22.2 比较新, 所以可以手动下载这些镜像并用 tag 命令进行修正:
    1
    2
    3
    4
    5
    6
    sudo docker pull coredns/coredns:1.8.4
    sudo docker tag coredns/coredns:1.8.4 registry.aliyuncs.com/google_containers/coredns:v1.8.4


    sudo docker pull cjk2atmb/kube-controller-manager:v1.22.2
    sudo docker tag cjk2atmb/kube-controller-manager:v1.22.2 registry.aliyuncs.com/google_containers/kube-controller-manager:v1.22.2
  3. 在上述准备工作完成后我们就可以开始安装: sudo apt-get install -y kubelet kubeadm kubectl

master 节点

  1. 初始化 Kubernetes master 节点:

    1
    sudo kubeadm init --image-repository=registry.aliyuncs.com/google_containers --pod-network-cidr=10.244.0.0/16
  2. 如果一切正常的话在上述命令运行完后会看到如下提示. 将下面的 kubeadm join 命令保存好以备后续添加 node 节点时使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    Your Kubernetes control-plane has initialized successfully!

    To start using your cluster, you need to run the following as a regular user:

    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config

    Alternatively, if you are the root user, you can run:

    export KUBECONFIG=/etc/kubernetes/admin.conf

    You should now deploy a pod network to the cluster.
    Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
    https://kubernetes.io/docs/concepts/cluster-administration/addons/

    Then you can join any number of worker nodes by running the following on each as root:

    sudo kubeadm join 172.16.0.1:6443 --token xxxxxxx \
    --discovery-token-ca-cert-hash sha256:xxxxx
  3. 运行以下命令初始化 kubectl:

    1
    2
    3
    4
    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
    echo 'source <(kubectl completion bash)' >> ~/.bashrc
  4. 安装 flannel 网络组件:
    kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

  5. 最后确保所有镜像均可正常运行:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    NAMESPACE     NAME                               READY   STATUS    RESTARTS       AGE
    default demoapp-79b7d5f68b-bp9z2 1/1 Running 0 30h
    kube-system coredns-7f6cbbb7b8-kwsng 1/1 Running 1 (41h ago) 42h
    kube-system coredns-7f6cbbb7b8-qbmdn 1/1 Running 1 (41h ago) 42h
    kube-system etcd-master01 1/1 Running 5 (41h ago) 42h
    kube-system kube-apiserver-master01 1/1 Running 5 (41h ago) 42h
    kube-system kube-controller-manager-master01 1/1 Running 1 (41h ago) 42h
    kube-system kube-flannel-ds-kghwp 1/1 Running 1 (41h ago) 41h
    kube-system kube-flannel-ds-rcjfq 1/1 Running 1 (41h ago) 42h
    kube-system kube-proxy-6mksg 1/1 Running 1 (41h ago) 42h
    kube-system kube-proxy-w95hs 1/1 Running 1 (41h ago) 41h
    kube-system kube-scheduler-master01 1/1 Running 5 (41h ago) 42h

node 节点

  1. 复制之前的 join 命令:

    1
    sudo kubeadm join 172.16.0.1:6443 --token xxxxxxx --discovery-token-ca-cert-hash sha256:xxxxx 

    如果 token 丢失或者过期可以重新生成: kubeadm token create --print-join-command

  2. 安装完成后用 kubectl get nodes 查看安装情况. 如果 node 一直显示Not Ready, 可以尝试重启 node. 如果 node 没有 role, 可以自己给node 打role 标签:

    1
    kubectl label node node01 node-role.kubernetes.io/worker=worker

这样基本完成了Kubernetes 集群的安装.