内容简介
本实验手册系列包含七个主题,涵盖了从应用容器化到 GitOps 工作流的实现与高级特性。通过这些实验手册,您将学习到如何构建、部署和管理应用,以及如何在 Kubernetes 集群上实现高效的持续交付流程。
以下是实验手册的七个章节:
- 应用程序容器化实验手册:学习如何将应用程序容器化,并为主流编程语言构建镜像。同时,了解如何缩减镜像体积和使用 GitHub Actions 自动构建镜像。
- 单节点 Kubernetes 集群部署实验手册:使用 kind 在本地部署单节点 Kubernetes 集群,安装基础服务,并熟悉 Kubernetes 的基本功能,如运行 Pod、调度工作负载、服务发布和自动扩缩容。
- 示例应用的部署和解析实验手册:深入了解示例应用的各个组件,学习如何在 Kubernetes 集群上部署、运行和管理这些组件,实现服务调用、应用配置和扩缩容等功能。
- 使用 Helm 定义应用实验手册:通过 Helm 对示例应用进行定义,以满足 GitOps 部署的需求。了解 Helm Chart 的创建和使用,以及预发布和生产环境的部署。
- 构建 GitOps 工作流实验手册:在 Kubernetes 集群上安装 ArgoCD,并使用 ArgoCD 定义示例应用进行部署,实现基于镜像版本变化触发的 GitOps 工作流。
- 实现 GitOps 高级发布策略实验手册:结合 ArgoCD 的高级特性,如 Argo Rollout、AnalysisTemplate 和 Argo Rollout Dashboard,实现蓝绿发布、金丝雀发布和自动渐进交付。
- ArgoCD 高级管理特性实验手册:探讨 ArgoCD 在 GitOps 场景中的高级特性,包括使用 ApplicationSet 实现多环境部署和使用 SealedSecret 保护密钥。
通过这七个实验手册,您将全面掌握应用容器化、Kubernetes 和 GitOps 的相关知识,为应用的持续交付提供可靠和高效的解决方案。
在之前的实验场景基础上,本实验手册将指导您使用 Helm 定义后续 GitOps 环境中所需的示例应用,以满足 GitOps 部署的要求。
本实验手册将涵盖以下主要实验环节:
- 改造示例应用:创建 Helm Chart 目录结构,编写
chart.yaml
文件,填充templates
目录。 - 部署 Helm Chart:分别在预发布环境和生产环境中进行部署。
- 发布 Helm Chart:将 Helm Chart 推送至 GitHub 仓库。
- 常见的 Helm 应用管理操作:了解 Helm 的基本命令和操作,以便更有效地进行应用管理
改造示例应用
创建 Helm Chart 目录结构
cd kubernetes-example && mkdir helm
mkdir helm/templates && touch helm/Chart.yaml && touch helm/values.yaml
$ ls helm
Chart.yaml templates values.yaml
配置 Chart.yaml 内容
将下面的内容复制到 Chart.yaml 文件内。
apiVersion: v2
name: kubernetes-example
description: A Helm chart for Kubernetes
type: application
version: 0.1.0
appVersion: "0.1.0"
<apiVersion>
字段设置为v2
,表示使用 Helm 3 来安装应用。<name>
表示 Helm Chart 的名称,当使用helm install
命令安装 Helm Chart 时,指定的名称也是此处配置的名称。<description>
表示 Helm Chart 的描述信息,可根据需要填写。<type>
表示类型,此处固定为application
,代表 Kubernetes 应用。<version>
表示打包的 Helm Chart 的版本,当使用helm install
时,可以指定此处定义的版本号。Helm Chart 的版本通过这个字段来管理,发布新的 Chart 时,需要更新此版本号。<appVersion>
与 Helm Chart 无关,用于定义应用的版本号,建立当前 Helm Chart 和应用版本的关系。
填充 helm/templates
helm/templates
目录用于存放模板文件,这些模板文件可以是 Kubernetes Manifest。因此,现在可以尝试不使用 Helm Chart 的模板功能,而是直接将 deploy
目录下的 Kubernetes Manifest 复制到 helm/templates
目录下。
cp -r deploy/ helm/templates/
helm
├── Chart.yaml
├── templates
│ └── deploy
│ ├── backend.yaml
│ ├── database.yaml
│ ├── frontend.yaml
│ ├── hpa.yaml
│ └── ingress.yaml
└── values.yaml
其中,values.yaml 的文件内容为空。
到这里,一个最简单的 Helm Chart 就编写完成了。在这个 Helm Chart 中,templates 目录下的 Manifest 的内容是确定的,安装这个 Helm Chart 等同于使用 kubectl apply 命令,接下来尝试使用 helm install 命令来安装这个 Helm Chart。
helm install my-kubernetes-example ./helm --namespace example --create-namespace
在此命令中,指定应用的名称为 my-kubernetes-example
,Helm Chart 目录为 ./helm
目录,并为应用指定命名空间为 example
。需要注意的是,example
命名空间并不存在,因此同时使用 --create-namespace
选项来让 Helm 自动创建这个命名空间。
此外,这里还涉及一个非常重要的概念:Release Name。在安装时,需要指定 Release Name,即 my-kubernetes-example
,它与 Helm Chart Name 存在本质区别。Release Name 是在安装时指定的,而 Helm Chart Name 在定义阶段就已经固定。
使用模板变量
然而,刚才改造的最简单的 Helm Chart 无法满足多环境配置差异化的需求。到目前为止,它只是一个纯静态应用。
为了将这个静态的 Helm Chart 改造成参数动态可控制的,需要使用模板变量和 values.yaml
。
还记得之前提到的 values.yaml
的概念吗?模板变量的值都会引自这个文件。在这个例子中,根据对不同环境配置差异化的要求,抽象了以下可配置项:
- 镜像版本
- HPA CPU 平均使用率
- 是否启用集群内
- 数据库连接地址、账号和密码
这些可配置项都需要从 values.yaml
文件中读取,因此,需要将以下内容复制到 helm/values.yaml
文件内。
frontend:
image: chengzh/frontend
tag: latest
autoscaling:
averageUtilization: 90
backend:
image: chengzh/backend
tag: latest
autoscaling:
averageUtilization: 90
database:
enabled: true
uri: pg-service
username: postgres
password: postgres
除了 values.yaml
,还需要让 helm/templates
目录下的文件能够读取 values.yaml
的内容,这就需要使用模板变量。
以一个简单的例子来说明,要读取 values.yaml
中的 frontend.image
字段,可以通过 {{ .Values.frontend.image }}
模板变量来获取值。
因此,为了将这个“静态”的 Helm Chart 改造成“动态”的,只需用模板变量替换 templates
目录下需要实现“动态”的字段。
了解原理后,接下来修改 helm/templates/backend.yaml
文件,用模板替换需要从 values.yaml
读取的字段
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
......
spec:
......
spec:
containers:
- name: flask-backend
image: "{{ .Values.backend.image }}:{{ .Values.backend.tag }}"
env:
- name: DATABASE_URI
value: "{{ .Values.database.uri }}"
- name: DATABASE_USERNAME
value: "{{ .Values.database.username }}"
- name: DATABASE_PASSWORD
value: "{{ .Values.database.password }}"
同理,修改 helm/templates/frontend.yaml
文件的 image 字段。
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
......
spec:
......
spec:
containers:
- name: react-frontend
image: "{{ .Values.frontend.image }}:{{ .Values.frontend.tag }}"
此外,还需要修改 helm/templates/hpa.yaml
文件的 averageUtilization 字段。
......
metadata:
name: frontend
spec:
......
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.frontend.autoscaling.averageUtilization }}
---
......
metadata:
name: backend
spec:
......
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.backend.autoscaling.averageUtilization }}
需要注意的是,与其他模板变量不同,在这里没有在模板变量的外部使用双引号。这是因为 averageUtilization
字段是一个整数(integer)类型,而双引号加上模板变量表示字符串(string)类型。
最后,希望使用 values.yaml
中的 database.enable
字段来控制是否向集群提交 helm/templates/database.yaml
文件。因此,在文件的首行和最后一行可以添加以下内容:
{{- if .Values.database.enabled -}}
......
{{- end }}
到这里,就成功地将“静态”的 Helm Chart 改造为了“动态”的 Helm Chart。
部署 Helm Chart
在将示例应用改造成 Helm Chart 之后,就可以使用 helm install 进行安装了。这里我会将 Helm Chart 分别安装到 helm-staging 和 helm-prod 命名空间,它们对应预发布环境和生产环境,接着我会介绍如何为不同的环境传递不同的参数。
部署预发布环境
为 Helm Chart 创建的 values.yaml 实际上是默认值,在预发布环境,希望将前后端的 HPA CPU averageUtilization 从默认的 90 调整为 60,可以在安装时使用 --set 来调整特定的字段,不需要修改 values.yaml 文件。
helm install my-kubernetes-example ./helm --namespace helm-staging --create-namespace --set frontend.autoscaling.averageUtilization=60 --set backend.autoscaling.averageUtilization=60
controlplane $ helm install my-kubernetes-example ./helm --namespace helm-staging --create-namespace --set frontend.autoscaling.averageUtilization=60 --set backend.autoscaling.averageUtilization=60
NAME: my-kubernetes-example
LAST DEPLOYED: Thu Feb 23 03:00:51 2023
NAMESPACE: helm-staging
STATUS: deployed
REVISION: 1
TEST SUITE: None
小插曲,可能会遇到如下错误
Error: unable to build kubernetes objects from release manifest: unable to recognize "": no matches for kind "HorizontalPodAutoscaler" in version "autoscaling/v2beta2"
解决方案,查询一下当前版本的 k8s 支持的 api 版本,对 hap.yaml 进行必要的调整
kubectl api-versions | grep autoscaling
autoscaling/v1
autoscaling/v2
在这个安装例子中,使用 --set 参数来调整 frontend.autoscaling.averageUtilization 字段值,其它的字段值仍然采用 values.yaml 提供的默认值。
部署完成后,可以查看为预发布环境配置的后端服务 HPA averageUtilization 字段值。
kubectl get hpa backend -n helm-staging --output jsonpath='{.spec.metrics[0].resource.target.averageUtilization}'
controlplane $ kubectl get hpa backend -n helm-staging --output jsonpath='{.spec.metrics[0].resource.target.averageUtilization}'
60controlplane $
返回值为 60,和配置的安装参数一致。
同时,也可以查看是否部署了数据库,也就是 postgres 工作负载。
kubectl get deployment postgres -n helm-staging
controlplane $ kubectl get deployment postgres -n helm-staging
NAME READY UP-TO-DATE AVAILABLE AGE
postgres 1/1 1 1 4m32s
postgres 工作负载存在,符合预期。
最后,可以查看 backend Deployment 的 Env 环境变量,以便检查是否使用集群内的数据库实例
kubectl get deployment backend -n helm-staging --output jsonpath='{.spec.template.spec.containers[0].env[*]}'
controlplane $ kubectl get deployment backend -n helm-staging --output jsonpath='{.spec.template.spec.containers[0].env[*]}'
{"name":"DATABASE_URI","value":"pg-service"} {"name":"DATABASE_USERNAME","value":"postgres"} {"name":"DATABASE_PASSWORD","value":"postgres"}controlplane $
部署生产环境
部署到生产环境的例子相对来说配置项会更多,除了需要修改 database.enable 字段,禁用集群内数据库实例以外,还需要修改数据库连接的三个环境变量。所以,使用另一种安装参数传递方式:使用文件传递。要使用文件来传递安装参数,
首先需要准备这个文件。需要将下面的内容保存为 helm/values-prod.yaml 文件。
frontend:
autoscaling:
averageUtilization: 50
backend:
autoscaling:
averageUtilization: 50
database:
enabled: false
uri: 10.10.10.10
username: external_postgres
password: external_postgres
接下来,使用 helm install 命令来安装它,同时指定新的 values-prod.yaml 文件作为安装参数。
helm install my-kubernetes-example ./helm -f ./helm/values-prod.yaml --namespace helm-prod --create-namespace
部署完成后,可以查看为生产环境配置的后端服务 HPA averageUtilization 字段值。
kubectl get hpa backend -n helm-prod --output jsonpath='{.spec.metrics[0].resource.target.averageUtilization}'
controlplane $ kubectl get hpa backend -n helm-prod --output jsonpath='{.spec.metrics[0].resource.target.averageUtilization}'
50controlplane $
返回值为 50,和在 values-prod.yaml 文件中定义的安装参数一致。
同时,也可以查看是否部署了数据库,也就是 postgres 工作负载。
kubectl get deployment postgres -n helm-prod
controlplane $ kubectl get deployment postgres -n helm-prod
Error from server (NotFound): deployments.apps "postgres" not found
可以发现,postgres 工作负载并不存在,符合预期。最后,可以查看 backend Deployment 的 Env 环境变量,检查是否使用了外部数据库。
kubectl get deployment backend -n helm-prod --output jsonpath='{.spec.template.spec.containers[0].env[*]}'
controlplane $ kubectl get deployment backend -n helm-prod --output jsonpath='{.spec.template.spec.containers[0].env[*]}'
{"name":"DATABASE_URI","value":"10.10.10.10"} {"name":"DATABASE_USERNAME","value":"external_postgres"} {"name":"DATABASE_PASSWORD","value":"external_postgres"}
返回结果同样符合预期。到这里,将实例应用改造成 Helm Chart 的工作已经全部完成了。
发布 Helm Chart
在 Helm Chart 编写完成之后,便能够在本地安装它了。不过,通常还会有和其他人分享 Helm Chart 的需求。
为实现这个需求,需要将在上面创建的 Helm Chart 打包并且上传到 Helm 仓库中即可。这里以 GitHub Package 为例,介绍如何将 Helm Chart 上传到镜像仓库。
创建 GitHub Token
为了创建一个GitHub Token,用于发布Helm Chart,您需要执行以下步骤:
- 登录到您的GitHub帐户。
- 点击右上角的头像,然后从下拉菜单中选择
Settings
(设置)。 - 在左侧的导航菜单中,点击
Developer settings
(开发者设置)。 - 点击
Personal access tokens
(个人访问令牌)选项卡。 - 点击页面右上角的
Generate new token
(生成新令牌)按钮。 - 输入一个描述性的令牌名称,例如“Helm Chart Publishing”。
- 选择要授予此访问令牌的权限范围。对于Helm Chart发布,通常需要以下权限:
repo
(仓库):允许对私有仓库和公共仓库的完全访问。write:packages
:允许将容器镜像发布到GitHub Packages。delete:packages
:允许删除GitHub Packages中的容器镜像(可选,取决于您是否需要删除功能)。
根据您的需求选择其他权限。
- 点击页面底部的
Generate token
(生成令牌)按钮。 - 成功创建令牌后,页面顶部会显示一个绿色的通知,其中包含新生成的访问令牌。请务必立即复制此令牌,因为您以后将无法再次查看它。如果您不小心关闭了页面,您需要生成一个新的访问令牌。
现在您已经创建了一个GitHub个人访问令牌,可以在API调用、命令行工具或GitHub Actions工作流程中使用它进行身份验证。为了安全起见,请不要在公共场所共享您的个人访问令牌。
(可选)接下来,您可以在GitHub仓库中创建一个Secret,用于存储您刚刚创建的访问令牌。这样,在GitHub Actions工作流程中,您可以通过${{ secrets.YOUR_SECRET_NAME }}
引用这个Secret。
推送 Helm Chart
在推送之前,还需要使用 GitHub ID 和刚才创建的 Token 登录到 GitHub Package。
helm registry login -u cloudzun https://ghcr.io
~/kubernetes-example$ helm registry login -u cloudzun https://ghcr.io
Password:
Login Succeeded
请注意,由于 GitHub Package 使用的是 OCI 标准的存储格式,如果使用的 helm 版本小于 3.8.0,则需要在运行这条命令之前增加 HELM_EXPERIMENTAL_OCI=1 的环境变量启用实验性功能。然后,返回到示例应用的根目录下,执行 helm package 命令来打包 Helm Chart。
然后,返回到示例应用的根目录下,执行 helm package 命令来打包 Helm Chart。
helm package ./helm
这条命令会将 helm 目录打包,并生成 kubernetes-example-0.1.0.tgz 文件。接下来,就可以使用 helm push 命令推送到 GitHub Package 了。
helm push kubernetes-example-0.1.0.tgz oci://ghcr.io/cloudzun/helm
命令运行结束后将展示 Digest 字段,就说明 Helm Chart 推送成功了。
helm package ./helm
Successfully packaged chart and saved it to: /home/chengzh/kubernetes-example/kubernetes-example-0.1.0.tgz
helm push kubernetes-example-0.1.0.tgz oci://ghcr.io/cloudzun/helm
Pushed: ghcr.io/cloudzun/helm/kubernetes-example:0.1.0
Digest: sha256:2f3d04c9f2fda3e948dd31a96ba60b9bd2a939f16708ef5fb964f5d81314281f
安装远端仓库的 Helm Chart
当成功把 Helm Chart 推送到 GitHub Package 之后,就可以直接使用远端仓库来安装 Helm Chart 了。和一般的安装步骤不同的是,由于 GitHub Package 仓库使用的是 OCI 标准的存储方式,所以无需执行 helm repo add 命令添加仓库,可以直接使用 helm install 命令来安装。
helm install my-kubernetes-example oci://ghcr.io/cloudzun/helm/kubernetes-example --version 0.1.0 --namespace remote-helm-staging --create-namespace --set frontend.autoscaling.averageUtilization=60 --set backend.autoscaling.averageUtilization=60
在上面的安装命令中,oci://ghcr.io/cloudzun/helm/kubernetes-example 是 Helm Chart 的完整的地址,并标识了 OCI 关键字。另外,version 字段指定的是 Helm Chart 的版本号。在安装时,同样可以使用 --set 或者指定 -f 参数来覆写 values.yaml 的字段。
helm install my-kubernetes-example oci://ghcr.io/cloudzun/helm/kubernetes-example --version 0.1.0 --namespace remote-helm-staging --create-namespace --set frontend.autoscaling.averageUtilization=60 --set backend.autoscaling.averageUtilization=60
Pulled: ghcr.io/cloudzun/helm/kubernetes-example:0.1.0
Digest: sha256:2f3d04c9f2fda3e948dd31a96ba60b9bd2a939f16708ef5fb964f5d81314281f
NAME: my-kubernetes-example
LAST DEPLOYED: Thu Feb 23 11:39:04 2023
NAMESPACE: remote-helm-staging
STATUS: deployed
REVISION: 1
TEST SUITE: None
Helm 应用管理
总结来说,Helm Chart 和 Manifest 之间一个最大的区别是,Helm 从应用的角度出发,提供了应用的管理功能,通常在实际使用 Helm 过程中会经常遇到下面几种场景。
调试 Helm Chart
在编写 Helm Chart 的过程中,为了方便验证,会经常渲染完整的 Helm 模板而又不安装它,这时候就可以使用 helm template 命令来调试 Helm Chart。
helm template ./helm -f ./helm/values-prod.yaml
此外,还可以在运行 helm install 命令时增加 --dry-run 参数来实现同样的效果。
helm install my-kubernetes-example oci://ghcr.io/cloudzun/helm/kubernetes-example --version 0.1.0 --dry-run
查看已安装的 Helm Release
要查看已安装的 Helm Release,可以使用 helm list 命令。
helm list -A
更新 Helm Release
要更新 Helm Release,可以使用 helm upgrade 命令,Helm 会自动对比新老版本之间的 Manifest 差异,并执行升级。
helm upgrade my-kubernetes-example ./helm -n example
查看 Helm Release 历史版本
要查看 Helm Release 的历史版本,可以使用 helm history 命令。
helm history my-kuebrnetes-example -n example
回滚 Helm Release
当 Helm Release 有多个版本时,可以通过 helm rollback 命令回滚到指定的版本。
helm rollback my-kubernetes-example 1 -n example
卸载 Helm Release
要卸载 Helm Release,可以使用 helm uninstall
helm uninstall my-kubernetes-example -n example
后记
本课程体系旨在为学员提供一套全面的云原生技术学习路径,包括容器技术、Kubernetes 部署和管理、Ingress 管理、持久化存储、应用部署、可观测性、服务网格、DevOps 工具链和流水线以及 GitOps 等方面的内容。通过学习这套课程体系,学员将掌握云原生技术的关键概念、原理和实践方法,从而提升云原生应用的部署、管理和协作效率。
- Docker 技术实战:学习容器技术的基础知识,包括 Docker 的运作原理、核心组件以及应用部署和监控管理。
- Kubernetes 部署和管理实战:深入了解 Kubernetes 的核心概念和基础组件,掌握 Kubernetes 集群的部署、管理和监控技能。
- Kubernetes Ingress 管理与运维:学习 Kubernetes Ingress 的概念、工作机制和运维管理方法,提升 Ingress 的部署和管理能力。
- Kubernetes 持久化存储实践:探讨 Kubernetes 持久化存储的原理、实现方式和实际应用,提高在 Kubernetes 上实现持久化存储的能力。
- Kubernetes 应用部署和管理:学习 Kubernetes 应用部署和管理的基本概念、原理和实现方法,掌握在 Kubernetes 上部署和管理应用的技巧。
- Kubernetes 可观测性实践:研究 Kubernetes 可观测性实践的概念、原理和实现方法,涉及监控、日志记录和分析等方面。
- 基于 Istio 的服务网格实战:深入了解基于 Istio 的服务网格概念、原理和实现方法,包括服务路由、流量管理、弹性能力和微服务可观测性等。
- DevOps 工具链与流水线实践:探讨 DevOps 工具链与流水线的概念、原理和实现方法,涵盖自动化构建、测试、部署和监控等环节。
- GitOps 云原生应用的高效部署与管理:全面掌握 GitOps 原理、技术和工具,提高云原生应用部署、管理和协作效率。
通过对这九门课程的学习,学员可以:
- 熟练运用 Docker 和 Kubernetes 进行容器化应用的部署和管理。
- 掌握 Ingress 和持久化存储在 Kubernetes 集群中的配置和管理方法。
- 了解 Kubernetes 可观测性实践,提高应用监控、日志和分析的能力。
- 探究 Istio 服务网格的原理和实现,实现微服务的高可用、弹性和安全。
- 运用 DevOps 工具链和流水线实现自动化构建、测试、部署和监控。
- 掌握 GitOps 的原理和技术,提升云原生应用的部署、管理和协作效率。
本课程体系适合对云原生技术感兴趣的开发者、运维工程师、架构师等专业人士。课程内容丰富、实践性强,旨在帮助学员在实际工作中更好地应用云原生技术,为企业的数字化转型做出贡献。