目录

GLCC——为ShenYu编写Helm Chart - Proposal

本文是GLCC某活动的一个 Proposal,当时写得比较赶,也比较浅,甚至有不少错误。留个纪念。

一、概述

1.1 项目背景

Apache ShenYu 是一个一个异步的,高性能的,跨语言的,响应式的 API 网关。在云原生时代,网关对于应用服务已经成了不可或缺的存在,是整个微服务的流量入口。

Kubernetes 为容器编排引擎,已经事实上成为了云原生的基础架构,甚至是操作系统。目前,ShenYu 也支持在 K8s 上部署。 k8s 采用了 YAML 声明资源,但正是这些零散配置文件,导致其难以统一管理、配置、更新。Helm 的出现,解决了这一问题,它是 k8s 的包管理工具,类似 apt 之于 linux。

这正是本项目的目的所在,为 ShenYu 编写 helm chart,使用户更加高效地在 K8s 集群中部署 ShenYu。

1.2 任务拆解

我认为,Helm 的核心在于建立了一套 K8s 配置的模板引擎,以及软件更新回滚逻辑。

对于 chart 开发者而言,不需要关注 chart 的内部架构,即如何实现版本控制,如何实现 CLI。开发者应当关注,如何使用 Helm 的模板引擎,灵活、高效地渲染出 K8s 需要的资源声明 YAML 文件。

同时,DevOps 越来越成熟,它可以做一些自动化操作,如编译、测试、发版(release),能有效地提高开发效率,缩短软件迭代周期。这也可以用在 Chart 的开发流程上。

综上,本项目主要可分为两个方面:

  1. 面向用户:开发 helm chart,使用户可以通过 Helm 实现对 ShenYu 的一键部署、版本更新、版本回滚。(当然,还有更新官方文档的 Helm 部署部分)。

  2. 面向社区开发者:使用 DevOps 提高 chart 发布效率。如 CI、release。

我将围绕这两方便展开详述。

二、Helm Chart 开发

如前文所述,对于开发者而言,开发者的开发核心在于通过模板语法定义生成 K8s 需要的资源声明文件,并统一管理。本章也将围绕此展开。

主要分为 chart 开发基本知识、基于现有 ShenYu K8s YAML 开发 chart、chart 开发工具与参考三部分。

2.1 Chart 开发基本知识

chart 的开发流程以及各种概念在 Heml 官网 已有详细介绍,我在此截取重要的部分并用自己的方式阐述,以介绍 chart 开发流程与展示我对 helm 模板开发的掌握度。

Chart 开发流程

  1. 使用 helm create 创建插件
  2. 编写 chart,定义模板
  3. 使用 helm lint 验证 chart 是否存在问题。主要是检查模板语法与渲染问题。
  4. 使用 helm package 打包,生成 tgz 文件。
  5. 使用 helm test ,执行发布版本的测试。可定义钩子,测试验证chart安装时是否按照预期工作。

Chart 目录结构

helm chart 的核心结构如下:

Chart.yaml     # chart 元数据
values.yaml    # chart 的默认值
charts/        # 依赖 charts
templates/     # 模板文件
  - _helpers.tpl    # 可复用的辅助对象
  - xxx.yaml   # 对应 K8s 最后生成的 YAML
  - NOTES.txt  # 帮助信息 

Chart 的模板语法

Helm 的模板语法基于 go template,并支持 Sprig 拓展函数。模板语法细节本段不详细罗列,将在下文结合 ShenYu 实际 K8s YAML 文件阐述。

2.2 基于现有 ShenYu K8s YAML 开发 chart

官网已经给出基于 K8s 部署的 配置文件,有两种部署方式,基于 h2 部署与基于 mysql 部署。

chart 开发的核心任务,可以理解为使用一套 chart 模板,兼容所有的部署方式,并暴露相应的配置到 values.yaml 中。

2.2.1 共性的处理

两种数据库部署方式,有 4 种资源是一致的,分别是:

  • Namespace:命名空间
  • ConfigMap:配置管理
  • shenyu-admin: shenyu 模块,包含 Service 与 Deployment
  • shenyu-bootstrap: shenyu 模块,包含 Service 与 Deployment

无论采取哪种部署方式,这些资源都是几乎一样的。

例如,通过文本比对工具,发现:

  • 两种部署方式的 shenyu-bootstrap 的配置文件完成一致;
  • Namespace 完全一致。
  • shenyu-admin ,也只是 mysql 方式在 specvolumes 部分与 spec.containers.env 的部分比 h2 多了些字段。

所以,可以采用 helm 的 “命名模板” 功能,实现相同文件的重复利用。

定义与使用模板的语法如下:

# 定义
{{ define "MY.NAME" }}
  # body of template here
{{ end }}

# 使用
{{ include "MY.NAME" }}

所有的辅助模板,都将定义在 /templates/_helpers.tpl 中,供 /templates 文件夹下的其他 yaml 文件引用。

当然,除了大段的配置项可以使用模板,对于一些常用的细小的配置项,也可使用模板。

2.2.2 多数据库兼容

1. 原因

