写点什么

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

评论

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

玖章算术CEO叶正盛在数据技术嘉年华分享NineData AIGC的应用实践

NineData

数据库 数据管理 AIGC 玖章算术 NineData

带你揭开神秘的Javascript AST面纱之Babel AST 四件套的使用方法

京东科技开发者

JavaScript AST 京东云 企业号 4 月 PK 榜

一文弄懂访问者模式

小小怪下士

Java 程序员 设计模式

上线半天下载量破100W!美团大佬的Java性能调优实战手册,超详细

Java你猿哥

Java 数据库 JVM java编程 Java性能优化

面试官:说说MySQL主从复制原理

Java永远的神

MySQL 数据库 程序员 面试 主从复制

GitHub程序调优「黑马」!阿里大牛的Java性能优化实战笔记已上线

Java 面试 性能优化 性能调优

对标大厂的技术派方案设计,带你了解一个项目从0到1实现的全过程

Java你猿哥

Java 架构 ssm 项目设计

iOS16新特性 | 灵动岛适配开发与到家业务场景结合的探索实践

京东科技开发者

ios 京东云 灵动岛 企业号 4 月 PK 榜

解决事务隔离产生问题的MVCC

园林绿化设计工具:GardenPlanner Mac版

真大的脸盆

Mac Mac 软件 Mac 系统 园林设计工具 绿化设计

物流路由线路配载前端算法逻辑实现方案

京东科技开发者

前端 京东云 京东物流 企业号 4 月 PK 榜

解决事务隔离产生问题的MVCC

Java你猿哥

Java ssm 架构师 MVCC

MyBatis整合Springboot多数据源实现

Java Spring Boot mybatis

一文读懂 Nautilus Chain 上首个 DEX PoseiSwap 的通证经济

西柚子

从内核源码看 slab 内存池的创建初始化流程

bin的技术小屋

操作系统 内存管理 Linux Kenel 内核 动态内存池

春风送暖,好久不见

BinTools图尔兹

版本发布

Flink CDC 在京东的探索与实践

Apache Flink

大数据 flink 实时计算

MyBatis整合Springboot多数据源实现

Java你猿哥

spring Spring Boot mybatis ssm 数据源

有限资源下如何实现最高效的数据处理?四个“智慧城市”项目寻找“最优解”

TDengine

tdengine 物联网 时序数据库 智慧城市 数据优化

对标大厂的技术派方案设计,带你了解一个项目从0到1实现的全过程

Java全栈架构师

数据库 微服务 程序人生 后端 架构师

历史性的时刻!OpenTiny 跨端、跨框架组件库正式升级 TypeScript,10 万行代码重获新生!

华为云开源

typescript Vue 组件库

软件测试/测试开发丨ChatGPT训练营来,手把手带你玩转ChatGPT

测试人

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

Spring全家桶思维笔记导图(Spring Boot+Cloud+IOC+AOP+MVC等)

Java你猿哥

spring Spring Cloud Spring Boot aop ioc

GPTCache:LLM 应用必备的【省省省】利器

Zilliz

Milvus Zilliz ChatGPT LLM 语义检索

自阿里P8爆出内部1031道java面试题后,在Boss直聘狂拿千份Offer

Java java面试 Java八股文 Java面试题 Java面试八股文

得帆云DeFusion融合集成iPaaS平台领先行业,打造先锋集成产品

得帆信息

打破信息孤岛 数据集成 集成平台 数据集成平台 ipaas

小程序SDK集成到App有哪些好处?

没有用户名丶

devops工具链基建建设评价标准

laofo

DevOps cicd 研发效能 持续交付 工程效率

前端代码安全与混淆

京东科技开发者

安全 京东云 企业号 4 月 PK 榜

Seal AppManager发布:基于平台工程理念的全新应用部署管理体验

SEAL安全

应用部署 企业号 4 月 PK 榜 Seal软件 SealAppManager

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