知识中心

Flagger(应用自动发布)介绍和原理剖析-阿里云开发者社区

2020-03-09 00:00:00 mimukeji

简介

Flagger是一个能使运行在k8s体系上的应用发布流程全自动(无人参与)的工具, 它能减少发布的人为关注时间, 并且在发布过程中能自动识别一些风险(例如:RT,成功率,自定义metrics)并回滚.

主要特性

features

整体架构

arch
简单介绍下上图含义:
• primary service: 服务稳定版本. 可以理解为已发布在线的服务
• canary service: 即将发布的新版本服务.
• Ingress: 服务网关.
• Flagger: 会通过flagger spec(下面会介绍), 以ingress/service mesh的规范来调整primary和canary的流量策略.以此来达到A/B testing, blue/green, canary(金丝雀)发布效果. 在调整流量过程中, 根据prometheus采集的各项指标(RT,成功率等)来决策是否回滚发布或者继续调整流量比例。在此过程中,用户可以自定义是否人工干预,审核,收到通知等.

实现原理

注: 以下原理介绍, 主要基于以下的官方的实例说明:

apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: podinfo
  namespace: test
spec:
  # service mesh provider (optional)
  # can be: kubernetes, istio, linkerd, appmesh, nginx, contour, gloo, supergloo
  provider: istio
  # deployment reference
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: podinfo
  # the maximum time in seconds for the canary deployment
  # to make progress before it is rollback (default 600s)
  progressDeadlineSeconds: 60
  # HPA reference (optional)
  autoscalerRef:
    apiVersion: autoscaling/v2beta1
    kind: HorizontalPodAutoscaler
    name: podinfo
  service:
    # service name (defaults to targetRef.name)
    name: podinfo
    # ClusterIP port number
    port: 9898
    # container port name or number (optional)
    targetPort: 9898
    # port name can be http or grpc (default http)
    portName: http
    # add all the other container ports
    # to the ClusterIP services (default false)
    portDiscovery: true
    # HTTP match conditions (optional)
    match:
      - uri:
          prefix: /
    # HTTP rewrite (optional)
    rewrite:
      uri: /
    # request timeout (optional)
    timeout: 5s
  # promote the canary without analysing it (default false)
  skipAnalysis: false
  # define the canary analysis timing and KPIs
  analysis:
    # schedule interval (default 60s)
    interval: 1m
    # max number of failed metric checks before rollback
    threshold: 10
    # max traffic percentage routed to canary
    # percentage (0-100)
    maxWeight: 50
    # canary increment step
    # percentage (0-100)
    stepWeight: 5
    # validation (optional)
    metrics:
    - name: request-success-rate
      # builtin Prometheus check
      # minimum req success rate (non 5xx responses)
      # percentage (0-100)
      thresholdRange:
        min: 99
      interval: 1m
    - name: request-duration
      # builtin Prometheus check
      # maximum req duration P99
      # milliseconds
      thresholdRange:
        max: 500
      interval: 30s
    - name: "database connections"
      # custom Prometheus check
      templateRef:
        name: db-connections
      thresholdRange:
        min: 2
        max: 100
      interval: 1m
    # testing (optional)
    webhooks:
      - name: "conformance test"
        type: pre-rollout
        url: http://flagger-helmtester.test/
        timeout: 5m
        metadata:
          type: "helmv3"
          cmd: "test run podinfo -n test"
      - name: "load test"
        type: rollout
        url: http://flagger-loadtester.test/
        metadata:
          cmd: "hey -z 1m -q 10 -c 2 http://podinfo.test:9898/"
    # alerting (optional)
    alerts:
      - name: "dev team Slack"
        severity: error
        providerRef:
          name: dev-slack
          namespace: flagger
      - name: "qa team Discord"
        severity: warn
        providerRef:
          name: qa-discord
      - name: "on-call MS Teams"
        severity: info
        providerRef:
          name: on-call-msteams

简单介绍以上配置含义, 下方会单独详细介绍:
• targetRef: 当前部署的新版本服务(可以是Deployment, 也可以是DaemonSet).
• progressDeadlineSeconds: canary, primary部署超时时间.如果超过这个时间还没有部署好,则不会进行流量调整了。
• autoscalerRef: K8s原生的HPA(自动伸缩).
• service: 可以理解为k8s service概念。当provider是Istio时, 和VirtualSercice(具有调整流量比例,路由策略等能力)相对应
• skipAnalysis:是否跳过metrcis分析. 如果为true, 相当于一次性将primary替换成canary service.
• analysis:
• 包含一些调整primary, canary流量策略配置
• metrics: 指标来源. 例如: avg RT, 成功率, 自定义metrics(可以直接配置prometheus PQL)等
• webhook:可以用来人工审核接入, 压力测试等.
• alerts: 进度详情, 告警通知等

