zoukankan      html  css  js  c++  java
  • 使用 Flux,Helm v3,Linkerd 和 Flagger 渐进式交付 Kubernetes

    介绍

    本指南将引导您在 Kubernetes 集群上设置渐进式交付 GitOps 管道。

    GitOps 是什么?

    GitOps 是一种进行持续交付的方法,它通过将 Git 用作声明性基础结构和工作负载的真实来源来工作。对于 Kubernetes,这意味着使用 git push 代替 kubectl create/apply 或者 kubectl create/apply

    GitOps vs CiOps 在传统的 CI/CD 管道中,CD 是由持续集成工具支持的实现扩展,用于将构建工件升级到生产环境。在 GitOps 管道模型中,对生产的任何更改必须先在源代码管理中提交(最好通过拉取请求),然后再应用于集群。如果整个生产状态受版本控制并在单个Git 存储库中进行描述,则在灾难发生时,可以快速恢复整个基础架构,而无需重新运行 CI 管道。

    Kubernetes 反模式:让我们做 GitOps,而不是 CIOps!

    为了将 GitOps 模型应用到 Kubernetes 上,你需要做三件事:

    • 一个 Git 存储库,其中包含以 YAM 格式定义的工作负载、Helm charts 和定义集群所需状态的任何其他 Kubernetes 自定义资源
    • 一个容器注册中心(registry),CI 系统在其中推送不可变的镜像(没有 latest 标签,使用 语义版本控制 或 git commit sha
    • 一个进行双向同步的 Kubernetes 控制器:
      • 监视配置存储库中的更改并将其应用于您的集群
      • 监视容器 registry(注册中心) 的新映像,并根据部署策略更新工作负载定义。

    在本研讨会中,您将使用 GitHub 托管配置存储库,使用 Docker Hub 作为容器注册中心,使用 Flux 作为 GitOps 控制器,并使用 Helm Operator 进行应用程序生命周期管理。

    什么是渐进式交付?

    渐进式交付是高级部署模式(如金丝雀,功能标记和 A/B 测试)的总称。
    通过给予应用程序开发人员和 SRE 团队对爆炸半径的细粒度控制,渐进交付技术被用来降低在生产中引入新软件版本的风险。

    使用金丝雀的好处是能够在生产环境中使用发现问题的安全回滚策略对新版本进行容量测试。通过缓慢增加负载,您可以监视和捕获有关新版本如何影响生产环境的指标。

    Martin Fowler 博客

    在本研讨会中,您将使用
    Flagger,
    Linkerd
    Prometheus
    来自动化金丝雀分布 Helm charts。

    前提条件

    为了安装研讨会的前提条件,您需要一个 Kubernetes 集群(1.13 或更新版本),并支持 负载平衡器RBAC
    确保您已经在本地安装了以下工具:

    • kubectl 1.16
    • git 2.20

    Helm v3

    在 macOS 上安装 Helm v3 CLI:

    brew install helm
    

    在 Linux 或 Windows 上,您可以从官方发布页面下载二进制文件。

    Git

    Fork workshop 仓库并克隆它到本地(使用你的 GitHub 用户名替换 GHUSER):

    export GHUSER=stefanprodan
    git clone https://github.com/${GHUSER}/gitops-helm-workshop
    

    设置您的 GitHub 用户名和电子邮件:

    cd gitops-helm-workshop
    git config user.name "${GHUSER}"
    git config user.email "your@main.address"
    

    集群状态目录结构:

    ├── cluster
        ├── canaries
        ├── charts
        │   └── podinfo
        ├── namespaces
        └── releases
    

    Flux

    将 Flux 存储库添加到 Helm 存储库:

    helm repo add fluxcd https://charts.fluxcd.io
    

    创建 fluxcd namespace:

    kubectl create ns fluxcd
    

    通过提供您的 GitHub 存储库 URL 安装 Flux:

    helm upgrade -i flux fluxcd/flux --wait 
    --namespace fluxcd 
    --set registry.pollInterval=1m 
    --set git.pollInterval=1m 
    --set git.url=git@github.com:${GHUSER}/gitops-helm-workshop
    

    安装 fluxctl:

    # macOS and linux
    curl -sL https://fluxcd.io/install | sh
    export PATH=$PATH:$HOME/.fluxcd/bin
    
    # windows
    https://github.com/fluxcd/flux/releases
    

    找到 Git SSH 公钥:

    export FLUX_FORWARD_NAMESPACE=fluxcd
    
    fluxctl identity
    

    复制公钥并在 GitHub 存储库上创建具有写访问权的部署密钥。转到 Settings > Deploy keys,单击 Add deploy key,选中 Allow write access,粘贴 Flux 公钥并单击 Add key

    Helm Operator

    fluxcd 命名空间中安装 Flux Helm Operator:

    helm upgrade -i helm-operator fluxcd/helm-operator --wait 
    --namespace fluxcd 
    --set git.ssh.secretName=flux-git-deploy 
    --set git.pollInterval=1m 
    --set chartsSyncInterval=1m 
    --set helm.versions=v3
    

    Linkerd

    下载 Linkerd v2 CLI:

    # macOS and linux
    curl -sL https://run.linkerd.io/install | sh
    export PATH=$PATH:$HOME/.linkerd2/bin
    
    # windows
    https://github.com/linkerd/linkerd2/releases
    

    linkerd 名称空间中安装 Linkerd 控制平面:

    linkerd install | kubectl apply -f -
    

    使用以下命令验证安装:

    linkerd check
    

    Flagger

    添加 Flagger Helm 仓库:

    helm repo add flagger https://flagger.app
    

    安装 Flagger 的金丝雀 CRD:

    kubectl apply -f https://raw.githubusercontent.com/weaveworks/flagger/master/artifacts/flagger/crd.yaml
    

    linkerd 命名空间中安装 Flagger:

    helm upgrade -i flagger flagger/flagger --wait 
    --namespace linkerd 
    --set crd.create=false 
    --set metricsServer=http://linkerd-prometheus:9090 
    --set meshProvider=linkerd
    

    Helm 发布

    一个 chart 发布是通过 Kubernetes 自定义资源 HelmRelease 进行描述的。

    一个 Helm release 可以引用的 chart,如下:

    • 通过 HTTPS 的公共或私有 Helm 存储库
    • 通过 SSH 的公共或私有 Git 存储库

    安装 NGINX

    为了将应用程序暴露在集群之外,您将使用 NGINX ingress 控制器。控制器将在 Linkerd 网格内运行。

    创建一个启用 linkerd 注入的名称空间:

    apiVersion: v1
    kind: Namespace
    metadata:
      annotations:
        fluxcd.io/ignore: "false"
        linkerd.io/inject: enabled
      name: ingress-nginx
    

    创建一个 Helm release 来安装 NGINX ingress 控制器:

    apiVersion: helm.fluxcd.io/v1
    kind: HelmRelease
    metadata:
      name: nginx-ingress
      namespace: ingress-nginx
      annotations:
        fluxcd.io/ignore: "false"
    spec:
      releaseName: nginx-ingress
      chart:
        repository: https://kubernetes-charts.storage.googleapis.com/
        name: nginx-ingress
        version: 1.33.4
      values:
        controller:
          service:
            type: LoadBalancer
    

    应用更改:

    git add -A && 
    git commit -m "install ingress" && 
    git push origin master && 
    fluxctl sync
    

    验证 Helm operator 是否已安装 release:

    kubectl -n ingress-nginx get hr
    

    查找 ingress 控制器的公共 IP:

    kubectl -n ingress-nginx get svc
    

    安装 podinfo

    Podinfo 是一个很小的 Go Web 应用程序。您将使用存储 cluster/charts/podinfo 的 git 仓库中的 Helm chart 安装 podinfo。

    创建启用 linkerd 注入的 prod 命名空间:

    apiVersion: v1
    kind: Namespace
    metadata:
      annotations:
        fluxcd.io/ignore: "false"
        linkerd.io/inject: enabled
      name: prod
    

    创建一个 Helm release 以安装 podinfo chart(替换 GHUSER 为你的 GitHub 用户名和使用你的 ingress IP 替换 LB-PUBLIC-IP):

    apiVersion: helm.fluxcd.io/v1
    kind: HelmRelease
    metadata:
      name: podinfo
      namespace: prod
      annotations:
        fluxcd.io/ignore: "false"
    spec:
      releaseName: podinfo
      chart:
        git: git@github.com:GHUSER/gitops-helm-workshop
        ref: master
        path: cluster/charts/podinfo
      values:
        image:
          repository: stefanprodan/podinfo
          tag: 3.1.0
        service:
          enabled: true
          type: ClusterIP
        ingress:
          enabled: true
          annotations:
            kubernetes.io/ingress.class: "nginx"
            nginx.ingress.kubernetes.io/configuration-snippet: |
              proxy_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:9898;
              proxy_hide_header l5d-remote-ip;
              proxy_hide_header l5d-server-id;
          path: /
          hosts:
            - LB-PUBLIC-IP.nip.io
    

    请注意,如果您使用的是 EKS,则主机应设置为 elb.amazonaws.com 地址:

    kubectl -n ingress-nginx get svc | grep Ingress
    

    应用更改:

    git add -A && 
    git commit -m "install podinfo" && 
    git push origin master && 
    fluxctl sync
    

    验证 Helm operator 是否已安装 podinfo:

    kubectl -n prod get hr
    

    打开浏览器并导航到 http://LB-PUBLIC-IP.nip.io/,您应该看到 podinfo v3.1.0 UI

    自动升级

    Flux 可以用于自动化集群中的容器映像更新。
    您可以通过注释 Helm release 对象来启用自动化 image 标记更新。
    您还可以通过使用 glob、regex 或语义版本表达式来控制更新应该考虑哪些标记。

    编辑 podinfo Helm release 并启用 Flux 自动 Image 更新:

    apiVersion: helm.fluxcd.io/v1
    kind: HelmRelease
    metadata:
      annotations:
        fluxcd.io/automated: "true"
        fluxcd.io/tag.chart-image: semver:~3.1
    

    应用更改:

    git add -A && 
    git commit -m "automate podinfo" && 
    git push origin master && 
    fluxctl sync
    

    验证 Helm operator 是否已升级 podinfo:

    kubectl -n prod get hr
    

    在本地拉取 Flux 所做的更改:

    git pull origin master
    

    打开浏览器并导航到 http://LB-PUBLIC-IP.nip.io/,您应该看到 podinfo v3.1.5 UI。

    密封的 secrets

    为了将 secrets 安全地存储在公共 Git 存储库中,您可以使用 Sealed Secrets 控制器 并将您的 Kubernetes Secrets 加密为 SealedSecrets。只能通过在集群中运行的控制器来解密密封的 secrets。

    创建 Sealed Secrets Helm release:

    apiVersion: helm.fluxcd.io/v1
    kind: HelmRelease
    metadata:
      name: sealed-secrets
      namespace: fluxcd
      annotations:
        fluxcd.io/ignore: "false"
    spec:
      releaseName: sealed-secrets
      chart:
        repository: https://kubernetes-charts.storage.googleapis.com/
        name: sealed-secrets
        version: 1.8.0
    

    应用更改:

    git add -A && 
    git commit -m "install sealed-secrets" && 
    git push origin master && 
    fluxctl sync
    

    安装 kubeseal CLI:

    wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v1.8.0/kubeseal-darwin-amd64
    sudo install -m 755 kubeseal-darwin-amd64 /usr/local/bin/kubeseal
    

    在启动时,sealed-secrets 控制器生成一个 RSA key 并记录公钥。使用 kubeseal,您可以将您的公钥保存为 pub-cert.pem,公钥可安全存储在 Git 中,可用于加密 secrets,无需直接访问 Kubernetes 集群:

    kubeseal --fetch-cert 
    --controller-namespace=fluxcd 
    --controller-name=sealed-secrets 
    > pub-cert.pem
    

    您可以使用 kubectl 在本地生成 Kubernetes secret,并使用 kubeseal 对其进行加密:

    kubectl -n prod create secret generic basic-auth 
    --from-literal=user=admin 
    --from-literal=password=admin 
    --dry-run 
    -o json > basic-auth.json
    
    kubeseal --format=yaml --cert=pub-cert.pem < basic-auth.json > basic-auth.yaml
    

    这将生成一个类型为 SealedSecret 的自定义资源,其中包含加密的凭据。

    Flux 将在您的集群上应用 sealed secret,然后 sealed-secrets 的控制器将其解密为 Kubernetes secret。

    为了准备进行灾难恢复,您应该使用以下命令备份 Sealed Secrets 控制器的私钥:

    kubectl get secret -n fluxcd sealed-secrets-key -o yaml 
    --export > sealed-secrets-key.yaml
    

    要在灾难后从备份中恢复,请替换新创建的密钥并重新启动控制器:

    kubectl replace secret -n fluxcd sealed-secrets-key -f sealed-secrets-key.yaml
    kubectl delete pod -n fluxcd -l app=sealed-secrets
    

    金丝雀发布

    一个金丝雀发布是用名为 Canary 的 Kubernetes 自定义资源描述的。

    应用程序启动

    编辑 podinfo Helm release 和禁用 image 更新和 ClusterIP 服务:

    apiVersion: helm.fluxcd.io/v1
    kind: HelmRelease
    metadata:
      name: podinfo
      namespace: prod
      annotations:
        fluxcd.io/automated: "false"
    spec:
      releaseName: podinfo
      values:
        image:
          repository: stefanprodan/podinfo
          tag: 3.1.0
        service:
          enabled: false
          type: ClusterIP
    

    应用更改:

    git add -A && 
    git commit -m "prep canary" && 
    git push origin master && 
    fluxctl sync
    

    创建一个针对 podinfo 的金丝雀发布:

    apiVersion: flagger.app/v1beta1
    kind: Canary
    metadata:
      name: podinfo
      namespace: prod
      annotations:
        fluxcd.io/ignore: "false"
    spec:
      targetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: podinfo
      service:
        port: 9898
      analysis:
        interval: 10s
        maxWeight: 100
        stepWeight: 5
        threshold: 5
        metrics:
          - name: request-success-rate
            thresholdRange:
              min: 99
            interval: 1m
          - name: request-duration
            thresholdRange:
              max: 500
            interval: 1m
        webhooks:
          - name: acceptance-test
            type: pre-rollout
            url: http://flagger-loadtester.prod/
            timeout: 30s
            metadata:
              type: bash
              cmd: "curl -sd 'test' http://podinfo-canary.prod:9898/token | grep token"
          - name: load-test
            type: rollout
            url: http://flagger-loadtester.prod/
            metadata:
              cmd: "hey -z 2m -q 10 -c 2 http://podinfo-canary.prod:9898/"
    

    应用更改:

    git add -A && 
    git commit -m "add canary" && 
    git push origin master && 
    fluxctl sync
    

    验证 Flagger 已经初始化金丝雀:

    kubectl -n prod get canary
    

    自动金丝雀提升

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

    apiVersion: helm.fluxcd.io/v1
    kind: HelmRelease
    metadata:
      name: load-tester
      namespace: prod
      annotations:
        fluxcd.io/ignore: "false"
    spec:
      releaseName: load-tester
      chart:
        git: https://github.com/weaveworks/flagger
        ref: 1.0.0-rc.1
        path: charts/loadtester
      values:
        fullnameOverride: load-tester
    

    当您部署新的 podinfo 版本时,Flagger 逐渐将流量转移到金丝雀,同时测量请求的成功率以及平均响应持续时间。
    基于对这些Linkerd提供的指标的分析,金丝雀部署要么提升要么回滚。

    通过更新容器映像来触发金丝雀部署:

    apiVersion: helm.fluxcd.io/v1
    kind: HelmRelease
    spec:
      releaseName: podinfo
      values:
        image:
          tag: 3.1.1
    

    应用更改:

    git add -A && 
    git commit -m "update podinfo" && 
    git push origin master && 
    fluxctl sync
    

    当 Flagger 检测到部署修订版本已更改时,它将开始新的部署。您可以使用以下方法监视流量的变化:

    watch kubectl -n prod get canaries
    

    自动回滚

    在金丝雀分析期间,您可能会生成 HTTP 500 错误和高延迟,以测试 Flagger 是否暂停并回滚有故障的版本。

    触发另一只金丝雀的发布:

    apiVersion: helm.fluxcd.io/v1
    kind: HelmRelease
    spec:
      releaseName: podinfo
      values:
        image:
          tag: 3.1.2
    

    应用更改:

    git add -A && 
    git commit -m "update podinfo" && 
    git push origin master && 
    fluxctl sync
    

    执行到测试 pod 和产生 HTTP 500 错误:

    kubectl -n prod exec -it $(kubectl -n prod get pods -o name | grep -m1 load-tester | cut -d'/' -f 2) bash
    
    $ hey -z 1m -c 5 -q 5 http://podinfo-canary:9898/status/500
    $ hey -z 1m -c 5 -q 5 http://podinfo-canary:9898/delay/1
    

    当检查失败的数量达到金丝雀分析阈值时,流量将路由回主要服务器,并且金丝雀将比例缩放为零。

    观看Flagger日志:

    $ kubectl -n linkerd logs deployment/flagger -f | jq .msg
    
     Starting canary analysis for podinfo.prod
     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 request duration 1.20s > 0.5s
     Halt podinfo.test advancement request duration 1.45s > 0.5s
     Rolling back podinfo.prod failed checks threshold reached 5
     Canary failed! Scaling down podinfo.test
    

    使用 Linkerd 进行监视

    Linkerd 仪表板可实时提供有关服务情况的高级视图。
    它可用于可视化服务依赖关系,流量拆分和了解特定服务路由的运行状况。

    通过运行以下命令打开仪表板:

    linkerd dashboard --port=50750
    

    在金丝雀分析期间,导航至:

    http://127.0.0.1:50750/namespaces/ingress-nginx/deployments/nginx-ingress-controller
    

    您可以使用以下命令从命令行监视生产名称空间的实时流量:

    linkerd -n prod top deploy
    

    您可以使用以下命令查看 podinfo 公开的所有路由:

    linkerd -n prod routes service/podinfo
    

    以上路由是从 podinfo swagger 规范生成的,并作为 Linkerd 服务配置文件导出。

    Canary Helm 测试

    Flagger 附带有一个测试服务,该服务在配置为 Webhook 时可以运行 Helm 测试。

    创建测试

    为 podinfo 令牌 API 创建一个测试:

    apiVersion: v1
    kind: Pod
    metadata:
      name: {{ template "podinfo.fullname" . }}-jwt-test-{{ randAlphaNum 5 | lower }}
      labels:
        heritage: {{ .Release.Service }}
        release: {{ .Release.Name }}
        chart: {{ .Chart.Name }}-{{ .Chart.Version }}
        app: {{ template "podinfo.name" . }}
      annotations:
        linkerd.io/inject: disabled
        "helm.sh/hook": test-success
    spec:
      containers:
        - name: tools
          image: giantswarm/tiny-tools
          command:
            - sh
            - -c
            - |
              TOKEN=$(curl -sd 'test' ${PODINFO_SVC}/token | jq -r .token) &&
              curl -H "Authorization: Bearer ${TOKEN}" ${PODINFO_SVC}/token/validate | grep test
          env:
          - name: PODINFO_SVC
            value: {{ template "podinfo.fullname" . }}:{{ .Values.service.externalPort }}
      restartPolicy: Never
    

    将以上文件保存在 cluster/charts/podinfo/tests 中。

    prod 名称空间中部署 Helm 测试运行器:

    apiVersion: helm.fluxcd.io/v1
    kind: HelmRelease
    metadata:
      name: helm-tester
      namespace: prod
      annotations:
        fluxcd.io/ignore: "false"
    spec:
      releaseName: helm-tester
      chart:
        git: https://github.com/weaveworks/flagger
        ref: 1.0.0-rc.1
        path: charts/loadtester
      values:
        fullnameOverride: helm-tester
        serviceAccountName: helm-tester
    

    应用更改:

    git add -A && 
    git commit -m "install helm-tester" && 
    git push origin master && 
    fluxctl sync
    

    运行测试

    将 helm 测试添加为预发布 webhook:

    apiVersion: flagger.app/v1beta1
    kind: Canary
    metadata:
      name: podinfo
      namespace: prod
    spec:
      analysis:
        webhooks:
          - name: "helm test"
            type: pre-rollout
            url: http://helm-tester.prod/
            timeout: 2m
            metadata:
              type: "helmv3"
              cmd: "test podinfo"
          - name: load-test
            url: http://load-tester.prod/
            metadata:
              cmd: "hey -z 2m -q 10 -c 2 http://podinfo-canary.prod:9898/"
    

    应用更改:

    git add -A && 
    git commit -m "update podinfo" && 
    git push origin master && 
    fluxctl sync
    

    当金丝雀分析开始时,Flagger 将在将流量路由到金丝雀之前调用预发布 Webhooks。
    如果 helm 测试失败,Flagger 将重试,直到达到分析阈值并且金丝雀回退为止。

  • 相关阅读:
    以用户名注册来分析三种Action获取数据的方式
    Struts2中的OGNL详解 《转》
    Module 'null' not found异常解决办法
    struts标签<logic:iterate>的用法
    struts2的核心和工作原理 <转>
    jstl标签怎么实现分页中下一页
    forward 和redirect
    forward 和redirect的区别
    今天早上起来就想着要问问龙虎有圆通没
    昨天晚上回来弄了两个皮蛋吃
  • 原文地址:https://www.cnblogs.com/hacker-linner/p/14262200.html
Copyright © 2011-2022 走看看