开发者可以通过kuberneters annotation,很容易控制服务的流量,实现灰度发布
应用场景
- 微服务各组件独立更新,然后验证又必须在实际环境中进行
- 部署新功能有风险,然后可以通过导流一小部分用户实际使用,来减小风险
- 依赖的第三方组件,无法很好地进行测试,只能依靠实际的使用,来验证是否能成功的对接。
过程
- 部署v2版本,定义导量1%
- 测试(请求多少次,有木有失败之类的,由业务方决定),观测和监控
- 没有问题则v2 100%(没有迭代的过程,区别滚动部署),下线v1版本
架构图
工作流程
- service annotation中定义配置,Kubernetes API 异步通知 Ambassador 的更改。
- Ambassador 将配置转换为抽象的中间代码 (IR)。
- 从 IR 中生成一个 Envoy 配置文件。
- 使用 Ambassador 验证 Envoy 配置文件。
- 如果配置文件有效,Ambassador 将使用 Envoy 的热重新启动机制来部署新的配置,并保持连接。
- 流量将会在新启动的 Envoy 进程中传输。
功能描述
Self-Service via Kubernetes Annotations
developer可以通过kubernetes service 的annotations来定义ambassadorf服务,很容易集成到你的现有项目中。
Flexible Canary Deployments
developer可以通过kuberneters annotation很容易控制到服务的流量,实现金丝雀发布。
Kubernetes-Native Architecture
利用k8s原生能力实现可靠性、可用性和可伸缩性。使用envoy实现路由和代理
gRPC and HTTP/2 Support
由envoy提供的能力
Istio Integration
和istio配合实现服务网格。ambassador作为边缘代理,实现外部流量到内部istio的桥梁。
Authentication
ambassador支持请求认证。如果配置了,ambassador在路由之前会事先请求第三方认证服务
Rate Limiting
ambassador支持限流。ambassador在路由之前会事先请求第三方速度限流服务
Integrated Diagnostics
ambassador包含一个诊断服务,可以快速定位问题
部署
测试
提前部署两个后台服务 sv1 和 sv2
sv1 请求返回"Hello World, this is test service num 1!"
sv2 请求返回"Hello World, this is test service num 2!"
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: svc1
spec:
replicas: 1
strategy:
type: RollingUpdate
template:
metadata:
labels:
app: svc1
spec:
containers:
- name: svc1
image: ambassador-sv1:1.0
ports:
- name: http-api
containerPort: 5000
resources:
limits:
cpu: "0.1"
memory: 100Mi
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: svc2
spec:
replicas: 1
strategy:
type: RollingUpdate
template:
metadata:
labels:
app: svc2
spec:
containers:
- name: svc2
image: ambassador-sv2:1.0
ports:
- name: http-api
containerPort: 5000
resources:
limits:
cpu: "0.1"
memory: 100Mi
根据weight进行灰度
以80%的概率路由到svc1, 20%的概率路由到svc2
svc1 (不配置权重,默认100%)
---
apiVersion: v1
kind: Service
metadata:
name: svc1
namespace: 295-a222222
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: svc1_mapping
prefix: /svc/
service: svc1.295-a222222:8080
spec:
selector:
app: svc1
ports:
- port: 8080
name: http-svc
targetPort: http-api
svc2
---
apiVersion: v1
kind: Service
metadata:
name: svc2
namespace: 295-a222222
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: svc2_mapping
prefix: /svc/
service: svc2.295-a222222:8080
weight: 20
spec:
selector:
app: svc2
ports:
- port: 8080
name: http-svc
targetPort: http-api
结果:
[root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 2![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 2![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 2![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl
根据请求头 header 进行灰度 (regex_headers 正则匹配)
请求头中包含Cookie: UM_distinctid=12345
的请求全部路由到svc2中
---
apiVersion: v1
kind: Service
metadata:
name: svc2
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: svc2_mapping
prefix: /svc/
service: svc2
headers:
Cookie: UM_distinctid=12345
spec:
selector:
app: svc2
ports:
- port: 80
name: http-svc2
targetPort: http-api
regex_headers
apiVersion: v1
kind: Service
metadata:
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: create
prefix: /svc/create/
service: create:8080
regex_headers:
Cookie: "ddddd.*"
结果:
[root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]# curl 10.104.75.142:80/svc/
Hello World, this is test service num 1![root@master01 ambassador]#
[root@master01 ambassador]#
[root@master01 ambassador]# curl -H "Cookie: UM_distinctid=12345" 10.104.75.142:80/svc/
Hello World, this is test service num 2![root@master01 ambassador]# curl -H "Cookie: UM_distinctid=12345" 10.104.75.142:80/svc/
Hello World, this is test service num 2![root@master01 ambassador]# curl -H "Cookie: UM_distinctid=12345" 10.104.75.142:80/svc/
Hello World, this is test service num 2![root@master01 ambassador]# curl -H "Cookie: UM_distinctid=12345" 10.104.75.142:80/svc/
Hello World, this is test service num 2![root@master01 ambassador]# curl -H "Cookie: UM_distinctid=12345" 10.104.75.142:80/svc/
Hello World, this is test service num 2![root@master01 ambassador]# curl -H "Cookie: UM_distinctid=12345" 10.104.75.142:80/svc/
Hello World, this is test service num 2![root@master01 ambassador]#
业务灰度流程
当前业务
即需要更新的业务,此时业务流向全走向svc1
kubectl apply -f svc1.yaml
apiVersion: v1
kind: Service
metadata:
name: svc1
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: svc1_mapping
prefix: /svc/
service: svc1
spec:
····
查看ambassador的流量代理
url | service | weight |
---|---|---|
http://172.31.133.26:31327/svc/ | svc1 | 100.0% |
灰度版本
部署svc2.yaml,此时带header: Cookie: UM_distinctid=12345
流量走向svc2,不带header流量依旧走svc1。
kubectl apply -f svc2.yaml
---
apiVersion: v1
kind: Service
metadata:
name: svc2
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: svc2_mapping
prefix: /svc/
service: svc2
headers:
Cookie: UM_distinctid=12345
spec:
···
查看ambassador的流量代理
url | service | weight |
---|---|---|
http://172.31.133.26:31327/svc/ | svc1 | 100.0% |
http://172.31.133.26:31327/svc/ Cookie: UM_distinctid=12345 |
svc2 | 100.0% |
流量切换
第一步
更新header(去掉header),此时一半流量到svc1,一半到svc2
kubectl apply -f svc2.yaml
---
apiVersion: v1
kind: Service
metadata:
name: svc2
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: svc2_mapping
prefix: /svc/
service: svc2
# headers:
# Cookie: UM_distinctid=12345
spec:
···
查看ambassador的流量代理
url | service | weight |
---|---|---|
http://172.31.133.26:31327/svc/ | svc1 svc2 |
50.0% 100.0% |
第二步
下线老的服务svc1,流量全部走到svc2
kubectl delete -f svc1.yaml
查看ambassador的流量代理
url | service | weight |
---|---|---|
http://172.31.133.26:31327/svc/ | svc2 | 100.0% |