整体流程

flow
说明:
• 上图Start到End的整个流程是在一个定时器中执行
• 上图中cancary和Canary不是同一个含义. Canary一般指Canary(Kind)对象或者指Canary 部署策略, canary指的是targetRef的对象(deployment, service)。
VirtualSerivice(privider是Istio): 是A/B testing, Blue/Green, Canry Release实现的关键. 具体可以参考Istio关于VirtualService相关介绍
• 关于A/B testing, Blue/Green, Canary下文会详细介绍

部署策略

A/B testing

analysis:
    # schedule interval (default 60s)
    interval: 1m
    # total number of iterations
    iterations: 10
    # max number of failed iterations before rollback
    threshold: 2
    # canary match condition
    match:
      - headers:
          x-canary:
            regex: ".*insider.*"
      - headers:
          cookie:
            regex: "^(.*?;)?(canary=always)(;.*)?$"

以上面代码示例为例:
• 会在创建VirtualService过(istio)程中, 设置多个HTTPRoute.
• 默认流量, 访问primary service
• 通过http header或者cookie 正则匹配方式, 将流量路由到canary service.
• 整个流程会执行10次,每次间隔1分钟, 最多允许2次metrics验证失败. 如果超过2次, 则进行回滚.
• 正常结束后, 会执行"confirm-promotion" webhook, 确认是否将primary替换成cannay

• 如果是, 会将primary替换成cananry的spec(deployemnt spec, configmap)相关信息
• 如果否, 继续等待

Blue/Green

 analysis:
    # schedule interval (default 60s)
    interval: 1m
    # total number of iterations
    iterations: 10
    # max number of failed iterations before rollback
    threshold: 2
    webhooks:
     - name: "load test"
       type: rollout
       url: http://flagger-loadtester.test/
       metadata:
         cmd: "hey -z 1m -q 10 -c 2 http://podinfo.test:9898/"

以上面代码示例为例:
• 整个流程会执行10次,每次间隔1分钟, 最多允许2次metrics验证失败.如果超过2次, 则进行回滚.
• 在这段时间会对canary service进行压力测试
• 正常结束后, 会执行"confirm-promotion" webhook, 确认是否将primary替换成cannay

• 如果是, 会将primary替换成cananry的spec(deployemnt spec, configmap)相关信息
• 如果否, 继续等待

如果配置了mirror=true(只有provider=istio时才支持该特性), 则会使用istio的mirror特性, 将流量分别copy 到primary和canary, 使用primary的reponse作为返回值. 这个时候要特别注意业务是否幂等.

Canary

analysis:
    # schedule interval (default 60s)
    interval: 1m
    # max number of failed metric checks before rollback
    threshold: 2
    # max traffic percentage routed to canary
    # percentage (0-100)
    maxWeight: 50
    # canary increment step
    # percentage (0-100)
    stepWeight: 2
  # deploy straight to production without
  # the metrics and webhook checks
  skipAnalysis: false

以上面代码示例为例:
• 整个流程会执行25(maxWeight/maxWeight)次,每次间隔1分钟, 最多允许2次metrics验证失败.如果超过2次, 则进行回滚.
• 每次primary减少stepWeight%流量, canary增加stepWeight%流量, 直到canary到达maxWeight
• 执行"confirm-promotion" webhook, 确认是否将primary替换成cannay

• 如果是, 会将primary替换成cananry的spec(deployemnt spec, configmap)相关信息
• 如果否, 继续等待

其它

Webhooks

webhooks: 在整个发布过程中, 定义了相应的扩展点:
• confirm-rollout: 在canary接收流量之前执行. 可以用于人工审核发布, 自动化测试通过等场景.
如果该webhook没有返回成功(例如:请求返回状态码200), 则发布一直等待.
• pre-rollout: 在第一次切流到canary前执行的webhook. 如果执行失败次数超过阀值, 则进行回滚
• rollout: 在发布的每个周期(例如每个stepWeight)中的metrics分析之前执行.如果执行失败次数超过阀值, 则进行回滚
• confirm-promotion: 在primary变更到canary配置相关信息之前执行.
如果不成功, 会一直等待.在等待的过程中, Flagger会继续执行metrics验证直到最终回滚.
• post-rollout: 在rollback或者finish后执行. 如果执行失败只会记录Event日志。
• rollback: 当Canary处于Progressing或者Waiting状态时. 提供人工执行回滚的能力.
• event: 在每个生命周期,都会产生一些相关k8s event. 如果配置event webhook, 则在产生k8s event的同时,发送相关event事件信息.

