paint-brush
CI/CD 实践:简单但实用的持续部署工作流程 [第 2 部分]经过@j04n
429 讀數
429 讀數

CI/CD 实践:简单但实用的持续部署工作流程 [第 2 部分]

经过 Joan Flotats14m2023/10/10
Read on Terminal Reader

太長; 讀書

手动部署不容易出错。此外,它们由一堆重复且复杂的任务组成。本文探讨了部署流程的自动化,以使用 FluxCD、Flagger 和 Grafana 将其转换为持续部署流程。
featured image - CI/CD 实践:简单但实用的持续部署工作流程 [第 2 部分]
Joan Flotats HackerNoon profile picture
0-item
1-item


手动部署不容易出错。此外,它们由一堆重复且复杂的任务组成。开发团队担心部署新版本应用程序的复杂性及其带来的麻烦。有时,部署应用程序需要高级平台技能。调试部署问题是一个乏味的过程。


FluxCD可帮助您减少手动和重复性任务的工作量。它还最大限度地减少了部署错误和人机交互。它提供了使用声明性文件跟踪和更新部署状态的工具,使开发团队的部署和调试过程更加轻松。


本文探讨了部署流程的自动化,以使用FluxCDFlaggerGrafana将其转换为持续部署流程。


查看第一篇文章,了解有关持续交付应用程序的更多信息:

CI/CD 实践:简单但实用的持续集成工作流程 [第 1 部分]



介绍

使用KinDTerraform设置 Kubernetes 集群。首先,创建集群并导出 Kubernetes 配置以设置 Kubernetes 提供程序:


 $ kind create cluster --name develop $ kind export kubeconfig --name develop --kubeconfig kubeconfig


创建一个新的 GitHub 存储库和具有存储库权限的开发人员令牌,Terrafom 需要它来设置 FluxCD。初始化 Terraform 并应用更改:


 $ terraform init $ terraform apply -var="github_owner=owner_name" -var="github_repository=repo_name" # Introduce your GitHub token


Terraform 完成安装过程后,您应该在 KinD 集群中运行 FluxCD,并在存储库中创建一个名为cluster的新文件夹。


地形

在幕后,Terraform 安装MetalLB并配置 IP 范围。您可以在文章的第一部分中阅读有关 MetalLB 配置的更多信息:


 resource "helm_release" "metallb" { name = "metallb" repository = "https://metallb.github.io/metallb" chart = "metallb" } data "docker_network" "kind" { name = "kind" } resource "kubectl_manifest" "kind-address-pool" { yaml_body = yamlencode({ "apiVersion" : "metallb.io/v1beta1", "kind" : "IPAddressPool", "metadata" : { "name" : "kind-address-pool" }, "spec" : { "addresses" : [replace(tolist(data.docker_network.kind.ipam_config)[0].subnet, ".0.0/16", ".255.0/24")] } }) depends_on = [helm_release.metallb] } resource "kubectl_manifest" "kind-advertisement" { yaml_body = <<YAML apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: kind-advertisement YAML depends_on = [helm_release.metallb] }


然后,它安装 FLuxCD Helm Chart 并配置 GitHub 存储库以使用 FluxCD:


 resource "helm_release" "flux" { repository = "https://fluxcd-community.github.io/helm-charts" chart = "flux2" name = "flux2" namespace = "flux-system" create_namespace = true version = "2.9.2" } resource "tls_private_key" "flux" { depends_on = [helm_release.flux] algorithm = "ECDSA" ecdsa_curve = "P256" } resource "github_repository_deploy_key" "flux" { depends_on = [tls_private_key.flux] title = "Flux" repository = var.github_repository key = tls_private_key.flux.public_key_openssh read_only = "false" } resource "flux_bootstrap_git" "this" { depends_on = [github_repository_deploy_key.flux] path = "clusters/develop" }


预提交挂钩建议:

  1. Terraformhttps://github.com/antonbabenko/pre-commit-terraform ):
    • TFSec:Terraform 的静态分析以发现潜在的错误配置
    • TFLint:Terraform 的静态格式检查器
  2. 检测秘密https://github.com/Yelp/detect-secrets ):防止新的秘密进入代码库。


