前因

之前在观看有关docker的视频时,总有人提到k8s。我见到很多这种评论之后,便去查了查什么叫k8s。按照我的理解,这应该是一个继承了高可用性的集群化容器平台。在实习的这段无聊的日子里阅读了大量有关kuberneters的资料后,我决定在本地搭建一个小型kuberneters集群。

0、minikuber

我首先尝试在办公室的电脑(i5-10500+8G RAM+1T HDD)上使用minikuber搭建一个单节点集群。结果无论是基于WSL2还是hyper-v均失败了,最后我只能回家,在我的那台服务器上尝试搭建完整的kuberneters。至于失败的原因,之后有时间再说吧。

1、初期准备

咱准备了三台虚拟机,配置均为8核心CPU+8GB RAM+50GB 硬盘。系统是debian11.每台虚拟机均配备两块网卡,一块以桥接的形式连接到家庭网络(192.168.31.110-112),另一块则用于内部网络通信(仅主机,172.16.31.110-112).

在安装系统阶段,就给了我当头一棒。或许是最近网络条件又恶化了吧。在安装debian时不能选择配置网络镜像,不然我就会在漫长等待后被告知安装失败。而其它的东西,无非就是在分区时不推荐开启Swap交换分区,和设置好hostname。apt软件包源可以在安装后参考这里进行配置。

接下来,为几台机器分别设置IP,并且将IP与hostname的对应关系写入/etc/hosts。

在Debian11上,我使用

hostnamectl set-hostname k8s-master

修改hostname为k8s-master。

这儿提一下咱踩过的一个小坑,运行特权命令,请不要直接运行

su

最好使用

sudo + 命令(前提是你的用户账户允许使用sudo)

以及

su - root

否则会出现很多离谱的问题,比如说shutdown和reboot找不到呀,明明安装了应用却打不开,dpkg安装报错等。

在安装完系统、配置好源之后,文档上还提示我应该转发 IPv4 并让 iptables 看到桥接流量。不过debian11似乎没有iptables,所以我直接忽略了iptables这一步。而开启转发,就是运行:

sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward

具体参考这里

接下来文档还提到了cgroup 驱动,因为我确定debian11使用的是systemd,同时文档也没有指出需要什么强制性操作,所以我就没有做进一步处理了。

这一步所有节点都必须执行。

2、安装docker

kuberneters需要一个容器引擎来完成一些基本操作。我看了看参考文档上的那些东西,觉得还是选择我最熟悉的docker吧。docker可以按照这份官方文档来进行安装。

在安装完了docker之后,还得要安装cri-dockerd,这是为了能够让docker使用容器运行时接口(CRI)来与kuberneters通信,并且让docker被kuberneters管理。

在安装好了之后,需要记录下CRI 套接字是 /run/cri-dockerd.sock,这个后面会用到。

这一步所有节点都必须执行。

3、安装 kubeadm

kubeadm是一个用来管理kuberneters的工具箱,我使用它创建kuberneters集群。

在安装这个工具之前,首先更新 apt 包索引并安装使用 Kubernetes apt 仓库所需要的一些依赖包:

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl

接下来,最好不要按照官网走,中国大陆地区很难连接上Google的软件仓库,转到这里进行接下来的步骤。

不过,gpg key还是得自己下载放到指定位置的,这一点得自己动手。我采取的方法是:先在Windows系统上下载好——在终端里使用scp命令将文件传输到普通用户目录——切换root用户将文件拷贝到指定位置。

接下来就是照着文档安装并锁定版本了:

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

这里安装的三个软件中,kubeadm用来创建集群和让节点加入集群。kubelet是用来保证容器都运行在 Pod 中的。具体的解释参考官方文档。简单的说,pod是容器的集合,一个pod里可以包含多个容器,每个pod有自己的IP地址,而kuberneters的调度也是以pod为单位。

kubectl,是一个用来管理kuberneters的命令行工具,后面会经常使用它。

这一步所有节点都必须执行。

4、初始化主节点

看上去很简单,只需要一条命令,如下:

kubeadm init \
--cri-socket unix:///var/run/cri-dockerd.sock
--apiserver-advertise-address=172.16.31.110 \
--control-plane-endpoint=k8s-master \
--service-cidr=10.1.0.0/16 \
--pod-network-cidr=10.244.0.0/16

实则里面有坑。

首先,因为无法访问gcr.io,所以我们得为docker服务配置代理(只配置终端代理没有用,kuberneters也得通过docker拉取镜像)或者使用镜像站(类似于再加一条--image-repository registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images \不过网传的这个registry.cn-hangzhou.aliyuncs.com似乎已经挂了)。

部分参数的解释:

cri-socket:之前的CRI套接字
apiserver-advertise-address:kuberneters api服务器的地址,一般是你的主控节点内部IP
control-plane-endpoint:将单个控制平面 kubeadm 集群升级成高可用,即为所有控制平面节点设置共享端点, 端点可以是负载均衡器的 DNS 名称或 IP 地址
service-cidr:service网络的IP地址范围,当你给一个pod暴露了端口的时候,pod的端口也会运行在这个内部IP上
pod-network-cidr:pod分配到的内部网络地址范围
image-repository:可以指定镜像仓库地址
kubernetes-version:可以指定需要部署的k8s的版本
文档里的说明

