Kubernetes家庭集群的冒险

注意事项 佩雷夫 :本文的作者Marshall Brekka在Fair.com上担任系统设计主管的职位,该系统将其应用于汽车租赁。 在业余时间,他喜欢利用他丰富的经验来解决“家庭”问题,这些问题不可能使任何怪胎都感到惊讶(因此,就以下所述的动作而言,“为什么?”这个问题是先验的)。 因此,马歇尔(Marshall)在他的出版物中分享了最近在... ARM板上部署Kubernetes的结果。



像许多其他怪胎一样,这些年来,我积累了各种开发板,例如Raspberry Pi。 就像许多极客一样,他们以为有一天会派上用场而在架子上撒满灰尘。 现在对我而言,这一天终于到了!

在寒假期间,出现了几周的工作时间,在这段时间内有足够的时间盘点所有积聚的铁并决定如何处理。 这是我所拥有的:

  • 具有USB3连接的5驱动器RAID机箱;
  • Raspberry Pi模型B(OG模型);
  • CubbieBoard 1;
  • 香蕉派M1;
  • HP上网本(2012?)。

在列出的5个铁组件中,除非RAID和上网本用作临时NAS,否则我将使用该组件。 但是,由于上网本中缺少USB3支持,因此RAID无法充分发挥速度的潜力。

人生目标


由于使用上网本时使用RAID并不是最佳选择,因此我制定了以下目标以获得最佳配置:

  1. 带有USB3和千兆以太网的NAS;
  2. 在设备上管理软件的最佳方法
  3. (奖励)将多媒体内容从RAID流传输到Fire TV的能力。

不幸的是,由于没有可用的设备支持USB3和千兆以太网,因此,我不得不额外购买。 选择权在ROC-RK3328-CC上 。 她拥有所有必要的规格以及对操作系统的充分支持。

解决了我的硬件需求(并等待该解决方案的到来)之后,我转向了第二个目标。

管理设备上的软件


部分原因是我过去与开发委员会有关的项目失败了,原因是对可重复性和文档问题的关注不足。 当创建满足当前需求的下一个配置时,我不必费心写下所采取的步骤或所关注博客文章的链接。 几个月或几年后,当出现问题并尝试解决问题时,我对所有内容的最初安排都不了解。

所以我告诉自己,这次一切都会有所不同!



他转向我对Kubernetes足够了解的事实。

尽管K8s很难解决一个相当简单的问题,但是在主要工作中使用各种工具(我自己的,kops等)管理集群近三年之后,我对这个系统非常熟悉。 此外,在云环境之外甚至在ARM设备上部署K8似乎是一项有趣的任务。

我还认为,由于可用的硬件不满足NAS的必要要求,因此我将尝试至少从中组装一个集群,并且可能某些资源要求不高的软件将能够在较旧的设备上运行。

Kubernetes在ARM上


在工作中,我没有机会使用kubeadm实用程序来部署集群,所以我决定现在该进行实际操作了。

选择Raspbian作为操作系统是因为它以对我的主板的最佳支持而闻名。

我找到了一篇很好的文章 ,介绍如何使用HypriotOS在Raspberry Pi上设置Kubernetes。 由于我不确定我所有主板的HypriotOS是否可用,因此我针对Debian / Raspbian修改了这些说明。

所需组件


首先,需要安装以下工具:

  • 码头工人
  • kubelet
  • 库贝阿姆
  • kubectl。

必须使用特殊脚本( 便捷脚本)安装Docker(如使用Raspbian时所示)。

 curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh 

之后,我根据Hypriot博客上的说明安装了Kubernetes组件,并对它们进行了修改,以便将特定版本用于所有依赖项:

 curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list apt-get update apt-get install -y kubelet=1.13.1-00 kubectl=1.13.1-00 kubeadm=1.13.1-00 

树莓派


尝试在Raspberry Pi B上引导集群时出现了第一个困难:

 $ kubeadm init Illegal instruction 

事实证明,Kubernetes 删除了对ARMv6的支持 。 好吧,我也有CubbieBoard和Banana Pi。

香蕉皮


最初,Banana Pi的相同操作顺序似乎更为成功,但是, kubeadm init命令在尝试等待控制平面工作时kubeadm init

 error execution phase wait-control-plane: couldn't initialize a Kubernetes cluster 

docker ps了解了容器的情况后,我看到kube-controller-managerkube-scheduler都工作了至少4-5分钟,但是kube-api-server才在1-2分钟前起床:

 $ docker ps CONTAINER ID COMMAND CREATED STATUS de22427ad594 "kube-apiserver --au…" About a minute ago Up About a minute dc2b70dd803e "kube-scheduler --ad…" 5 minutes ago Up 5 minutes 60b6cc418a66 "kube-controller-man…" 5 minutes ago Up 5 minutes 1e1362a9787c "etcd --advertise-cl…" 5 minutes ago Up 5 minutes 

显然, api-server快要死了,或者锶进程正在杀死它并重新启动它。