助焊剂CD

FluxCD是一个 GitOps 工具,用于使 Kubernetes 集群保持最新的源代码控制更改(如 Git 存储库)。 Flux 自动部署新代码。


Flux 在集群中运行后,让我们看看它是如何工作的。我们将部署 ingress-nginx 作为入口提供程序。 Flux 不强制执行项目文件夹结构。您可以根据需要进行配置或遵循您的首选标准。


在名为基础设施的文件夹内创建名为base的文件夹。基本文件夹包含所有集群的基本基础架构配置。接下来,创建一个名为ingress-nginx的文件夹。使用命名空间名称作为文件夹名称。


 --- apiVersion: v1 kind: Namespace metadata: name: ingress-ngnix --- apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: HelmRepository metadata: name: ingress-nginx spec: interval: 2h url: https://kubernetes.github.io/ingress-nginx --- apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: ingress-nginx spec: interval: 15m chart: spec: chart: ingress-nginx version: 4.7.1 sourceRef: kind: HelmRepository name: ingress-nginx interval: 15m --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: ingress-ngnix resources: - namespace.yaml - helmrepository.yaml - helmrelease.yaml


使用多个文件来定义对象: helmrelease.yamlhelmrepository.yamlnamespace.yamlkustomization.yaml等。


Kustomization读取并处理资源以应用它们。最后但并非最不重要的一点是,您需要创建一个 Kustomization 对象来同步集群配置。在cluster/cluster_name文件夹中创建一个名为基础设施.yaml的 YAML 文件:


 --- apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: infra-base namespace: flux-system spec: interval: 1h retryInterval: 1m timeout: 5m sourceRef: kind: GitRepository name: flux-system path: ./infrastructure/base prune: true wait: true


提交更改并将其推送到存储库后,Flux 将协调集群状态以安装 ingress-nginx Helm Chart。


弗拉格

Flagger是一个 Kubernetes 操作员,它使用蓝/绿部署、金丝雀发布或 A/B 测试逐步交付您的应用程序。


您可以使用基本文件夹将堆栈安装到所有集群中,或使用不同的文件夹根据集群自定义安装。例如,我们只想将 Flagger 安装到开发集群中。


使用您的集群名称在基础架构文件夹中创建一个新文件夹。然后,在cluster/cluster_name中创建一个名为 i nfrastruct.yaml的文件:


 --- apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: infra-cluster-name namespace: flux-system spec: dependsOn: - name: infra-base interval: 1h retryInterval: 1m timeout: 5m sourceRef: kind: GitRepository name: flux-system path: ./infrastructure/cluster_name prune: true


FluxCD 将在应用基础设施 Kustomization 后同步集群状态。安装 Flagger,在基础设施/cluster_name/flaagger-system文件夹中创建以下 YAML 文件:


 --- apiVersion: v1 kind: Namespace metadata: name: flagger-system --- apiVersion: source.toolkit.fluxcd.io/v1beta2 kind: HelmRepository metadata: name: flagger spec: interval: 1h url: https://flagger.app --- apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: flagger spec: interval: 1h install: crds: CreateReplace upgrade: crds: CreateReplace chart: spec: chart: flagger version: 1.xx interval: 6h sourceRef: kind: HelmRepository name: flagger --- apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: flagger-loadtester spec: interval: 1h chart: spec: chart: loadtester version: 0.xx interval: 6h sourceRef: kind: HelmRepository name: flagger --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: flagger-system resources: - namespace.yaml - helmrepository.yaml - helmrelease.yaml


持续部署

要构建Podinfo应用程序持续部署管道,请在apps/cluster_name/podinfo *:* 中创建安装 YAML 文件


--- apiVersion: v1 kind: Namespace metadata: name: podinfo --- apiVersion: source.toolkit.fluxcd.io/v1beta2 kind: HelmRepository metadata: name: podinfo spec: interval: 5m url: https://stefanprodan.github.io/podinfo --- apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: podinfo spec: releaseName: podinfo chart: spec: chart: podinfo version: 6.5.0 sourceRef: kind: HelmRepository name: podinfo interval: 50m install: remediation: retries: 3 values: ingress: enabled: true className: nginx hpa: enabled: true --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: podinfo resources: - namespace.yaml - helmrepository.yaml - helmrelease.yaml


