3 种发布策略,解决 K8s 中快速交付应用的难题
- - DockOne.io作者 | 郝树伟(流生)阿里云高级研发工程师. 软件技术更新换代很快,但我们追求的目标是一直不变的,那就是在安全稳定的前提下,增加应用的部署频率,缩短产品功能的迭代周期,这样的好处就是企业可以在更短的时间内获得产品的价值、更快地获得客户反馈和响应客户需求,从而进一步提升产品的竞争力;除此之外,企业还可以释放更多的资源投入到创新业务的研发上,创造更多的价值,这是一个良性循环的过程.
apiVersion: v1
kind: Service
metadata:
name: wordpress
spec:
type: ClusterIP # 默认的service类型,服务仅暴露为集群内部可访问
ports:
- port: 80 # 暴露给集群内部的服务端口
targetPort: 80 # 容器监听的服务端口
protocol: TCP
selector:
app: wordpress # 转发请求到有相同标签的后端pod
apiVersion: v1
kind: Service
metadata:
name: wordpress
spec:
type: NodePort # NodePort service类型,服务暴露一个固定的静态端口用于集群外部访问
ports:
- port: 80 # 暴露给集群内部的服务端口
targetPort: 80 # 容器监听的服务端口
protocol: TCP
nodePort: 31570 # 集群外部可以通过此端口访问服务
selector:
app: wordpress # 转发请求到有相同标签的后端pod
apiVersion: v1
kind: Service
metadata:
name: wordpress
spec:
type: LoadBalancer # LoadBalancer service类型,一般依赖于公共云厂商供的负载均衡能力
ports:
- port: 80 # 暴露给集群内部的服务端口
targetPort: 80 # 容器监听的服务端口
protocol: TCP
selector:
app: wordpress # 转发请求到有相同标签的后端pod
ClusterIP
服务类型仅限集群内通信, NodePort
可以实现暴露服务访问入口,但每个节点都会占用一个端口,会增加端口管理的复杂性,LoadBalancer 通常需要第三方云提供商支持,有一定的约束性。而 Ingress 这个服务类型跟我们前面的三种服务类型不一样,它实际上不是一种服务类型,而是类似一种集群服务入口的存在,它可以基于你配置的不同路径或者子域名把流量路由到对应的后端服务,更像是一个“智能路由”服务。 go-demo-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-demo
spec:
replicas: 3
selector:
matchLabels:
app: go-demo
template:
metadata:
labels:
app: go-demo
spec:
containers:
- name: go-demo
image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v1
imagePullPolicy: Always
ports:
- containerPort: 8080
apiVersion: v1
kind: Service
metadata:
name: go-demo
spec:
ports:
- port: 80
targetPort: 8080
name: go-demo
selector:
app: go-demo
type: ClusterIP
$ kubectl apply -f go-demo-v1.yaml
$ kubectl get po
NAME READY STATUS RESTARTS AGE
go-demo-78bc65c564-2rhxp 1/1 Running 0 19s
go-demo-78bc65c564-574z6 1/1 Running 0 19s
go-demo-78bc65c564-sgl2s 1/1 Running 0 19s
$ while sleep 0.1; do curl http://172.19.15.25; done
Version: v1
Version: v1
Version: v1
Version: v1
Version: v1
Version: v1
go-demo-v1.yaml
为 go-demo-v2.yaml
并更新镜像 tag...
registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v2
...
$ kubectl apply -f go-demo-v2.yaml
$kubectl get po -w
NAME READY STATUS RESTARTS AGE
application-demo-8594ff4967-85jsg 1/1 Running 0 3m24s
application-demo-8594ff4967-d4sv8 1/1 Terminating 0 3m22s
application-demo-8594ff4967-w6lpz 0/1 Terminating 0 3m20s
application-demo-b98d94554-4mwqd 1/1 Running 0 3s
application-demo-b98d94554-ng9wx 0/1 ContainerCreating 0 1s
application-demo-b98d94554-pmc5g 1/1 Running 0 4s
$ while sleep 0.1; do curl http://172.19.15.25; done
Version: v1
Version: v2
Version: v1
Version: v1
Version: v2
Version: v1
Version: v1
Version: v2
go-demo-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-demo-v1
spec:
replicas: 4
selector:
matchLabels:
app: go-demo
version: v1
template:
metadata:
labels:
app: go-demo
version: v1
spec:
containers:
- name: go-demo
image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v1
imagePullPolicy: Always
ports:
- containerPort: 8080
go-demo-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-demo-v2
spec:
replicas: 4
selector:
matchLabels:
app: go-demo
version: v2
template:
metadata:
labels:
app: go-demo
version: v2
spec:
containers:
- name: go-demo
image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v2
imagePullPolicy: Always
ports:
- containerPort: 8080
service.yaml
apiVersion: v1
kind: Service
metadata:
name: go-demo
spec:
ports:
- port: 80
targetPort: 8080
name: go-demo
selector:
app: go-demo
version: v1
type: ClusterIP
$ kubectl apply -f go-demo-v1.yaml -f go-demo-v2.yaml -f service.yaml
$ while sleep 0.1; do curl http://172.19.8.137; done
Version: v1
Version: v1
Version: v1
Version: v1
Version: v1
service.yaml
的 spec.selector 下 version=v2 apiVersion: v1
kind: Service
metadata:
name: go-demo
spec:
ports:
- port: 80
targetPort: 8080
name: go-demo
selector:
app: go-demo
version: v2
type: ClusterIP
$ kubectl apply -f service.yaml
$ [root@iZbp13u3z7d2tqx0cs6ovqZ blue-green]# while sleep 0.1; do curl http://172.19.8.137; done
Version: v2
Version: v2
Version: v2
go-demo-v1.yaml
设定副本数为 9apiVersion: apps/v1
kind: Deployment
metadata:
name: go-demo-v1
spec:
replicas: 9
selector:
matchLabels:
app: go-demo
version: v1
template:
metadata:
labels:
app: go-demo
version: v1
spec:
containers:
- name: go-demo
image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v1
imagePullPolicy: Always
ports:
- containerPort: 8080
go-demo-v2.yaml
设定副本数为 1apiVersion: apps/v1
kind: Deployment
metadata:
name: go-demo-v2
spec:
replicas: 1
selector:
matchLabels:
app: go-demo
version: v2
template:
metadata:
labels:
app: go-demo
version: v2
spec:
containers:
- name: go-demo
image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v2
imagePullPolicy: Always
ports:
- containerPort: 8080
service.yaml
apiVersion: v1
kind: Service
metadata:
name: go-demo
spec:
ports:
- port: 80
targetPort: 8080
name: go-demo
selector:
app: go-demo
type: ClusterIP
$ kubectl apply -f go-demo-v1.yaml -f go-demo-v2.yaml -f service.yaml
$ while sleep 0.1; do curl http://172.19.8.248; done
Version: v1
Version: v2
Version: v1
Version: v1
Version: v1
Version: v1
Version: v1
Version: v1
Version: v1
Version: v1
Version: v1
go-demo-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-demo-v1
spec:
replicas: 3
selector:
matchLabels:
app: go-demo
version: v1
template:
metadata:
labels:
app: go-demo
version: v1
spec:
containers:
- name: go-demo
image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v1
imagePullPolicy: Always
ports:
- containerPort: 8080
go-demo-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-demo-v2
spec:
replicas: 1
selector:
matchLabels:
app: go-demo
version: v2
template:
metadata:
labels:
app: go-demo
version: v2
spec:
containers:
- name: go-demo
image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v2
imagePullPolicy: Always
ports:
- containerPort: 8080
service-v1.yaml
apiVersion: v1
kind: Service
metadata:
name: go-demo-v1
spec:
ports:
- port: 80
targetPort: 8080
name: go-demo
selector:
app: go-demo
version: v1
type: ClusterIP
service-v2.yaml
apiVersion: v1
kind: Service
metadata:
name: go-demo-v2
spec:
ports:
- port: 80
targetPort: 8080
name: go-demo
selector:
app: go-demo
version: v2
type: ClusterIP
ingress.yaml
, 设置 nginx.ingress.kubernetes.io/service-weight: | go-demo-v1: 100, go-demo-v2: 0
, 版本1 - 100% 流量, 版本2 - 0% 流量apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/service-weight: |
go-demo-v1: 100, go-demo-v2: 0
name: go-demo
labels:
app: go-demo
spec:
rules:
- host: go-demo.example.com
http:
paths:
- path: /
backend:
serviceName: go-demo-v1
servicePort: 80
- path: /
backend:
serviceName: go-demo-v2
servicePort: 80
$ kubectl apply -f go-demo-v1.yaml -f go-demo-v2.yaml -f service-v1.yaml -f service-v2.yaml -f nginx.yaml
$ while sleep 0.1; do curl http://go-demo.example.com; done
Version: v1
Version: v1
Version: v1
Version: v1
Version: v1
Version: v1
ingress.yaml
, 设置流量比为 50:50apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/service-weight: |
go-demo-v1: 50, go-demo-v2: 50
name: go-demo
labels:
app: go-demo
spec:
rules:
- host: go-demo.example.com
http:
paths:
- path: /
backend:
serviceName: go-demo-v1
servicePort: 80
- path: /
backend:
serviceName: go-demo-v2
servicePort: 80
$ while sleep 0.1; do curl http://go-demo.example.com; done
Version: v2
Version: v1
Version: v1
Version: v1
Version: v2
Version: v2
Version: v1
Version: v1
Version: v2
Version: v2
ingress.yaml
, 设置流量比为 0:100apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/service-weight: |
go-demo-v1: 0, go-demo-v2: 100
name: go-demo
labels:
app: go-demo
spec:
rules:
- host: go-demo.example.com
http:
paths:
- path: /
backend:
serviceName: go-demo-v1
servicePort: 80
- path: /
backend:
serviceName: go-demo-v2
servicePort: 80
$ while sleep 0.1; do curl http://go-demo.example.com; done
Version: v2
Version: v2
Version: v2
Version: v2
Version: v2
Version: v2
Version: v2
Version: v2
Version: v2
Version: v2
“ 阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的技术圈。”