渐进式交付(Progressive delivery)是一种软件发布策略,旨在更安全、更可控地将新版本软件逐步推出给用户。它是持续交付的进一步提升,允许开发团队在发布新版本时拥有更细粒度的控制,例如可以根据用户反馈、性能指标和其他关键数据来调整发布过程。渐进式交付通过利用一系列现代部署方案如蓝绿部署(Blue-Green Deployments)、金丝雀发布(Canary Releases)等让开发团队能够更灵活地管理风险,同时加快新功能的发布速度。
Argo Rollouts 包括一个 Kubernetes控制器 和一组 CRD,提供如蓝绿色、金丝雀、金丝雀分析、体验等高级部署功能和 Kubernetes 的渐进交付功能。
之前曾分享过 使用 Argo Rollouts 和服务网格实现自动可控的金丝雀发布(彼时的服务网格现已更名为 FSM),这是通过服务网格技术实现了东西向流量的金丝雀发布。虽然以此可以确保内部服务之间的平滑过渡,但这并不足以保证最终用户体验的质量。我们还需要手段来控制新版本对最终用户的可变性及影响,因此对于南北向流量 – 入口的网络流量 – 金丝雀发布变得不可或缺。
对于 Kubernetes 的入口流量管理,常见的有如 Ingress Controller、Gateway API。作为服务网格 FSM 组件之一的 FSM Gateway 是一个开源的 Kubernetes Gateway API 实现,它使用可编程应用引擎 Pipy 作为代理配置路由和策略来管理入口流量。关于 FSM Gateway 的使用,可以查看之前的 系列文章。
rollouts-plugin-trafficrouter-gatewayapi 是 Argo Rollouts 的一个插件它实现了 Kubernetes Gateway API 规范。使用它可以使用 FSM Gateway 实现渐进式的交付,当然你可以使用其他的实现。
今天就以 FSM Gateway 为例介绍如何使用 Argo Rollouts 进行南北向流量的金丝雀发布。
前置条件
- Kubernetes 集群,最低版本 1.23
- kubectl cli
准备环境
安装 FSM Gateway
我们可以通过 FSM CLI 来安装 FSM Gateway,参考 文档 下载并安装 FSM CLI,当前最新的版本为 1.2.3。
system=$(uname -s | tr '[:upper:]' '[:lower:]')
arch=$(uname -m | sed -E 's/x86_/amd/' | sed -E 's/aarch/arm/')
release=v1.2.3
curl -L https://github.com/flomesh-io/fsm/releases/download/$release/fsm-$release-$system-$arch.tar.gz | tar -vxzf -
./$system-$arch/fsm version
cp ./$system-$arch/fsm /usr/local/bin/fsm
使用下面的命令安装 FSM Gateway,作为 服务网格 FSM 的众多组件之一,FSM Gateway 的运行会由 FSM 控制器管理。
fsm install \
--set=fsm.fsmGateway.enabled=true
如果你已经安装了 FSM,可以通过下面的命令来启用网关。
fsm gateway enable
在成功安装 FSM Gateway 之后,可以看到 gateway class fsm-gatweay-cls
已经就绪。
kubectl get gatewayclass
NAME CONTROLLER ACCEPTED AGE
fsm-gateway-cls flomesh.io/gateway-controller True 2m35s
与 FSM Gateway 一同安装的还有 Gateway API 的 CRD。
创建 Gateway 对象
安装了 FSM Gateway 并不意味着马上可以开始接管流量,我们还需要创建 Gateway 对象。
kubectl apply -n default -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: simple-fsm-gateway
spec:
gatewayClassName: fsm-gateway-cls
listeners:
- protocol: HTTP
port: 80
name: http
allowedRoutes:
namespaces:
from: Same
EOF
获取 Gateway 的 IP 地址。
export GATEWAY_IP=$(kubectl get svc -n default -l app=fsm-gateway -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}')
安装 Argo Rollouts
使用下面的命令在集群中安装最新的 Argo Rollouts,其运行在命名空间 argo-rollouts
中。
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
为了 Argo Rollouts 能够通过修改路由来控制流量,需要为其创建 ClusterRole
和 ClusterRoleBinding
。(这个操作在每个集群只需一次即可)
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gateway-controller-role
namespace: argo-rollouts
rules:
- apiGroups:
- "*"
resources:
- "*"
verbs:
- "*"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: gateway-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: gateway-controller-role
subjects:
- namespace: argo-rollouts
kind: ServiceAccount
name: argo-rollouts
EOF
安装 kubectl argo 插件
使用 kubectl argo 插件可以通过命令行对发布进行操作。
在 macOS 下,其他平台参考 官方安装文档。
brew install argoproj/tap/kubectl-argo-rollouts
通过下面的命令启动 Argo Rollouts Dashboard,在浏览器中打开 [http://localhost:3100/rollouts](http://localhost:3100/rollouts)
就可访问 Dashboard。
kubectl argo rollouts dashboard
安装 Rollouts Gateway API 插件
安装 Gateway API 插件需要在 Configmap 中指定插件的下载地址,执行下面的命令后 Rollouts 的控制面会从该地址下载并安装。截止本文发布,插件的最新版本是 0.2.0。
注意,请安装对应平台的插件。
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: argo-rollouts-config # must be so name
namespace: argo-rollouts # must be in this namespace
data:
trafficRouterPlugins: |-
- name: "argoproj-labs/gatewayAPI"
location: "https://github.com/argoproj-labs/rollouts-plugin-trafficrouter-gatewayapi/releases/download/v0.2.0/gateway-api-plugin-linux-amd64"
EOF
创建 Service
创建两个 Service argo-rollouts-stable-service
和 argo-rollouts-canary-service
,这两个 Service 将作为 Gateway 的后端服务,由 Rollouts 控制到各个 Service 的流量权重。
kubectl apply -n default -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: argo-rollouts-stable-service
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: rollouts-demo
---
apiVersion: v1
kind: Service
metadata:
name: argo-rollouts-canary-service
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: rollouts-demo
EOF
创建 HTTP 路由
有了服务之后,就是在 Gateway 创建对应的 HTTPRoute
配置路由,默认将所有的流量都代理到稳定版。
kubectl apply -n default -f - <<EOF
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: argo-rollouts-http-route
spec:
parentRefs:
- name: simple-fsm-gateway
port: 80
hostnames:
- "demo.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: argo-rollouts-stable-service
kind: Service
port: 100
- name: argo-rollouts-canary-service
kind: Service
port: 0
EOF
创建 Rollout
创建资源 Rollout:
- 使用策略
canary
- 指定创面创建的两个 Service 分别作为
stableService
和canaryService
- 流量路由使用插件
argoproj-labs/gatewayAPI
,以及操作的HTTPRoute
为argo-rollouts-http-route
- 指定发布的流程
steps
- 最终要的就是
template
中配置我们的应用,也就是稳定版,与 Deployment 的template
一致。
kubectl apply -n default -f- <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: rollouts-demo
spec:
replicas: 3
strategy:
canary:
canaryService: argo-rollouts-canary-service # our created canary service
stableService: argo-rollouts-stable-service # our created stable service
trafficRouting:
plugins:
argoproj-labs/gatewayAPI:
httpRoute: argo-rollouts-http-route # our created httproute
namespace: default
steps:
- setWeight: 30
- pause: { duration: 30s }
- setWeight: 60
- pause: { duration: 30s }
- setWeight: 100
- pause: { duration: 30s }
revisionHistoryLimit: 2
selector:
matchLabels:
app: rollouts-demo
template:
metadata:
labels:
app: rollouts-demo
spec:
containers:
- name: rollouts-demo
image: kostiscodefresh/summer-of-k8s-app:v1
ports:
- name: http
containerPort: 8080
protocol: TCP
resources:
requests:
memory: 32Mi
cpu: 5m
EOF
创建完成后便通过命令行访问示例应用了。
curl -H "host: demo.example.com" $GATEWAY_IP/callme
此时会看到如下的结果,说明正在运行的 1.0 版本。
<div class='pod' style='background:#44B3C2'> ver: 1.0
</div>
执行金丝雀发布
接着我们修改 Rollout
,将示例应用的镜像更新为 2.0 版本。
kubectl patch rollout rollouts-demo -n default \
--type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"kostiscodefresh/summer-of-k8s-app:v2"}]'
可以通过下命令持续查看示例应用的运行。
while true; do curl -H "host: demo.example.com" $GATEWAY_IP/callme; done
当然,在 Argo Rollouts 的 Dashboard 中我们可以更加直观地看到 Rollout 的执行流程。
最终,rollouts-demo 完成升级,旧版本的实例完全退出。
关于 Flomesh
Flomesh(易衡科技)成立于 2018 年,自主研发并开源了高性能可编程代理 Pipy(https://github.com/flomesh-io/pipy)。以 Pipy 为基础,Flomesh 研发了软件负载均衡、服务网格两款软件产品。为工信部认证的可信云产品、可信开源项目。
Flomesh 核心竞争力来自完全自研的核心组件 Pipy,该组件高性能、高可靠、低延迟、可编程、可扩展、低依赖,采用 C++ 开发,内置自研的 JS 引擎,支持适用 JS 脚本做扩展开发。支持包括 x86、arm、龙芯、海光等硬件 CPU 架构;支持 Linux、FreeBSD、macOS、Windows、OpenWrt 等多种核心的操作系统。
Flomesh 成立以来,以技术为根基、以客户为导向,产品被应用在头部股份制商业银行总行、大型保险公司、运营商总部以及研究院等众多客户和多个场景。