Metrics

Metrics: 用于决策(A/B, Blue/Green, Canary)流量是否验证失败, 超过制定阀值(threshold)就会回滚发布
• 缺省自带的metrics

analysis:
    metrics:
    - name: request-success-rate
      interval: 1m
      # minimum req success rate (non 5xx responses)
      # percentage (0-100)
      thresholdRange:
        min: 99
    - name: request-duration
      interval: 1m
      # maximum req duration P99
      # milliseconds
      thresholdRange:
        max: 500
  • request-success-rate(请求成功率). 上例说明成功率不能低于99%
  • request-duration(avg RT): RT均值不能超过500ms
    request-success-rate和request-duration是Flagger缺省自带的metrics.

不同的provider有不通实现. 例如:应用可以提供prometheus metrics

• 自定义metrics

  1. 创建MetricTemplate. 比如业务自定义的业务metrics, 如订单支付失败率
apiVersion: flagger.app/v1beta1
kind: MetricTemplate
metadata:
  name: not-found-percentage
  namespace: istio-system
spec:
  provider:
    type: prometheus
    address: http://promethues.istio-system:9090
  query: |
    100 - sum(
        rate(
            istio_requests_total{
              reporter="destination",
              destination_workload_namespace="{{ namespace }}",
              destination_workload="{{ target }}",
              response_code!="404"
            }[{{ interval }}]
        )
    )
    /
    sum(
        rate(
            istio_requests_total{
              reporter="destination",
              destination_workload_namespace="{{ namespace }}",
              destination_workload="{{ target }}"
            }[{{ interval }}]
        )
    ) * 100
  1. 引用MetricTemplate

    analysis:
       metrics:
    - name: "404s percentage"
     templateRef:
       name: not-found-percentage
       namespace: istio-system
     thresholdRange:
       max: 5
     interval: 1m

    上例表示canary的关于404错误/s的metrics不能超过5%

Alter

Alter: 用于发布过程中信息通知.
1.定义AlterProvider(可以是slack, 也可以是dingding)

apiVersion: flagger.app/v1beta1
kind: AlertProvider
metadata:
  name: on-call
  namespace: flagger
spec:
  type: slack
  channel: on-call-alerts
  username: flagger
  # webhook address (ignored if secretRef is specified)
  address: https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
  # secret containing the webhook address (optional)
  secretRef:
    name: on-call-url
---
apiVersion: v1
kind: Secret
metadata:
  name: on-call-url
  namespace: flagger
data:
  address: <encoded-url>

2.使用Alter

analysis:
    alerts:
      - name: "on-call Slack"
        severity: error
        providerRef:
          name: on-call
          namespace: flagger

• serverity: 通知信息的等级, 类似日志级别. 包含info, warn, error
在整个部署过程中,不同阶段都会使用alter来发送通知信息, 例如发布成功, webhook执行失败等场景。

总结

• Flagger对应用自动化发布流程进行了很好的抽象, 提供了丰富的扩展机制(webhook, alter, metrics等).
这些特性比较吸引人,那是否能能直接就能在集团内使用呢?
答案是不行。Flagger要求应用构建在k8s基础上, 例如服务发现机制, 另外要求部署Ingress/service mesh(这两者都具备调整流量策略的能力). 以HSF为例,它的服务发现机制是根据configserver, 服务是面向接口, 而不是应用。
如果不经过一定改造,估计还是无法使用.

• 另外Flagger也有一些改进的地方(我个人人为):
canary实例在切流过程中的扩缩容是根据HPA(如果配置了)来进行的, HPA扩缩容不及时就会对业务有影响.
改进方案: 可以根据stepWeight的变化动态调整canary的实例数, 这个只针对Canary release.
对于Blue/Green, A/B tesing可以通过webhook提前准备容量.

• Flagger正在规划primary和canary流量比较特性,这个似乎和集团Doom干的是同一件事情。未来可以期待一下.