QCon北京「鸿蒙专场」火热来袭!即刻报名,与创新同行~ 了解详情
写点什么

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

评论

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

软件测试丨Git分支管理实操,搞定在线合并和本地合并

测试人

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

iQOO11 国内安卓首发背景音过滤,人声更突显,通话更隐私

极客天地

YMatrix:超融合数据库如何在泵车智能运维场景实现 One for All 价值

YMatrix 超融合数据库

智能运维 三一重工 超融合数据库 智能化运维 YMatrix

空间音频技术与生态发展高峰论坛成功举办,业界首个Audio Vivid创作工具花瓣三维声亮相

HarmonyOS SDK

HMS Core

架构实战营 2-4 架构质量提升随堂练习

西山薄凉

「架构实战营」

华为侯金龙:能源流与信息流融合,共建绿色低碳城市

极客天地

flutter系列之:如丝般顺滑的SliverAppBar

程序那些事

flutter 程序那些事

Databend 索引结构说明

Databend

数据库运维 | 携程分布式图数据库NebulaGraph运维治理实践

NebulaGraph

图数据库 数据库运维

7天搞定一门新技术!5个含金量很高的短篇课程推荐

博文视点Broadview

对于Getaverse,灵魂绑定和去中心化身份是什么?

Geek_Web3

Web3 Daily 去中心化信任 #区块链# did

中台+低代码 企业数字化转型新范式

力软低代码开发平台

时序数据库破局开放探讨

YMatrix 超融合数据库

物联网 时序数据库 超融合数据库 数据库架构选型 YMatrix

Elasticsearch Head插件使用小结

京东科技开发者

elasticsearch 索引 chorme 数据库· 数据查询

用户面对面 | 对话某新能源汽车行业工程师:如何落地Atlassian工具?

龙智—DevSecOps解决方案

最全数据分类分级标准汇编,有必要了解一下!

极盾科技

代码质量与安全 | 如何应对网络安全威胁,保障软件安全?

龙智—DevSecOps解决方案

软件安全 安全软件开发生命周期 网络安全威胁

喜报 | 秒云获评2022(第二届)“金信通”金融科技创新应用优秀案例

MIAOYUN

金融科技 解决方案 信创

《2022年数据库大调查》正式启动,共同助力国产数据库发展

墨天轮

数据库 oracle TiDB 问卷调查 国产数据库

【附视频】在线研讨会回顾|龙智引入自动化测试工具,帮助企业优化DevSecOps工具链,提升QA效率

龙智—DevSecOps解决方案

自动化测试

版本控制 | 如何将UnrealGameSync与Perforce Helix Core结合使用

龙智—DevSecOps解决方案

虚拟引擎 UnrealGameSync

十亿国民新宠:皮皮App线上派对新社交

联营汇聚

校招Java岗学到什么程度,才能找到所谓的好工作呢?

Java永远的神

Java 程序员 面试 程序人生 秋招

通过 NFTScan 实时监控钱包地址和 NFT 合约地址

NFT Research

区块链 数据分析 NFT

基于人眼视觉模型,实现码率、质量、成本的最优均衡

阿里云CloudImagine

云计算 阿里云

时间复杂度和空间复杂度

C++后台开发

数据结构 算法 网络编程 linux开发 C++开发

模型精度再被提升,统一跨任务小样本学习算法 UPT 给出解法!

阿里云大数据AI技术

人工智能 自然语言处理 机器学习 模型 12 月 PK 榜

数字化转型的十大优势

优秀

数字化转型 数字化升级

2.1如何设计可扩展架构

程序员小张

「架构实战营」

Karmada多云多集群生产实践专场圆满落幕|CNDC南京站

科技热闻

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