写在前面
通过POD 应用就有了存在的形式,通过deployment 保证了POD在一定的数量,通过service 可以实现一定数量的POD以负载均衡的方式对外提供服务。但,如果是程序开发了新功能,需要上线,该怎么办呢?对此k8s提供了平滑升级的解决方案,本文就一起来看下吧!
1:k8的版本是什么
在正式开始前,我们还需要看下什么是版本。在我们日常开发中完成一个功能后,一般都会在git上打一个tag,比如tag-v1.0,之后可能还会有其它版本,如下图:
这就是程序的版本,那么对于k8s来说版本是什么呢?当然肯定不是git这里的版本,而是yaml文件POD的template
内容,但是yaml文件可能很大,总不能将其整个内容作为版本号吧,自然是不可以的,所以k8s采用的方案是将template部分执行hash得到一个一定长度的字符串,如下:
dongyunqi@mongodaddy:~/k8s$ kubectl get pod
NAME READY STATUS RESTARTS AGE
ngx-dep-name-bfbb5f64b-ds78j 1/1 Running 0 6s
ngx-dep-name-bfbb5f64b-xr6gw 1/1 Running 0 6s
NAME列中的bfbb5f64b
就是哈希template后的版本号了。
2:如何平滑升级
这里我们使用Nginx的镜像来测试,首先定义个ConfigMap,如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: ngx-conf
data:
default.conf: |
server {
listen 80;
location / {
default_type text/plain;
return 200
'ver : $nginx_version\nsrv : $server_addr:$server_port\nhost: $hostname\n';
}
}
apply:
dongyunqi@mongodaddy:~/k8s$ kubectl apply -f smooth-upgrade-cm.yml
configmap/ngx-conf created
dongyunqi@mongodaddy:~/k8s$ kubectl get cm
NAME DATA AGE
ngx-conf 1 8s
接着我们来创建deployment,yaml如下:
dongyunqi@mongodaddy:~/k8s$ cat smooth-upgrade-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: ngx-dep-app
name: ngx-dep-name
spec:
replicas: 3
selector:
matchLabels:
app: ngx-dep-pod
template:
metadata:
labels:
app: ngx-dep-pod
spec:
volumes:
- name: ngx-conf-vol
configMap:
name: ngx-conf
containers:
- image: nginx:alpine
name: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /etc/nginx/conf.d
name: ngx-conf-vol
apply后查看如下:
dongyunqi@mongodaddy:~/k8s$ kubectl apply -f smooth-upgrade-deployment.yml
deployment.apps/ngx-dep-name created
dongyunqi@mongodaddy:~/k8s$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
ngx-dep-name 3/3 3 3 5s
看下POD:
dongyunqi@mongodaddy:~/k8s$ kubectl get pod -l app=ngx-dep-pod
NAME READY STATUS RESTARTS AGE
ngx-dep-name-dcc8b7bfd-bhksq 1/1 Running 0 111s
ngx-dep-name-dcc8b7bfd-t96np 1/1 Running 0 111s
ngx-dep-name-dcc8b7bfd-tsvmc 1/1 Running 0 111s
可以看到此时的版本号是dcc8b7bfd
,但此时我们还不能访问POD,需要继续定义service,yaml如下:
dongyunqi@mongodaddy:~/k8s$ cat smooth-upgrade-service.yml
apiVersion: v1
kind: Service
metadata:
name: ngx-svc
spec:
selector:
app: ngx-dep-pod # 查找app label为ngx-dep-pod的POD
ports:
- port: 80
targetPort: 80
protocol: TCP
以上service的80端口映射到后端POD们的80端口。
apply后查看如下:
dongyunqi@mongodaddy:~/k8s$ kubectl apply -f smooth-upgrade-service.yml
service/ngx-svc created
dongyunqi@mongodaddy:~/k8s$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
ngx-svc ClusterIP 10.99.187.192 <none> 80/TCP 6s
dongyunqi@mongodaddy:~/k8s$ kubect describe service ngx-svc
kubect: command not found
dongyunqi@mongodaddy:~/k8s$ kubectl describe service ngx-svc
Name: ngx-svc
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=ngx-dep-pod
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.99.187.192
IPs: 10.99.187.192
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.10.4.10:80,10.10.4.11:80,10.10.4.12:80
Session Affinity: None
Events: <none>
接着为了能够在外部访问我们使用port-forward来转发Node的8080端口到service的80端口,如下:
dongyunqi@mongodaddy:~/k8s$ kubectl port-forward svc/ngx-svc 8080:80 &
[1] 115371
dongyunqi@mongodaddy:~/k8s$ Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
然后就可以访问了,如下:
dongyunqi@mongodaddy:~/k8s$ curl 127.0.0.1:8080
Handling connection for 8080
ver : 1.21.5
srv : 127.0.0.1:80
host: ngx-dep-name-dcc8b7bfd-bhksq
可以看到此时Nginx的版本号是1.21.5
,接着我们来修改Nginx的版本号为nginx:1.22-alpine
模拟应用的升级,deployment的yaml修改后如下:
dongyunqi@mongodaddy:~/k8s$ cat smooth-upgrade-deploymentv2.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: ngx-dep-app
name: ngx-dep-name
spec:
minReadySeconds: 15 # 确认Pod就绪的等待时间
replicas: 3
selector:
matchLabels:
app: ngx-dep-pod
template:
metadata:
labels:
app: ngx-dep-pod
spec:
volumes:
- name: ngx-conf-vol
configMap:
name: ngx-conf
containers:
- image: nginx:1.22-alpine
name: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /etc/nginx/conf.d
name: ngx-conf-vol
这里增加了minReadySeconds: 15
来增加POD创建的间隔时间,不然k8s升级POD过快,不方便看到整个平滑升级的过程,接着apply:
dongyunqi@mongodaddy:~/k8s$ kubectl apply -f smooth-upgrade-deploymentv2.yml
deployment.apps/ngx-dep-name configured
然后通过命令kubectl rollout status deployment ngx-dep-name
来查看升级的过程:
dongyunqi@mongodaddy:~/k8s$ kubectl rollout status deployment ngx-dep-name
Waiting for deployment "ngx-dep-name" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "ngx-dep-name" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "ngx-dep-name" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "ngx-dep-name" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "ngx-dep-name" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "ngx-dep-name" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "ngx-dep-name" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "ngx-dep-name" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "ngx-dep-name" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "ngx-dep-name" rollout to finish: 1 old replicas are pending termination...
deployment "ngx-dep-name" successfully rolled out
以上展示了新POD的升级和老POD的销毁过程,我们也可以通过命令kubectl describe deploy ngx-dep-name
来查看整个升级的过程,如下:
dongyunqi@mongodaddy:~/k8s$ kubectl describe deploy ngx-dep-name
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 33m deployment-controller Scaled up replica set ngx-dep-name-dcc8b7bfd to 3
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set ngx-dep-name-7cfd649b6 to 1
Normal ScalingReplicaSet 10m deployment-controller Scaled down replica set ngx-dep-name-dcc8b7bfd to 2
Normal ScalingReplicaSet 10m deployment-controller Scaled up replica set ngx-dep-name-7cfd649b6 to 2
Normal ScalingReplicaSet 10m deployment-controller Scaled down replica set ngx-dep-name-dcc8b7bfd to 1
Normal ScalingReplicaSet 10m deployment-controller Scaled up replica set ngx-dep-name-7cfd649b6 to 3
Normal ScalingReplicaSet 9m45s deployment-controller Scaled down replica set ngx-dep-name-dcc8b7bfd to 0
每一行的含义如下:
Scaled up replica set ngx-dep-name-dcc8b7bfd to 3
老版本POD有3个
Scaled up replica set ngx-dep-name-7cfd649b6 to 1
新版本POD增加到1个
Scaled down replica set ngx-dep-name-dcc8b7bfd to 2
老版本POD减少到2个
Scaled up replica set ngx-dep-name-7cfd649b6 to 2
新版本POD增加到2个
Scaled down replica set ngx-dep-name-dcc8b7bfd to 1
老版本POD减少到1个
Scaled up replica set ngx-dep-name-7cfd649b6 to 3
新版本POD增加到3个
Scaled down replica set ngx-dep-name-dcc8b7bfd to 0
老版本POD减少到0个
整个过程新POD的个数就好像滚雪球
一样越来越多,所以这个过程也被称为滚动更新
,整个过程用图展示的话如下:
接着我们可以查看新POD的版本信息:
dongyunqi@mongodaddy:~/k8s$ kubectl get pod -l app=ngx-dep-pod
NAME READY STATUS RESTARTS AGE
ngx-dep-name-7cfd649b6-6ddnk 1/1 Running 0 5m23s
ngx-dep-name-7cfd649b6-fslcz 1/1 Running 0 3m45s
ngx-dep-name-7cfd649b6-pwd5r 1/1 Running 0 4m2s
可以看到此时版本变成了7cfd649b6
,也可以访问确认Nginx升级是否成功:
dongyunqi@mongodaddy:~/k8s$ Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
dongyunqi@mongodaddy:~/k8s$ curl 127.0.0.1:8080
Handling connection for 8080
ver : 1.22.1
srv : 127.0.0.1:80
host: ngx-dep-name-7cfd649b6-6ddnk
可以看到此时Nginx的版本号就变成了1.22.1
了,说明Nginx就升级成功了。
3:更新历史维护
系统升级后并非万事大吉,因为可能会因为一个严重的bug需要我们将应用回退到之前的版本,k8s针对这种情况也提供了对应的解决方案,具体是使用命令kubectl rollout
,如下查看更新历史:
dongyunqi@mongodaddy:~/k8s$ kubectl rollout history deploy ngx-dep-name
deployment.apps/ngx-dep-name
REVISION CHANGE-CAUSE
1 <none>
2 <none>
可以看到此时我们有1和2两个版本,但CHANGE-CAUSE
是<none>
,就好像提交的代码没有comment一样,多少有些别扭,想要让该列有值需要在deployment的metadata中增加annotations: kubernetes.io/change-cause: 更新原因
,为了测试,我们再来对Nginx进行一次升级,使用版本1.23.3
,修改后yaml如下:
dongyunqi@mongodaddy:~/k8s$ cat smooth-upgrade-deploymentv3.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: ngx-dep-app
name: ngx-dep-name
annotations:
kubernetes.io/change-cause: upgrade ngixn to 1.23.3 # ***
spec:
replicas: 3
selector:
matchLabels:
app: ngx-dep-pod
template:
metadata:
labels:
app: ngx-dep-pod
spec:
volumes:
- name: ngx-conf-vol
configMap:
name: ngx-conf
containers:
- image: nginx:1.23.3 # ***
name: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /etc/nginx/conf.d
name: ngx-conf-vol
***
为修改的行。apply后再来查看更新历史:
dongyunqi@mongodaddy:~/k8s$ kubectl rollout history deploy ngx-dep-name
deployment.apps/ngx-dep-name
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 upgrade ngixn to 1.23.3
可以看到此时CHANGE-CAUSE就有值了(看着舒服多了)
,有了这个更新历史之后,就可以使用命令 kubectl rollout undo,也可以加上参数 --to-revision 回退到任意一个历史版本,如下回退到最老的版本1
:
dongyunqi@mongodaddy:~/k8s$ kubectl rollout undo deploy ngx-dep-name --to-revision=1
deployment.apps/ngx-dep-name rolled back
写在后面
小结
本文我们一起看了k8s的平滑升级方案,并分析了滚动更新的具体过程,查看了更新历史,以及如何回滚更新到指定版本等内容。希望本文能够帮助到你。
参考文章列表
k8s之Service 。