avatar

用kubernetes对服务进行灰度发布和蓝绿部署


基本概念

灰度发布(又名金丝雀发布)是指在黑与白之间,能够平滑过渡的一种发布方式。在其上可以进行A/B testing,即让一部分用户继续用产品特性A,一部分用户开始用产品特性B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。

蓝绿部署是不停老版本,部署新版本然后进行测试,确认OK,将流量切到新版本,然后老版本同时也升级到新版本。

灰度是不同版本共存,蓝绿是新旧版本切换,2种模式的出发点不一样。

环境准备

1. 下载安装minikube

minikube是一个可以快速在单机上部署kubernetes并运行容器的工具,由于条件有限,我都是用它来学习Kubernetes知识。

Mac OSX

1curl -Lo minikube https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/releases/v1.13.0/minikube-darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/

Linux

1curl -Lo minikube https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/releases/v1.13.0/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/

2. 启动

本机环境需提前安装好docker-engine

1minikube start --driver=none

启动成功之后,查看启动的pods

1kubectl get pods -A
NAMESPACE              NAME                                        READY   STATUS    RESTARTS   AGE
kube-system            coredns-6c76c8bb89-nz22j                    1/1     Running   2          24h
kube-system            etcd-minikube                               1/1     Running   2          24h
kube-system            kube-apiserver-minikube                     1/1     Running   2          24h
kube-system            kube-controller-manager-minikube            1/1     Running   2          24h
kube-system            kube-proxy-2qwq9                            1/1     Running   2          24h
kube-system            kube-scheduler-minikube                     1/1     Running   2          24h
kube-system            storage-provisioner                         1/1     Running   3          24h
kubernetes-dashboard   dashboard-metrics-scraper-c95fcf479-7qnhf   1/1     Running   0          24h
kubernetes-dashboard   kubernetes-dashboard-5c448bc4bf-6gccm       1/1     Running   0          24h

3. 准备镜像

准备Dockerfile文件

FROM python:alpine 
RUN pip install flask -i https://pypi.douban.com/simple
COPY app.py /app.py
EXPOSE 5000
ENTRYPOINT ["python", "/app.py"]

app.py

 1from flask import Flask
 2from flask import request
 3from flask import jsonify
 4import socket
 5
 6
 7app = Flask(__name__)
 8
 9@app.route('/')
10def index():
11    return jsonify({'Version': 'v1',
12                    'Hostname': socket.gethostname(),
13                    'Address': socket.gethostbyname(socket.gethostname()),
14                    'Message': 'Hello, World',
15                    })
16		    
17
18
19if __name__ == '__main__':
20    app.run('0.0.0.0', 5000)

构建第一个镜像:

1docker build . -t flask-app:v1

构建第二个镜像:

先将app.py里面的v1改为v2

1docker build . -t flask-app:v2

如此我们便有了两个版本的镜像。

蓝绿部署

准备deployment和service文件,内容如下:

deployment-v1.yaml

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: flask-app
 5spec:
 6  replicas: 1
 7  selector:
 8    matchLabels:
 9      app: flask-app
10      version: v1
11  template:
12    metadata:
13      labels:
14        app: flask-app
15        version: v1
16    spec:
17      containers:
18      - image: flask-app:v1
19        name: flask-app
20        ports:
21        - containerPort: 5000

deployment-v2.yaml

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: flask-app-v2
 5spec:
 6  replicas: 1
 7  selector:
 8    matchLabels:
 9      app: flask-app
10      version: v2
11  template:
12    metadata:
13      labels:
14        app: flask-app
15        version: v2
16    spec:
17      containers:
18      - image: flask-app:v2
19        name: flask-app
20        ports:
21        - containerPort: 5000

service.yaml

 1apiVersion: v1
 2kind: Service
 3metadata:
 4  name: flask-app
 5spec:
 6  ports:
 7  - name: "http"
 8    port: 5000
 9    protocol: TCP
10    targetPort: 5000
11  selector:
12    app: flask-app
13    version: v1
14  type: NodePort

执行: kubectl apply -f deployment-v1.yaml

执行: kubectl apply -f service.yaml

执行: minikube ip 查看节点ip, kubectl get svc查看nodeport端口

执行: curl $http://${node_ip}:${node_port}

输出:

{"Address":"172.17.0.4","Hostname":"flask-app-69cd76c45c-kpzn5","Message":"Hello, World","Version":"v1"}

执行: kubectl apply -f deployment-v2.yaml

将service.yaml里面的v1全部改为v2

执行: kubectl apply -f service.yaml

继续执行: curl $http://${node_ip}:${node_port}

输出:

{"Address":"172.17.0.8","Hostname":"flask-app-v2-6748f77677-vb4rx","Message":"Hello, World","Version":"v2"}

灰度发布

进行灰度发布之前先清理一下之前的deployment和service

1kubectl delete -f deployment-v1.yaml
2kubectl delete -f deployment-v2.yaml
3kubectl delete -f service.yaml

准备几个文件
deployment-canary-v1.yaml

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: flask-app-v1
 5spec:
 6  replicas: 1
 7  selector:
 8    matchLabels:
 9      app: flask-app
10  template:
11    metadata:
12      labels:
13        app: flask-app
14    spec:
15      containers:
16      - image: flask-app:v1
17        name: flask-app
18        ports:
19        - containerPort: 5000

deployment-canary-v2.yaml

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: flask-app-v2
 5spec:
 6  replicas: 1
 7  selector:
 8    matchLabels:
 9      app: flask-app
10  template:
11    metadata:
12      labels:
13        app: flask-app
14    spec:
15      containers:
16      - image: flask-app:v2
17        name: flask-app
18        ports:
19        - containerPort: 5000

service-canary.yaml

 1apiVersion: v1
 2kind: Service
 3metadata:
 4  name: flask-app
 5spec:
 6  ports:
 7  - name: "http"
 8    port: 5000
 9    protocol: TCP
10    targetPort: 5000
11  selector:
12    app: flask-app
13  type: NodePort

执行:

1kubectl apply -f deployment-canary-v1.yaml
2kubectl apply -f deployment-canary-v2.yaml
3kubectl apply -f service-canary.yaml

执行: kubectl get svc查看nodeport

执行:

1while true; do curl http://${node_ip}:${node_port}; done

输出:

{"Address":"172.17.0.7","Hostname":"flask-app-69cd76c45c-knn4c","Message":"Hello, World","Version":"v1"}
{"Address":"172.17.0.4","Hostname":"flask-app-v2-7c957654cc-2mtbb","Message":"Hello, World","Version":"v2"}
{"Address":"172.17.0.4","Hostname":"flask-app-v2-7c957654cc-2mtbb","Message":"Hello, World","Version":"v2"}
{"Address":"172.17.0.4","Hostname":"flask-app-v2-7c957654cc-2mtbb","Message":"Hello, World","Version":"v2"}
{"Address":"172.17.0.7","Hostname":"flask-app-69cd76c45c-knn4c","Message":"Hello, World","Version":"v1"}
{"Address":"172.17.0.7","Hostname":"flask-app-69cd76c45c-knn4c","Message":"Hello, World","Version":"v1"}
{"Address":"172.17.0.4","Hostname":"flask-app-v2-7c957654cc-2mtbb","Message":"Hello, World","Version":"v2"}

利用service roundrobin负载均衡,可以看到v1与v2的服务共存。

评论列表:

暂无评论 😭