【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

著名 FinTech 公司如何使用 k3s+ 树莓派在生产中构建轻量 K8S 裸机集群

  • 2020-05-18
  • 本文字数:5249 字

    阅读完需:约 17 分钟

著名FinTech公司如何使用k3s+树莓派在生产中构建轻量K8S裸机集群

Boogie Software 是欧洲著名的金融科技公司,多年来致力于为银行提供 Fintech、AI、大数据高性能后端、移动应用程序、数据分析及 UX 等创新服务,帮助银行推动数字化转型。凭借过去十多年在该领域的独特经验,Boogie 已成为数字银行服务提供商中的领导者。

本文作者是 Boogie Software 的资深软件架构师 Jari Tenhunen。他拥有超过 15 年的软件开发经验,擅长信息安全和网络协议。并且长期管理项目和团队,在其中主导软件架构和技术,成功将多个产品推向市场。


Boogie Software 的 IT 团队在很多客户银行的核心银行业务数字化的项目中使用到了 Kubernetes 和容器技术,因此我们始终在想 Kubernetes 能如何使用更合适的硬件在本地工作。在本文中,我将详细介绍我们如何在树莓派上构建轻量级裸机集群,以在公司网络中运行应用程序和服务。


我们之所以这么做,有两个原因:第一,通过建立集群,我们将可以拥有一个平台,来可靠、灵活地运行公司网络内部应用程序和服务;第二,我们可以通过这次机会学习更多关于 Kubernetes、微服务以及容器的技能。如果你也想要参照我们的经验来构建一个相似的系统,我建议你至少要了解关于 Docker 容器、Kubernetes 关键概念(节点、pod、服务、deployment 等)以及 IP 网络的基础知识。

硬件准备

你需要准备以下设备:


  • 树莓派 2B/3B/3B+ 的型号,至少一个。你甚至在单个开发板上运行某些应用程序,但是建议使用两个或更多的开发板来分散负载并增加冗余。

  • 电源和可用于树莓派的 SD 卡,现有的以太网交换机或空闲端口以及一些电缆。


在我们的设置中,我们目前有 4 个树莓派 3 代 B+开发板,所以在集群中有一个 master/server 和 3 个代理节点。如果树莓派有外壳当然更好,我们的同事用 3d 打印机设计了一个。此外,机壳的背面有两个用于冷却的风扇,每个开发板都位于一个托盘上,该托盘可以热插拔以进行维护。这些托盘前面还设有 activity/heartbeat LED 和电源开关的位置,它们都连接到开发板的 GPIO 接头。



软件准备

对于 Kubernetes 的实现,我们使用的是 k3s。k3s是由 Rancher Labs 推出的一款轻量级、 通过 CNCF 一致性认证 的 Kubernetes 发行版。尽管这是一款刚推出不久的产品,但它真的 十分稳定和易用,可以实现秒级启动 。让 k3s 从其他轻量的 Kubernetes 发行版脱颖而出的原因是,k3s 可供生产使用,而诸如 microk8s 或 Minikube 之类的项目则无法实现这一目的,并且 k3s 十分轻巧,还可以在基于 ARM 的硬件上很好地运行。在 k3s 中,任何设备上安装 Kubernetes 所需的一切都包含在这一个 40MB 的二进制文件当中。


k3s 几乎能在任何 Linux 发行版中很好地运行,因此我们决定将 Raspbian Stretch Lite 作为基础 OS,因为我们不需要在开发板上添加任何额外的服务或者桌面 UI。k3s 确实需要在 Linux 内核中启用 cgroup,这可以在 Raspbian 上通过向/boot/cmdline.txt:添加以下参数来实现:


cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
复制代码

安装 k3s

k3s 非常友好的地方在于,它可以实现平滑安装过程。你准备好你的 server 硬件之后,仅需几分钟就可以完成设置,因为它仅需一行命令就能安装 server(主节点):


curl -sfL https://get.k3s.io | sh -
复制代码


代理节点也是如此:


curl -sfL https://get.k3s.io | K3S_TOKEN=<token_from_server> K3S_URL=https://<server_ip>:6443 sh -
复制代码


其中 token_from_server 是来自服务器的文件/ var / lib / rancher / k3s / server / node-token 的内容,server_ip 是服务器节点的 IP 地址。至此,我们的集群已经启动并正在运行,我们可以开始部署工作负载:


root@k3s-server:~# kubectl get nodesNAME         STATUS   ROLES    AGE    VERSIONk3s-node1    Ready    <none>   40s    v1.13.4-k3s.1k3s-server   Ready    <none>   108s   v1.13.4-k3s.1
复制代码