之后就是等待了。如果你的网络连接Google正常,那么大约只需要半个小时左右就可以安装好,安装好后,会显示类似于这样的话:

kubeadm join 192.168.31.110:6443 --token e6itty.nahyjrbe9uu4jc3z \
--discovery-token-ca-cert-hash sha256:b8f7a6720e6ae23c6657a0e283c844ea908836f40e628b521cb2bcc4daaf2a84

需要记下这一段命令,用于后面加入节点使用。

这一步只需要主控节点执行。

5、设置配置文件

使用kubecli需要有admin.conf配置文件,复制一份到用户目录下的.kube文件夹里就行了。

cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

接下来,得把这个文件复制到各个节点上的相同位置,但是因为它们没有/etc/kubernetes/admin.conf,不能使用cp命令,只能一个个手动复制过去了。

然后,执行:

systemctl status systemd-resolved
systemctl start systemd-resolved

来避免拉取镜像时出现

Failed to create pod sandbox: open /run/systemd/resolve/resolv.conf: no such file or directory

这样的报错。

这一步所有节点都必须执行。

6、安装网络插件

必须要安装网络插件才能够让核心DNS启动,可以先尝试在主节点上运行

cubectl get nodes

来查看现有master节点的运行情况。不出意料应该是notready的。所以需要安装网络插件来让功能完整。

网络插件类型众多,而且它们和kuberneters之间还有版本的对应关系。我参考了这篇文章,使用了Calico网络插件,不过因为我的kuberneters版本过新,使用了最新的3.25版Calico

下载资源清单文件(官方文档就是这个叫法):

wget https://docs.projectcalico.org/archive/v3.25/manifests/calico.yaml

然后部署插件:

kubectl apply -f calico.yaml

然后还是等待。这里还是得注意网络问题。如果在半个小时之后发现master还没有ready,而运行

kubectl get pods -n kube-system

发现报错 init:ImagePullBackOff,那么说明拉取镜像失败了。我这里采用的方法是打开calico.yaml文件,找到里面标有image的镜像,一个个手动用docker pull拉取....

在拉取镜像后再次等待一下,master节点应该已经Ready了。

而如果使用

journalctl -u kubelet

这个命令查看kubelet运行情况时,发现出现network: stat /var/lib/calico/nodename: no such file or directory: check that the calico/n这样的报错,那么需要删除calico的配置文件并重启kubelet:

rm -rf /etc/cni/net.d/*
rm -rf /var/lib/cni/calico
rm -rf /var/lib/calico
systemctl  restart kubelet

这一步只需要主控节点执行。

7、worker节点加入集群

千辛万苦终于来到了这一步。使用之前记下来的加入命令,再加上--cri-socket unix:///var/run/cri-dockerd.sock \,也就是:

kubeadm join 192.168.31.110:6443 --token e6itty.nahyjrbe9uu4jc3z \
--cri-socket unix:///var/run/cri-dockerd.sock \
--discovery-token-ca-cert-hash sha256:b8f7a6720e6ae23c6657a0e283c844ea908836f40e628b521cb2bcc4daaf2a84

在worker节点上运行,把worker节点加入集群。接下来就是等待它们Ready了。

这里同样需要注意网络问题,如果有必要就挂代理拉镜像。

在主节点使用

kubectl get nodes

来查看加入情况。

8、部署管理面板

像我这种命令行苦手,那肯定是不用GUI就不舒服,所以管理面板也得安排上。

kuberneters有官方的管理面板,参考这里的说明,首先用这条部署它:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml

然后便是修改配置,让端口暴露出来。这里需要运行

KUBE_EDITOR="nano" kubectl edit svc kubernetes-dashboard -n kubernetes-dashboard

这里前面的“KUBE_EDITOR="nano"”代表使用nano取代默认的编辑器vi来修改配置文件。我用nano只是因为个人确实不习惯vi。

在出现的窗口中,将type: ClusterIP 改为 type: NodePort即可让dashboard的端口暴露。这里还得留心一下上面的端口号。

然后便是认证,创建一个yaml文件:

nano dashuser.yaml

写入以下内容:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard

这里的文件的大概解释是创建角色并手动授予所需的权限,使用命名空间中的名称创建服务帐户。我也不是很理解,这里参考的是这篇文章,虽然我后面在使用过程中出错了,不过还是正常获取到了tocken。

接着执行资源清单并获取tocken:

kubectl apply -f dash.yaml
kubectl -n kubernetes-dashboard create token admin-user

记下这段tocken,然后在浏览器里访问集群里任意主机的https://外部IP:刚刚记下的端口号,记不住可以用端口扫描工具把集群IP的所有扫一遍。

如果无法访问,就运行

kubectl get pods -A

来确认dashboard运行正常。

浏览器里忽略证书错误,复制tocken并将其粘贴到登录屏幕上的字段中,即可进入dashboard。

9、后记

其实我有点后悔去踩这个坑,k8s比docker难多了,特别是大陆特殊的网络问题,折磨得我十分无语。家庭服务器弄这个感觉也没什么必要。可能只是咱自己想要折腾吧。以后有时间和硬件或许会研究研究k8s的家庭应用?后面的事,又有谁能确定呢?

写到这里已经快晚上11点了,由于咱自己本身就是小白而且还是盲从网上的大神们搭建起来的,所以请大家务必不要抄我这个才60分的作业,如果有错误,欢迎指正,我会修改的。

最后更新于 2023-03-04