学习了Replication ControllerReplica Set两种资源对象,RCRS的功能基本上是差不多的,唯一的区别就是RS支持集合的selector。我们也学习到了用RC/RS来控制Pod副本的数量,也实现了滚动升级Pod的功能。现在看上去似乎一切都比较完美的运行着,但是我们上节课最后也提到了现在我们推荐使用Deployment这种控制器了,而不是我们之前的RC或者RS,这是为什么呢?

没有对比就没有伤害对吧,我们来对比下二者之间的功能吧,首先RCKubernetes的一个核心概念,当我们把应用部署到集群之后,需要保证应用能够持续稳定的运行,RC就是这个保证的关键,主要功能如下:

  • 确保Pod数量:它会确保Kubernetes中有指定数量的Pod在运行,如果少于指定数量的PodRC就会创建新的,反之这会删除多余的,保证Pod的副本数量不变。
  • 确保Pod健康:当Pod不健康,比如运行出错了,总之无法提供正常服务时,RC也会杀死不健康的Pod,重新创建新的。
  • 弹性伸缩:在业务高峰或者低峰的时候,可以用过RC来动态的调整Pod数量来提供资源的利用率,当然我们也提到过如果使用HPA这种资源对象的话可以做到自动伸缩。
  • 滚动升级:滚动升级是一种平滑的升级方式,通过逐步替换的策略,保证整体系统的稳定性。

Deployment同样也是Kubernetes系统的一个核心概念,主要职责和RC一样的都是保证Pod的数量和健康,二者大部分功能都是完全一致的,我们可以看成是一个升级版的RC控制器,那Deployment又具备那些新特性呢?

  • RC的全部功能:Deployment具备上面描述的RC的全部功能
  • 事件和状态查看:可以查看Deployment的升级详细进度和状态
  • 回滚:当升级Pod的时候如果出现问题,可以使用回滚操作回滚到之前的任一版本
  • 版本记录:每一次对Deployment的操作,都能够保存下来,这也是保证可以回滚到任一版本的基础
  • 暂停和启动:对于每一次升级都能够随时暂停和启动

创建Deployment

  1. [root@master01 ~]# kubectl explain Deployment
  2. KIND: Deployment
  3. VERSION: apps/v1
  4. DESCRIPTION:
  5. Deployment enables declarative updates for Pods and ReplicaSets.
  6. FIELDS:
  7. apiVersion <string>
  8. APIVersion defines the versioned schema of this representation of an
  9. object. Servers should convert recognized schemas to the latest internal
  10. value, and may reject unrecognized values. More info:
  11. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
  12. kind <string>
  13. Kind is a string value representing the REST resource this object
  14. represents. Servers may infer this from the endpoint the client submits
  15. requests to. Cannot be updated. In CamelCase. More info:
  16. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
  17. metadata <Object>
  18. Standard object metadata.
  19. spec <Object>
  20. Specification of the desired behavior of the Deployment.
  21. status <Object>
  22. Most recently observed status of the Deployment.
cat > myapp-deploy.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
  labels:
    app: myapp
    type: deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      type: deploy
  template:
    metadata:
      name: myapp-pod
      labels:
        app: myapp
        type: deploy
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - name: http
          containerPort: 80
EOF
kubectl apply -f myapp-deploy.yaml
[root@master01 ~]# kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
myapp-deploy-696fdb5868-22lnq   1/1     Running   0          52s
myapp-deploy-696fdb5868-2tjqw   1/1     Running   0          52s
myapp-deploy-696fdb5868-c9c4b   1/1     Running   0          52s

[root@master01 ~]# kubectl get deployment
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
myapp-deploy   3/3     3            3           67s

[root@master01 ~]# kubectl get rs
NAME                      DESIRED   CURRENT   READY   AGE
myapp-deploy-696fdb5868   3         3         3       75s

查看Deployment

[root@master01 ~]# kubectl  describe deployments.apps  myapp-deploy 
Name:                   myapp-deploy
Namespace:              default
CreationTimestamp:      Mon, 13 Jan 2020 15:12:50 +0800
Labels:                 app=myapp
                        type=deploy