为了管理和监控集群,我们安装了 Kubernetes Dashboard,它能够提供给非常方便的 web 界面来查看整个系统的状态、执行管理员操作并访问日志。同时,本地安装和运行 kubectl 命令也非常有帮助,因为它可以让你从自己的计算机管理集群,而无需 ssh 进入集群。为此,你只需要安装 kubectl,然后将集群信息从服务器节点 config /etc/rancher/k3s/k3s.yaml 复制到本地 kubeconfig 文件中(通常是 ${HOME}/.kube/config)。

使用负载均衡器暴露服务

默认情况下,部署在 Kubernetes 集群上的应用程序仅可以在集群中获取(默认服务类型是 ClusterIP)。如果想要从集群外部获取应用程序,有两个选项。你可以使用 NodePort 类型配置服务,该服务在静态端口的每个节点 IP 上暴露服务,你也可以使用负载均衡器(服务类型 LoadBalancer)。然而,NodePort 服务有限制:它们使用自己专用的端口范围,我们只能通过端口号来区分应用。k3s 内置了一个简单的负载均衡器,但由于它使用的是节点的 IP 地址,我们可能很快就会用完 IP/端口组合并且无法将服务绑定到某个虚拟 IP。基于这些原因,我们决定部署 MetalLB——一种用于裸机集群的负载均衡器实现。


只需应用 YAML manifest 即可安装 MetalLB。在现有网络中运行 MetalLB 的最简单方法是使用所谓的第 2 层模式,这意味着集群节点通过 ARP 协议宣布本地网络中服务的虚拟 IP。为此,我们从内部网络保留了一小部分 IP 地址用于集群服务。MetalLB 的配置如下所示:


apiVersion: v1kind: ConfigMapmetadata:  namespace: metallb-system  name: configdata:  config: |    address-pools:    - name: company-office      protocol: layer2      addresses:      - 10.10.10.50-10.10.10.99

复制代码


使用此配置,集群服务将被暴露在范围为 10.10.10.50—10.10.10.99 的地址中。为了绑定服务到指定的 IP,你可以在服务清单中使用 loadBalancerIP 参数:


apiVersion: v1kind: Servicemetadata:  name: my-web-appspec:  ports:  - name: http    port: 80    protocol: TCP    targetPort: 8080  loadBalancerIP: 10.10.10.51  selector:    app: my-web-app  type: LoadBalancer
复制代码


在负载均衡中,我们面临诸多挑战。例如,Kubernetes 中限制在单个负载均衡器中同时使用 TCP 和 UDP 端口。要解决这一问题,你可以定义两个服务实例,一个用于 TCP 端口,另一个用于 UDP 端口。其缺点是,除非启用 IP 地址共享,否则你需要在不同的 IP 地址中运行这两个服务。而且,由于 MetalLB 是一个年轻项目,因此也存在一些小问题,但我们相信这些很快都会得到解决。

添加存储

k3s 暂时没有内置的存储解决方案,所以为了使 Pod 能够访问持久性文件存储,我们需要使用 Kubernetes 的插件来创建一个。由于 Kubernetes 的目标之一是使应用程序与基础架构解耦并使其可移植,因此 Kubernetes 中用 PersistentVolume(PV)和 PersistentVolumeClaim(PVC)的概念定义了用于存储的抽象层。详细的概念解释可以参照我们之前发过的文章:详解Kubernetes存储关键概念。PV 是通常由管理员配置并可供应用程序使用的存储资源。另一方面,PVC 描述了应用程序对某种类型和一定数量的存储的需求。创建 PVC(通常作为应用程序的一部分)时,如果有一个尚未使用且满足应用程序 PVC 要求的可用 PVC,它将绑定到 PV。配置和维护所有这些需要手动工作,因此动态配置卷应运而生。


在我们的基础架构中,我们已经有一个现有的 NFS 服务器,因此我们决定将其用于集群持久性文件存储。在我们的案例中,最简单的方法是使用支持动态配置 PV 的 NFS-Client Provisioner。Provisioner 只需在现有的 NFS 共享上为每个新 PV(集群映射到 PVC)上创建新目录,然后将 PV 目录挂载在使用它的容器中。这样就无需配置 NFS 共享到单个 pod 中的卷,而是全部动态运行。

为 ARM 交叉构建容器镜像

显然,在基于 ARM 的硬件上(如树莓派)运行应用程序容器时,需要根据 ARM 的架构构建容器。在 ARM 架构容器中构建自己的应用程序时,可能会遇到一些陷阱。首先,基础镜像需要可用于你的目标架构体系。对于树莓派 3 来说,通常需要使用 arm32v7 的基础镜像,它们可以在大部分 Docker 镜像仓库中被调用。所以,当交叉构建应用程序时,确保你的 Dockerfile 包含以下代码:


