使用 Flagger 和 Istio 进行自动金丝雀部署

使用 Flagger 和 Istio 进行自动金丝雀部署

CD 被认为是一种企业软件实践,是既定 CI 原则自然演变的结果。 然而,CD 仍然很少见,这可能是由于管理的复杂性以及担心部署失败会影响系统可用性。

旗手 是一个开源的 Kubernetes 操作符,旨在消除混淆关系。 它使用 Istio 流量偏移和 Prometheus 指标自动促进金丝雀部署,以分析托管部署期间的应用程序行为。

以下是在 Google Kubernetes Engine (GKE) 上设置和使用 Flagger 的分步指南。

设置 Kubernetes 集群

您首先使用 Istio 附加组件创建一个 GKE 集群(如果您没有 GCP 帐户,您可以注册 这里 - 获得免费学分)。

登录 Google Cloud,创建项目,并为其启用计费。 安装命令行实用程序 并设置您的项目 gcloud init.

设置默认项目、计算区域和区域(替换 PROJECT_ID 为您的项目):

gcloud config set project PROJECT_ID
gcloud config set compute/region us-central1
gcloud config set compute/zone us-central1-a

启用 GKE 服务并使用 HPA 和 Istio 附加组件创建集群:

gcloud services enable container.googleapis.com
K8S_VERSION=$(gcloud beta container get-server-config --format=json | jq -r '.validMasterVersions[0]')
gcloud beta container clusters create istio 
--cluster-version=${K8S_VERSION} 
--zone=us-central1-a 
--num-nodes=2 
--machine-type=n1-standard-2 
--disk-size=30 
--enable-autorepair 
--no-enable-cloud-logging 
--no-enable-cloud-monitoring 
--addons=HorizontalPodAutoscaling,Istio 
--istio-config=auth=MTLS_PERMISSIVE

上面的命令将创建一个包含两个虚拟机的默认节点池 n1-standard-2 (vCPU:2,RAM 7,5 GB,磁盘:30 GB)。 理想情况下,您应该将 Istio 组件与您的工作负载隔离开来,但是没有简单的方法可以在专用节点池中运行 Istio Pod。 Istio 清单被认为是只读的,GKE 将撤消任何更改,例如链接到节点或从 pod 分离。

设置凭据 kubectl:

gcloud container clusters get-credentials istio

创建集群管理员角色绑定:

kubectl create clusterrolebinding "cluster-admin-$(whoami)" 
--clusterrole=cluster-admin 
--user="$(gcloud config get-value core/account)"

安装命令行工具 头盔:

brew install kubernetes-helm

Homebrew 2.0 现在也可用于 Linux.

为 Tiller 创建服务账户和集群角色绑定:

kubectl -n kube-system create sa tiller && 
kubectl create clusterrolebinding tiller-cluster-rule 
--clusterrole=cluster-admin 
--serviceaccount=kube-system:tiller

在命名空间中展开 Tiller kube-system:

helm init --service-account tiller

您应该考虑在 Helm 和 Tiller 之间使用 SSL。 有关保护 Helm 安装的更多信息,请参阅 文档.helm.sh

确认设置:

kubectl -n istio-system get svc

几秒钟后,GCP 应该为该服务分配一个外部 IP 地址 istio-ingressgateway.

配置 Istio 入口网关

使用名称创建静态 IP 地址 istio-gateway使用 Istio 网关的 IP 地址:

export GATEWAY_IP=$(kubectl -n istio-system get svc/istio-ingressgateway -ojson | jq -r .status.loadBalancer.ingress[0].ip)
gcloud compute addresses create istio-gateway --addresses ${GATEWAY_IP} --region us-central1

现在您需要一个 Internet 域并访问您的 DNS 注册商。 添加两条A记录(替换 example.com 到您的域):

istio.example.com   A ${GATEWAY_IP}
*.istio.example.com A ${GATEWAY_IP}

验证 DNS 通配符是否正常工作:

watch host test.istio.example.com

创建一个通用 Istio 网关以通过 HTTP 在服务网格外部提供服务:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: public-gateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - "*"

将上述资源保存为 public-gateway.yaml 然后应用它:

kubectl apply -f ./public-gateway.yaml

任何生产系统都不应在没有 SSL 的情况下在 Internet 上提供服务。 要使用证书管理器、CloudDNS 和 Let's Encrypt 保护 Istio 入口网关,请阅读 文件 弗拉格 G.K.E.

标记器安装

GKE Istio 附加组件不包含清理 Istio 遥测服务的 Prometheus 实例。 因为 Flagger 使用 Istio HTTP 指标来执行金丝雀分析,所以您需要部署以下 Prometheus 配置,类似于官方 Istio Helm 模式附带的配置。

REPO=https://raw.githubusercontent.com/stefanprodan/flagger/master
kubectl apply -f ${REPO}/artifacts/gke/istio-prometheus.yaml