您可以使用更新主机 Python 脚本来更新本地环境主机,如本文第一部分中所述。


然后,在cluster/cluster_name文件夹中创建 Kustomization 文件以同步您的应用程序:


 --- apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: apps namespace: flux-system spec: interval: 10m0s dependsOn: - name: infra-cluster-name sourceRef: kind: GitRepository name: flux-system path: ./apps/cluster_name prune: true wait: true timeout: 5m0s


接下来,我们可以配置 FluxCD 自动更新 Podinfo 镜像 Helm Chart 版本。要配置映像自动更新,我们需要创建一个映像存储库来扫描新的映像标签,一个映像更新策略来定义要更新的版本模式,以及一个映像自动更新来配置存储库以推送更改。


 --- apiVersion: image.toolkit.fluxcd.io/v1beta2 kind: ImageRepository metadata: name: podinfo-chart spec: image: ghcr.io/stefanprodan/charts/podinfo interval: 5m --- apiVersion: image.toolkit.fluxcd.io/v1beta2 kind: ImagePolicy metadata: name: podinfo-chart spec: imageRepositoryRef: name: podinfo-chart policy: semver: range: 6.xx --- apiVersion: image.toolkit.fluxcd.io/v1beta1 kind: ImageUpdateAutomation metadata: name: podinfo-chart spec: interval: 30m sourceRef: kind: GitRepository name: flux-system namespace: flux-system git: checkout: ref: branch: main commit: author: email: [email protected] name: fluxcdbot messageTemplate: 'chore(develop): update podinfo chart to {{range .Updated.Images}}{{println .}}{{end}}' push: branch: main update: path: ./apps/cluster_name/podinfo strategy: Setters --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: podinfo resources: [...] - imagepolicy.yaml - imagerepository.yaml - imageautoupdate.yaml


最后,将图像更新策略应用到要更新的图像或标签:


 apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: podinfo spec: releaseName: podinfo chart: spec: chart: podinfo version: 6.5.0 # {"$imagepolicy": "podinfo:podinfo-chart:tag"} sourceRef: kind: HelmRepository name: podinfo interval: 50m install: remediation: retries: 3


每当 Podinfo Chart 有 6.xx 范围内的新版本时,FluxCD 都会将提交推送到存储库,用较新的版本更新当前版本。


通量CD。 https://fluxcd.io/flux/components/image


金丝雀发布

向一小部分用户发布新的应用程序版本,以确保应用程序的功能、性能和安全性达到预期。 FluxCD 自动更新 Chart 版本并将其提供给用户。如果出现故障,FluxCD 会自动将映像版本回滚到之前的版本。

Flagger 逐步将新的应用程序版本交付给一部分用户并监控应用程序状态。它为新的应用程序版本创建新的部署,并逐步将传入流量重定向到新的部署。成功分析指标后,它将促进金丝雀部署。如果发生故障,Flagger 会删除新部署并重新建立到旧部署的流量。此过程假装在将应用程序交付给所有用户之前检测到缺陷、问题和错误。



旗手。 https://docs.flaagger.app/tutorials/nginx-progressive-delivery


首先,创建一个指标模板,让 Flagger 知道哪个是应用程序状态。我们使用Prometheus来衡量请求成功率:


 --- apiVersion: flagger.app/v1beta1 kind: MetricTemplate metadata: name: podinfo-request-success-rate spec: provider: type: prometheus address: http://loki-stack-prometheus-server.loki-stack:80 query: | 100 - sum( rate( http_requests_total{ app_kubernetes_io_name="podinfo", namespace="{{ namespace }}", status!~"5.*" }[{{ interval }}] ) ) / sum( rate( http_requests_total{ app_kubernetes_io_name="podinfo", namespace="{{ namespace }}", }[{{ interval }}] ) ) * 100 --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: podinfo resources: [...] - metrictemplate.yaml


