通过前面一节的 Flagger基本学习,这节学习它的工作原理,以帮助加深理解应用!
Flagger 是如何工作的-工作原理?
可以通过一个名为 canary 的自定义资源来配置 Kubernetes 工作负载的自动化发布过程.
Canary resource
Canary 自定义资源定义了在 Kubernetes 上运行的应用程序的释放过程,并且可以across clusters, service meshes 和 ingress providers 进行移植.
对于名为 podinfo 的 deployment ,带有渐进式流量转移的 Canary 发布可以定义为:
代码语言:javascript复制apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: podinfo
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: podinfo
service:
port: 9898
analysis:
interval: 1m
threshold: 10
maxWeight: 50
stepWeight: 5
metrics:
- name: request-success-rate
thresholdRange:
min: 99
interval: 1m
- name: request-duration
thresholdRange:
max: 500
interval: 1m
webhooks:
- name: load-test
url: http://flagger-loadtester.test/
metadata:
cmd: "hey -z 1m -q 10 -c 2 http://podinfo-canary.test:9898/"
当 deployment 一个新版本的应用时,Flagger 会逐渐将流量转移到 Canary,同时测量请求成功率以及平均响应时间,可以通过自定义指标、验收和负载测试来扩展 Canary 的分析,以加强应用发布过程的验证过程
如果在同一个集群中运行多个服务网格或入口控制器,可以用 spec.provider 覆盖特定 canary 的全局提供者
Canary target
Canary 资源可以针对 Kubernetes Deployment 或 DaemonSet
Kubernetes Deployment 的例子:
代码语言:javascript复制spec:
progressDeadlineSeconds: 60
targetRef:
apiVersion: apps/v1
kind: Deployment
name: podinfo
autoscalerRef:
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
name: podinfo
基于上述配置,Flagger 生成了以下 Kubernetes对象:
. deployment/<targetRef.name>-primary
. hpa/<autoscalerRef.name>-primary
primary deployment 被认为是应用程序的稳定版本,默认情况下,所有流量都被路由到这个版本,而 target deployment 被扩展为 0, Flagger 会检测到target deployment 的变化(包括secrets 和 configmaps),并在将新版本提升为 primary 版本之前进行 Canary 分析.
注意,target deployment 必须有一个单一的 label selector,格式为 app: <DEPLOYMENT-NAME>:
代码语言:javascript复制apiVersion: apps/v1
kind: Deployment
metadata:
name: podinfo
spec:
selector:
matchLabels:
app: podinfo
template:
metadata:
labels:
app: podinfo
除了 app 之外,Flagger 还支持 name 和 app.kubernetes.io/name 选择器, 如果使用不同的约定,可以在 Flagger deployment 清单中容器 args 下的 -selector-labels=my-app-label 命令标志来指定标签,或者在用 Helm 安装 Flagger 时设置 --set selectorLabels=my-app-label
如果 target deployment 使用 secrets 或 configmaps,Flagger 将使用 -primary 后缀创建每个对象的副本并在 primary deployment 中引用这些对象,
如果用 flagger.app/config-tracking: disabled 来注释 ConfigMap 或 Secret,Flagger 将在 primary deployment 中使用相同的对象而不是制作 primary 副本,
可以在 Flagger deployment 清单中的 containers args 下使用 -enable-config-tracking=false 命令标志全局禁用 secrets/configmaps 跟踪,或者在用 Helm 安装 Flagger 时设置,
-set configTracking.enabled=false,但使用每个 Secret/ConfigMap 注释禁用 config-tracking 可能更符合使用情况
autoscaler 的引用是可选的,当指定时, Flagger 将暂停流量的增加,同时 target 和 primary deployment 被放大或缩小, HPA 可以帮助减少在 canary 分析过程中的资源使用,
当指定 autoscaler 参考时,对 autoscaler 的任何改变只有在 deployment 的 rollout 开始并成功完成时才会在 primary autoscaler 中被激活,
可以选择创建两个 HPA,一个用于 canary,一个用于 primary,以更新 HPA 而不做新的展开, 由于 Canary 的 deployment 将被缩减到 0,Canary 上的 HPA 将不活跃
注意: Flagger 需要 HPA 的 autoscaling/v2 或 autoscaling/v2beta2 API 版本
进度截止日期表示 Canary deployment 在回滚前取得进展的最大时间(秒),默认为 10 分钟。
Canary service
Canary 资源决定了 target 工作负载在集群内的暴露方式, Canary target 应该暴露一个 TCP 端口,该端口将被 Flagger 用来创建 ClusterIP 服务:
代码语言:javascript复制spec:
service:
name: podinfo
port: 9898
portName: http
appProtocol: http
targetPort: 9898
portDiscovery: true
来自 target 工作负载的容器端口应该与 service.port 或 service.targetPort 匹配, service.name 是可选的,默认为 spec.targetRef.name, service.targetPort 可以是一个容器端口号或名称service.portName 是可选的(默认为 http),如果工作负载使用 gRPC,则将端口名称设为 grpc, service.appProtocol 是可选的,更多细节可以在 这里 找到
如果启用了端口发现功能,Flagger 会扫描 target 工作负载并提取容器端口,但不包括 canary service 和 service mesh sidecar 端口中指定的端口, 这些端口将在生成 ClusterIP 服务时使用。
基于 canary 规格的服务,Flagger 创建以下 Kubernetes ClusterIP 服务:
. <service.name>.<namespace>.svc.cluster.local
代码语言:txt复制selector app=<name>-primary
. <service.name>-primary.<namespace>.svc.cluster.local
代码语言:txt复制selector app=<name>-primary
. <service.name>-canary.<namespace>.svc.cluster.local
代码语言:txt复制selector app=<name>
这确保了到 podinfo.test:9898 的流量将被路由到应用程序的最新稳定版本, podinfo-canary.test:9898 地址只在 canary 分析期间可用,可用于一致性测试或负载测试
可以配置 Flagger 来为生成的服务设置annotations 和 labels:
代码语言:javascript复制spec:
service:
port: 9898
apex:
annotations:
test: "test"
labels:
test: "test"
canary:
annotations:
test: "test"
labels:
test: "test"
primary:
annotations:
test: "test"
labels:
test: "test"
请注意,apex 注解被添加到生成的 Kubernetes 服务和生成的 service mesh/ingress 对象, 这允许在 Istio VirtualService 和 TraefikServices 中使用外部 DNS,
要注意 这里 的配置冲突
除了端口映射和元数据,service specification 可以包含 URI 匹配和重写规则、超时和重试策略:
代码语言:javascript复制spec:
service:
port: 9898
match:
- uri:
prefix: /
rewrite:
uri: /
retries:
attempts: 3
perTryTimeout: 1s
timeout: 5s
当使用 Istio 作为网格提供者时,还可以指定 HTTP头操作、CORS 和流量策略、Istio 网关和 hosts, Istio 的路由配置可以在 这里 找到
Canary status
可以使用 kubectl 来获取集群范围内 canary deployment 的当前状态:
代码语言:javascript复制kubectl get canaries --all-namespaces
状态条件反映了 Canary 分析的最后已知状态:
代码语言:javascript复制kubectl -n test get canary/podinfo -oyaml | awk '/status/,0'
一个成功的 rollout 状态:
代码语言:javascript复制status:
canaryWeight: 0
failedChecks: 0
iterations: 0
lastAppliedSpec: "14788816656920327485"
lastPromotedSpec: "14788816656920327485"
conditions:
- lastTransitionTime: "2019-07-10T08:23:18Z"
lastUpdateTime: "2019-07-10T08:23:18Z"
message: Canary analysis completed successfully, promotion finished.
reason: Succeeded
status: "True"
type: Promoted
促成状态条件可以有以下原因之一:Initialized(初始化)、Waiting(等待)、Progressing(进展)、WaitingPromotion(等待推广)、Promotion(推广)、Finalising(最终完成)、Succeeded(成功)或 Failed(失败),失败的 Canary 将把推广状态设置为 false,原因为 failed,最后应用的规格将与最后推广的规格不同
等待成功推广:
代码语言:javascript复制kubectl wait canary/podinfo --for=condition=promoted
CI example:
代码语言:javascript复制# update the container image
kubectl set image deployment/podinfo podinfod=stefanprodan/podinfo:3.0.1
# wait for Flagger to detect the change
ok=false
until ${ok}; do
kubectl get canary/podinfo | grep 'Progressing' && ok=true || ok=false
sleep 5
done
# wait for the canary analysis to finish
kubectl wait canary/podinfo --for=condition=promoted --timeout=5m
# check if the deployment was successful
kubectl get canary/podinfo | grep Succeeded
Canary finalizers
Flagger 在 Canary 删除时的默认行为是让不属于控制器的资源保持其当前状态, 这简化了删除动作并避免了在资源最终确定时可能出现的死锁,
如果 Canary 与现有资源(即服务、虚拟服务等)一起被引入,它们将在初始化阶段被突变,不再反映其初始状态,
如果删除时希望的功能是将资源恢复到它们的初始状态,可以启用 revertOnDeletion 属性
代码语言:javascript复制spec:
revertOnDeletion: true
当一个删除动作被提交给集群时,Flagger 将尝试恢复以下资源:
. Canary target 副本将被更新为 primary 副本数量
. Canary service 选择器将被恢复
. Mesh/Ingress 流量被路由到 target 上
禁用 Canary 分析的推荐方法是利用 skipAnalysis 属性,它限制了对资源调节的需求, 当不打算再依赖 Flagger进行 deployment 管理时,应启用 revertOnDeletion 属性
注意: 当这个特性被启用时,由于调节的原因,删除动作会有延迟
Canary analysis
Canary 分析定义了:
. Deployment 策略的类型
. 用来验证 Canary 版本的指标
. 用于一致性测试、负载测试和手动门控的 webhooks
. 警报设置
代码语言:javascript复制Spec:
analysis:
# schedule interval (default 60s)
interval:
# max number of failed metric checks before rollback
threshold:
# max traffic percentage routed to canary
# percentage (0-100)
maxWeight:
# canary increment step
# percentage (0-100)
stepWeight:
# promotion increment step
# percentage (0-100)
stepWeightPromotion:
# total number of iterations
# used for A/B Testing and Blue/Green
iterations:
# threshold of primary pods that need to be available to consider it ready
# before starting rollout. this is optional and the default is 100
# percentage (0-100)
primaryReadyThreshold: 100
# threshold of canary pods that need to be available to consider it ready
# before starting rollout. this is optional and the default is 100
# percentage (0-100)
canaryReadyThreshold: 100
# canary match conditions
# used for A/B Testing
match:
- # HTTP header
# key performance indicators
metrics:
- # metric check
# alerting
alerts:
- # alert provider
# external checks
webhooks:
- # hook
Canary 分析周期性地运行,直到达到最大流量权重或迭代次数。在每次运行时,Flagger 都会调用 webhooks,检查指标,如果达到失败检查的阈值,则停止分析并回滚 canary。如果配置了警报,Flagger 将使用警报提供者发布分析结果