Istio 结合 Flagger 进行灰度发布

灰度发布也叫金丝雀部署 ,是指通过控制流量的比例,实现新老版本的逐步替换。比如对于服务 A 有两个版本(蓝和绿两个版本),当前两个版本同时部署,但是 version1 比例 90% ,version2 比例 10% ,然后我们可以观察 version2 的实际运行效果,如果符合预期,则可以逐步调整流量占比,比如调整为 80:20 -> 70:30 -> 10:90 -> 0:100 ,最终 version1 版本下线,全部替换成 version2 版本。如果验证失败,切换 100%流量回 v1 版本(回滚)。灰度发布的特点是:

flagger

在 Istio 中要实现灰度发布有多种方案,比如 Flagger、Argo Rollouts 等。

Flagger

Flagger 是一个渐进式交付的 Kubernetes Operator,它可以自动执行 Kubernetes 上运行的应用程序的发布过程。它通过在测量指标和运行一致性测试的同时逐渐将流量转移到新版本,降低了在生产中引入新软件版本的风险。

Flagger 通过使用服务网格(App Mesh、Istio、Linkerd、Kuma、Open Service Mesh)或 Ingress 控制器(Contour、Gloo、NGINX、Skipper、 Traefik、APISIX)用于流量路由。对于发布分析,Flagger 可以查询 Prometheus、InfluxDB、Datadog、New Relic、CloudWatch、Stackdriver 或 Graphite,并使用 Slack、MS Teams、Discord 和 Rocket 来发出警报。

Flagger

Flagger 可以使用 Kubernetes CRD 进行配置,并且与任何为 Kubernetes 制作的 CI/CD 解决方案兼容。由于 Flagger 是声明性的对 Kubernetes 事件做出反应,因此它可以与诸如此类的工具一起在 GitOps 管道中使用。

安装 Flagger

要使用 Flagger,需要先选择一个受支持的路由提供商(比如我们这里使用 Istio),然后使用 Helm 或 Kustomize 安装 Flagger。

Flagger 需要 Kubernetes 集群 v1.16 或更高版本以及 Istio v1.5 或更高版本。

首先当然需要安装 Istio,并开启 Prometheus 插件:

# demo 或者 default 都可以
istioctl manifest install --set profile=demo -y

# istio 根目录
kubectl apply -f samples/addons/prometheus.yaml

然后在 istio-system 命名空间安装 Flagger:

$ git clone https://github.com/fluxcd/flagger && cd flagger
$ kubectl apply -k kustomize/istio
$ kubectl get pods -n istio-system -l app=flagger
NAME                      READY   STATUS    RESTARTS   AGE
flagger-ff76bfdff-kkcmz   1/1     Running   0          17m

测试应用

下面我们创建一个名为 test 的命名空间,并为其启用 Istio sidecar 自动注入:

kubectl create ns test
kubectl label namespace test istio-injectinotallow=enabled

接下来我们使用 flagger 官方提供的 podinfo 应用来进行测试:

kubectl apply -k kustomize/podinfo

该命令会为 podinfo 应用创建对应的 Deployment 和一个 HPA 对象。

$ kubectl get deployment -n test
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
podinfo   2/2     2            0           96s
$ kubectl get hpa -n test
NAME      REFERENCE            TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
podinfo   Deployment/podinfo   <unknown>/99%   2         4         2          60s

部署后,我们可以看到 podinfo 应用的容器数量已经变成了 2 个(自动注入了 istio sidecar),而且 HPA 也已经生效。

