Java ,Java EE ,spring-framework

Java ,Java EE ,spring-framework

本篇是Docker&Kubenetes系列的第四篇,在前面的篇幅中,我们向Kubenetes中部署了单个应用实例。如果单个节点故障了,那么服务就不可用了,这在实际环境中是不能接受的。在实际的正式环境中,我们不仅要避免单点,还要根据负载变化动态的调整节点数量。为了实现这个目的,我们可以借助于Kubenetes的Deployment,Deployment可以创建指定数量的Pod,并有自愈能力,还能完成升级更新及回滚操作。

向Kubenetes中部署一个3节点的集群

和之前介绍的一样部署集群也由过yml配置文件开始的,本例我们依然使用前面篇幅中创建的docker镜像来部署集群。Deployment配置文件内容如下,这个配置文件是从Kubenetes官网复制的,手写yml文件太容易出错了,yml格式挺烦的。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-first-demo-dep
  labels:
    app: my-first-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-first-demo
  template:
    metadata:
      labels:
        app: my-first-demo
    spec:
      containers:
      - name: my-first-demo
        image: hellodm/my-first-demo:v1.0
        ports:
        - containerPort: 80

配置文件中,replicas=3表示要启动3个副本,使用的镜像是hellodm/my-first-demo:v1.0。配置完了之后,我们来启动集群,命令如下:

$ kubectl create -f dep.yml
deployment.apps/my-first-demo-dep created

我们来看查看副本集情况:

$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
my-first-demo-dep-5647fd55f   3         3         3       3m15s

在查看一下pod:

$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
my-first-demo-dep-5647fd55f-4wzxs   1/1     Running   0          22s
my-first-demo-dep-5647fd55f-c9lwx   1/1     Running   0          22s
my-first-demo-dep-5647fd55f-nnwt6   1/1     Running   0          22s

暴露集群,使得我们可以在访问集群内部的应用。

$ kubectl apply -f svc.yml
service/my-first-demo-svc created

访问:

$ curl 'http://localhost:30000/'
<h1>Hello world! <h1>

OK,成功了。

Kubenetes 扩容演示

上面我们部署了3个节点的集群,假设现在3个节点已经有点吃力了,我们准备扩展到4个节点。编辑上面的Deployment文件,修改的地方如下:

spec:
  replicas: 4

其他的不变,只是replicas为4了。重新启动一下看看:

$ kubectl apply -f dep.yml --record=true
deployment.apps/my-first-demo-dep configured

看下副本集,如下,变成4个了。

$ kubectl get rs
NAME                           DESIRED   CURRENT   READY   AGE
my-first-demo-dep-5647fd55f    4         4         4       10h

检查Kubenetes集群的自愈性

我们来删掉2个Pod,模拟宕机情况,执行kubectl delete pod命令,如下:

$ kubectl delete pod my-first-demo-dep-5647fd55f-4wzxs my-first-demo-dep-5647fd55f-c9lwx

立马查看Pod是否恢复:

$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
my-first-demo-dep-5647fd55f-bxpn7   1/1     Running   0          25s
my-first-demo-dep-5647fd55f-nnwt6   1/1     Running   0          5m8s
my-first-demo-dep-5647fd55f-vwxgz   1/1     Running   0          25s

可以看到还是3台,从NAME和AGE可以看出,多了两个新的。OK,至此,我们演示了扩容和自愈性。

Kubenetes滚动升级

为了演示滚动升级,我们先制作v2.0版本的镜像,修改index的内容为:

<h1>Hello worldls , this is Version 2.</h1>

这里我故意拼错了一个单词,别急,后面有妙用。下面我们来

制作v2.0的镜像:

$ docker build . -t my-frist-demo:v2.0
Sending build context to Docker daemon  6.144kB
Step 1/2 : FROM nginx
 ---> 602e111c06b6
Step 2/2 : COPY index.html /usr/share/nginx/html
 ---> 7484909c0df2
Successfully built 7484909c0df2
Successfully tagged my-frist-demo:v2.0

发布镜像:

$ docker tag my-frist-demo:v2.0 hellodm/my-first-demo:v2.0

$ docker push hellodm/my-first-demo:v2.0
The push refers to repository [docker.io/hellodm/my-first-demo]
a3e37d09f192: Preparing
b3003aac411c: Preparing
216cf33c0a28: Preparing
c2adabaecedb: Layer already exists
denied: requested access to the resource is denied

