九、使用 Azure Kubernetes 服务的 CI/CD
软件开发已经稳步地向持续集成和持续交付的模型发展。这一过程中的一个关键推动因素是云原生应用的引入。云原生计算基金会将云原生定义为
一个开源软件栈,将应用部署为微服务,将每个部分打包到自己的容器中,并动态编排这些容器以优化资源利用率。
希望其中一些术语对你来说已经开始有点熟悉了。应用的每个部分都打包成一个容器,很可能使用 Docker 映像。微服务由 orchestrator(如 Kubernetes)部署和维护。正如我们将在本章中看到的,如果软件使用容器打包,并以一致和可重复的方式部署,那么持续集成和交付软件的过程将会更加高效。Kubernetes 与 CI/CD 流水线工具(如 Azure DevOps 流水线)相结合,使开发人员能够更快地迭代并创建更可靠的应用。
在这一章中,我们将打破神秘的 CI/CD 缩写,剖析 CI 和 CD 的组成部分。您将看到持续集成软件意味着什么,以及如何使用构建流水线来实现这一点。然后,我们将看看连续交付和部署,以及如何使用发布流水线来完成每一项。最后,我们将回顾一些在 Azure Kubernetes 服务中使用 CI/CD 的最佳实践。
我们将使用前面章节中的 IAKS 投票应用来帮助您将集成、交付和部署的抽象概念应用到现实场景中。投票应用是基于容器的应用,由运行 node.js 的 web 前端和运行 Redis 的存储后端组成,如图 9-1 所示。
图 9-1
投票应用
该项目有用于部署到 Kubernetes 的清单文件,这些文件已经打包在一个 Helm 图表中。我们将遵循更新应用的流程,并将更新部署到开发环境,然后部署到生产环境。
CI/CD 概述
你可能以前见过缩写词 CI/CD,可能想知道它是什么意思。这是一个看起来很奇怪的缩写,营销人员喜欢把它随意地洒在产品上,就好像它是某种神奇的咒语一样。但是 CI/CD 实际上代表了某些东西,或者更具体地说,它代表了两种东西。CI 代表持续集成,这是开发人员编写代码时,他们应该一天几次将代码签入共享主线的想法。一会儿我们会详细阐述这个想法。
CD 代表连续交付或连续部署。主要思想是软件的最新版本应该是可用的,并且随时可以部署到生产中。如果构建已经准备好了,但是没有在生产中运行,那么我们可以说它已经交付了。如果有一个自动化的过程将交付的构建转移到生产中,那么我们可以说它已经被部署了。这两个选项都方便地缩写为 CD,所以常见的缩写 CI/CD 在这两种情况下都适用。通过上下文可以推断出使用的是哪个“D”——部署还是交付。
连续累计
持续集成(CI)是一种软件开发实践,它有一些关键原则,如图 9-2 所示。应该有一个共同的共享代码库,开发人员可以从这里开始工作。开发人员应该检查出最新版本的代码,进行修改,然后将更新后的代码合并回主线。在签入之前,开发人员将获得主线的最新版本,并将任何更改集成到他们的本地版本中。通过经常向主线提交,开发人员永远不会离代码的主线版本太远,因此集成过程会更简单,不太可能需要重构。集成本地代码副本和主线副本的持续过程被称为持续集成。
图 9-2
持续集成过程
虽然 CI 在理论上是一个好概念,但是直到支持工具集的出现,这个概念才变成现实。支持该过程的主要组件是源代码控制管理(SCM)软件、构建服务器和自动化流水线。对于我们的 IAKS 投票应用示例,我们将使用 Azure DevOps 来提供这些 CI 组件。Azure Repos 将提供基于 git 的 SCM。Azure Pipelines 将提供自动化和构建服务器。Azure Container Registry 将成为存储完整构建工件的目标。
共享存储库
当开发人员在代码上进行协作时,通常会有几份代码副本。每个开发人员在他们的工作站上都有一个本地副本,他们将使用它来开发新的特性或功能。还有一个共享的代码库,通常在一个 SCM 服务中,开发者将提交他们的变更并从中获取最新版本的代码。今天最常用的配置管理是 Git,尽管还有其他的如 Subversion、CVS 和 TFS。
注意
对软件开发的 Git 和版本控制的全面讨论超出了本章的范围。我们将假设您对源代码控制和分支的概念有些熟悉。如果这对你来说完全陌生,那么我们推荐你查看一下 GitHub 上的 hello-world 活动( https://guides.github.com/activities/hello-world/
)作为入门。
IAKS 投票应用使用 Azure Repos 来托管其代码的共享副本,如图 9-3 所示。用于管理代码的源代码控制机制是 Git。应用有一个用于生产用途的主分支和一个用于开发新特性的特性分支。一旦一个新的特性被测试和批准,这个分支将被合并到主中。
图 9-3
投票应用 git 存储库
构建流水线
构建流水线支持将提交的代码与更大的代码库集成。构建流水线是持续集成的一部分,发生在开发人员执行到主线的推送之后。有许多不同的产品会为您运行构建流水线。虽然不同产品的术语可能略有不同,但核心概念是一致的。
生成流水线由生成代理以串行或并行方式执行的一系列步骤组成。构建流水线的输出是一组表示功能应用的工件。发布流水线应该能够获取这些工件并将应用部署到目标环境中。
构建代理通常是运行代理软件并监听新请求的虚拟机。当构建流水线准备好执行某个步骤中的某个任务时,它将查找满足任务要求的可用构建代理,并让该构建代理执行该任务。无论任务成功与否,任务的结果都将报告给构建流水线。此时,流水线可能继续运行,也可能失败,具体取决于任务设置。
IAKS 投票应用将使用 Azure 构建流水线,如图 9-4 所示,作为其 CI 流程的一部分。Azure 构建流水线使用yaml
来表达它们的配置。流水线定义可以与应用的其余部分一起存在于源代码控制中,确保对流水线的更改与其余代码一起被跟踪和版本化。
图 9-4
持续集成构建流水线
扳机
流水线中的触发器定义了流水线执行的条件。触发器的作用域通常是特定的分支、标记或特性,因此流水线中的步骤只有在作用域内的内容被提交时才会执行。对于大型代码库,确定触发器的范围对于确保只有已更改的组件才能在构建过程中运行非常重要。
IAKS 投票应用使用名为 features 的代码分支为应用开发新功能。该应用的当前版本仅支持两个投票选项。有一个功能正在开发中,以增加第三个投票选项。添加该特性的代码使用分支特性/vote3/0.5 。清单 9-1 显示了包含触发条件的流水线文件中的代码。
trigger:
branches:
include:
- master
- feature/*
Listing 9-1Trigger conditions
只有向主或特征下的分支提交,流水线才会启动。
变量
构建流水线不会将每个任务使用的所有值硬编码到文件中。将有动态属性、秘密和计算值用作流水线的一部分。例如,流水线可能需要数据库密码或 API 密钥。该值不应以纯文本形式存储在流水线定义文件中;相反,它可以存储为在构建时注入的秘密。构建号、构建分支和构建日期等属性也是动态的,可以在命名工件时使用。清单 9-2 显示了 IAKS 投票应用构建流水线的变量定义。
variables:
versionNumber: $[format('{0}.{1}', variables['Build.BuildNumber], variables['Build.BuildId'])]
repositoryName: 'iaks'
Listing 9-2Build pipeline variables
虽然这些值是在流水线文件中定义的,但也可以在运行时覆盖这些值。
步伐
构建流水线由流水线进行过程中要采取的步骤组成。一组通用步骤如图 9-5 所示。
图 9-5
持续集成流水线
用于执行每个步骤的构建代理可以在每个步骤中定义,也可以在流水线的开始处定义。更复杂的步骤可能需要具有特定操作系统、专门应用或地理位置的构建代理。在 IAKS 投票应用中,清单 9-3 中的构建代理被定义为一个托管的 Ubuntu 代理,带有最新版本的操作系统。
pool:
vmImage: 'ubuntu-latest'
Listing 9-3Build pipeline agent definition
Azure DevOps 提供按需分配的托管 Windows 和 Linux 代理。也可以在 Azure 或其他地方建立专用的构建代理池。
代码将被测试、打包,并作为工件的集合放置在指定的位置。发布流水线将使用工件来部署应用。
IAKS 投票应用首先构建前端 web 应用容器映像,如清单 9-4 所示。
- task: Docker@2
inputs:
containerRegistry: 'iaks'
repository: 'azure-voting-app'
command: 'buildAndPush'
tags: '$(versionNumber)'
Dockerfile: '**/CICD/azure-vote/Dockerfile'
Listing 9-4Build pipeline docker task
该任务在托管代理上构建映像,然后使用我们之前定义为标签的versionNumber
变量标记并将映像推送到 Azure 容器注册表(ACR ),以区分多个构建。
清单 9-5 中显示的下一步是获取用于部署应用的 Helm 图表,并将其打包到 Helm 归档文件中。打包过程还将使用提交的版本和应用版本号更新 Chart.yaml 值。
- task: HelmInstaller@1
inputs:
helmVersionToInstall: 'latest'
- task: HelmDeploy@0
inputs:
command: 'package'
chartPath: '**/Helm/aks/iaks'
chartVersion: '$(versionNumber)'
arguments: '--app-version $(versionNumber)'
Listing 9-5Build pipeline Helm install
默认情况下,构建代理没有安装 Helm,因此第一个任务安装最新版本的 Helm,第二个任务使用图表版本和应用版本的versionNumber
变量在本地创建 Helm 包。
我们将打包的 Helm chart 存储在与 web 前端容器映像相同的 ACR 中。Azure CLI 命令用于推送包,因为没有将 Helm 包推送到 ACR 的内置任务,如清单 9-6 所示。
- task: AzureCLI@1
inputs:
azureSubscription: $(AzureSubscriptionId)
scriptLocation: 'inlineScript'
inlineScript: 'az acr helm push $(System.ArtifactsDirectory)/$(repositoryName)-$(versionNumber).tgz --name $(AzureContainerRegistry);'
Listing 9-6Build pipeline ACR task
清单 9-7 中显示的最后两个任务将这个构建的版本号放到一个文本文件中,并将该文本文件作为工件发布。版本号在变量中定义为 BuildNumber 和 BuildId 的组合。versionNumber
变量用于标记容器映像和 Helm 图。发布流水线在运行时需要正确的版本号来找到正确的映像和图表。
- task: Bash@3
inputs:
targetType: 'inline'
script: 'sudo echo $(versionNumber) > $(System.DefaultWorkingDirectory)/versionNumber.txt'
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(System.DefaultWorkingDirectory)/versionNumber.txt'
artifact: 'versionNumber'
Listing 9-7Build pipeline bash script
通知
当构建流水线完成时,无论成功与否,都应该发出通知。通知有很多选择,最常见的是电子邮件、聊天或 webhook。
Azure DevOps 的通知在流水线之外处理,在项目设置中定义。第三方应用,如 Slack,可以直接订阅某个版本或发布,并向特定频道提供通知。IAKS 投票应用在一个名为 iaks 的松弛通道上被监控。当一个构建流水线完成时,图 9-6 中的以下通知出现在通道中。
图 9-6
Azure 流水线通知
史前古器物
一个成功的构建流水线将产生工件,发布流水线可以使用这些工件来交付并可能部署应用。由构建产生的工件应该被一致地用于在较低的环境和生产中发生的任何验收测试。这保证了在产品化或 QA 中部署的任何代码都将与在生产中部署的代码相匹配。强烈反对在构建流水线之外修补工件,就像永远不要这样做一样。
你为什么不应该修补那些艺术品?假设您已经构建了应用的新版本,并将其部署到 QA 和试运行中。在登台环境中有一个小问题,但是您发现您可以通过调整配置文件中的设置来修复它。
您进行了更改,现在测试通过了。因为您在产品化阶段调整了工件,所以正在部署的代码不再匹配源代码控制中的内容。在随后的构建中,您的更改将会丢失,您修复的东西现在又会被破坏。
充其量,你打破了舞台。在最坏的情况下,丢失的变更会进入生产环境,并在那里中断。故事的士气?不要改动文物。更改代码并运行新版本。
IAKS 投票应用创建了三个工件。web 前端容器映像、Helm 图表和versionNumber
文本文件。容器映像和图表存储在 Azure 容器注册实例中。该文本文件作为构建中的工件发布,这使得它可用于任何发布流水线。当我们进入发布流水线部分时,我们将看到来自构建的工件是如何被发布所吸收和使用的。
持续交付/部署
正如本章开头所提到的,CD 可以代表持续交付或部署。主要的区别是自动化过程在什么点停止。在连续交付环境中,CD 流水线的末端是生产就绪版本。有一个手动步骤可以将发布正式部署到生产中。连续部署环境会自动完成最后一步。
注意
在本节中,我们将主要关注如何建立一个连续的交付流水线。适用时,将明确注明持续部署。
释放流水线
构建流水线的最终结果是组成应用的一组工件。这些工件应该处于可部署的状态。发布流水线的工作是获取这些工件,将应用部署到一个或多个环境中,并运行测试来验证应用的功能。图 9-7 显示了一个常见的释放流水线示例。
图 9-7
连续输送流水线
流水线将提取由特定构建创建的工件。然后,它将工件作为应用部署到开发环境中,并运行系统测试。假设这些系统测试通过,流水线将创建一个 pull 请求,将 feature 分支合并到 master 分支中。然后,流水线将把相同的工件部署到一个进行验收测试的阶段环境中。如果验收测试是成功的,那么工件可以被标记为生产就绪,或者被转移到一个只生产的存储库中。工件向生产存储库的移动可以作为一个触发器,启动将这些工件部署到生产的流水线中的另一个阶段。
IAKS 投票应用使用来自 Azure Pipelines 的两个发布流水线来处理连续交付。从功能分支构建的代码将触发 helm-dev-release 流水线。该流水线将从特性构建中提取工件,并将它们部署到 AKS 集群上的开发名称空间。除了使用单一的开发名称空间,还可以在 AKS 集群上启用 Dev Spaces 特性。Dev Spaces 创建了一个可由多个开发人员共享的专用开发环境,能够在更大的开发环境中创建每个用户的空间,以实时测试新特性。
当代码通过 pull 请求合并到 master 分支时,会触发 helm-qa-release 流水线。该流水线将从上一次成功的构建中提取工件,并将它们部署到 AKS 集群上的 qa 名称空间。一旦执行了验收测试,将调用第二个阶段,从构建中提取工件,并将它们复制到 ACR 上的生产存储库中。还有第三个手动阶段,将生产标记的工件部署到生产 AKS 集群。
Azure 发布流水线使用图形用户界面来表达,而不是通过yaml
文件。这很可能很快会改变,使构建和发布流水线之间的接口一致。可以使用JSON
文件导出或导入发布流水线。对于本节中的示例,屏幕截图将用于显示发布流水线配置的相关部分。
扳机
CD 流水线的常见触发因素是 CI 流水线的成功完成。也可能有这样的情况,触发器是基于时间的,按每天的时间表触发,或者基于来自另一个分支的拉请求。
IAKS 投票应用由来自功能分支的代码的成功构建或来自主分支的拉请求触发。Helm 开发释放流水线上特征分支触发器的配置如图 9-8 所示。
图 9-8
连续部署触发器
每当来自特性路径上的分支的新构建可用时,该流水线将执行。图 9-9 中显示的 helm-qa-release 的配置是相同的,除了构建分支被设置为主并且增加了一个拉取请求触发器。
图 9-9
Azure Pipelines QA 版本
阶段
CD 流水线中各阶段的术语取决于软件,但一般来说,CD 流水线中会有多个阶段。每个阶段可以由一个或多个作业组成,每个作业由一个或多个任务组成。阶段和作业可以是连续的,也可以是并行运行的。作业中的任务通常是连续运行的。
图 9-10 中的 Helm-dev-release 管线由单级组成,只有一个作业。
图 9-10
Azure 流水线开发版本
该阶段的工件来源于构建过程。工件可能有多个来源。在有几个微服务的大型应用中,工件可能来源于每个微服务流水线的成功构建。
图 9-11 中的 Helm-qa-release 由三个阶段组成,每个阶段有一项工作。
图 9-11
Azure Pipelines 临时发布
所有阶段的作业都在发布代理上运行,就像构建任务在构建代理上执行一样。开发发布工作如图 9-12 所示,以供参考。
图 9-12
Azure 流水线代理配置
在图 9-12 中,您可以看到代理首先下载包含 versionNumber.txt 文件的流水线工件。下面的任务是一个 bash 脚本,它从文本文件中获取版本号,并用该版本号设置一个发布流水线变量。然后,代理安装 Helm 并使用 Azure CLI 添加 ACR 存储库,用于部署的 Helm 图表驻留在该存储库中。最后,在图 9-13 中,Helm 使用 Helm 图表和容器映像在开发名称空间中的 AKS 集群上运行升级,这些图表和容器映像是构建流水线中工件的一部分。
图 9-13
Azure 流水线掌 Helm 部署
当部署完成后,AKS 集群中的开发名称空间将运行 IAKS 投票应用的新部署,如清单 9-8 所示。
helm ls --tls --namespace development
NAME STATUS CHART APP VERSION
iaks-45 DEPLOYED iaks-20190725.4.45 20190725.4.45
iaks-46 DEPLOYED iaks-20190725.4.46 20190725.4.46
Listing 9-8Helm deployment listing
每个版本的命名都包含了BuildId
属性,所以每个成功的构建都将被创建为它自己在 AKS 集群上的部署。helm-qa-release 使用相同的任务将应用的副本部署到 qa 名称空间,但是它不使用BuildId
属性来命名 helm release。因此,当 helm-qa-release 流水线运行时,它会就地升级任何现有的应用。
在 helm-qa-release 中的部署任务结束时,图 9-14 显示有一个批准条件。QA 部门的某个人需要审查部署,并验证它已经通过了所有的验收标准。
图 9-14
Azure 流水线后期部署
通过批准试运行-发布阶段,执行流水线中的下一个标记工件阶段,如图 9-15 所示,该阶段涉及将构建工件移动到生产存储库。在 Azure Container Registry 中,有一个单独的注册表实例叫做 acriaksprod 。标记工件阶段的目标是将存储在 acriaks 中的工件转移到 acriaksprod 中。
图 9-15
Azure 流水线标记工件
部署流程下载versionNumber.txt
工件并将其作为变量导入。然后,它安装 Helm 和 Docker 客户端。第一个 Azure CLI 任务将 acriaks ACR 添加为 Helm 存储库。
az acr helm repo add -n $(acrName)
然后,Helm 任务从 acriaks 库中获取 iaks 图表,并将其保存在本地。
helm fetch $(acrName)/iaks
在清单 9-9 中显示的最后一个任务中,Azure CLI 首先将 Helm 图推送到 acriaksprod 存储库。然后,它同时登录到 acriaks 和 acriaksprod 。使用 docker CLI,它从 acriaks 中提取当前 web 前端映像,为 *acriaksprod、*重新标记它,并将映像推送到 acriaksprod 。
az acr helm push iaks-$(versionNumber).tgz --name $(acrName)prod
az acr login -n $(acrName)prod
az acr login -n $(acrName)
docker pull $(imagePath):$(versionNumber)
docker tag $(imagePath):$(versionNumber) $(prodImagePath):$(versionNumber)
docker push $(prodImagePath):$(versionNumber)
Listing 9-9Azure CLI tasks
掌 Helm 图和 web 前端映像现在都存储在生产存储库中,并准备好部署到生产中。生产环境运行在单独的 AKS 集群上。我们可以使用ImagePolicyWebhook
配置准入策略,只允许将存储在 acriaksprod 注册表中的映像部署到生产集群。
在 helm-qa-release 中有一个单独的阶段,如图 9-16 所示,可以手动运行以部署到生产中。
图 9-16
Azure Pipelines 产品发布
生产-发布阶段中的任务反映了阶段-发布阶段中的任务,但是如图 9-17 所示,一些值已经被更改,以使用正确的 ACR 实例 acriaksprod ,并部署到为生产使用保留的单独的 AKS 集群。
图 9-17
Azure 流水线生产掌 Helm 任务
尽管生产-发布阶段目前被设置为手动触发——使其成为一个连续的交付流水线——但它可以更新为在标记工件阶段完成并由一组选定的人员批准后触发。
测试
正确的测试是整个 CI/CD 流程不可或缺的一部分。测试有不同的阶段,每个测试都建立在最后一个之上。最终,测试的目标是产生满足技术和商业需求的可靠软件。在代码被推送到共享存储库之前,一部分测试将在开发人员的工作站上进行。一旦代码被推送到共享存储库,CI 流水线将开始执行。CI 流水线的步骤将包括自动化测试,有时还包括手动测试,目标是生产稳定的软件,可以在 QA 或试运行环境中部署和测试。CI/CD 环境中的最后一组测试将在 CD 流水线中执行,希望最终能够发布一个可以在生产中部署的可接受的版本。
根据部署模型的不同,测试不一定在部署到生产环境时就结束了。代码可能会逐渐推广到一部分用户或某些地理位置。部署期间收集的遥测数据可用于进一步验证软件是否按预期工作。
在接下来的小节中,我们将简要地看一下一些更常见的测试阶段,以及它们在 CI/CD 过程的大环境中所处的位置。
单元测试
当开发一个新的特性或功能时,它必须满足一些需求。对于一组给定的输入,它应该产生一定的输出。例如,假设您正在开发一个将两个整数相加的函数。单元测试将验证给定两个整数-1 和 2-该函数产生预期的 3。单元测试将有几种情况要测试,包括无效输入,如浮点数或文本而不是整数。我们可能知道花生酱和巧克力等于棒极了,但是我们的加法函数可能会抛出一个错误。
单元测试将在开发人员的本地工作站上进行,或者在 CI 流水线的早期阶段进行。
集成测试
在一个特性或功能通过自身验证后,它需要与应用的其他部分进行交互测试。在我们的例子中,很有可能应用的某些部分已经在使用一个函数将整数相加。当您用新功能替换该功能时,您必须测试应用的这些部分,以确保它们仍然正常工作。换句话说,您正在测试代码与它所交互的组件的集成。
集成测试将作为 CI 流水线中的一个阶段进行,然后发布构建以在下一个测试阶段进行部署。
系统试验
云原生应用由微服务组成,每个微服务向应用的其他组件或外部源提供服务。虽然不是所有的组件都将直接与被更新的代码部分交互,但是仍然可能存在不可预见的附带影响。系统测试是在整个应用上执行的,而不仅仅是在那些直接与更新交互的组件上。在我们的例子中,这将是一个标准的测试套件,适用于整个应用,而不仅仅是使用您的新的和完全令人敬畏的加法函数的部分。
系统测试将在构建版本之后进行,通常是在开发或 QA 环境中测试版本的 CD 流水线期间。
验收测试
系统测试从技术角度确定系统是否按预期工作,但是还有其他的验证标准。安全、法规遵从性和 QA 团队可能希望运行他们的自动化或手动测试套件来验证应用是否满足他们的业务需求。有时一组用户也会被包括在测试中,以确保用户群体对应用的功能感到满意。
验收测试将在 CI 流水线完成之后、应用部署到生产环境之前进行。在一个 CD 流水线中可能会有几轮由不同团队进行的验收测试,最终会产生一个可以投入生产的版本。
开发空间
在 AKS 中,有一个名为 Dev Spaces 的功能目前正在预览中。Dev Spaces 背后的意图是使个人开发者的开发和测试过程更简单。实际上,在 AKS 集群中创建了一个父开发空间,为团队中的每个开发人员创建了一个或多个子空间,如图 9-18 所示。在父空间中,部署了应用的完整版本。当开发人员对他们的代码进行更新时,产生的构建被部署在他们唯一的空间中,但是它可以与运行应用其余部分的父空间进行交互。
图 9-18
开发空间布局
例如,让我们考虑一个包含时间跟踪服务的微服务应用。您可能正在使用时间跟踪服务,该服务与组成应用的许多其他服务进行交互。不是试图在您的工作站上运行整个应用,而是在称为开发的开发空间中的 AK 上运行应用的实例。当您提交新版本的时间跟踪服务时,Dev Spaces 可以在您的个人空间(一个名为 Development/Dev1 的子空间)中部署生成的 pod。出于测试目的,您现在可以在开发中使用应用,但是让您的应用端点在开发/Dev1 中使用更新的时间跟踪服务。一旦您成功地执行了您的单元和集成测试,您可以将您的代码合并到开发分支中,并且在开发空间中的应用将被更新。
Dev Spaces 确实需要准备代码来使用它,创建一个 Dev Spaces 配置文件,并使用一些客户端工具来与之交互。主要的好处是,开发人员不必尝试维护应用的本地副本来进行测试,团队中的每个人都使用已经在 Kubernetes 中运行的公共环境来执行测试和调试。
AK 的 CI/CD 最佳实践
谈到 CI/CD,有许多最佳实践,我们不会在这里试图总结它们。相反,我们希望将 CI/CD 应用于 Azure Kubernetes 服务。最佳实践可以分为两个不同的领域,集群操作员和应用开发人员。
聚类运算符
集群操作员负责管理和维护 AKS 集群。他们负责配置集群的安全性、更新 Kubernetes 的版本、配置伸缩和节点池等等。如果您经常部署和更改 AKS 集群,您可能属于这一类。集群操作者主要关心 CI/CD 的持续交付部分,尽管他们可能会参与帮助开发人员开发空间或为集成测试划分许可的名称空间。
独立的环境
当涉及到交付和部署时,一个版本会经历几个环境:开发、QA、试运行、生产,等等。这些环境需要某种程度的分离,有两种主要方法可以实现这一点,名称空间和集群。
Kubernetes 中的名称空间是分离工作负载的逻辑结构。命名空间可以在 RBAC 规则中使用,限制帐户可以部署到哪些命名空间。命名空间也有自己的 DNS 空间用于名称解析,例如,开发命名空间中的服务可能有地址 app . development . SVC . cluster . local。命名空间可能有分配给它们的资源配额,允许您限制命名空间在群集内可以使用的资源量。
对于不需要彼此硬分离的环境,名称空间具有逻辑意义。需要特别注意防火墙规则和限制,因为名称空间不提供相互之间的网络分离或分段。一个常见的最佳实践是使用名称空间来分隔多个开发环境,以及其他非生产环境。
AKS 中的集群在环境之间提供了更强的隔离。从 Kubernetes 管理的角度来看,每个集群都是完全独立的。从网络的角度来看,创建一个单独的集群提供了一个额外的分段级别,这对于某些环境(如生产环境)可能是理想的。多个集群增加了管理负担,因为现在集群操作员负责管理和维护它们。一个常见的最佳实践是为生产环境或其他可能需要更高级别的隔离的环境使用单独的集群。
还有第三种可能的选择,那就是在 AKS 中使用节点池。AKS 正在预览节点池,但在不久的将来应该会正式推出。一个群集可以有多个节点池,每个节点池由相同大小和类型的节点组成。通过使用节点污染和选择器,可以将环境分成不同的节点池,这将增加隔离,而不需要管理另一个 AKS 集群。
限制访问
有了合适的发布渠道,开发人员不应该直接部署到 AKS。他们应该遵循提交代码的过程,让 CI 和 CD 流水线完成剩下的工作。除了 Dev Spaces,开发人员不应该有权限直接部署到 AKS 中的任何环境。
构建和发布流水线可以与 Azure 中的服务主体相关联,这些服务主体可以被授予部署到 AKS 的必要权限。每个环境都应该有自己的服务主体,对编辑流水线的访问也应该受到限制。
限制开发人员的访问,以及您自己的访问,会迫使每个人都遵循 CI/CD 流程,并阻止他们在流程之外进行可能在未来的部署中被遗忘或忽略的更改。
准入控制
集群上的准入控制有助于确定是否接受部署,或者在接受之前是否需要对部署进行任何更改。这可能包括要求特定的标签、资源限制或映像注册。为了防止发布流水线中可能的篡改,最佳实践是创建阻止某些部署成功的准入策略。根据您在 AKS 集群上运行的 Kubernetes 版本,AKS 启用了几个准入控制插件。
用于部署的 Azure 监视器
Azure Monitor 是微软 Azure 中多个监控服务的组合。运行有效的 CI/CD 操作的很大一部分是收集反馈。集群操作员主要关心部署或集群维护后应用的运行状况。Azure Monitor 可以配置为从 AK 收集信息,供操作员在警报或趋势分析中使用。
应用开发人员
集群操作员关心其权限内 AKS 集群的正常运行和维护。应用开发人员关注他们的应用的健康和性能。如果您正在编写将在 AKS 集群上运行的代码,您可能属于这一类。应用开发人员关心 CI/CD 的持续集成和持续交付组件。
调试立方结构
根据应用运行的环境,它们的功能可能会有所不同。为此,在最接近生产条件的环境中测试和调试应用是有意义的。AKS 提供了在 Kubernetes 上直接调试的能力,或者通过整个团队的专用开发环境,或者通过 Dev Spaces。特别是使用 Dev Spaces 为整个团队提供了一个公共的基线环境,同时仍然允许对应用的特定组件进行单独的开发和调试。
外部存储凭据
凭证和其他机密信息不应该放入代码、部署文件或 CI/CD 流水线中。它们应该存储在一个安全的保险库中,在应用运行时可以通过适当的权限和安全控制进行访问。
AKS 和 Azure DevOps 能够利用 Azure Key Vault。AKS 和 Azure DevOps 都使用 Azure Active Directory 对 Key Vault 进行身份验证,并访问存储在那里的机密、证书和密钥。AKS 可以使用其节点的托管安全身份和 pod 级 Azure AD 身份验证来访问密钥库。
应用开发人员应该利用 Azure Key Vault 集成将任何凭据、机密和证书移出他们的代码。
Azure 发展监控
Azure Monitor 是微软 Azure 中多个监控服务的组合,包括应用洞察和日志分析。日志、跟踪和调试信息都可以发送到 Azure Monitor 进行警告和分析。虽然集群运营商关心他们的 AKS 集群的健康状况,但开发人员更关注他们的应用的健康状况,尤其是在部署新版本的应用或流量突然激增时。CI/CD 流水线还可以在每个阶段执行时向 Azure Monitor 发送信息,使数据可用于警报和分析。
应用开发人员应该在他们的代码和流水线中添加挂钩,以支持额外的 Azure Monitor 集成。
摘要
在更大的 DevOps 世界中,持续集成和持续交付是巨大的主题。虽然我们刚刚触及了 CI/CD 背后的一些核心概念,但是我们希望您能够看到 AKS 是如何与软件的自动化构建和发布联系在一起的。一般来说,Kubernetes,特别是 AKS,为开发和部署云原生应用提供了一致且稳定的环境。与 CI/CD 原则协同工作,可以快速迭代并为最终用户生成稳定的应用。
在本章中,您学习了什么是 CI/CD,以及源代码控制、应用构建和发布流水线背后的一些基础知识。我们回顾了 Azure DevOps 中的构建流水线,并看到了代码提交如何产生可交付的可用工件。然后,我们看了一个发布流水线,以及如何使用相同的工件在多个环境中部署应用。最后,我们回顾了将 AK 与 CI/CD 结合使用的一些最佳实践。