```bash
$ kubectl get pods -n test
NAME                                  READY   STATUS            RESTARTS   AGE
podinfo-584c4546df-fzw4d              0/2     PodInitializing   0          5m26s
podinfo-584c4546df-n28cf              0/2     PodInitializing   0          5m11s

接着我们再部署一个负载测试服务用于在金丝雀分析期间生成流量:

kubectl apply -k kustomize/tester

创建金丝雀

接下来我们就可以创建一个 Canary 自定义资源来实现我们的金丝雀发布了。Canary 对象是 Flagger 的核心,它描述了金丝雀发布的目标。如下所示,我们为 podinfo 应用创建一个 Canary 对象:

# podinfo-canary.yaml
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: podinfo
  namespace: test
spec:
  targetRef: # deployment 引用
    apiVersion: apps/v1
    kind: Deployment
    name: podinfo
  progressDeadlineSeconds: 60 # 金丝雀部署升级最大处理时间(以秒为单位)(默认600秒)
  autoscalerRef: # HPA 引用(可选)
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    name: podinfo
  service:
    port: 9898
    targetPort: 9898
    gateways: # Istio 网关(可选)
      - istio-system/public-gateway
    hosts: # VirtualService 主机名 (optional)
      - podinfo.k8s.local
    trafficPolicy: # Istio 流量策略(可选)
      tls:
        # use ISTIO_MUTUAL when mTLS is enabled
        mode: DISABLE
    retries: # Istio 重试策略(可选)
      attempts: 3
      perTryTimeout: 1s
      retryOn: "gateway-error,connect-failure,refused-stream"
  analysis: # 金丝雀分析
    interval: 1m # 金丝雀分析间隔时间(默认 60s)
    threshold: 5 # 金丝雀分析失败阈值(默认 5)
    maxWeight: 50 # 金丝雀最大流量权重(默认 50)
    stepWeight: 10 # 金丝雀流量权重步长(默认 10)
    metrics:
      - name: request-success-rate
        # minimum req success rate (non 5xx responses)
        # percentage (0-100)
        thresholdRange:
          min: 99
        interval: 1m
      - name: request-duration
        # maximum req duration P99
        # milliseconds
        thresholdRange:
          max: 500
        interval: 30s
    # testing (optional)
    webhooks:
      - name: acceptance-test
        type: pre-rollout
        url: http://flagger-loadtester.test/
        timeout: 30s
        metadata:
          type: bash
          cmd: "curl -sd 'test' http://podinfo-canary:9898/token | grep token"
      - name: load-test
        url: http://flagger-loadtester.test/
        timeout: 5s
        metadata:
          # 使用 hey 工具对 podinfo-canary 进行为期1分钟的负载测试,每秒发送10个请求,且测试过程中会维持2个并发连接。
          cmd: "hey -z 1m -q 10 -c 2 http://podinfo-canary.test:9898/"

上面的配置文件中,我们定义了 podinfo 应用的金丝雀发布策略,其中 targetRef 指定了要进行金丝雀发布的 Deployment 对象,service 指定了金丝雀发布的服务,analysis 指定了金丝雀分析策略,这里我们指定了两个内置的指标检查:request-success-rate 和 request-duration,其中 request-success-rate 指定了 HTTP 请求成功率,request-duration 指定了请求持续时间。对于每个指标,你可以使用 thresholdRange 和窗口大小或时间序列指定可接受的值范围和时间间隔。内置检查适用于每个服务网格/Ingress 控制器,并通过 Prometheus 查询实现。

在 service 中我们指定了 Istio 的 Gateway(istio-system/public-gateway)以及 VirtualService 要使用的主机名,首先我们可以为该应用创建一个 Gateway 对象:

# public-gateway.yaml
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:
        - "*"

另外我们在上面的对象中通过 webhooks 字段指定了金丝雀分析期间要执行的测试,其中 acceptance-test 用于在金丝雀分析开始之前执行,load-test 用于在金丝雀分析期间执行。

金丝雀部署

接下来我们可以直接创建 Canary 对象了:

kubectl apply -f podinfo-canary.yaml

当创建了 Canary 对象后,Flagger 会自动创建一个名为 pod-info-primary 的 Deployment 以及两个版本的 Service 对象:

$ kubectl get deploy -n test
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
flagger-loadtester   1/1     1            1           42m
podinfo              0/0     0            0           46m
podinfo-primary      2/2     2            2           7m3s
$ kubectl get svc -ntest
NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
flagger-loadtester   ClusterIP   10.106.172.190   <none>        80/TCP     35m
podinfo-canary       ClusterIP   10.101.184.213   <none>        9898/TCP   39s
podinfo-primary      ClusterIP   10.110.105.36    <none>        9898/TCP   39s

可以看到我们原本的 podinfo 应用已经从 podinfo 这个 Deployment 迁移到了 podinfo-primary 这个 Deployment 之上。

此外还有 Istio 相关的对象:

$ kubectl get vs -ntest
NAME      GATEWAYS                          HOSTS                             AGE
podinfo   ["istio-system/public-gateway"]   ["podinfo.k8s.local","podinfo"]   91s
$ kubectl get dr -ntest
NAME              HOST              AGE
podinfo-canary    podinfo-canary    95s
podinfo-primary   podinfo-primary   95s

我们可以查看下自动生成的 VirtualService 对象:

$ kubectl get vs -ntest podinfo -oyaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: podinfo
  namespace: test
spec:
  gateways:
  - istio-system/public-gateway
  hosts:
  - podinfo.k8s.local
  - podinfo
  http:
  - retries:
      attempts: 3
      perTryTimeout: 1s
      retryOn: gateway-error,connect-failure,refused-stream
    route:
    - destination:
        host: podinfo-primary
      weight: 100
    - destination:
        host: podinfo-canary
      weight: 0

从上面的配置中我们可以看到当前 podinfo 应用的流量全部被路由到了 podinfo-primary 对象上,而 podinfo-canary 对象的流量权重为 0,当然同样可以查看 DestinationRule 对象:

$ kubectl get dr podinfo-primary -ntest -oyaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: podinfo-primary
  namespace: test
spec:
  host: podinfo-primary
  trafficPolicy:
    tls:
      mode: DISABLE
$ kubectl get dr podinfo-canary -ntest -oyaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: podinfo-canary
  namespace: test
spec:
  host: podinfo-canary
  trafficPolicy:
    tls:
      mode: DISABLE

所以默认情况下现在我们访问到的就是 podinfo-primary 这个 Deployment 对象,也就是目前的默认版本。我们可以在浏览器中访问 podinfo 来查看当前的版本:

podinfo

自动金丝雀发布

我们可以看到现在的版本是 podinfo v6.0.0,接下来我们来升级应用触发金丝雀发布。要触发金丝雀发布,可以由以下任何对象的更改来触发:

  • Deployment PodSpec(容器镜像、命令、端口、环境变量、资源等)
  • 作为卷挂载或映射到环境变量的 ConfigMaps
  • 作为卷挂载或映射到环境变量的 Secrets

比如我们可以直接修改 Deployment 对象的镜像版本来触发自动化的金丝雀发布:

kubectl -n test set image deployment/podinfo podinfod=ghcr.io/stefanprodan/podinfo:6.0.1

Flagger 检测到 Deployment 更改后就会开始新的部署:

$ kubectl describe canaries podinfo -ntest
# ......
Events:
  Type     Reason  Age                From     Message
  ----     ------  ----               ----     -------
  Warning  Synced  15m                flagger  podinfo-primary.test not ready: waiting for rollout to finish: observed deployment generation less than desired generation
  Normal   Synced  14m (x2 over 15m)  flagger  all the metrics providers are available!
  Normal   Synced  14m                flagger  Initialization done! podinfo.test
  Normal   Synced  56s                flagger  New revision detected! Scaling up podinfo.test

需要注意在金丝雀分析期间对 Deployment 应用新的更改,Flagger 将重新启动分析。第一步是先会去扩容 podinfo 应用:

$ kubectl get pods -ntest
NAME                                  READY   STATUS    RESTARTS   AGE
flagger-loadtester-78dd9787d4-dq5fc   2/2     Running   0          67m
podinfo-5d5dbc4d84-f2mp6              2/2     Running   0          31s
podinfo-5d5dbc4d84-gd8ln              2/2     Running   0          31s
podinfo-primary-64f865cf4-bhr79       2/2     Running   0          3m31s
podinfo-primary-64f865cf4-tgsdj       2/2     Running   0          3m31s

然后就会根据我们在 Canary 对象中定义的金丝雀分析策略来进行分析,并一步步将金丝雀版本的权重提高。

Warning Synced 4m4s flagger podinfo-primary.test not ready: waiting for rollout to finish: observed deployment generation less than desired generation
Normal Synced 3m4s (x2 over 4m4s) flagger all the metrics providers are available!
Normal Synced 3m4s flagger Initialization done! podinfo.test
Normal Synced 64s flagger New revision detected! Scaling up podinfo.test
Normal Synced 4s flagger Starting canary analysis for podinfo.test
Normal Synced 4s flagger Pre-rollout check acceptance-test passed
Normal Synced 4s flagger Advance podinfo.test canary weight 10

最后会自动将流量全部切换到金丝雀版本上。

金丝雀版本

整个过程就是通过控制 VirtualService 的权重来实现的金丝雀发布。

自动回滚

在金丝雀分析期间,我们可以生成 HTTP 500 错误和高延迟来测试 Flagger 是否暂停发布。

比如我们触发另一个金丝雀发布:

kubectl -n test set image deployment/podinfo podinfod=ghcr.io/stefanprodan/podinfo:6.0.2

然后进入 loadtester 容器:

kubectl -n test exec -it flagger-loadtester-xx-xx sh

使用下面的命令来生成 HTTP 500 错误:

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

也可以添加延迟:

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

当失败检查的次数达到金丝雀分析配置的阈值时,流量将路由回主节点,金丝雀将缩放为零,并将部署标记为失败。

Normal   Synced  8m10s (x3 over 45m)  flagger  New revision detected! Scaling up podinfo.test
Normal   Synced  7m10s (x2 over 44m)  flagger  Pre-rollout check acceptance-test passed
Normal   Synced  7m10s (x2 over 44m)  flagger  Advance podinfo.test canary weight 10
Normal   Synced  7m10s (x2 over 44m)  flagger  Starting canary analysis for podinfo.test
Warning  Synced  6m10s                flagger  Halt podinfo.test advancement success rate 55.86% < 99%
Warning  Synced  5m10s                flagger  Halt podinfo.test advancement success rate 97.61% < 99%
Warning  Synced  4m10s                flagger  Halt podinfo.test advancement success rate 8.00% < 99%
Warning  Synced  3m10s                flagger  Halt podinfo.test advancement success rate 98.13% < 99%
Warning  Synced  2m10s                flagger  Halt podinfo.test advancement success rate 7.69% < 99%
Warning  Synced  70s (x2 over 14m)    flagger  Canary failed! Scaling down podinfo.test
Warning  Synced  70s                  flagger  Rolling back podinfo.test failed checks threshold reached 5

关于 Flagger 的更多使用请关注后续文章。

文章来源网络,作者:管理,如若转载,请注明出处:https://shuyeidc.com/wp/298309.html<

(0)
管理的头像管理
上一篇2025-05-22 21:18
下一篇 2025-05-22 21:20

相关推荐

  • 云服务器和云虚拟主机怎么选?云服务器和虚拟主机区别

    云服务器适合业务增长快、需弹性扩展的场景,而云虚拟主机适合预算有限、技术门槛低的小型静态网站或测试环境,二者核心区别在于资源独享性与运维复杂度,核心差异解析:从底层架构到使用体验很多人容易混淆这两者,觉得它们都是“买空间建站”,它们的底层逻辑完全不同,云服务器(ECS)就像是你租了一整栋别墅,水电网络独立,你想……

    2026-06-29
    0
  • 赣州智慧旅游招聘是真的吗?赣州旅游人才招聘信息

    中级岗位(3-5年经验)月薪范围通常在6000-10000元,这类岗位需要独立负责项目模块,如独立运营一个抖音账号,或维护一个景区小程序的功能迭代,具备成功案例的候选人议价能力较强,高级岗位(5年以上经验)月薪范围通常在10000-20000元,部分核心管理岗可达更高,这类人才需要具备战略规划能力,如制定整个景……

    2026-06-29
    0
  • 赣州智能物联网车位锁如何管理?智能车位锁管理系统多少钱

    赣州智能物联网车位锁管理的核心在于通过云端平台实现远程控锁、状态实时监控及自动计费,彻底解决传统车位“被占难管”与“找位难”的痛点,在赣州这样的城市,随着机动车保有量的持续增长,老旧小区、商业综合体以及私人固定车位的资源矛盾日益凸显,传统的机械地锁或简易遥控锁,不仅操作繁琐,更无法实现数据化管理,引入智能物联网……

    2026-06-29
    0
  • 赣州智能消防栓好用吗,智能消防栓多少钱一个

    赣州智能消防栓通过物联网技术实现实时监测与远程报警,能显著降低火灾响应时间并提升城市消防安全管理水平,是目前智慧城市建设中不可或缺的基础设施,赣州智能消防栓的核心价值与应用场景传统消防栓往往存在“看不见、摸不着、用不了”的痛点,在赣州这样地形复杂、老城区与新城区并存的区域,传统设施的管理难度极大,智能消防栓的出……

    2026-06-29
    0
  • 云服务器和物理机到底有啥区别?

    云服务器本质上是虚拟化资源池中的弹性实例,而传统物理服务器是独占的硬件实体,前者胜在弹性与运维便捷,后者强在物理隔离与性能稳定,具体选择取决于业务对成本、扩展性及安全合规的权衡,很多人初次接触服务器时,容易把“云服务器”和“传统物理服务器”混为一谈,觉得它们都是用来跑网站或存数据的盒子,这两者的底层逻辑完全不同……

    2026-06-29
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注