详解 K8S Helm CI/CD发布流程
注:译文,可能有些文字含义会有偏差
在本文中,您将学习如何创建 Helm chart 并将其发布到公共存储库中。我们将为基于 Spring Boot REST 的应用程序准备一个 Helm Chart 作为练习。目标是拥有一个完全自动化的过程来构建、测试和发布它。为此,我们将在 CircleCI 中定义一个管道。此 CI/CD 管道将在公共Artifact Hub[1]中发布 Helm Chart。
源代码
如果您想自己尝试,可以随时查看本次演示中的源代码。为此,您需要克隆 GitHub 存储库[2]。
创建 Helm Chart
在这部分练习中,我们将使用 helm
CLI。在整个过程中,本地安装的 Helm 不是必需的,但可以帮助您了解接下来的步骤会发生什么。因此,最好安装它。请参考 Helm 官方文档[3]以找到安装方法。
在第一步中,我们将创建一个示例 Chart。它是网络应用程序的典型 Chart。例如,它在容器外部公开 8080 端口,或者允许我们定义检查 HTTP 端点的活动性和就绪性探测。这个 Helm chart 不能太复杂,也不能太简单,因为我们要为它创建自动化测试。
这是我们的Deployment
模板。它将一些标准标签添加到部署清单中。它还设置资源请求和限制,正如我之前提到的,Chart 已经添加了 liveness probe 和 readiness probe。并公开端口 8080 。我们也可以直接设置环境变量或从 ConfigMap
和 Secret
中注入环境变量。
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.app.name }}
labels: # (1)
app: {{ .Values.app.name }}
env: {{ .Values.app.environment }}
owner: {{ .Values.app.owner }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Values.app.name }}
template:
metadata:
labels:
app: {{ .Values.app.name }}
env: {{ .Values.app.environment }}
spec:
containers:
- name: {{ .Values.app.name }}
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
resources: # (2)
{{- toYaml .Values.resources | nindent 12 }}
livenessProbe: # (3)
initialDelaySeconds: {{ .Values.liveness.initialDelaySeconds }}
httpGet:
port: {{ .Values.liveness.port }}
path: {{ .Values.liveness.path }}
failureThreshold: {{ .Values.liveness.failureThreshold }}
successThreshold: {{ .Values.liveness.successThreshold }}
timeoutSeconds: {{ .Values.liveness.timeoutSeconds }}
periodSeconds: {{ .Values.liveness.periodSeconds }}
readinessProbe: # (4)
initialDelaySeconds: {{ .Values.readiness.initialDelaySeconds }}
httpGet:
port: {{ .Values.readiness.port }}
path: {{ .Values.readiness.path }}
failureThreshold: {{ .Values.readiness.failureThreshold }}
successThreshold: {{ .Values.readiness.successThreshold }}
timeoutSeconds: {{ .Values.readiness.timeoutSeconds }}
periodSeconds: {{ .Values.readiness.periodSeconds }}
ports: # (5)
{{- range .Values.ports }}
- containerPort: {{ .value }}
name: {{ .name }}
{{- end }}
{{- if .Values.envs }}
env: # (6)
{{- range .Values.envs }}
- name: {{ .name }}
value: {{ .value }}
{{- end }}
{{- end }}
{{- if or .Values.extraEnvVarsConfigMap .Values.extraEnvVarsSecret }}
envFrom:
{{- if or .Values.extraEnvVarsConfigMap }}
- configMapRef:
name: {{ .Values.extraEnvVarsConfigMap }}
{{- end }}
{{- if or .Values.extraEnvVarsSecret }}
- secretRef:
name: {{ .Values.extraEnvVarsSecret }}
{{- end }}
{{- end }}
securityContext:
runAsNonRoot: true
还有一个Service
对象模板。
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.app.name }}
labels:
app: {{ .Values.app.name }}
env: {{ .Values.app.environment }}
owner: {{ .Values.app.owner }}
spec:
type: {{ .Values.service.type }}
selector:
app: {{ .Values.app.name }}
ports:
{{- range .Values.ports }}
- port: {{ .value }}
name: {{ .name }}
{{- end }}
现在,可以用默认值填充模板。示例存储库中提供了以下values.yaml
文件。
replicaCount: 1
app:
name: sample-spring-boot-api
environment: dev
owner: default
image:
repository: piomin/sample-spring-kotlin-microservice
tag: "1.1"
nameOverride: ""
fullnameOverride: ""
service:
type: ClusterIP
ports:
- name: http
value: 8080
resources:
limits:
cpu: 1000m
memory: 512Mi
requests:
cpu: 100m
memory: 256Mi
liveness:
initialDelaySeconds: 10
port: http
path: /actuator/health/liveness
failureThreshold: 3
successThreshold: 1
timeoutSeconds: 3
periodSeconds: 5
readiness:
initialDelaySeconds: 10
port: http
path: /actuator/health/readiness
failureThreshold: 3
successThreshold: 1
timeoutSeconds: 3
periodSeconds: 5
envs:
- name: INFO
value: Spring Boot REST API
您可以使用helm
CLI 轻松测试新创建的模板。为此,只需在存储库根目录中执行以下命令。将看到从示例模板创建的 YAML 清单。
$ helm template charts/spring-boot-api-app
这样的测试方法是可以的,但是只是在 Chart 开发过程中在本地运行它。假设我们需要创建一个交付管道,我们需要一个更高级的工具。
Helm Chart 的单元测试
在我看来,CI/CD 流水线中最重要的是自动化测试。没有它,我们将发布未经验证的软件,这可能会导致许多并发症。单个 Helm Chart 可以被多个应用程序使用,因此我们应该尽一切努力对其进行详细测试。幸运的是,有一些专门用于 Helm Chart 测试的工具。
我的选择了helm-unittest[4]。它允许我们用纯 YAML 编写单元测试文件。我们可以将其安装为 Helm 插件或在 Docker 容器中运行。在将其推送到 Git 存储库之前,在本地进行验证工作:
$ helm plugin install https://github.com/helm-unittest/helm-unittest
我们应该将单元测试放在 Chart 中的test
目录中。这是 Chart 存储库的结构:
第一步,我们创建单元测试文件。如前所述,我们可以使用 YAML 符号创建测试,这非常直观。我们需要传递值文件的位置和经过测试的 Helm 模板的位置。在测试部分,我们必须定义一个断言列表。重要的是我可以轻松测试每个 YAML 清单的路径。它可以是精确比较或正则表达式。它还支持用于 mappings 和 arrays 的 JsonPath。这是测试用到的deployment_test.yaml
:
suite: test deployment
values:
- ./values/test.yaml # (1)
templates:
- templates/deployment.yaml # (2)
chart:
version: 0.3.4+test
appVersion: 1.0.0
tests:
- it: should pass all kinds of assertion
template: templates/deployment.yaml
documentIndex: 0
asserts: # (3)
- equal:
path: spec.template.spec.containers[?(@.name == "sample-spring-boot-api")].image
value: piomin/sample-spring-kotlin-microservice:1.1
- equal:
path: metadata.labels.app
value: sample-spring-boot-api
- equal:
path: metadata.labels.env
value: dev
- equal:
path: metadata.labels.owner
value: default
- matchRegex:
path: metadata.name
pattern: ^.*-api$
- contains:
path: spec.template.spec.containers[?(@.name == "sample-spring-boot-api")].ports
content:
containerPort: 8080
name: http
- notContains:
path: spec.template.spec.containers[?(@.name == "sample-spring-boot-api")].ports
content:
containerPort: 80
- isNotEmpty:
path: spec.template.spec.containers[?(@.name == "sample-spring-boot-api")].livenessProbe
- isNotEmpty:
path: spec.template.spec.containers[?(@.name == "sample-spring-boot-api")].readinessProbe
- isKind:
of: Deployment
- isAPIVersion:
of: apps/v1
现在,可以通过在项目根目录下执行以下命令来在本地验证测试:
$ helm unittest charts/*
目前,charts
目录中只有一个 Chart。假设我们有很多,它会运行所有 Chart 的测试。这是得到的结果:
如果在测试中改变了一些东西来破坏它。现在,结果将如下所示:
CircleCI 中的 Helm Chart 发布管道
一旦我们创建了 Chart 和测试,我们就可以继续进行交付管道。在 CircleCI 管道中,不仅要执行与之前相同的步骤,还需要包括一个发布部分。
首先,将使用 GitHub Releases 和 GitHub Pages 来发布和托管 Chart。为了简化流程,我们可能会使用一个专门用于发布 Helm Chart 的工具:Chart Releaser[5]。
我们还需要创建一个个人令牌以传递给 Helm Chart Release 工作流程。访问 Settings > Developer Settings > Personal Access Token
。使用repo
范围的权限生成个人令牌。然后,应该将这个标记放入 CircleCI 上下文中。您可以为上下文选择任何名称,但环境变量的名称必须是CR_TOKEN
,Chart Releaser 需要该名称。我的上下文的名称是GitHub
.
以下是需要在管道中执行的步骤列表:
helm
在机器上安装 CLI(我们将使用cimg/base
镜像作为测试执行器)安装 Helm unit-test
插件运行单元测试 只有当我们在 master
分支中进行更改时,才会进行发布部分。第一步,需要用helm package
命令打包 Chart安装 Chart Releaser 使用 Chart Releaser 的 upload
命令在 GitHub 中发布 Chart生成 Chart index.yaml
并将其发布到 GitHub Pages
现在让我们定义的 CircleCI 管道。首先,需要在存储库根目录中创建.circleci
目录并将config.yml
文件放在那里。我们可以使用helm
orb 来简化 helm CLI 安装的过程。一旦我们安装了 helm CLI,我们就可以安装unit-test
插件并运行单元测试。然后我们定义一个过滤master
分支的规则。如果更改被推送到master
分支,我们将 Chart 打包为 TAR 存档并将其放在.deploy
目录中。然后我们安装 Chart Releaser 并创建一个 GitHub release。在最后一步中,我们使用 Chart Releaser 生成 index.yaml 文件并将其提交到gh-pages
分支。
version: 2.1
orbs:
helm: circleci/helm@2.0.1 # (1)
jobs:
build:
docker:
- image: cimg/base:2023.02
steps:
- checkout
- helm/install-helm-client # (2)
- run:
name: Install Helm unit-test
command: helm plugin install https://github.com/helm-unittest/helm-unittest
- run: # (3)
name: Run unit tests
command: helm unittest charts/*
- when:
condition: # (4)
equal: [ master, << pipeline.git.branch >> ]
steps:
- run:
name: Package chart # (5)
command: helm package charts/* -d .deploy
- run:
name: Install chart releaser
command: |
curl -L -o /tmp/cr.tgz https://github.com/helm/chart-releaser/releases/download/v1.5.0/chart-releaser_1.5.0_linux_amd64.tar.gz
tar -xv -C /tmp -f /tmp/cr.tgz
mv /tmp/cr ~/bin/cr
- run:
name: Release chart # (6)
command: cr upload -o piomin -r helm-charts -p .deploy
- run:
name: Create index on GitHub pages # (7)
command: |
git config user.email "job@circleci.com"
git config user.name "CircleCI"
git checkout --orphan gh-pages
cr index -i ./index.yaml -p .deploy -o piomin -r helm-charts
git add index.yaml
git commit -m "New release"
git push --set-upstream --force origin gh-pages
workflows:
helm_test:
jobs:
- build:
context: GitHub
执行 Helm Chart 发布管道
一旦我们将更改推送到helm-charts
存储库,管道就会启动。如您所见,管道成功完成。我们正在发布0.3.5
Chart 版本。
让我们看看 GitHub 发布的列表。如您所见,该0.3.5
版本已经发布。
如何访问 Helm 存储库。为了检查它,请转到存储库Settings > Pages。该存储库的 GitHub 页面地址是 Helm 存储库的地址。在那里发布index.yaml
,内容包含了存储库中 Chart 定义的文件。如您所见,Helm 存储库的地址是piomin.github.io/helm-charts
:
我们可以通过调用https://piomin.github.io/helm-charts/index.yaml
URL 来查看index.yaml
文件的结构。这是当前发布版本的index.yaml
片段。
apiVersion: v1
entries:
spring-boot-api-app:
- apiVersion: v2
appVersion: 1.0.0
created: "2023-02-28T13:06:28.835693321Z"
description: A Helm chart for Kubernetes
digest: b308cbdf9f93f79baf5b39de8a7c509834d7b858f33d79d0c76b528e0cd7ca11
name: spring-boot-api-app
type: application
urls:
- https://github.com/piomin/helm-charts/releases/download/spring-boot-api-app-0.3.5/spring-boot-api-app-0.3.5.tgz
version: 0.3.5
假设我们想要使用 Helm Chart,可以轻松访问它。首先,使用 CLI 添加 Helm 存储库:
$ helm repo add piomin https://piomin.github.io/helm-charts/
然后,可以验证存储库中存在的 Helm Chart 列表:
$ helm search repo piomin
NAME CHART VERSION APP VERSION DESCRIPTION
piomin/spring-boot-api-app 0.3.5 1.0.0 A Helm chart for Kubernetes
将 Helm Chart 发布到 Artifact Hub
为了在 Artifact Hub 上发布您的 Helm 存储库和 Chart,您需要转到该artifacthub 站点[6]并创建一个帐户。完成后,只需单击按钮即可添加新存储库。然后你只需要选择你的 repo 的名称并输入正确的地址。
现在,我们可以在包列表中找到我们的spring-boot-api-app
Chart。
可以看到它的细节。值得在README.md
文件中发布一些说明文字。完成后,您可以在 Artifact Hub 的 Chart 详细信息中查看它。
最后,我们可以轻松地使用 Chart 部署 Spring Boot 应用程序,例如使用 Argo CD。
- END -
基于Kubernetes构建完整的DevOps体系
Jenkins 自动化发布前端项目
Ngnix IP封禁以及实现自动封禁IP
Nginx 可视化配置神器,一键生成!
这篇文章学会 Ansible 足够了!40个 Nginx 常问面试题Linux运维工程师 50个常见面试题一台服务器最大能支持多少条TCP连接?K8S运维必知必会的 Kubectl 命令总结
16 张图硬核讲解 Kubernetes 网络
史上最全 Jenkins Pipeline流水线详解9 个实用 Shell 脚本,建议收藏!主流监控系统 Prometheus 学习指南搭建一套完整的企业级 K8s 集群(二进制方式)
点亮,服务器三年不宕机