FROM arm32v7/alpine:latest
复制代码


第二件需要注意的事是,你的主机 Docker 需要能够运行 ARM 二进制文件。如果你在 mac 上运行 Docker,那操作将十分轻松,因为它对此有内置支持。如果是在 Linux 上,你需要执行一些步骤:

添加 QEMU 二进制文件到你的基础镜像

为了在 Linux 上的 Docker 中运行 ARM 二进制文件,镜像需要一个 QEMU 二进制文件。你可以选择一个已经包含了 QEMU 二进制文件的基础镜像,也可以在镜像构建过程中复制


qemu-arm-static 二进制文件到其中,例如,通过将以下行添加到你的 Dockerfile 中:


COPY --from=biarms/qemu-bin /usr/bin/qemu-arm-static /usr/bin/qemu-arm-static
复制代码


安全警示:请注意下载和运行未知的容器就如同下载和运行位置的.exe 文件。除业余项目外,其他任何项目都应使用扫描/审核过的镜像(如 Docker 官方镜像)或来自信任的组织和公司的容器镜像。


然后,你需要在创建 Docker 镜像的主机 OS 上注册 QEMU。这可以简单地通过以下方式实现:


docker run --rm --privileged multiarch/qemu-user-static:register --reset
复制代码


可以在构建实际镜像之前将该命令添加到你的构建脚本中。总结一下,你的 Dockerfile.arm 应该看起来像这样:


FROM arm32v7/alpine:latestCOPY --from=biarms/qemu-bin /usr/bin/qemu-arm-static /usr/bin/qemu-arm-static# commands to build your app go here…# e.g. RUN apk add --update <pkgs that you need…>
复制代码


并且你的 build /CI 脚本应该是:


docker run --rm --privileged multiarch/qemu-user-static:register --resetdocker build -t my-custom-image-arm . -f Dockerfile.arm
复制代码


这将为你提供 ARM 架构的容器镜像。如果你对细节很感兴趣,请参阅:


https://www.ecliptik.com/Cross-Building-and-Running-Multi-Arch-Docker-Images/

自动化构建和上传到镜像仓库

最后一步是自动化整个流程,以便容器镜像可以自动构建并且自动上传到一个镜像仓库,在那里可以轻松地将其部署到我们地 k3s 集群。在内部,我们使用 GitLab 进行源代码管理和 CI/CD,因此我们自然希望在其中运行这些构建,它甚至包括一个内置的容器镜像仓库,因此不需要设置单独的镜像仓库。


