树莓派玩转Kubernetes(1)-准备

前言

不知不觉,已工作三年,回顾这三年,发现自身技术上的成长并没有想象中的那么大, 在这个充满焦虑的社会自己难得静下心来系统的学习和缺少实践。
最近在学习kubernetes, 决定写一个系列,来记录这个过程。同时为了不让过程那么枯燥,决定用我的树莓派集群来实践,定一个小目标:花一个月的时间将树莓派集群上运行的大部分应用(nginx、postgresql、gitea、homeassistant、prometheus、grafana等)部署在kubernetes上!

硬件

我用到的硬件如下:

树莓派4 4GB * 4
tf卡 * 4
256G SSD(通过USB3.0连接到树莓派) * 4
type-c电源线 * 4
63W 五口USB电源
八口千兆交换机
网线若干
树莓派集群支架(带风扇)

虽然准备搭建的是一个用于测试的k8s环境,但存储介质一定要选好,tf卡鱼龙混杂,建议选购不低于1元/1GB的大牌产品(推荐闪迪、三星)。
我打算用三个SSD固态硬盘作为ceph的OSD节点,一个SSD用作Master节点的系统盘,提升系统速度和可靠性。

软件

  • 系统: RPi OS 64Bit Lite, 更换为testing源,直接升级到debian 11

  • 软件: kubernetes v1.21, docker v20.10.7(1.20之后的k8s不再依赖docker,习惯上使用docker作为默认的容器运行时)

kubernetes的安装(kubeadm、kubelet 和 kubectl):install-kubeadm
docker的安装: install-docker

  • 其他: 搭建k8s时需要大量访问境外网站,所以需要有一个FQ代理,我在其中一个树莓派上已经运行了一个v2ray和一个对外的http代理,这样其他的树莓派就能通过这个http代理访问外网了

准备

安装好系统后配置时区、local、扩展系统空间等初始化工作就不详述了,下面说说安装k8s必须要配置的内容。
主要有配置静态IP、ssh互信、关闭Swap、配置docker的cgroup驱动、配置iptables、预先拉取镜像等。

设置静态IP

为每个树莓派设置静态IP, 编辑/etc/dhcpcd.conf, 在文件末尾添加以下几行:

1
2
3
4
5
interface eth0

static ip_address=192.168.10.100/24
static routers=192.168.10.1
static domain_name_servers=192.168.10.1 114.114.114.114

表示给eth0网卡设置了一个静态IP 192.168.10.100, 子网掩码是24(255.255.255.0),网关地址为192.168.10.1, DNS设置了一个192.168.10.1和114.114.114.114。
依次给其他三个树莓派设置IP为192.168.10.101、192.168.10.102、192.168.10.103

hostname和hosts设置

使用hostnamectl命令为每台树莓派设置hostname:

1
sudo hostnamectl set-hostname RPi-0

另外三个树莓派hostname依次设置为RPi-1, RPi-2, RPi-3

编辑hosts文件, 添加以下内容:

1
2
3
4
127.0.0.1		    RPi-0
192.168.10.101 RPi-1
192.168.10.102 RPi-2
192.168.10.103 RPi-3

注意:设置每个树莓派的hosts中自身的hostname指向127.0.0.1

ssh互相免密

在每个树莓派上生成ssh秘钥:

1
ssh-keygen

一直回车就好。

然后在RPi-0上使用ssh-keyscan收集四个树莓派的公钥指纹:

1
ssh-keyscan RPi-0 RPi-1 RPi-2 RPi-3 >> ~/.ssh/known_hosts 2>/dev/null

将RPi-0上的~/.ssh/known_hosts 文件copy到其他三个树莓派上同样的位置。

在每个树莓派上查看公钥:

1
cat .ssh/id_rsa.pub

将所有树莓派的公钥一行一个进行汇总, 添加到每个树莓派的.ssh/authorized_keys文件。这样, 所有树莓派之间都可以通过ssh免密登录了,可在任一树莓派上执行 ssh RPi-1、 ssh RPi-2、 ssh RPi-3 进行验证。
(以上操作如果使用ansible将会很便捷。)

关闭Swap