修改deployment的配置文件,改用v2.0的镜像,如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-first-demo-dep
  labels:
    app: my-first-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-first-demo
  template:
    metadata:
      labels:
        app: my-first-demo
    spec:
      containers:
      - name: my-first-demo
        image: hellodm/my-first-demo:v2.0
        ports:
        - containerPort: 80

执行发布,这次附带了一个参数--record=true让 Kubernetes 把这行命令记到发布历史中方便后面查看。

$ kubectl apply -f dep.yml --record=true
deployment.apps/my-first-demo-dep configured

赶紧查看一下pod状态如下,可以发现已经在滚动发布了,ContainerCreating状态的表示新版本的容器正在启动,Running的是新版本的已经运行起来了,Terminating的这个是老版本正在停止。

$ kubectl get pods
NAME                                 READY   STATUS              RESTARTS   AGE
my-first-demo-dep-54596847d8-6m4n9   0/1     ContainerCreating   0          2s
my-first-demo-dep-54596847d8-jrm8g   1/1     Running             0          4s
my-first-demo-dep-5647fd55f-cbcrz    1/1     Running             0          56s
my-first-demo-dep-5647fd55f-ll7tt    0/1     Terminating         0          56s
my-first-demo-dep-5647fd55f-s8d6l    1/1     Running             0          56s

再赶快查看一下滚动发布的状态:

$ kubectl rollout status deployment my-first-demo-dep
Waiting for rollout to finish: 1 old replicas are pending termination...
deployment "my-first-demo-dep" successfully rolled out

如上命令所表示,随着最后一个old replicas 终止,新版本的deployment成功发布了successfully rolled out

简直是太激动了,验证一下是不是3个pod,如下,没问题,3个Running状态。

$ kubectl get pods
NAME                                 READY   STATUS    RESTARTS   AGE
my-first-demo-dep-54596847d8-6m4n9   1/1     Running   0          36s
my-first-demo-dep-54596847d8-jrm8g   1/1     Running   0          38s
my-first-demo-dep-54596847d8-nqgmn   1/1     Running   0          34s

访问一下看看:

$ curl 'http://localhost:30000/'
<h1>Hello worldls , this is Version 2.</h1>

已经是新版本了,可惜啊,新版本有问题啊!单词拼错了,world写成了worldls,我们来赶紧回滚一下。

Kubenetes应用集群回滚

上面我们使用滚动发布,将网站升级为version2了。但是有错误,我们来查看一下发布历史:

$ kubectl rollout history deployment my-first-demo-dep
deployment.extensions/my-first-demo-dep
REVISION  CHANGE-CAUSE
1         kubectl apply --filename=dep.yml --record=true
2         kubectl apply --filename=dep.yml --record=true

可以看到,有两个版本,我们回滚到版本1,执行如下命令:

$ kubectl rollout undo deployment my-first-demo-dep --to-revision=1
deployment.extensions/my-first-demo-dep rolled back

查看回滚过程状态:

$ kubectl rollout status deployment my-first-demo-dep
Waiting for deployment "my-first-demo-dep" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "my-first-demo-dep" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "my-first-demo-dep" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "my-first-demo-dep" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "my-first-demo-dep" rollout to finish: 1 old replicas are pending termination...
deployment "my-first-demo-dep" successfully rolled out

上面的日志显示了完整的回滚过程,看到最后一行successfully rolled out输出的时候,说明回滚完成了。这时候响应的应该就是 Hello world!,我们来验证一下回滚效果:

$ curl 'http://localhost:30000/'
<h1>Hello world! <h1>

OK,成功了,回滚到了没有错误的原始版本。

总结

本篇演示了Kubenetes集群发布,集群副本集查看,集群自愈能力演示,集群扩容,滚动升级,以及回滚。然而这一切来得是如此的简单,我们只需要修改一下配置,执行一个命令,剩下的工作Kubenetes都帮我们做了。当我在回顾我几年前所在的某家公司的时候,程序升级上线都是由运维手工完成,虽然也完成了任务,但是那种原始的操作方式,在时下如果还有人用的话,那简直是不敢想象。

Docker & k8s 系列一:快速上手docker
Docker & k8s 系列二:本机k8s环境搭建
Docker & k8s 系列三:在k8s中部署单个服务实例

05-20 11:01