关于构建 Docker 镜像,GitLab 有十分完善的文档(https://docs.gitlab.com/ee/ci/docker/using_docker_build.html),因此我们不在此赘述。在为 docker 构建配置 GitLab Runner 之后,剩下要做的就是为该项目创建.gitlab-ci.yml 文件。在我们的例子中,它看起来像这样:


image: docker:stable
stages: - build - release variables: DOCKER_DRIVER: overlay2 CONTAINER_TEST_IMAGE: ${CI_REGISTRY_IMAGE}/${CI_PROJECT_NAME}-arm:${CI_COMMIT_REF_SLUG} CONTAINER_RELEASE_IMAGE: ${CI_REGISTRY_IMAGE}/${CI_PROJECT_NAME}-arm:latest before_script:- docker info- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY build_image: stage: build script: - docker pull $CONTAINER_RELEASE_IMAGE || true - docker run --rm --privileged multiarch/qemu-user-static:register --reset - docker build --cache-from $CONTAINER_RELEASE_IMAGE -t $CONTAINER_TEST_IMAGE . -f Dockerfile.arm - docker push $CONTAINER_TEST_IMAGE release: stage: release script: - docker pull $CONTAINER_TEST_IMAGE - docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE - docker push $CONTAINER_RELEASE_IMAGE
复制代码


既然在容器镜像仓库中我们有了我们的镜像,我们只需要将它们部署到我们的集群中。为了授予集群访问镜像仓库的权限,我们在 GitLab 中创建了一个 deploy 令牌,然后将令牌凭据作为 docker-registry 密钥添加到集群中:


kubectl create secret docker-registry deploycred --docker-server=<your-registry-server> --docker-username=<token-username> --docker-password=<token-password> --docker-email=<your-email>
复制代码


之后,可以在 YAML 文件 PodSpec 中使用 deploy 令牌密钥:


    imagePullSecrets:      - name: deploycred     containers:      - name: myapp        image: gitlab.mycompany.com:4567/my/project/my-app-arm:latest
复制代码


完成所有这些步骤之后,我们终于拥有了一个从私有镜像仓库中的源代码到 ARM 容器镜像的自动 CI / CD 流水线,可以将其部署到集群中。

结语

总而言之,事实证明,建立和运行自己的裸机 Kubernetes 集群比预期的要容易。而且 k3s 确实是在边缘计算场景中和一般配置较低的硬件上运行容器化服务的明智选择。


一个小缺点是 k3s 尚不支持高可用(多主设备配置)。尽管单个主服务器设置已经具有相当的弹性,因为即使主服务器离线,服务仍可在代理节点上继续运行,我们还是希望为主节点提供一些冗余。显然,此功能正在开发中,但在此功能可用之前,我们建议从服务器节点配置中进行备份。


2020-05-18 18:01840

评论

发布
暂无评论
发现更多内容

EMQ x 阿里云:云上高效构建,IoT 数据一站处理|直播预告

阿里云弹性计算

物联网 IoT 计算巢

手把手教你成为荣耀开发者:如何进行注册与认证?

荣耀开发者服务平台

开发者 手机 新手指南 荣耀 honor

知识经济时代,企业该如何进行知识管理?

Baklib

效率工具 知识管理 企业 知识 知识经济

来了!2022 XDR网络安全运营新理念峰会即将开幕!

未来智安XDR SEC

网络安全

Go语言 if判断和for循环实战 goto使用的那些坑

王中阳Go

Go golang 学习方法 面试题 10月月更

Kubernetes fror Flink 硬气功实践

CTO技术共享

flink 个人成长 10月月更

开源日志收集 肿么选型??

CTO技术共享

个人成长 log 10月月更

SAP | abap的数据对象

暮春零贰

SAP 10月月更 数据对象

外包和自研应该选择呢?教你三招选出最合适自己的平台

千锋IT教育

真·workshop,来自联通、移动、爱奇艺等14位资深专家与你面对面聊云原生硬核技术|2022云栖大会

OpenAnolis小助手

云原生 虚拟化 云栖大会 龙蜥社区 专场

谷歌?新手不推荐 选它就对了

江拥羡橙

前端 工具 浏览器 谷歌 10月月更

你一定要看的:Go slice切片详解和实战

王中阳Go

Go golang 高效工作 学习方法 10月月更

navicat的使用与数据库的DML操作

渔戈

MySQL SQL语句 10月月更

ElasticSearch + Kibana for Kubernetes 硬气功实践 2

CTO技术共享

elasticsearch 个人成长 10月月更

团队实现知识管理,先从知识库做起!

Baklib

效率 效率工具 知识管理 团队 知识

手把手完成智慧路灯的开发,完成设备上云【华为云IoT】

DS小龙哥

10月月更

数据产品经理那点事儿四

松子(李博源)

大数据 深度思考 高效工作 数据产品经理

一起学习 Go 语言设计模式之单例模式

宇宙之一粟

设计模式 单例模式 Go 语言 10月月更

ERP外贸管理系统是什么?哪家好?如何选?

优秀

外贸管理 ERP系统 ERP外贸管理系统

技术使用点-mixins的使用

默默的成长

前端 Vue 3 10月月更

Vue组件入门(十)Attributes 继承

Augus

Vue 3 10月月更

数据分析有 AI 帮你,Sugar BI 智能分析全场景介绍

Baidu AICLOUD

数据分析 可视化 BI

分布式事务-引出分布式事务

zarmnosaj

10月月更

NFT卡牌链游系统开发Web3游戏技术

薇電13242772558

dapp web3

打破汽车零部件企业供应链壁垒,数商云SCM供应链系统实现一体化采购协同

数商云

数字化转型 供应链 企业数字化

vivo 鲁班平台 RocketMQ 消息灰度方案

阿里巴巴云原生

阿里云 云原生 Apache RocketMQ

SAP | Local结构和Global结构

暮春零贰

SAP 结构 10月月更

秒云入选2022年成都市新经济梯度培育企业

MIAOYUN

成都市新经济梯度培育企业

超级app+轻应用带来的改变

Geek_99967b

小程序

你会用Go语言的rune类型吗?

王中阳Go

Go golang 学习方法 数据处理 10月月更

【Java深入学习】一个关于“锁”的程序-上

Geek_65222d

10月月更

著名FinTech公司如何使用k3s+树莓派在生产中构建轻量K8S裸机集群_文化 & 方法_Rancher_InfoQ精选文章