2

引言

Kubernetes有一个资源对象,称为Deployments。 当你将应用程序更新到新版本时,Deployments具有进行容器滚动更新的功能。 滚动更新是一种更新应用程序的好方法,因为应用程序在更新过程中使用的资源与未更新时使用的资源数量大致相同,从而对性能和可用性的影响最小。

但是,有许多旧版应用程序不能很好地与滚动更新配合使用,某些应用程序只需要部署一个新版本并立即转换到新版本即可。 为此,我们需要执行蓝/绿部署,将现有版本(蓝色)一起部署应用程序的新副本(绿色), 然后将更新过的应用程序对应的ingress/router切换到新版本(绿色 ,接着等待旧的(蓝色)版本完成发送给它的请求,在绝大多数情况下,应用的流量会立刻切换到新版本。
image.png
Kubernetes不支持内置的蓝/绿部署,这里使用的方法是创建一个新的deployment,然后更新该应用程序的服务以指向新的deployment。

蓝色部署

Kubernetes deployment指定一组应用程序实例,它创建了一个副本集(replicaset),该副本集负责保持指定数量的实例正常运行。

image.png
通过将以下yaml保存到文件blue.yaml中来创建“ blue”deployment。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-1.10
spec:
  replicas: 3
  template:
    metadata:
      labels:
        name: nginx
        version: "1.10"
    spec:
      containers: 
        - name: nginx
          image: nginx:1.10
          ports:
            - name: http
              containerPort: 80

使用kubectl命令行创建deployment

$ kubectl apply -f blue.yaml

部署完成后,我们可以提供一种通过创建service来访问deployment实例的方法。 service与deployment是分离的,这意味着无需明确将service指向deployment。 你要做的是指定一个标签选择器(label selector),该标签选择器用于列出组成service的pod。 使用deployment时,通常会设置标签选择器使其与deployment的pod匹配。
在本例中有两个标签,name= nginx和version= 1.10。 我们将它们设置为以下service的标签选择器,将其保存到service.yaml。

apiVersion: v1
kind: Service
metadata: 
  name: nginx
  labels: 
    name: nginx
spec:
  ports:
    - name: http
      port: 80
      targetPort: 80
  selector: 
    name: nginx
    version: "1.10"
  type: LoadBalancer

创建service的同时创建一个可以在群集外部访问的load balancer。

$ kubectl apply -f service.yaml

看起来像这样:

image.png
测试这个service是否可访问并获取它的版本号。

$ EXTERNAL_IP=$(kubectl get svc nginx -o jsonpath="{.status.loadBalancer.ingress[*].ip}")
$ curl -s http://$EXTERNAL_IP/version | grep nginx

绿色部署

现在创建一个新的deployment叫做green deployment(绿色部署),使用green.yaml来创建

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-1.11
spec:
  replicas: 3
  template:
    metadata:
      labels:
        name: nginx
        version: "1.11"
    spec:
      containers: 
        - name: nginx
          image: nginx:1.11
          ports:
            - name: http
              containerPort: 80

执行创建

$ kubectl apply -f green.yaml

现在有两个deployment但是service仍然指向blue deployment
image.png

更新应用

为了切换到“green”deployment,我们将更新service的selector。 编辑service.yaml并将selector版本更改为“ 1.11”,使其与“green”deployment中的pod匹配。

apiVersion: v1
kind: Service
metadata: 
  name: nginx
  labels: 
    name: nginx
spec:
  ports:
    - name: http
      port: 80
      targetPort: 80
  selector: 
    name: nginx
    version: "1.11"
  type: LoadBalancer

更新当前的nginx service

$ kubectl apply -f service.yaml

现在的情况变成了下面这样
image.png
立即更新service的selector你将会看到新版本的nginx正在接收外部流量

$ EXTERNAL_IP=$(kubectl get svc nginx -o jsonpath="{.status.loadBalancer.ingress[*].ip}")
$ curl -s http://$EXTERNAL_IP/version | grep nginx

自动化

使用脚本实现自动化的蓝/绿部署,以下脚本使用service的名称,要部署的版本以及green deployment的yaml文件的路径,并使用kubectl进行完整的蓝/绿部署,使用jq从API对其进行解析并输出原始JSON文件,在更新service definition之前,它通过检查deployment对象上的status.conditions等待green deployment准备就绪。
下面提供一个脚本

#!/bin/bash
# bg-deploy.sh <servicename> <version> <green-deployment.yaml>
# Deployment name should be <service>-<version>
DEPLOYMENTNAME=$1-$2
SERVICE=$1
VERSION=$2
DEPLOYMENTFILE=$3
kubectl apply -f $DEPLOYMENTFILE
# Wait until the Deployment is ready by checking the MinimumReplicasAvailable condition.
READY=$(kubectl get deploy $DEPLOYMENTNAME -o json | jq '.status.conditions[] | select(.reason == "MinimumReplicasAvailable") | .status' | tr -d '"')
while [[ "$READY" != "True" ]]; do
    READY=$(kubectl get deploy $DEPLOYMENTNAME -o json | jq '.status.conditions[] | select(.reason == "MinimumReplicasAvailable") | .status' | tr -d '"')
    sleep 5
done
# Update the service selector with the new version
kubectl patch svc $SERVICE -p "{\"spec\":{\"selector\": {\"name\": \"${SERVICE}\", \"version\": \"${VERSION}\"}}}"
echo "Done."

想深入学习的话,我在github上提供了一个教程和一些示例清单。


EngineerLeo
598 声望38 粉丝

专注于云原生、AI等相关技术