Annotations:            deployment.kubernetes.io/revision: 1
                        kubectl.kubernetes.io/last-applied-configuration:
                          {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"labels":{"app":"myapp","type":"deploy"},"name":"myapp-deploy","n...
Selector:               app=myapp,type=deploy
Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=myapp
           type=deploy
  Containers:
   myapp:
    Image:        ikubernetes/myapp:v1
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   myapp-deploy-696fdb5868 (3/3 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  7m53s  deployment-controller  Scaled up replica set myapp-deploy-696fdb5868 to 3

扩展Deployment

[root@master01 ~]# kubectl scale deployment myapp-deploy --replicas=5
deployment.apps/myapp-deploy scaled

[root@master01 ~]# kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
myapp-deploy-696fdb5868-22lnq   1/1     Running   0          10m
myapp-deploy-696fdb5868-2tjqw   1/1     Running   0          10m
myapp-deploy-696fdb5868-8f7qq   1/1     Running   0          8s
myapp-deploy-696fdb5868-c9c4b   1/1     Running   0          10m
myapp-deploy-696fdb5868-vlqgk   1/1     Running   0          8s

滚动升级

镜像版本v1-v2

cat > myapp-deploy.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
  labels:
    app: myapp
    type: deploy
spec:
  replicas: 5
  minReadySeconds: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  selector:
    matchLabels:
      app: myapp
      type: deploy
  template:
    metadata:
      name: myapp-pod
      labels:
        app: myapp
        type: deploy
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v2
        ports:
        - name: http
          containerPort: 80
EOF
[root@master01 ~]# kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
myapp-deploy-8644746745-8f7qz   1/1     Running   0          30s
myapp-deploy-8644746745-cf6ln   1/1     Running   0          22s
myapp-deploy-8644746745-gt8fw   1/1     Running   0          15s
myapp-deploy-8644746745-mhp2q   1/1     Running   0          22s
myapp-deploy-8644746745-wqc8t   1/1     Running   0          30s

[root@master01 ~]# kubectl get deployments.apps 
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
myapp-deploy   5/5     5            5           18m

t@master01 ~]# kubectl get rs
NAME                      DESIRED   CURRENT   READY   AGE
myapp-deploy-696fdb5868   0         0         0       18m
myapp-deploy-8644746745   5         5         5       51s
  • minReadySeconds:
    • Kubernetes在等待设置的时间后才进行升级
    • 如果没有设置该值,Kubernetes会假设该容器启动起来后就提供服务了
    • 如果没有设置该值,在某些极端情况下可能会造成服务服务正常运行
  • maxSurge:
    • 升级过程中最多可以比原先设置多出的POD数量
    • 例如:maxSurage=1,replicas=5,则表示Kubernetes会先启动1一个新的Pod后才删掉一个旧的POD,整个升级过程中最多会有5+1个POD。
  • maxUnavaible:
    • 升级过程中最多有多少个POD处于无法提供服务的状态
    • maxSurge不为0时,该值也不能为0
    • 例如:maxUnavaible=1,则表示Kubernetes整个升级过程中最多会有1个POD处于无法服务的状态。

rollout升级回滚

[root@master01 ~]# kubectl set image deployment myapp-deploy myapp=ikubernetes/myapp:v3
deployment.apps/myapp-deploy image updated

[root@master01 ~]# kubectl rollout status deployment myapp-deploy
deployment "myapp-deploy" successfully rolled out
[root@master01 ~]# kubectl get deployments.apps 
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
myapp-deploy   5/5     5            5           33m
[root@master01 ~]# kubectl get rs
NAME                      DESIRED   CURRENT   READY   AGE
myapp-deploy-66865f759d   5         5         5       2m16s
myapp-deploy-696fdb5868   0         0         0       33m
myapp-deploy-8644746745   0         0         0       16m

查看Deployment的升级历史

[root@master01 ~]# kubectl rollout history deployment myapp-deploy 
deployment.apps/myapp-deploy 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3         <none>

接回退到当前版本的上一个版本

kubectl rollout undo deployment myapp-deploy
[root@master01 ~]# kubectl get deployments.apps 
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
myapp-deploy   5/5     5            5           37m

[root@master01 ~]# kubectl get rs
NAME                      DESIRED   CURRENT   READY   AGE
myapp-deploy-66865f759d   0         0         0       6m26s
myapp-deploy-696fdb5868   0         0         0       38m
myapp-deploy-8644746745   5         5         5       20m

[root@master01 ~]# kubectl rollout history deployment myapp-deploy 
deployment.apps/myapp-deploy 
REVISION  CHANGE-CAUSE
1         <none>
3         <none>
4         <none>

回退指定版本

kubectl rollout undo deployment myapp-deploy --to-revision=1
[root@master01 ~]# kubectl get deployments.apps 
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
myapp-deploy   5/5     5            5           46m

[root@master01 ~]# kubectl get rs
NAME                      DESIRED   CURRENT   READY   AGE
myapp-deploy-66865f759d   0         0         0       15m
myapp-deploy-696fdb5868   5         5         5       46m
myapp-deploy-8644746745   0         0         0       28m

ot@master01 ~]# kubectl rollout history deployment myapp-deploy 
deployment.apps/myapp-deploy 
REVISION  CHANGE-CAUSE
3         <none>
4         <none>
5         <none>

在执行Deployment升级的时候最好带上record参数,便于我们查看历史版本信息

[root@master01 ~]# kubectl apply -f myapp-deploy.yaml --record=true
deployment.apps/myapp-deploy configured

[root@master01 ~]# kubectl rollout history deployment myapp-deploy 
deployment.apps/myapp-deploy 
REVISION  CHANGE-CAUSE
3         <none>
5         <none>
6         kubectl apply --filename=myapp-deploy.yaml --record=true

删除Deployment

kubectl delete deployments.apps myapp-deploy