虽然大部分配置一致,但不同的数据库部署方式,还是有很多配置项是不一致,甚至所需的资源都不一致。

其中,由于 h2 是纯 Java 的轻量级数据库,可直接嵌入到应用程序中,不需要额外的资源;而 mysql 需要保存mysql-connector.jar 以及指定外部数据库配置,所以需要 pv 存储文件,以及 endpoint 代理。

所以,需要一套兼容多数据库的模板渲染方案。

2. 解决方案

这里用到了 helm 的 “模板函数” 功能。 helm 支持非常多的模板函数,其中一类是 ”流控制",包含了 ifwithrange 等功能。其中 if 不用过多解释,with 用来改变标识的范围,range 可用于 for each 类的循环。

我们可以在 values.yaml 中定义一个新的配置,db_type,默认为 h2。预先定义好所有部署方式需要的资源,利用 if 语法,根据 db_type 字段,只渲染该数据库部署方式需要的资源与配置。

例如,在 mysql 的 Service YAML 定义中,可以这么写:

{{- if eq .Values.db_type "mysql" -}}
kind: Service
apiVersion: v1
metadata:
  name: mysql
  namespace: shenyu
spec:
  ports:
  - port: 3306
    name: mysql
    targetPort: {{.Values.mysql.port}}
{{- end -}}

其中:

  • {{}} 表示模板语法,heml 将会解析被 {{}} 包围的内容。
  • .Values.db_type 即为读取 values.yaml 中的 db_type 配置字段。
  • if eq .Values.db_type "mysql"if 语法,eq 为 “equal”, 即判断 db_type 是否为 “mysql”。
  • - 为去除模板文件周围的空白符。
  • 最终效果:若 db_type 为 “mysql",此文件渲染;否则,此配置文件是"空"。(空配置文件 helm 不会报错)

ShenYu 的 ConfigMap 文件,对于不同的数据库部署方式也不相同。主要区别在于,h2 部署方式,data 只含 application-local.yml,而 mysql 部署方式,同时含有 application-local.ymlapplication-mysql.yml。也可以使用相似的方式实现对 ConfigMap 的多数据库部署方式的差异化渲染。

值得一提的是,虽然目前只以 h2 与 mysql 两种数据库举例子。若后续支持 postgresql 与 oracle 的 helm 部署,此方法也是可行的。

2.2.3 配置项的暴露

如何暴露

将默认配置写入到 values.yaml 中,在模板中以 .Values.key 的格式引用即可。

用户部署的时候,可以用 --set 以命令行的覆盖指定配置项的值,也可以使用 --values 直接提供 YAML 文件批量覆盖默认配置值。

暴露哪些配置

目前,ShenYu 官网给出的 K8s 配置文件中,需要用户更改的值,已由 {your_mysql_port} 的格式进行提醒。

所以本项目会将 {xxx} 格式的配置项移到 values.yaml 中,设定默认配置值。对于某些必须要设定的配置项,使用 helm 的 require 语法强制用户设置。后期可与社区详细讨论,确定配置项的细节。

注(补充于项目完成后):现在看来,这里写的所谓的难点和实现方式,其实只是"开始"阶段的一些问题。后面的实际开发过程中还遇到了很多其他的地方需要处理,比如自动下载数据库驱动等。但是,对于大部分开源活动而言,也不可能预料到所有的难点,所以要对自己有信心,认真写认真分析,就总有机会。

2.3 chart 开发工具与参考

helm 的官方使用 Artifact Hub 托管 chart 仓库,里面有一些好用的 chart library 以及优秀的 chart application 作为参考。例如:

  1. common 1.16.0 · bitnami/bitnami 里面定义了一些常用的辅助模板,可以复用。
  2. mysql 9.1.8 · bitnami/bitnami mysql chart,可参考。
  3. wordpress 15.0.4 · bitnami/bitnami wordpress chart, 可参考。

三、Chart 发布: CI 与 Release

3.1 Chart 的发布流程

chart 编写完成后,需要发布到 chart 仓库来供用户拉取使用。主要的流程有,package, lint, test, release。

3.2 CI 介绍

持续集成(Continuous Integration)指的是,频繁地(一天多次)将代码集成到主干。 持续集成的目的,就是让产品可以快速迭代,同时还能保持高质量。持续集成是指软件发布流程的构建和单元测试阶段,提交的每一个修订都会触发自动化的构建和测试操作。这也意味着,我们可以利用持续集成,在 chart 代码被修改时,自动打包 chart,并运行相应的测试,如 lint、test,再进行 index等操作。

项目将采用 GitHub Actions(GitHub 工作流)作为 CI 工具,原因如下:

  • GitHub Actions 免费
  • ShenYu 目前的项目托管在 GitHub
  • GitHub 托管的 chart 仓库能够被 Artifact Hub 直接获取。
  • GitHub Actions 已有非常成熟的与 helm 相关的 actions 工具
  • 我有 GitHub Actions 的实际使用经验,相对熟悉