在检查日志时,我看到了非常标准的启动过程-在TLS握手中出现许多错误之前,有记录开始监听安全端口,并且暂停了很长时间:

 20:06:48.604881 naming_controller.go:284] Starting NamingConditionController 20:06:48.605031 establishing_controller.go:73] Starting EstablishingController 20:06:50.791098 log.go:172] http: TLS handshake error from 192.168.1.155:50280: EOF 20:06:51.797710 log.go:172] http: TLS handshake error from 192.168.1.155:50286: EOF 20:06:51.971690 log.go:172] http: TLS handshake error from 192.168.1.155:50288: EOF 20:06:51.990556 log.go:172] http: TLS handshake error from 192.168.1.155:50284: EOF 20:06:52.374947 log.go:172] http: TLS handshake error from 192.168.1.155:50486: EOF 20:06:52.612617 log.go:172] http: TLS handshake error from 192.168.1.155:50298: EOF 20:06:52.748668 log.go:172] http: TLS handshake error from 192.168.1.155:50290: EOF 

此后不久,服务器结束了工作。 谷歌搜索导致了这样的问题 ,表明在某些ARM设备上加密算法运行缓慢的可能原因。

我走得更远,以为api-server可能从schedulercontroller-manager收到太多重复请求。

从清单目录中删除这些文件将告诉kubelet停止执行相应的pod:

 mkdir /etc/kubernetes/manifests.bak mv /etc/kubernetes/manifests/kube-scheduler.yaml /etc/kubernetes/manifests.bak/ mv /etc/kubernetes/manifests/kube-controller-mananger.yaml /etc/kubernetes/manifests.bak/ 

查看最新的api-server日志显示,现在该过程进一步进行了,但是,大约2分钟后它仍然死了。 然后我想起了清单可能包含一个活动样本,对于这样一个缓慢的设备,其超时值太低。

因此,我检查了/etc/kubernetes/manifests/kube-api-server.yaml当然,在其中...

 livenessProbe: failureThreshold: 8 httpGet: host: 192.168.1.155 path: /healthz port: 6443 scheme: HTTPS initialDelaySeconds: 15 timeoutSeconds: 15 

Pod在135秒后被杀死( initialDelaySeconds + timeoutSeconds * timeoutSeconds )。 将initialDelaySeconds增加到120 ...

成功! 好吧,握手错误仍然会发生(大概是来自kubelet),但是启动仍然发生了:

 20:06:54.957236 log.go:172] http: TLS handshake error from 192.168.1.155:50538: EOF 20:06:55.004865 log.go:172] http: TLS handshake error from 192.168.1.155:50384: EOF 20:06:55.118343 log.go:172] http: TLS handshake error from 192.168.1.155:50292: EOF 20:06:55.252586 cache.go:39] Caches are synced for autoregister controller 20:06:55.253907 cache.go:39] Caches are synced for APIServiceRegistrationController controller 20:06:55.545881 controller_utils.go:1034] Caches are synced for crd-autoregister controller ... 20:06:58.921689 storage_rbac.go:187] created clusterrole.rbac.authorization.k8s.io/cluster-admin 20:06:59.049373 storage_rbac.go:187] created clusterrole.rbac.authorization.k8s.io/system:discovery 20:06:59.214321 storage_rbac.go:187] created clusterrole.rbac.authorization.k8s.io/system:basic-user 

api-server启动时,我将控制器和调度程序的YAML文件移回了清单目录,然后它们也正常启动。

现在,如果您将所有文件都保留在源目录中,就可以确保下载成功:是否足以更改livenessProbe初始化的允许延迟?

 20:29:33.306983 reflector.go:134] k8s.io/client-go/informers/factory.go:132: Failed to list *v1.Service: Get https://192.168.1.155:6443/api/v1/services?limit=500&resourceVersion=0: dial tcp 192.168.1.155:6443: i/o timeout 20:29:33.434541 reflector.go:134] k8s.io/client-go/informers/factory.go:132: Failed to list *v1.ReplicationController: Get https://192.168.1.155:6443/api/v1/replicationcontrollers?limit=500&resourceVersion=0: dial tcp 192.168.1.155:6443: i/o timeout 20:29:33.435799 reflector.go:134] k8s.io/client-go/informers/factory.go:132: Failed to list *v1.PersistentVolume: Get https://192.168.1.155:6443/api/v1/persistentvolumes?limit=500&resourceVersion=0: dial tcp 192.168.1.155:6443: i/o timeout 20:29:33.477405 reflector.go:134] k8s.io/client-go/informers/factory.go:132: Failed to list *v1beta1.PodDisruptionBudget: Get https://192.168.1.155:6443/apis/policy/v1beta1/poddisruptionbudgets?limit=500&resourceVersion=0: dial tcp 192.168.1.155:6443: i/o timeout 20:29:33.493660 reflector.go:134] k8s.io/client-go/informers/factory.go:132: Failed to list *v1.PersistentVolumeClaim: Get https://192.168.1.155:6443/api/v1/persistentvolumeclaims?limit=500&resourceVersion=0: dial tcp 192.168.1.155:6443: i/o timeout 20:29:37.974938 controller_utils.go:1027] Waiting for caches to sync for scheduler controller 20:29:38.078558 controller_utils.go:1034] Caches are synced for scheduler controller 20:29:38.078867 leaderelection.go:205] attempting to acquire leader lease kube-system/kube-scheduler 20:29:38.291875 leaderelection.go:214] successfully acquired lease kube-system/kube-scheduler 