添加 Flagger Helm 存储库:

helm repo add flagger [https://flagger.app](https://flagger.app/)

将 Flagger 扩展到命名空间 istio-system通过启用 Slack 通知:

helm upgrade -i flagger flagger/flagger 
--namespace=istio-system 
--set metricsServer=http://prometheus.istio-system:9090 
--set slack.url=https://hooks.slack.com/services/YOUR-WEBHOOK-ID 
--set slack.channel=general 
--set slack.user=flagger

您可以在任何命名空间中安装 Flagger,只要它可以与端口 9090 上的 Istio Prometheus 服务通信即可。

Flagger 有一个用于金丝雀分析的 Grafana 仪表板。 在命名空间中安装 Grafana istio-system:

helm upgrade -i flagger-grafana flagger/grafana 
--namespace=istio-system 
--set url=http://prometheus.istio-system:9090 
--set user=admin 
--set password=change-me

通过创建虚拟服务(替换 example.com 到您的域):

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: grafana
  namespace: istio-system
spec:
  hosts:
    - "grafana.istio.example.com"
  gateways:
    - public-gateway.istio-system.svc.cluster.local
  http:
    - route:
        - destination:
            host: flagger-grafana

将上面的资源保存为grafana-virtual-service.yaml 然后应用:

kubectl apply -f ./grafana-virtual-service.yaml

当移动到 http://grafana.istio.example.com 在浏览器中,您应该被定向到 Grafana 登录页面。

使用 Flagger 部署 Web 应用程序

Flagger 部署 Kubernetes 并可选择自动横向扩展 (HPA),然后创建一系列对象(Kubernetes 部署、ClusterIP 服务和 Istio 虚拟服务)。 这些对象将应用程序暴露给服务网格并控制金丝雀分析和进度。

使用 Flagger 和 Istio 进行自动金丝雀部署

创建启用 Istio Sidecar 注入的测试命名空间:

REPO=https://raw.githubusercontent.com/stefanprodan/flagger/master
kubectl apply -f ${REPO}/artifacts/namespaces/test.yaml

创建 deployment 和 pod 自动扩容工具:

kubectl apply -f ${REPO}/artifacts/canaries/deployment.yaml
kubectl apply -f ${REPO}/artifacts/canaries/hpa.yaml

部署测试负载服务以在金丝雀分析期间生成流量:

helm upgrade -i flagger-loadtester flagger/loadtester 
--namepace=test

创建自定义金丝雀资源(替换 example.com 到您的域):

apiVersion: flagger.app/v1alpha3
kind: Canary
metadata:
  name: podinfo
  namespace: test
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: podinfo
  progressDeadlineSeconds: 60
  autoscalerRef:
    apiVersion: autoscaling/v2beta1
    kind: HorizontalPodAutoscaler
    name: podinfo
  service:
    port: 9898
    gateways:
    - public-gateway.istio-system.svc.cluster.local
    hosts:
    - app.istio.example.com
  canaryAnalysis:
    interval: 30s
    threshold: 10
    maxWeight: 50
    stepWeight: 5
    metrics:
    - name: istio_requests_total
      threshold: 99
      interval: 30s
    - name: istio_request_duration_seconds_bucket
      threshold: 500
      interval: 30s
    webhooks:
      - name: load-test
        url: http://flagger-loadtester.test/
        timeout: 5s
        metadata:
          cmd: "hey -z 1m -q 10 -c 2 http://podinfo.test:9898/"

将上述资源保存为 podinfo-canary.yaml 然后应用它:

kubectl apply -f ./podinfo-canary.yaml

上述分析如果成功,将运行五分钟,每半分钟检查一次 HTTP 指标。 您可以使用以下公式确定验证和推广金丝雀部署所需的最短时间: interval * (maxWeight / stepWeight). 记录了 Canary CRD 字段 这里.

几秒钟后,Flagger 将创建金丝雀对象:

# applied 
deployment.apps/podinfo
horizontalpodautoscaler.autoscaling/podinfo
canary.flagger.app/podinfo
# generated 
deployment.apps/podinfo-primary
horizontalpodautoscaler.autoscaling/podinfo-primary
service/podinfo
service/podinfo-canary
service/podinfo-primary
virtualservice.networking.istio.io/podinfo

打开浏览器并转到 app.istio.example.com, 你应该看到版本号 演示应用.

自动金丝雀分析和推广

Flagger 实现了一个控制循环,逐渐将流量转移到金丝雀,同时测量关键性能指标,例如 HTTP 请求成功率、平均请求持续时间和 pod 健康状况。 根据KPI分析,推进或中断金丝雀,并将分析结果发布到Slack。

使用 Flagger 和 Istio 进行自动金丝雀部署

当以下对象之一发生更改时,会触发金丝雀部署:

  • 部署 PodSpec(容器镜像、命令、端口、环境等)
  • ConfigMap 挂载为卷或映射到环境变量
  • 秘密作为卷安装或转换为环境变量

更新容器镜像时运行 canary deploy:

kubectl -n test set image deployment/podinfo 
podinfod=quay.io/stefanprodan/podinfo:1.4.1

Flagger 检测到部署版本已更改并开始解析它:

kubectl -n test describe canary/podinfo

Events:

New revision detected podinfo.test
Scaling up podinfo.test
Waiting for podinfo.test rollout to finish: 0 of 1 updated replicas are available
Advance podinfo.test canary weight 5
Advance podinfo.test canary weight 10
Advance podinfo.test canary weight 15
Advance podinfo.test canary weight 20
Advance podinfo.test canary weight 25
Advance podinfo.test canary weight 30
Advance podinfo.test canary weight 35
Advance podinfo.test canary weight 40
Advance podinfo.test canary weight 45
Advance podinfo.test canary weight 50
Copying podinfo.test template spec to podinfo-primary.test
Waiting for podinfo-primary.test rollout to finish: 1 of 2 updated replicas are available
Promotion completed! Scaling down podinfo.test

在分析期间,可以使用 Grafana 跟踪金丝雀结果:

使用 Flagger 和 Istio 进行自动金丝雀部署

请注意,如果在金丝雀分析期间将新更改应用于部署,则 Flagger 将重新启动分析阶段。

列出集群中的所有金丝雀:

watch kubectl get canaries --all-namespaces
NAMESPACE   NAME      STATUS        WEIGHT   LASTTRANSITIONTIME
test        podinfo   Progressing   15       2019-01-16T14:05:07Z
prod        frontend  Succeeded     0        2019-01-15T16:15:07Z
prod        backend   Failed        0        2019-01-14T17:05:07Z

如果您启用了 Slack 通知,您将收到以下消息:

使用 Flagger 和 Istio 进行自动金丝雀部署

自动回滚

在 Canary 分析期间,您可以生成合成 HTTP 500 错误和高响应延迟,以查看 Flagger 是否会停止部署。

创建一个测试 pod 并在其中执行以下操作:

kubectl -n test run tester 
--image=quay.io/stefanprodan/podinfo:1.2.1 
-- ./podinfo --port=9898
kubectl -n test exec -it tester-xx-xx sh

生成 HTTP 500 错误:

watch curl http://podinfo-canary:9898/status/500

延迟生成:

watch curl http://podinfo-canary:9898/delay/1

当失败的检查次数达到阈值时,流量被路由回主通道,金丝雀缩放为零,部署被标记为失败。

Canary 错误和延迟峰值被记录为 Kubernetes 事件,并由 Flagger 以 JSON 格式记录:

kubectl -n istio-system logs deployment/flagger -f | jq .msg

Starting canary deployment for podinfo.test
Advance podinfo.test canary weight 5
Advance podinfo.test canary weight 10
Advance podinfo.test canary weight 15
Halt podinfo.test advancement success rate 69.17% < 99%
Halt podinfo.test advancement success rate 61.39% < 99%
Halt podinfo.test advancement success rate 55.06% < 99%
Halt podinfo.test advancement success rate 47.00% < 99%
Halt podinfo.test advancement success rate 37.00% < 99%
Halt podinfo.test advancement request duration 1.515s > 500ms
Halt podinfo.test advancement request duration 1.600s > 500ms
Halt podinfo.test advancement request duration 1.915s > 500ms
Halt podinfo.test advancement request duration 2.050s > 500ms
Halt podinfo.test advancement request duration 2.515s > 500ms
Rolling back podinfo.test failed checks threshold reached 10
Canary failed! Scaling down podinfo.test

如果您启用了 Slack 通知,当超过截止日期或达到分析中失败检查的最大数量时,您将收到一条消息:

使用 Flagger 和 Istio 进行自动金丝雀部署

总之

除了 Kubernetes 之外,运行像 Istio 这样的服务网格将提供自动指标、日志和协议,但工作负载部署仍然依赖于外部工具。 Flagger 旨在通过添加 Istio 功能来改变这一点 累进供应.

Flagger 与任何 Kubernetes CI/CD 解决方案兼容,并且可以轻松扩展金丝雀分析 网络钩子 执行系统集成/验收测试、负载测试或任何其他自定义检查。 由于 Flagger 是声明式的并且响应 Kubernetes 事件,它可以与 GitOps 管道一起使用 编织助焊剂 или 詹金斯X. 如果您使用的是 JenkinsX,则可以使用 jx 插件安装 Flagger。

支持旗手 织布厂 并提供金丝雀部署 织云. 该项目正在使用 kubeadm 在 GKE、EKS 和裸机上进行测试。

如果您有改进 Flagger 的建议,请在 GitHub 上提交问题或 PR stefanprodan/举报人. 我们非常欢迎您的贡献!

谢谢 曾雷.

来源: habr.com

添加评论