速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

著名 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:01984

评论

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

5分钟搞懂Jenkins分布式架构

俞凡

架构 DevOps cicd 最佳实践

版本控制 | SVN,Git与Helix Core,谁的数据管理基础设施更安全?

龙智—DevSecOps解决方案

git svn 版本控制 版本控制系统

华为云桌面解决方案,打造安全高效办公新体验

科技怪授

云桌面

当云原生网关遇上图数据库,NebulaGraph 的 APISIX 最佳实践

NebulaGraph

图数据库 API网关

华为云桌面,助力企业数字化转型

爱尚科技

Docker daemon configuration overview(Docker 守护进程配置概览)

独钓寒江

内网穿透你真的了解吗?

C++后台开发

网络安全 NAT Linux服务器开发 内网 网络穿透

多年缓慢成长,近3年野蛮狂飙,谁是这个赛道的王者?

ToB行业头条

天翼云斩获2022全球分布式云大会两项大奖

天翼云开发者社区

研讨会回顾 | 自动化测试“领导者”SmartBear解析软件质量与测试现状调研

龙智—DevSecOps解决方案

软件测试 自动化测试 测试自动化

基于Seata探寻分布式事务的实现方案

京东科技开发者

大数据 分布式事务 微服务架构 关系型数据库 seata

使用无代码构建客户门户

间隔

【经验】硬件工程师与PCB槽孔斗智斗勇的故事

华秋PCB

工具 PCB PCB设计 槽孔

小程序游戏的3大分发平台

FinFish

小程序 小游戏 小游戏运营

【从零开始学爬虫】采集全国高校导师数据

前嗅大数据

数据采集 爬虫教程 爬虫入门

代码质量与安全 | 如何将清洁代码标准扩展到整个企业,促进业务上的成功?

龙智—DevSecOps解决方案

代码质量 代码安全

案例丨多元业态管理服务厂商如何走通数字化转型之路

优秀

数字化转型 数字化管理

MySQL分库分表,可能真的要退出历史舞台了!

Java永远的神

MySQL 程序员 后端 架构师 分布分表

架构实战营第 10 期 - 模块三作业:外包学生管理系统详细架构设计文档

kaizen

「架构实战营」

【观察】融云百幄:为政企数智办公按下“快进键”

融云 RongCloud

融云 数智化 政企 百幄

融云任杰:激活组织生命力 让听见炮火的人做决策 | TGO专访

融云 RongCloud

专访 程序员‘

32篇年度最佳AI论文;Python编译器Codon开源;ChatGPT的前世今生

OneFlow

人工智能 深度学习 大模型

AI 训练加速原理解析与工程实践分享

百度Geek说

人工智能 机器学习 12 月 PK 榜

语音生成领域模型又填一名猛将

felix

深度学习 语音合成 TTS

软件测试面试真题 | 什么是 Redis ? Redis缓存应用场景有哪些?

测试人

redis 软件测试 自动化测试 测试开发

模块四课后作业 - 设计千万级学生管理系统的考试试卷存储方案

闲人Eric

架构实战营

小游戏开发投放平台及分成政策盘点

Onegun

小游戏 小游戏开发

SpringMVC还是Spring WebFlux?谁是下一代的Java程序员技术栈?

程序员小毕

Java spring 程序员 后端 springmvc

外包学生管理系统架构文档

白杨

华为云桌面,让企业随时随地开启云上办公

爱尚科技

PHP转Go之后,我又开始研究机器学习和自动驾驶了。

王中阳Go

自动驾驶 Apollo

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