是的,一切正常,尽管这些旧设备显然不打算启动控制平面,因为重复的TLS连接会导致严重的刹车。 一种或另一种方式-可以在ARM上正常安装K8! 让我们更进一步...

RAID挂载


由于SD卡从长远来看不适合记录,因此我决定对文件系统中最易失的部分(在本例中为RAID)使用更可靠的存储。 其中突出显示了4个部分:

  • 50 GB;
  • 2×20 GB;
  • 3.9磅

对于20 GB的分区,我尚未提出具体的用途,但我想为将来留下更多的机会。

/etc/fstab对于50 GB分区,挂载点指定为/mnt/root ,对于3.9 TB- /mnt/raid 。 之后,我将带有etcd和docker的目录安装到50 GB分区:

 UUID=655a39e8-9a5d-45f3-ae14-73b4c5ed50c3 /mnt/root ext4 defaults,rw,user,auto,exec 0 0 UUID=0633df91-017c-4b98-9b2e-4a0d27989a5c /mnt/raid ext4 defaults,rw,user,auto 0 0 /mnt/root/var/lib/etcd /var/lib/etcd none defaults,bind 0 0 /mnt/root/var/lib/docker /var/lib/docker none defaults,bind 0 0 

到货ROC-RK3328-CC


新板交付时,我在其上安装了K8的必要组件(请参阅本文的开头),并启动了kubeadm init 。 几分钟的等待就是join命令的成功以及在其他节点上运行的输出。

太好了! 不用大惊小怪的超时。

而且由于RAID也将在此板上使用,因此需要重新配置安装座。 总结所有步骤:

1.在/ etc / fstab中挂载磁盘


 UUID=655a39e8-9a5d-45f3-ae14-73b4c5ed50c3 /mnt/root ext4 defaults,rw,user,auto,exec 0 0 UUID=0633df91-017c-4b98-9b2e-4a0d27989a5c /mnt/raid ext4 defaults,rw,user,auto 0 0 /mnt/root/var/lib/etcd /var/lib/etcd none defaults,bind 0 0 /mnt/root/var/lib/docker /var/lib/docker none defaults,bind 0 0 

2.安装Docker和K8s二进制文件


 curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh 

 curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list apt-get update apt-get install -y kubelet=1.13.1-00 kubectl=1.13.1-00 kubeadm=1.13.1-00 

3.配置唯一的主机名(重要的是添加了许多节点)


 hostnamectl set-hostname k8s-master-1 

4. Kubernetes初始化


我省略了与控制平面的相位,因为我希望能够在此节点上计划普通吊舱:

 kubeadm init --skip-phases mark-control-plane 

5.安装网络插件


Hypriot文章中有关此信息的信息过时了,因为ARM现在还支持 Weave网络插件:

 export KUBECONFIG=/etc/kubernetes/admin.conf kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')" 

6.添加主机标签


在此节点上,我将启动NAS服务器,因此我将在其上标记标签以备将来在调度程序中使用:

 kubectl label nodes k8s-master-1 marshallbrekka.raid=true kubectl label nodes k8s-master-1 marshallbrekka.network=gigabit 

将其他节点连接到集群


设置其他设备(Banana Pi,CubbieBoard)也很容易。 对于它们,您需要重复前三个步骤(根据其可用性更改安装磁盘/闪存介质的设置),然后运行kubeadm join命令而不是kubeadm init

查找适用于ARM的Docker容器


大多数必要的Docker容器通常是在Mac上构建的,但是对于ARM来说,要复杂一些。 在找到了许多有关如何使用QEMU达到这些目的的文章之后,我得出的结论是,我所需的大多数应用程序已经组装好了,其中许多可以在linuxserver使用

后续步骤


仍然没有以我想要的自动化/脚本形式获得设备的初始配置,我至少编写了一组基本命令(mounts, kubeadmkubeadm )并将它们记录在Git存储库中。 其余使用的应用程序还收到了存储在同一存储库中的K8的YAML配置,因此现在很容易从头开始获得必要的配置。

将来,我希望实现以下目标:

  1. 使主站点高度可用
  2. 添加监视/通知以了解任何组件的故障;
  3. 更改路由器的DCHP设置以使用群集中的DNS服务器,以简化发现应用程序的过程(谁想要记住内部IP地址?);
  4. 运行MetalLB将群集服务转发到专用网络(DNS等)。


译者的PS


另请参阅我们的博客:

Source: https://habr.com/ru/post/zh-CN435526/


All Articles