GitHub Actions 的流程可抽象为以下三个操作:

  1. 触发规则。例如检测到 pull request、代码推送至特定分支上。
  2. 运行环境建立。一般是建立一个 ubuntu 运行环境。
  3. 执行 jobs。在 GitHub 提供的临时 ubuntu 内,执行一系列 Jobs。如安装 helm,执行 lint、运行测试函数等。

3.2 CI 流程

图1 CI 流程与工具

如上图,当 chart 代码发生更改时,用户提交 PR,触发 trigger。将会执行以下 jobs:

  1. 在 Ubuntu 下运行所有程序
  2. 使用 Kind Cluster GitHub Action 搭建以 kind 为基础的 K8s 测试环境。
  3. 使用 Helm tool installer 安装 helm
  4. 使用 Helm Chart Testing 安装 chart-tesing,并执行 lint、test、install 等操作。

注(补充于项目完成后):其实这里不是叫 “CI”,应该是 CI-test

3.3 Release

发布使用的是 Helm Chart Releaser,它是一个将GitHub项目转换成自托管Helm chart仓库的GitHub操作流。

为了在一个仓库内实现 chart 开发与 chart 发布,我们至少需要两个分支。一个分支名为 gh-pages,用于发布 chart;另一个分支用于存放 chart 代码。

与 CI 流程类似,每次需要 release 时,我们可以建立一个新的 Release x.x.x 分支,并将其合入到 main 分支。这将触发一系列的 chart 编译、检查、测试。

一切通过后,该工作流将会生成与 chart 版本对应的 tgz 文件,并同时发布在两个地方:

  1. gh-pages 分支,供 Artifact Hub 拉取。同时将创建或更新包含元数据的 index.yaml 文件。
  2. GitHub Release。

图2 release 流程

注(补充于项目完成后):最后实际采用的方式不是建立新分支,而是每次改动的时候都更新版本号,并 Release,以保证 Chart 的不可变性。(参考了 Prometheus Helm Chart 的设计)

四、能为社区做的贡献

  1. 对用户:使用 Helm 在 K8s 上一键部署 ShenYu,减轻 K8s 维护复杂度,使安装、升级、回滚更容易。
  2. 对开发者:CI 提高 chart 开发效率,自动测试保证了交付质量,自动 Release 保证了交付效率。
  3. 对社区:我主力语言为 Go,而 helm chart 的模板语法基于 go template,由熟悉 Go 的我来编写与维护 chart 更适合。(当然我也会 Java,毕业设计的后端部分使用的 Java)

五、时间规划

时间规划
7.1-7.15与导师进行深入讨论,沟通项目详细需求与设计细节
7.16.7.31参考优秀的 chart 案例,编写 chart 模板
8.1-8.15研究 heml chart 相关 GitHub Actions 的具体使用
8.16-8.31完成 CI 与 Release 的编写
9.1-9.15项目测试与改进
9.16-9.30补全官网文档、撰写 Chart 文档,提交代码

六、 个人简介

杭州电子科技大学,研一学生,计算机学院,发展方向为云原生。

近一年主要项目经历:

DevStream 社区

今年5月初刚接触开源,加入 DevStream 社区(开源DevOps工具链管理器),现在是社区 Member。近日,DevStream 成功加入 CNCF 沙箱。

目前为社区开发了一个核心插件,gitlab-ce-docker。可在配置文件内指定端口等信息,在装有 Docker 的机器上一键安装 gitlab-ce。当配置文件改变时,或容器的状态发生变化时,再次执行命令,插件将会把 gitlab 更新成期望的状态。

由我完成了 0.7.0 的发版工作;平时会 review 一些 pr;提出一些 good fisrt issue 并引导社区贡献者。

我也是一名开源新人,才参与开源两个月左右的时间。DevStream 相对 ShenYu 要稚嫩很多。

虽然我的主力语言是 Go,可能无法对 ShenYu 的主项目贡献太多代码。但正因为如此,我熟悉 go template,以及我的主研方向是 DevOps,或许能为 ShenYu 的自动化做一些贡献。

杭电助手社团

杭电助手社团是一个技术性的学生服务社团。

  • 承接了学校的疫情防控系统,已迭代两年多,学校所有学生出入校门都需经过该系统请假。包含健康打卡、请假审批、校门闸机联动、核酸获取等模块。
  • 教务类服务内容:如查课表、查成绩、空教室查询等等。
  • 报到:杭州电子科技大学目前的报到系统是杭电助手开发并维护的。

我是第9届的后端理事,第10届主席团技术顾问。

目前主力维护疫情防控系统,并参与报到系统、公众号等内容的 feature 开发与维护。

七、参考文献

  1. https://shenyu.apache.org/zh/docs/index
  2. https://helm.sh/zh/docs/
  3. https://cloud.aiops.red
  4. https://github.com/jenkinsci/helm-charts
  5. https://github.com/helm/chart-testing
  6. https://github.com/quintush/helm-unittest
  7. https://artifacthub.io/packages/helm/bitnami/mysql
  8. https://artifacthub.io/packages/helm/bitnami/wordpress
  9. http://masterminds.github.io/sprig/
  10. https://aws.amazon.com/cn/devops/continuous-integration/