执行free -m查看:

1
2
3
4
pi@RPi-0:~ $ free -m
total used free shared buff/cache available
Mem: 3794 2073 75 3 1645 1678
Swap: 99 99 0

会发现RPi OS启用了Swap,使用以下命令来关闭:

1
2
3
4
sudo dphys-swapfile swapoff
sudo dphys-swapfile uninstall
sudo update-rc.d dphys-swapfile remove
sudo systemctl disable dphys-swapfile

再次执行free -m:

1
2
3
4
pi@RPi-0:~ $ free -m
total used free shared buff/cache available
Mem: 3794 2073 75 3 1645 1678
Swap: 0 0 0

已经成功关闭Swap。

启用cgroup限制

如果没有启用cgroup限制,执行docker info命令后在末尾会输出以下警告:

/boot/cmdline.txt末尾(空格隔开,不换行)添加以下内容:

1
2
3
4
cgroup_enable=cpuset
cgroup_enable=memory
cgroup_memory=1
swapaccount=1

可使用sed命令来完成快速修改:

1
sudo sed -i '$ s/$/ cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1 swapaccount=1/' /boot/cmdline.txt

重启后再次执行docker info,会发现上图的警告已经没了。

配置docker的cgroup驱动

执行docker info | grep "Cgroup Driver"查看docker的cgroup驱动是否为systemd:

1
2
pi@RPi-0:~ $ docker info | grep "Cgroup Driver"
Cgroup Driver: systemd

docker最新版默认systemd,无需更改, 如果不是请按以下方法更改。

创建或替换 /etc/docker/daemon.json 以启用 cgroup 的 systemd 驱动,内容如下:

1
2
3
4
5
6
7
8
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}

重启树莓派,再次执行docker info | grep "Cgroup Driver"查看Cgroup Driver项是否已变成systemd。

允许 iptables 检查桥接流量

为了让你的 Linux 节点上的 iptables 能够正确地查看桥接流量,你需要确保在你的 sysctl 配置中将 net.bridge.bridge-nf-call-iptables 设置为 1。

1
2
3
4
5
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system

加载ipvs内核模块

kube-proxy支持 iptables 和 ipvs 两种模式, 如果要使用ipvs模式,需要加载相应的内核模块。

  • 安装ipvsadm和ipset:

    1
    sudo apt install ipvsadm ipset
  • 列出ipvs相应的模块并写入/etc/modules:

    1
    sudo ls /lib/modules/$(uname -r)/kernel/net/netfilter/ipvs | grep -o "^[^.]*" >> /etc/modules
  • 重启之后检查是否加载ipvs模块(没有输出则未加载):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    pi@RPi-0:~ $ lsmod | grep ip_vs
    ip_vs_wrr 16384 0
    ip_vs_wlc 16384 0
    ip_vs_sh 20480 0
    ip_vs_sed 16384 0
    ip_vs_rr 16384 9
    ip_vs_pe_sip 16384 0
    nf_conntrack_sip 36864 1 ip_vs_pe_sip
    ip_vs_nq 16384 0
    ip_vs_lc 16384 0
    ip_vs_lblcr 20480 0
    ip_vs_lblc 20480 0
    ip_vs_ftp 20480 0
    nf_nat 49152 3 nft_chain_nat,xt_MASQUERADE,ip_vs_ftp
    ip_vs_dh 20480 0
    ip_vs 143360 35 ip_vs_wlc,ip_vs_rr,ip_vs_dh,ip_vs_lblcr,ip_vs_sh,ip_vs_nq,ip_vs_lblc,ip_vs_pe_sip,ip_vs_wrr,ip_vs_lc,ip_vs_sed,ip_vs_ftp
    nf_conntrack 139264 6 xt_conntrack,nf_nat,nf_conntrack_sip,nf_conntrack_netlink,xt_MASQUERADE,ip_vs

镜像拉取

在RPi-0上查看需要的镜像:

1
kubeadm config images list

在每个树莓派上使用docker pull命令来拉取以上列表的镜像

以上,便完成了k8s搭建前的准备工作,可以重启全部树莓派以确保环境生效。接下来就是集群的搭建了。