这篇文章上次修改于 318 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

k8s 集群安装笔记

要做的事

  1. 配置每个节点的 host & hostname
  2. 关闭 swap, 开启必须的内核支持
  3. 下载集群所需的软件, 指定要使用的 container
  4. 初始化主节点
  5. 安装第三方网络插件
  6. 登录从节点, 重复前三步并加入集群

硬件要求

  • 两台以上 Linux, 虚拟机也算.
  • 2H2G 以上配置
  • 网络能够互相访问

其中网络这里如果是云服务器应该会遇到各种防火墙问题, 但我是内网环境部署.

配置主节点

配置 host & hostname

host 文件配置也很简单, 和 Windows 下是一样的, 大概写成这样:

# /etc/hosts
10.0.0.1 k8s-master1
10.0.10.1 k8s-node1
10.0.10.2 k8s-node2

设备名将作为节点名出现在 kubectl get ndoes 中, 一般命名方式就是 k8s-master node1 这样.

sudo hostnamectl set-hostname "xxx"

关闭 swap

# 临时关闭
sudo swapoff -a
# 效果是在 /etc/fstab 文件注释掉带有 swap 的配置行
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

但是我发现重启设备后仍然开启了 swap, 用 systemctl --type swap --all 命令也能看到有输出.
解决方案也很简单, 直接删了 swap 分区 (或者这样

$ systemctl --type swap
  UNIT                                   LOAD   ACTIVE SUB    DESCRIPTION
  dev-disk-by\x2ddiskseq-1\x2dpart2.swap loaded active active Swap Partition

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.
1 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

# 因为包含转义字符所以一定要引号
$ sudo systemctl mask "dev-disk-by\x2ddiskseq-1\x2dpart2.swap"
Created symlink /etc/systemd/system/dev-disk-by\x2ddiskseq-1\x2dpart2.swap → /dev/null.

开启内核

这里可以暂时先跳过, 如果有问题后续报错会给出具体缺少哪些支持.
另外 modules-load.d 文件夹是安装 containerd 时自动创建的.

可以先用 lsmod | grep -e br_netfilter -e overlay 验证, 已经开启就不需要管了.
我配置的时候发现 Ubuntu 没开 br_netfilter.

# vim /etc/modules-load.d/k8s.conf
overlay
br_netfilter

sysctl 在 kubeadm init 时会自动配置, 从节点存疑. 根据系统不同可能有 /etc/sysctl.d 文件夹并且有其他配置.
其中 bridge 参数依赖上面的 br_netfilter 模块, 临时开启用 sudo modprobe br_netfilter.

# vim /etc/sysctl.conf
net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-iptables=1

应用改变

sudo sysctl --system

安装必要软件

Arch 系安装非常简单, 其他发行版参考官方文档.
安装时可能会提示 iptables 和 iptables-nft 冲突, 查了一下可以直接平替不影响系统.

按照官方文档来看, 比较推荐使用 containerd 作为 runtime, 它使用 crictl 进行管理.
这意味着现在将不再依赖 docker.

# 只需要安装这些, 其他的将作为软件依赖或者由 kubeadm 自动安装到 containerd.
yay -S kubeadm kubectl kubelet containerd

配置服务自启

sudo systemctl enable --now kubelet.service containerd.service

指定 runtime 为 containerd, 否则每次使用都会遍历 sock 并报错.

sudo crictl config runtime-endpoint unix:///run/containerd/containerd.sock

这些软件之间的关系:

  • kubeadm 是一个方便的 kubernetes cluster 安装工具, 可以快速部署每个节点, 其中主节点用 kubeadm init 初始化, 从节点用初始化输出内容中的 kubeadm join 加入集群.
  • kubectl 负责与集群的通信, 默认情况下只有主节点可以用, 在从节点上执行会请求本机的 8080 端口, 这没有用.
  • kubelet 最重要的东西, 也是唯一一个 service. 用来启动本机的 pod 和 container.
  • containerd 官方现在推荐的容器运行时, 旧版本则使用 docker.

说到这里, 可以发现它们和集群的主从节点之间并没有什么关联, 也就是说不管什么节点都需要安装这些软件!
主从节点只是代表了分工的不同, 但它们仍然都是节点, 并且在高可用集群中身份也是可以互换的.

不同于其他三个, kubeadm 是非必须软件. 它做的只是帮你自动配置集群.
但是 kubernetes 的配置过程极其复杂, 就算不用 kubeadm 也会选择其他的平替软件.

crictl image ls 命令查看已配置完成的主从节点的镜像, 发现有很大的区别.

从节点的镜像

IMAGE                                  TAG                 IMAGE ID            SIZE
docker.io/flannel/flannel-cni-plugin   v1.2.0              a55d1bad692b7       3.88MB
docker.io/flannel/flannel              v0.23.0             01cdfa8dd262f       28.1MB
registry.k8s.io/kube-proxy             v1.28.4             83f6cc407eed8       24.6MB
registry.k8s.io/pause                  3.9                 e6f1816883972       322kB

主节点的镜像

IMAGE                                     TAG                 IMAGE ID            SIZE
docker.io/flannel/flannel-cni-plugin      v1.2.0              a55d1bad692b7       3.88MB
docker.io/flannel/flannel                 v0.23.0             01cdfa8dd262f       28.1MB
registry.k8s.io/coredns/coredns           v1.10.1             ead0a4a53df89       16.2MB
registry.k8s.io/etcd                      3.5.9-0             73deb9a3f7025       103MB
registry.k8s.io/kube-apiserver            v1.28.4             7fe0e6f37db33       34.7MB
registry.k8s.io/kube-controller-manager   v1.28.4             d058aa5ab969c       33.4MB
registry.k8s.io/kube-proxy                v1.28.4             83f6cc407eed8       24.6MB
registry.k8s.io/kube-scheduler            v1.28.4             e3db313c6dbc0       18.8MB
registry.k8s.io/pause                     3.9                 e6f1816883972       322kB

初始化 kubeadm

首先可以提前拉取镜像 (可选, 如果对自己的网络环境自信可以直接跳到下一步), 或者在执行 kubeadm init 时将自动拉取, 我整个初始化时间是两分半, 但网络环境不好就无法保证了.
如果是国内服务器应该用第二条, 因为默认镜像源是 k8s.io, 仓库地址是 prod-registry-k8s-io-ap-southeast-1.s3.dualstack.ap-southeast-1.amazonaws.com, 不管是哪个裸连体验都要比 docker 和 github 还要差.

sudo kubeadm config images pull
sudo kubeadm config images pull --image-repository registry.aliyuncs.com/google_containers

然后再执行初始化操作, 因为包含了一些重要信息最好记录一下这里的输出内容.
如果后续有问题可以执行 sudo kubeadm reset -f 来重新开始 init.

# 这里需要加上 --image-repository registry.aliyuncs.com/google_containers 才会使用刚才拉取到的阿里云镜像
$ sudo kubeadm init --pod-network-cidr 10.244.0.0/16 --service-cidr 10.96.0.0/12 --apiserver-advertise-address 10.0.0.1 --control-plane-endpoint k8s.kazusa.cc
[init] Using Kubernetes version: v1.28.4
......
[certs] apiserver serving cert is signed for DNS names [coda kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 10.0.0.1]
......
[certs] etcd/server serving cert is signed for DNS names [coda localhost] and IPs [10.0.0.1 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [coda localhost] and IPs [10.0.0.1 127.0.0.1 ::1]
......
[mark-control-plane] Marking the node coda as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node coda as control-plane by adding the taints [node-role.kubernetes.io/control-plane:NoSchedule]
[bootstrap-token] Using token: blkkkw.f0a5598qnshl5w7z
......
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
......
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:

kubeadm join 10.0.0.1:6443 --token blkkkw.f0a5598qnshl5w7z \
        --discovery-token-ca-cert-hash sha256:26654980f017cafd0ccec0476c862c724c35c0ee7e072d45cd96670e47ebb779

根据输出选择其中一种配置文件的存储方式, 这种服务还是上 root 权限比较稳, 有几种方式都可以实现自动加载环境变量, 这里我选择 environment.

export KUBECONFIG=/etc/kubernetes/admin.conf
echo 'KUBECONFIG=/etc/kubernetes/admin.conf' | sudo tee -a /etc/environment
# source /etc/environment

查看一下刚才拉取的镜像, 感觉和 docker 差不多.

$ sudo crictl image ls
IMAGE                                     TAG                 IMAGE ID            SIZE
registry.k8s.io/coredns/coredns           v1.10.1             ead0a4a53df89       16.2MB
registry.k8s.io/etcd                      3.5.9-0             73deb9a3f7025       103MB
registry.k8s.io/kube-apiserver            v1.28.4             7fe0e6f37db33       34.7MB
registry.k8s.io/kube-controller-manager   v1.28.4             d058aa5ab969c       33.4MB
registry.k8s.io/kube-proxy                v1.28.4             83f6cc407eed8       24.6MB
registry.k8s.io/kube-scheduler            v1.28.4             e3db313c6dbc0       18.8MB
registry.k8s.io/pause                     3.8                 4873874c08efc       311kB
registry.k8s.io/pause                     3.9                 e6f1816883972       322kB

注意到这里有两个相邻版本的 pause, 这是因为 containerd 默认的更旧, 同时 init 也输出了 detected that the sandbox image "registry.k8s.io/pause:3.8" of the container runtime is inconsistent with that used by kubeadm. It is recommended that using "registry.k8s.io/pause:3.9" as the CRI sandbox image., 既然如此我们手动替换一下.
不知道为什么我这里都没有 containerd 文件夹, 之前在 kali WSL 中测试是有的. 但是没关系, 直接把默认的配置导出到对应位置就好了.
通过查看帮助找到默认配置文件是 /etc/containerd/config.toml

sudo mkdir /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
sudo vim /etc/containerd/config.toml

配置文件也不算很长, 就不说怎么找了. 将 sandbox_image = "registry.k8s.io/pause:3.8" 替换为 3.9 即可. 如果使用镜像源这一行会带有例如 aliyuncs.com 的字样
然后重启软件再重置 kubeadm.

sudo systemctl restart containerd
sudo kubeadm reset
sudo crictl rmi 4873874c08efc
sudo kubeadm init --pod-network-cidr 10.244.0.0/16 --service-cidr 10.96.0.0/12 --apiserver-advertise-address 10.0.0.1

发现这一次没有下载 pause:3.8 了.

安装第三方网络插件

这一步很重要, 后期想换插件比较麻烦, 而且方式一点都不优雅. 所以最好一开始就选定要使用的网络插件.

这里我选择 Flannel, 因为它好像更简单.

cd /srv/k8s/config
wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
sudo kubectl apply -f kube-flannel.yml

根据 项目文档 的描述, 如果使用那个默认网段什么都不用修改.

If you use custom podCIDR (not 10.244.0.0/16) you first need to download the above manifest and modify the network to match your one.

* 类似于 docker compose, k8s 的默认文件名为 kustomization.yaml

配置从节点

有了之前的经验配置起来就很快了, 大概是这样:

  1. 重复之前的前三步
  2. 命令由 kubeadm init 改为 kubeadm join 作为从节点加入集群
  3. 网络插件 (存疑)

先写到这, 下次开三个虚拟机测试一下.
todo: Hyper-V 装 iso
补充 Debian 配置软件源并 hold 版本
配置 dashboard
完善超链接

参考文章

https://www.drxcloud.club/662.html
https://github.com/chaseSpace/k8s-tutorial-cn/blob/main/install_by_kubeadm/install.md
https://www.linuxtechi.com/install-kubernetes-cluster-on-debian/
https://kubernetes.io/zh-cn/docs
https://zhuanlan.zhihu.com/p/613288409
https://www.qikqiak.com/post/manual-install-high-available-kubernetes-cluster/
https://alanhou.org/kubernetes-recipes/