如何在DigitalOceanKubernetes上使用Flagger逐步交付版本
作为 Write for DOnations 计划的一部分,作者选择了 Free and Open Source Fund 来接受捐赠。
介绍
对托管在 Kubernetes 上的资源的更新几乎会立即进行传播。 Kubernetes 可以监控集群的健康状况并在需要时重新启动容器,但它不包括处理坏或有问题的容器的策略。 这意味着,如果应用了新的容器版本并开始出现意外行为,Kubernetes 将无法通过启动回滚到早期版本或完全停止传播来正确解决这种情况。
Flagger 是 Kubernetes 的渐进式交付运营商,它通过在监控配置指标的同时将流量逐渐转移到新版本来解决概述的问题。 它可以对新版本执行自动分析和测试,决定是否将其传播到整个集群或发现问题时停止。 Flagger 会缓慢增加新版本的负载,同时保持旧版本可用,从而确保最短的停机时间。 它可以向 Slack、Microsoft Teams 和其他平台发送通知,以通知您和您的团队发生的事件。
在本教程中,您将安装 Flagger 并使用它为 podinfo 应用程序设置渐进式交付到您的 DigitalOcean Kubernetes 集群。 podinfo
是一个 Web 应用程序,可提供有关其运行环境的详细信息。 您将设置 Flagger 以监视其部署的资源,自动测试新版本,并使用 webhook 在 Slack 上通知您。 最后,如果请求的更改有问题,您将很快收到通知,而不会使集群部署处于不可用状态。
先决条件
在开始本教程之前,您需要:
DigitalOcean Kubernetes 集群,版本 1.19 或更高版本,您的连接配置配置为
kubectl
默认值。 如何配置kubectl
的说明显示在创建集群时显示的 连接到集群 步骤下。 要了解如何在 DigitalOcean 上创建 Kubernetes 集群,请参阅 Kubernetes 快速入门 。安装在本地计算机上的 Helm 包管理器。 为此,请完成 如何使用 Helm 3 包管理器 教程在 Kubernetes 集群上安装软件的 步骤 1。
安装在集群上的 Nginx Ingress Controller 和 Cert-Manager。 有关如何执行此操作的指南,请参阅 如何使用 Helm 在 DigitalOcean Kubernetes 上设置 Nginx 入口。
您所属的 Slack 工作区。 要了解如何创建工作空间,请访问 官方文档 。
具有 DNS A 记录的域名指向 Ingress 使用的 DigitalOcean 负载均衡器。 如果您使用 DigitalOcean 管理您域的 DNS 记录,请参考 如何管理 DNS 记录 创建 A 记录。 在本教程中,我们将 A 记录称为
app.your_domain
。注意:您在本教程中使用的域名必须与如何在DigitalOcean Kubernetes先决条件教程中设置Nginx Ingress中使用的域名不同。
第 1 步 — 安装 Flagger 并配置 Nginx Ingress Controller
在本节中,您将使用 Helm 将 Flagger 安装到您的集群中。 您还将配置 Nginx Ingress Controller 以使其内部指标可供其他应用程序访问,Flagger 将根据其执行方式来决定是允许还是拒绝新版本。
您首先需要通过运行将包含 Flagger 的存储库添加到 Helm:
helm repo add flagger https://flagger.app
输出将类似于以下内容:
Output"flagger" has been added to your repositories
更新 Helm 让它知道它包含什么:
helm repo update
然后,运行以下命令来安装 Flagger:
helm install flagger flagger/flagger \ --set prometheus.install=true \ --set meshProvider=nginx
此命令从您刚刚添加的图表存储库中安装 Flagger,并将 Helm 版本命名为 flagger
。 由于它将监控 Web 应用程序,因此 flagger
版本将绑定到 Nginx Ingress 控制器。
输出将类似于以下内容,详细说明已部署 Flagger:
OutputNAME: flagger LAST DEPLOYED: ... NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Flagger installed
要公开 Nginx Ingress Controller 指标,您需要在其 Helm 版本中设置其他变量,同时保留已定义的变量。 您可以通过运行 helm upgrade
并传入 --reuse-values
参数以及新的变量值来实现:
helm upgrade nginx-ingress ingress-nginx/ingress-nginx \ --reuse-values \ --set controller.metrics.enabled=true \ --set controller.podAnnotations."prometheus\.io/scrape"=true \ --set controller.podAnnotations."prometheus\.io/port"=10254
此命令修改 nginx-ingress
Helm 版本,并在控制器及其 Pod 上启用 Prometheus 指标收集。
输出将类似于以下内容:
OutputRelease "nginx-ingress" has been upgraded. Happy Helming! NAME: nginx-ingress LAST DEPLOYED: ... NAMESPACE: default STATUS: deployed REVISION: 2 TEST SUITE: None NOTES: The ingress-nginx controller has been installed. ...
请注意,修订号现在为 2
,表示已发生升级。
在本节中,您已经安装了 Flagger 并配置了 Nginx Ingress Controller 以公开其内部指标。 在下一步中,您将部署一个应用程序并设置 Flagger 以控制其发布。
第 2 步 — 部署应用程序
现在您将部署 podinfo
Web 应用程序并创建一个 canary 资源 来控制其发布。 Canary 资源 来自 Flagger,并告诉它如何、何时以及在多长时间内测试新版本,然后再应用或拒绝它。 他们还控制逐渐将流量从旧版本转移到新版本的流量。
podinfo
应用程序将存储在名为 test
的命名空间中。 运行以下命令来创建它:
kubectl create ns test
然后,通过运行部署 podinfo
:
kubectl apply -k https://github.com/fluxcd/flagger//kustomize/podinfo?ref=main
此命令将从官方 Flagger GitHub 存储库中提取 podinfo
清单并将它们应用到您的集群。
kubectl
将显示以下输出:
Outputdeployment.apps/podinfo created horizontalpodautoscaler.autoscaling/podinfo created
要验证它是否已部署,请运行以下命令:
kubectl get pods -n test
您将看到与此类似的输出:
OutputNAME READY STATUS RESTARTS AGE podinfo-78fd6c49bf-jsjm5 1/1 Running 0 18s podinfo-78fd6c49bf-k2nh4 0/1 Running 0 3s
现在 Pod 正在运行,您将创建一个 Ingress 以在您的域中公开该应用程序。 打开一个名为 podinfo-ingress.yaml
的文件进行编辑:
nano podinfo-ingress.yaml
添加以下行:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: podinfo namespace: test labels: app: podinfo spec: ingressClassName: nginx rules: - host: "app.your_domain" http: paths: - pathType: Prefix path: "/" backend: service: name: podinfo port: number: 80
此 Ingress 在 app.your_domain
域中公开 podinfo
服务。 请记住将其替换为您自己的域,然后保存并关闭文件。
请注意,您的集群中尚不存在 podinfo
服务。 它将在稍后由 Flagger 作为金丝雀的一部分自动创建。 这不会阻止 Ingress 的部署。
通过运行以下命令在 Kubernetes 中创建 Ingress:
kubectl apply -f podinfo-ingress.yaml
在创建金丝雀之前,您需要部署 Flagger 的负载测试器,它允许金丝雀资源通过发送 HTTP 请求来测试版本。 运行以下命令,使用 Helm 将其安装在 test
命名空间中:
helm install flagger-loadtester flagger/loadtester -n test
Helm 将显示以下输出:
OutputNAME: flagger-loadtester LAST DEPLOYED: Thu Jan 6 11:37:45 2022 NAMESPACE: test STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Flagger's load testing service is available at http://flagger-loadtester.test/
您现在将定义金丝雀并将其存储在一个名为 podinfo-canary.yaml
的文件中。 通过运行打开它进行编辑:
nano podinfo-canary.yaml
添加以下行:
apiVersion: flagger.app/v1beta1 kind: Canary metadata: name: podinfo namespace: test spec: provider: nginx targetRef: apiVersion: apps/v1 kind: Deployment name: podinfo ingressRef: apiVersion: networking.k8s.io/v1 kind: Ingress name: podinfo progressDeadlineSeconds: 60 service: port: 80 targetPort: 9898 analysis: interval: 10s threshold: 10 maxWeight: 50 stepWeight: 5 metrics: - name: request-success-rate thresholdRange: min: 99 interval: 1m webhooks: - name: acceptance-test type: pre-rollout url: http://flagger-loadtester.test/ timeout: 30s metadata: type: bash cmd: "curl -sd 'test' http://podinfo-canary/token | grep token" - name: load-test url: http://flagger-loadtester.test/ timeout: 5s metadata: cmd: "hey -z 1m -q 10 -c 2 http://app.your_domain/"
首先,您设置金丝雀将驻留的名称和命名空间。 在 spec
下,首先定义 targetRef
,它指定要监视的部署,即 podinfo
。 同样,您刚刚创建的随附 Ingress 在 ingressRef
下指定。
使用 progressDeadlineSeconds
,您可以让金丝雀在任何时候最多空闲 60 秒,然后才能完全恢复新的更改。 这可以防止停滞并为其执行设置最后期限。 然后,定义 Ingress 将使用的 podinfo
服务。 Flagger 也可以在金丝雀执行期间创建多个临时服务,但主要的服务将在金丝雀的生命周期内始终可用。
analysis
块定义了 Flagger 将如何查看它从 Nginx Ingress Controller 接收到的指标。 interval
指示它每 10 秒查看一次,threshold
限制在回滚新版本之前度量检查失败或不可用的次数。 可以路由到新版本的最大流量百分比为 50
,如 maxWeight
中所指定。 stepWeight
控制每个测试步骤中通往金丝雀的流量会增加多少。
接下来的两个部分 metrics
和 webhooks
定义了如何测试新版本 - 通过使用您之前部署的负载测试器创建流量,并监控请求的成功率。 如果成功请求的百分比高出 99% or,则该版本通过测试。
请记住用您自己的域替换突出显示的域,然后保存并关闭文件。
用 kubectl
推出:
kubectl apply -f podinfo-canary.yaml
您将看到正在创建的金丝雀:
Outputcanary.flagger.app/podinfo created
您现在可以导航到 app.your_domain
。 您将看到 podinfo
应用程序:
主页显示已提供给您的 podinfo
版本以及来自哪个 pod。 您可以按 Ping 按钮刷新其他 pod 的版本号。
要验证 Flagger 是否按照 canary 中概述的配置接管更新部署的过程,请运行以下命令以设置 podinfo
的不同版本:
kubectl set image deployment/podinfo podinfod=stefanprodan/podinfo:6.0.3 -n test
部署将更新:
Outputdeployment.apps/podinfo image updated
Flagger 将检测到部署修订号已更改,您可以通过列出与 podinfo
金丝雀相关的事件来检查:
kubectl describe canary/podinfo -n test
一段时间后,输出将与此类似:
OutputEvents: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Synced 117s flagger New revision detected! Scaling up podinfo.test Warning Synced 107s flagger canary deployment podinfo.test not ready: waiting for rollout to finish: 0 of 2 (readyThreshold 100%) updated replicas are available Warning Synced 97s flagger canary deployment podinfo.test not ready: waiting for rollout to finish: 1 of 2 (readyThreshold 100%) updated replicas are available Normal Synced 87s flagger Starting canary analysis for podinfo.test Normal Synced 87s flagger Pre-rollout check acceptance-test passed Normal Synced 87s flagger Advance podinfo.test canary weight 5 Warning Synced 67s (x2 over 77s) flagger Halt advancement no values found for nginx metric request-success-rate probably podinfo.test is not receiving traffic: running query failed: no values found Normal Synced 57s flagger Advance podinfo.test canary weight 10 Normal Synced 47s flagger Advance podinfo.test canary weight 15 Normal Synced 37s flagger Advance podinfo.test canary weight 20 Normal Synced 27s flagger Advance podinfo.test canary weight 25 ...
Flagger 根据金丝雀定义记录它采取的所有操作。 在检测到新修订后,它会从中启动测试 pod,并通过提高金丝雀权重开始分析,这意味着更多流量被转移到新 pod。
返回您的浏览器并观察版本号随着应用程序不断刷新而闪烁。 版本正在发生变化,因为 Flagger 正在增加路由到正在测试的新版本的流量:
Flagger 表示以 Advance podinfo.test canary weight
开头的事件的流量转移,然后是被转移的流量百分比:
Output... Normal Synced 116s flagger Advance podinfo.test canary weight 10 Normal Synced 106s flagger Advance podinfo.test canary weight 15 ...
一段时间后,金丝雀部署应该会成功并且版本号会稳定下来:
金丝雀的最终事件日志将如下所示:
OutputEvents: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Synced 2m56s flagger New revision detected! Scaling up podinfo.test Warning Synced 2m46s flagger canary deployment podinfo.test not ready: waiting for rollout to finish: 0 of 2 (readyThreshold 100%) updated replicas are available Warning Synced 2m36s flagger canary deployment podinfo.test not ready: waiting for rollout to finish: 1 of 2 (readyThreshold 100%) updated replicas are available Normal Synced 2m26s flagger Starting canary analysis for podinfo.test Normal Synced 2m26s flagger Pre-rollout check acceptance-test passed Normal Synced 2m26s flagger Advance podinfo.test canary weight 5 Warning Synced 2m6s (x2 over 2m16s) flagger Halt advancement no values found for nginx metric request-success-rate probably podinfo.test is not receiving traffic: running query failed: no values found Normal Synced 116s flagger Advance podinfo.test canary weight 10 Normal Synced 106s flagger Advance podinfo.test canary weight 15 Normal Synced 96s flagger Advance podinfo.test canary weight 20 Normal Synced 86s flagger Advance podinfo.test canary weight 25 Normal Synced 76s flagger Advance podinfo.test canary weight 30 Warning Synced 16s flagger podinfo-primary.test not ready: waiting for rollout to finish: 1 old replicas are pending termination Normal Synced 6s (x6 over 66s) flagger (combined from similar events): Routing all traffic to primary
最后一个事件表示流量将被路由到主服务,这意味着金丝雀部署已经完成。
在此步骤中,您已部署 podinfo
应用程序并创建了一个 Ingress 以在您的域中公开它。 您还创建了一个金丝雀资源来控制和测试新的部署修订。 您现在将配置 Flagger 以向 Slack 报告金丝雀事件以获得更好的可见性。
第 3 步 — 向 Slack 报告
您现在将设置 Flagger 以将其日志发送到您的 Slack 工作区,这样您和您的团队将始终能够查看事件的完整日志。
要使用 Slack 集成,您需要在 Slack 上为您的工作区安装一个 传入 webhook。 Incoming webhooks 是应用程序提供来自其他应用程序的实时信息的一种简单方式。 如果您从未创建过 webhook,则首先需要为您的工作区创建一个应用程序。
为此,首先登录 Slack 并导航到 应用程序创建页面 。 选择一个您会识别的名称,选择所需的工作区,然后单击 Create App。
您将被重定向到新应用的设置页面。 点击左侧导航栏上的Incoming Webhooks。
通过翻转标题 Activate Incoming Webhooks 旁边的开关按钮来启用 webhook。
将发现页面下方的新部分。 向下滚动并单击 Add New Webhook to Workspace 按钮。 在下一页上,选择您希望将报告发送到的通道,然后单击允许。
您将被重定向回 webhook 的设置页面,并且您会在表格中看到一个新的 webhook。 单击 Copy 将其复制到剪贴板并记下以备后用。
要配置 Flagger 以将日志发送到 Slack,您需要通过运行以下命令更新其 Helm 版本:
helm upgrade flagger flagger/flagger \ --reuse-values \ --set slack.url=your_hook_URL \ --set slack.channel=your_channel_name \ --set slack.user=username
请记住将 your_hook_URL
替换为您之前记下的 webhook URL,将 your_channel_name
替换为所需通道的名称,并将 username
替换为创建 webhook 的用户的用户名。
因为传入了 --reuse-values
,Helm 将基于现有的 Flagger 版本发布新的 Flagger。 这意味着设置变量的现有值将保持不变,就像您在本教程的第一步中重新配置 Nginx 入口控制器时一样。
输出将类似于以下内容:
OutputRelease "flagger" has been upgraded. Happy Helming! NAME: flagger LAST DEPLOYED: ... NAMESPACE: default STATUS: deployed REVISION: 2 TEST SUITE: None NOTES: Flagger installed
您现在可以尝试通过运行以下命令发布新的 podinfo
部署:
kubectl set image deployment/podinfo podinfod=stefanprodan/podinfo:3.1.1 -n test
您很快就会在 Slack 中看到消息:
Slack 消息描述了有关金丝雀分析的基本信息,例如截止日期以及在中止部署之前测试可能失败的次数。 在 Traffic Routing 下,您可以看到路由流量的百分比在每次迭代期间增加了多少,直到达到显示的限制。
部署此版本时,您将看到一条成功消息:
让我们看看 Flagger 如何报告失败。 由于金丝雀要求所有 HTTP 请求(它从 Nginx 入口控制器读取)的成功率都为 99% s,因此您将创建一个新版本并在测试期间从中生成 HTTP 500 错误。
对于新版本,通过运行再次部署 6.0.3
版本:
kubectl set image deployment/podinfo podinfod=stefanprodan/podinfo:6.0.3 -n test
您将在 Slack 上看到一条来自 Flagger 的新消息,表明检测到新修订。 要模拟故障,您将使用 podinfo
的 status
API,它允许您生成您指定的 HTTP 状态报告。
运行以下命令创建大量 HTTP 500 状态:
watch curl http://app.your_domain/status/500
一段时间后,您会看到 Flagger 决定不应用新版本,因为 HTTP 请求成功率连续 10 次低得令人无法接受:
要退出 curl
,请按 CTRL+C
。
现在,只要检测到 podinfo
部署的新修订版,您就可以向 Slack 报告 Flagger。 您还将收到有关新版本结果的通知,因此您和您的团队将始终了解您的应用程序发布是否成功。
要销毁已部署的资源,请运行以下命令:
kubectl delete -f podinfo-ingress.yaml kubectl delete -f podinfo-canary.yaml
结论
您现在已经学习了如何使用 Flagger 自动测试推送到 Kubernetes 集群的新版本,而不会影响现有部署。 您还为 Slack 设置了警报,因此您将始终实时了解正在发生的部署,并主动通知您新版本中存在的问题。
canary 分析 流程可以通过高级 Prometheus 查询进行扩展——例如,根据 HTTP 请求延迟采取行动。 您可以在 Flagger 的 官方文档 中了解更多信息。