然后,定义金丝雀发布流程。我们使用 nginx 作为提供者来调整传入流量。 Flagger 提供了多种方法和工具来配置您的版本。


 --- apiVersion: flagger.app/v1beta1 kind: Canary metadata: name: podinfo spec: provider: nginx targetRef: apiVersion: apps/v1 kind: Deployment name: podinfo ingressRef: apiVersion: networking.k8s.io/v1 kind: Ingress name: podinfo autoscalerRef: apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler name: podinfo progressDeadlineSeconds: 60 service: port: 9898 targetPort: 9898 analysis: interval: 10s threshold: 10 maxWeight: 50 stepWeight: 5 metrics: - name: podinfo-request-success-rate thresholdRange: min: 99 interval: 1m webhooks: - name: acceptance-test type: pre-rollout url: http://flagger-loadtester.flagger-system/ timeout: 30s metadata: type: bash cmd: curl -sd 'test' http://podinfo-canary.podinfo:9898/token | grep token - name: load-test url: http://flagger-loadtester.flagger-system/ timeout: 5s metadata: cmd: hey -z 1m -q 10 -c 2 http://podinfo-canary.podinfo:9898/healthz --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: podinfo resources: [...] - canary.yaml


Flagger 需要对您的部署、入口和 Pod 自动扩展器的引用。每当Flagger检测到新版本时,它就会扩大部署,创建主服务和辅服务,并配置nginx将传入流量发送到相应的服务。使用 maxWeight 和 stepWeight 属性来配置最大流量重定向百分比和增量步长百分比。

使用 Flagger hook 对您的应用程序进行负载测试。它有多个挂钩。验收挂钩检查金丝雀部署准备情况,负载测试挂钩生成持续的传入流量。

Flagger 将使用预定义的成功率指标来监控金丝雀发布状态,以决定金丝雀部署升级案例。 Flagger 预计请求成功率将达到 99%,以促进金丝雀部署。使用阈值属性配置回滚之前失败指标检查的最大数量。


监控

使用Loki堆栈使用Grafana + Loki + Prometheus监控集群资源的状态。通过在基础设施/cluster_name/loki-stack文件夹中创建以下 YAML 文件来安装 Loki 堆栈:


 --- apiVersion: v1 kind: Namespace metadata: name: loki-stack --- apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: HelmRepository metadata: name: grafana spec: interval: 2h url: https://grafana.github.io/helm-charts --- apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: loki-stack spec: interval: 1h chart: spec: chart: loki-stack version: v2.9.11 sourceRef: kind: HelmRepository name: grafana interval: 1h values: grafana: enabled: true ingress: enabled: true annotations: kubernetes.io/ingress.class: nginx hosts: - grafana.local prometheus: enabled: true nodeExporter: enabled: true --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: loki-stack resources: - namespace.yaml - helmrepository.yaml - helmrelease.yaml


Loki 堆栈安装使 Grafana Ingress 能够访问 Grafana,Prometheus 能够收集您的环境指标,Node Exporter 能够导出您的节点指标。


您可以使用更新主机 Python 脚本来更新本地环境主机,如本文第一部分中所述


使用管理员用户名和密码登录 Grafana。您可以使用安装值定义管理员密码。默认情况下,Chart 创建一个 Kubernetes 密钥来存储随机密码。描述秘密以获取 Base64 密码值并对其进行解码。


您可以使用 ID 或复制原始 JSON 导入您最喜欢的仪表板:


Grafana - Prometheus K8s 仪表板


Grafana - Prometheus FluxCD 仪表板


Grafana - Loki 日志


结论

第一篇文章探讨了如何交付经过充分测试的应用程序。本文探讨如何持续部署可交付成果并监控部署的状态。


FluxCD 和 Flagger 提供多种功能来持续测试、部署和监控您的应用程序状态。本文使用了其中的一些,但我们没有看到 webhooks 和通知功能。使用通知功能了解部署何时失败,或使用 Web 挂钩功能将部署提升到新环境或针对新版本启动测试。将 FluxCD 与其他工具集成以丰富您的部署管道。

避免手动部署。它们很复杂并且不易出错。鼓励开发团队维护他们的应用程序,使部署过程更加容易。自动部署减少了交付时间、反馈循环和总体成本。开发人员可以专注于真正重要的事情。