基本理论介绍

什么是云原生

Pivotal公司的Matt Stine于2013年首次提出云原生(Cloud-Native)的概念;2015年,云原生刚推广时,Matt Stine在《迁移到云原生架构》一书中定义了符合云原生架构的几个特征:12因素、微服务、自敏捷架构、基于API协作、扛脆弱性;到了2017年,Matt Stine在接受InfoQ采访时又改了口风,将云原生架构归纳为模块化、可观察、可部署、可测试、可替换、可处理6特质;而Pivotal最新官网对云原生概括为4个要点:DevOps+持续交付+微服务+容器

总而言之,符合云原生架构的应用程序应该是:采用开源堆栈(K8S+Docker)进行容器化,基于微服务架构提高灵活性和可维护性,借助敏捷方法、DevOps支持持续迭代和运维自动化,利用云平台设施实现弹性伸缩、动态调度、优化资源利用率。

此处摘选自《知乎-华为云官方帐号》

在这里插入图片描述

什么是kubernetes

kubernetes,简称K8s,是用8代替8个字符"ubernete"而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效,Kubernetes提供了应用部署,规划,更新,维护的一种机制

传统的应用部署方式:是通过插件或脚本来安装应用。这样做的缺点是应用的运行、配置、管理、所有生存周期将与当前操作系统绑定,这样做并不利于应用的升级更新/回滚等操作,当然也可以通过创建虚拟机的方式来实现某些功能,但是虚拟机非常重,并不利于可移植性。

新的部署方式:是通过部署容器方式实现,每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。相对于虚拟机,容器能快速部署,由于容器与底层设施、机器文件系统解耦的,所以它能在不同云、不同版本操作系统间进行迁移。

容器占用资源少、部署快,每个应用可以被打包成一个容器镜像,每个应用与容器间成一对一关系也使容器有更大优势,使用容器可以在build或release 的阶段,为应用创建容器镜像,因为每个应用不需要与其余的应用堆栈组合,也不依赖于生产环境基础结构,这使得从研发到测试、生产能提供一致环境。类似地,容器比虚拟机轻量、更"透明",这更便于监控和管理。

Kubernetes是Google开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。在生产环境中部署一个应用程序时,通常要部署该应用的多个实例以便对应用请求进行负载均衡。

在Kubernetes中,我们可以创建多个容器,每个容器里面运行一个应用实例,然后通过内置的负载均衡策略,实现对这一组应用实例的管理、发现、访问,而这些细节都不需要运维人员去进行复杂的手工配置和处理。

此处摘选自《百度百科》

kubernetes核心功能

  • 存储系统挂载(数据卷):pod中容器之间共享数据,可以使用数据卷
  • 应用健康检测:容器内服务可能进程阻塞无法处理请求,可以设置监控检查策略保证应用健壮性
  • 应用实例的复制(实现pod的高可用):pod控制器(deployment)维护着pod副本数量(可以自己进行设置,默认为1),保证一个pod或一组同类的pod数量始终可用,如果pod控制器deployment当前维护的pod数量少于deployment设置的pod数量,则会自动生成一个新的pod,以便数量符合pod控制器,形成高可用。
  • Pod的弹性伸缩:根据设定的指标(比如:cpu利用率)自动缩放pod副本数
  • 服务发现:使用环境变量或者DNS插件保证容器中程序发现pod入口访问地址
  • 负载均衡:一组pod副本分配一个私有的集群IP地址,负载均衡转发请求到后端容器。在集群内部其他pod可通过这个clusterIP访问应用
  • 滚动更新:更新服务不会发生中断,一次更新一个pod,而不是同时删除整个服务。
  • 容器编排:通过文件来部署服务,使得应用程序部署变得更高效
  • 资源监控:node节点组件集成cAdvisor资源收集工具,可通过Heapster汇总整个集群节点资源数据,然后存储到InfluxDb时序数据库,再由Grafana展示。
  • 提供认证和授权:支持角色访问控制(RBAC)认证授权等策略

Pod控制器详解

  • 我们知道kubernetes最小的控制单元是Pod,而Pod很少直接被创建(不过可以通过配置文件的方式直接创建Pod),一般来说都是用Pod控制器来创建Pod

  • 为什么我们很少直接创建Pod,而是用Pod控制器来创建Pod?

    • 使用Pod控制器来创建Pod有很高的可用性。假设我们的Pod控制器设置Pod副本数为3,那么Pod控制器将会创建3个Pod并与他们进行关联(使用到了Label进行关联),例如这个Pod控制器有2个Pod被删除了(或者崩溃了),此时存活的Pod也就只有1个了,存活数<我们定义的Pod控制器副本数(值为3),此时Pod控制器就会检测到数量不符合之前预先的设置,就会自动重新创建2个Pod(使存活数=我们定义的Pod控制器副本数),这样就展示了Pod控制器的高可用性。
    • 如果我们直接创建Pod,而不是用Pod控制器来创建Pod的话,这个Pod假如被删除了(或者崩溃了)将不会继续提供服务,也不会自动重新创建一个新Pod,需要手动创建新Pod,这在生产环境下是十分不利的
  • kubernetes有很多Pod控制器,分别是:

    • ReplicationController:非常原始的Pod控制器,已经被ReplicaSet替代。(已淘汰
    • ReplicaSet:保证指定数量的Pod运行,并支持Pod数量变更,镜像版本变更。
    • Deployment:通过控制ReplicaSet来控制Pod,并支持滚动升级、版本回退。(主流使用)
    • Horizontal Pod AutoScalerHPA和Deployment一起使用可以使Deployment功能大幅加强增加动态Pod扩缩容功能,面对高并发场景更加强大。
    • DaemonSet:一旦创建了DaemonSet,其就会自动在k8s集群中的工作节点node上都运行一个Pod,一般用于守护进程类的任务。
    • Job:通过Job创建出来的任务(也就是Pod)只要完成任务就立即退出,用于执行一次性任务。
    • CronJob:它创建的Pod会周期性的执行,用于执行周期性的任务。
    • StatefulSet:管理有状态的应用。
ReplicaSet(RS)

在这里插入图片描述

概述
  • ReplicaSet的主要的作用是能够保证指定数量的Pod正常运行如果被ReplicaSet所创建出来的Pod被删除,那么ReplicaSet会自动启动一个新的Pod去填补空位,直到其创建出来的存活的Pod数量==ReplicaSet定义的副本数,此时才不会继续创建Pod,反之则会继续创建,直到Pod数量符合预期。同时它还支持对Pod数量的扩缩容和版本镜像的升级
创建ReplicaSet
  • 创建配置文件:
vim podcontroller-replicaset.yaml
  • 内容如下:
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: apps/v1 # 版本号
kind: ReplicaSet # 类型
metadata: # 元数据
  name: podcontroller-replicaset # rs名称
  namespace: test # 命名类型
spec: # 详细描述
  replicas: 3 # 副本数量
  selector: # 选择器,通过它指定该控制器可以管理哪些Pod
    matchLabels: # Labels标签匹配规则
      app: nginx-pod
  template: # 模块。当副本数据不足的时候,会根据下面的模板创建Pod副本
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx # 容器名称
          image: nginx:1.17 # 容器需要的镜像地址
          ports:
            - containerPort: 80 # 容器所监听的端口
  • 执行配置文件:
[root@k8s-master ~]# kubectl apply -f podcontroller-replicaset.yaml 
namespace/test created
replicaset.apps/podcontroller-replicaset created
  • 查看ReplicaSet:
    • DESIRED预期的Pod数量。(也就是上面replicas定义的值)
    • CURRENT:目前有多少个Pod。
    • READY:正在运行的Pod数量(或者说可以正常提供服务的Pod数量)
[root@k8s-master ~]# kubectl get ReplicaSet -n test -o wide
NAME                       DESIRED   CURRENT   READY   AGE    CONTAINERS   IMAGES       SELECTOR
podcontroller-replicaset   3         3         3       2m3s   nginx        nginx:1.17   app=nginx-pod
  • 查看Pod:(可以看到我们通过Pod控制器创建的Pod会被调度到不同的node节点上去运行
[root@k8s-master ~]# kubectl get pods -n test -o wide
NAME                             READY   STATUS    RESTARTS   AGE   IP            NODE          NOMINATED NODE   READINESS GATES
podcontroller-replicaset-2d7mx   1/1     Running   0          16s   10.244.2.33   k8s-slave02   <none>           <none>
podcontroller-replicaset-4dvfd   1/1     Running   0          16s   10.244.2.32   k8s-slave02   <none>           <none>
podcontroller-replicaset-hqbkv   1/1     Running   0          16s   10.244.1.34   k8s-slave01   <none>           <none>
ReplicaSet扩缩容的两种方式

案例过程:

1:使用kubectl edit对上面的名为podcontroller-replicaset的ReplicaSet进行扩容,将Pod扩容到5个。

2:用kubectl scale对上面的名为podcontroller-replicaset的ReplicaSet进行缩容,将Pod缩容到2个。

kubectl edit扩缩容
  • 1:进入podcontroller-replicaset的配置页面:(这里只演示扩容,缩容也是一样的操作)
kubectl edit ReplicaSet podcontroller-replicaset -n test
  • 2:找到replicas,修改成5,然后执行:wq(和vim一样的操作),这样ReplicaSet就会将Pod数量变成5。

  • 3:查看ReplicaSet的Pod数量:

[root@k8s-master ~]# kubectl get ReplicaSet podcontroller-replicaset -n test 
NAME                       DESIRED   CURRENT   READY   AGE
podcontroller-replicaset   5         5         5       4h32m

可以看到我们已经成功扩容了ReplicaSet。

kubectl scale扩缩容
  • 1:对上面的名为podcontroller-replicaset的ReplicaSet进行缩容,将Pod减少到2(这里只演示缩容,扩容也是一样的操作)
[root@k8s-master ~]# kubectl scale ReplicaSet podcontroller-replicaset -n test --replicas=2 
replicaset.apps/podcontroller-replicaset scaled
  • 2:查看ReplicaSet的Pod数量:
[root@k8s-master ~]# kubectl get ReplicaSet -n test 
NAME                       DESIRED   CURRENT   READY   AGE
podcontroller-replicaset   2         2         2       4h39m

可以看到我们已经成功缩容了ReplicaSet。

镜像更新的两种方式(注意⭐:ReplicaSet不支持镜像升级功能)

案例过程:

1:使用kubectl edit对上面的名为podcontroller-replicaset的ReplicaSet的nginx1.17版本升级(更新)到nginx:1.22。

2:使用kubectl set image对上面的名为podcontroller-replicaset的ReplicaSet的nginx1.22版本降级(更新)到nginx:1.17。

kubectl edit更新镜像
  • 1:查看ReplicaSet的镜像版本:(可以看到现在是nginx:1.17)
[root@k8s-master ~]# kubectl get ReplicaSet -n test -o wide
NAME                       DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES       SELECTOR
podcontroller-replicaset   3         3         3       5h43m   nginx        nginx:1.17   app=nginx-pod
  • 2:进入podcontroller-replicaset的配置页面:
kubectl edit ReplicaSet podcontroller-replicaset -n test
  • 3:找到containers下面的image,并把其值修改成nginx:1.22,然后执行:wq(和vim一样的操作)

  • 4:再次查看ReplicaSet的镜像版本:(可以看到我们的ReplicaSet镜像已经成功升级到nginx:1.22了)

[root@k8s-master ~]# kubectl get ReplicaSet -n test -o wide
NAME                       DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES       SELECTOR
podcontroller-replicaset   3         3         3       5h47m   nginx        nginx:1.22   app=nginx-pod
kubectl set image更新镜像

kubectl set image格式:

kubectl set image ReplicaSet ReplicaSet名称 需要升级的容器名称=新的镜像版本 -n 命名空间
  • 1:升级镜像:
[root@k8s-master ~]# kubectl set image ReplicaSet  podcontroller-replicaset nginx=nginx:1.17 -n test 
replicaset.apps/podcontroller-replicaset image updated
  • 2:查看镜像版本:
[root@k8s-master ~]# kubectl get ReplicaSet -n test -o wide
NAME                       DESIRED   CURRENT   READY   AGE    CONTAINERS   IMAGES       SELECTOR
podcontroller-replicaset   3         3         3       6h7m   nginx        nginx:1.17   app=nginx-pod
为什么说ReplicaSet不支持镜像升级功能?
  • 1:将ReplicaSet升级到一个从来就没有的版本(这里升级成:nginx:1.5201314),看看是否能正常运行:
kubectl set image ReplicaSet  podcontroller-replicaset nginx=nginx:1.5201314 -n test 
  • 2:查看ReplicaSet:
[root@k8s-master ~]# kubectl get ReplicaSet -n test -o wide
NAME                       DESIRED   CURRENT   READY   AGE    CONTAINERS   IMAGES            SELECTOR
podcontroller-replicaset   3         3         3       6h9m   nginx        nginx:1.5201314   app=nginx-pod
  • 3:查看Pod运行状态:
[root@k8s-master ~]# kubectl get pods -n test 
NAME                             READY   STATUS    RESTARTS   AGE
podcontroller-replicaset-2d7mx   1/1     Running   1          6h9m
podcontroller-replicaset-hqbkv   1/1     Running   1          6h9m
podcontroller-replicaset-j9hjq   1/1     Running   0          50m

可以看到我们的ReplicaSet升级到nginx:1.5201314这个不存在的版本却都能正常运行,说明这个ReplicaSet的镜像升级功能就是摆设,没有任何意义。

删除ReplicaSet
  • 方式1:通过配置文件删除:
[root@k8s-master ~]# kubectl delete -f podcontroller-replicaset.yaml 
namespace "test" deleted
replicaset.apps "podcontroller-replicaset" deleted
  • 方式2:通过ReplicaSet的名称删除:
[root@k8s-master ~]# kubectl delete ReplicaSet podcontroller-replicaset -n test 
replicaset.apps "podcontroller-replicaset" deleted
Deployment(deploy)

在这里插入图片描述

概述
  • kubernetes在v1.2版本开始,就引入了新的Pod控制器-Deployment,Deployment并不会直接控制Pod,实际上它的底层是通过控制ReplicaSet,利用ReplicaSet来控制Pod,所以我们完全可以说Deployment是ReplicaSet的升级版,ReplicaSet有的功能Deployment全都有,并且新增了很多功能。所以我们在实际开发中,不建议去使用ReplicaSet,而是推荐使用Deployment,反正闭着眼睛选Deployment就是了。

  • Deployment的核心功能:

    • 1:ReplicaSet的所有功能和特性。
    • 2:滚动更新。
    • 3:版本回退。
    • 4:灰度发布。

Deployment配置文件大全:

apiVersion: apps/v1 # 版本号 
kind: Deployment # 类型 
metadata: # 元数据 
  name: # deployment名称 
  namespace: # 命名空间 
  labels: #标签 
    app: deploy 
spec: # 详情描述 
  replicas: 3 # Pod数量 
  revisionHistoryLimit: 3 # 保留历史版本,默认为10。(也就是保留前10个版本)
  paused: false # 暂停部署,默认是false 
  progressDeadlineSeconds: 600 # 部署超时时间(s),默认是600 
  strategy: # 配置策略 
    type: RollingUpdate # 滚动更新策略(可选Recreate和RollingUpdate(推荐这个)) 
    rollingUpdate: # 这个配置只有当上面的type为RollingUpdate才需要,Recreate不用写这个配置
      maxUnavailable: #用来指定在升级过程中不可用的Pod的最大数量,默认为25%。
      maxSurge: # 用来指定在升级过程中可以超过期望的Pod的最大数量,默认为25%。
  selector: # Pod选择器,下面写上要控制的Pod的Label
    matchLabels: # Labels匹配规则 
      app: nginx-pod 
    matchExpressions: # Expressions匹配规则 
      - {key: app, operator: In, values: [nginx-pod]} 
  template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本 
    metadata: 
      labels: 
        app: nginx-pod 
    spec: 
      containers: 
      - name: nginx 
        image: nginx:1.17
        ports: 
        - containerPort: 80
创建Deployment(入门一个最简单的Deployment)
  • 创建配置文件:
vim podcontroller-deployment.yaml
  • 内容如下:
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
  name: podcontroller-deployment # deployment的名称
  namespace: test # 命名类型
spec: # 详细描述
  replicas: 3 # 副本数量
  selector: # 选择器,通过它指定该控制器可以管理哪些Pod
    matchLabels: # labels匹配规则
      app: nginx-pod
  template: # 模块 当副本数据不足的时候,会根据下面的模板创建Pod副本
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx # 容器名称
          image: nginx:1.17 # 容器需要的镜像地址
          ports:
            - containerPort: 80 # 容器所监听的端口
  • 执行配置文件:
[root@k8s-master ~]# kubectl apply -f podcontroller-deployment.yaml 
namespace/test unchanged
deployment.apps/podcontroller-deployment created
  • 查看deployment:
    • READY:例如x/y。x就是成功运行的Pod数量,y就是预期的Pod数量(也就是上面配置文件的replicas的值)
    • UP-TO-DATE:只统计最新版本的Pod数量
      • 例如当我们滚动更新镜像时,从nginx:1.17->nginx:1.22,由于我们是滚动更新,所以此时会存在一部分Pod版本为nginx:1.17(假设这个版本Pod数量为X),另外一部分Pod版本时nginx:1.22(假设这个版本Pod数量为Y),所以Pod的总数就是X+Y,而UP-TO-DATE的值为Y。
    • AVAILABLE:当前可用的Pod数量。
[root@k8s-master ~]# kubectl get deployments -n test -o wide
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment   3/3     3            3           27s   nginx        nginx:1.17   app=nginx-pod
  • 查看Pod:
[root@k8s-master ~]# kubectl get pods -n test 
NAME                                        READY   STATUS    RESTARTS   AGE
podcontroller-deployment-6555988b6c-6dqsn   1/1     Running   0          10m
podcontroller-deployment-6555988b6c-9wq4x   1/1     Running   0          10m
podcontroller-deployment-6555988b6c-zzx8h   1/1     Running   0          10m
  • 查看ReplicaSet:
[root@k8s-master ~]# kubectl get ReplicaSet -n test 
NAME                                  DESIRED   CURRENT   READY   AGE
podcontroller-deployment-6555988b6c   3         3         3       27m

总结:从上面可以发现,1个Deployment管理1个ReplicaSet,1个ReplicaSet管理n个Pod。

Deployment扩缩容的两种方式

案例过程:

1:使用kubectl edit对上面的名为podcontroller-deployment的deployment进行扩容,将Pod扩容到5个。

2:用kubectl scale对上面的名为podcontroller-deployment的deployment进行缩容,将Pod缩容到2个。

kubectl edit扩缩容
  • 1:进入podcontroller-deployment的配置页面:(这里只演示扩容,缩容也是一样的操作)
kubectl edit deployments podcontroller-deployment -n test
  • 2:找到replicas,修改成5,然后执行:wq(和vim一样的操作)

  • 3:查看deployment的Pod数量:

[root@k8s-master ~]# kubectl get deployments -n test -o wide
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment   5/5     5            5           38m   nginx        nginx:1.17   app=nginx-pod

扩容成功。

kubectl scale扩缩容
  • 1:对上面的名为podcontroller-deployment的deployment进行缩容,将Pod缩容到2个**(这里只演示缩容,扩容也是一样的操作)**
[root@k8s-master ~]# kubectl scale deployment podcontroller-deployment -n test --replicas=2
deployment.apps/podcontroller-deployment scaled
  • 2:查看deployment的Pod数量:
[root@k8s-master ~]# kubectl get deployments -n test 
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
podcontroller-deployment   2/2     2            2           42m

缩容成功。

镜像更新的两种方式
  • Deployment支持两种镜像更新的策略:重建更新滚动更新(默认),可以通过strategy选项进行配置。
strategy: 指定新的Pod替代旧的Pod的策略,支持两个属性
  type: 指定策略类型,支持两种策略(Recreate或者RollingUpdate)
  rollingUpdate: 当type为RollingUpdate的时候生效,用于为rollingUpdate设置参数,支持两个属性:
    maxUnavailable: 用来指定在升级过程中不可用的Pod的最大数量,默认为25%。
    maxSurge: 用来指定在升级过程中可以超过期望的Pod的最大数量,默认为25%。
重建更新Recreate(不太推荐)
  • 特点:在创建出新的Pod之前会先关闭掉所有已经存在的Pod(这样就带来了一个大缺陷,此时如果外部有请求访问这个Deployment的话是无法访问的,因为没有Pod正在运行中。所以一般来说不使用这种模式。

  • 创建配置文件:

vim podcontroller-deployment.yaml
  • 内容如下:
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
  name: podcontroller-deployment # deployment的名称
  namespace: test # 命名类型
spec: # 详细描述
  replicas: 8 # 副本数量
  strategy: # 镜像更新策略
    type: Recreate # 重建更新
  selector: # 选择器,通过它指定该控制器可以管理哪些Pod
    matchLabels: # labels匹配规则
      app: nginx-pod
  template: # 模块 当副本数据不足的时候,会根据下面的模板创建Pod副本
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx # 容器名称
          image: nginx:1.17 # 容器需要的镜像地址
          ports:
            - containerPort: 80 # 容器所监听的端口
  • 执行配置文件:
[root@k8s-master ~]# kubectl apply -f podcontroller-deployment.yaml 
namespace/test created
deployment.apps/podcontroller-deployment created
  • 开启一个新的shell窗口动态监控deployment:(后面可以查看其Pod变化)
[root@k8s-master ~]# kubectl get deployments -n test -o wide -w
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment   8/8     8            8           2m25s   nginx        nginx:1.17   app=nginx-pod

  • 开始升级镜像:(如果拉取新镜像慢的话,可以去各个工作节点node,使用docker pull手动拉取)
[root@k8s-master ~]# kubectl set image deployment podcontroller-deployment nginx=nginx:1.22 -n test
deployment.apps/podcontroller-deployment image updated
  • 查看刚刚开的那个shell窗口:
[root@k8s-master ~]# kubectl get deployments -n test -o wide -w
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment   8/8     8            8           5m17s   nginx        nginx:1.17   app=nginx-pod


podcontroller-deployment   8/8     8            8           6m9s    nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   8/8     0            8           6m9s    nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   4/8     0            4           6m9s    nginx        nginx:1.22   app=nginx-pod

podcontroller-deployment   0/8     0            0           6m9s    nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   0/8     0            0           6m14s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   0/8     0            0           6m14s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   0/8     8            0           6m14s   nginx        nginx:1.22   app=nginx-pod



podcontroller-deployment   1/8     8            1           12m     nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   2/8     8            2           12m     nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   3/8     8            3           12m     nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   4/8     8            4           12m     nginx        nginx:1.22   app=nginx-pod

podcontroller-deployment   5/8     8            5           13m     nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   6/8     8            6           13m     nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     8            7           13m     nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   8/8     8            8           14m     nginx        nginx:1.22   app=nginx-pod

总结:对比下面的滚动更新,我们可以看到重建更新有很长的一段时间Pod为0,此时是不会提供服务的,这样效果十分不好,而下面的滚动更新却会始终都有大量的Pod正常运行。

滚动更新RollingUpdate(非常推荐⭐)
  • 特点:滚动更新就是先创建一些新版本的Pod,能到这些新Pod正常运行后再删除旧版本的Pod,一直循环此操作,直到Deployment全部为新版本Pod为止。(好处就是:即使这个时候有请求访问这个Deployment也是完全可以访问的,因为滚动更新的Deployment一直都会保持着足够多的Pod正在运行,特点是这个Deployment会同时存在新版本Pod和旧版本Pod。

  • 创建配置文件:

vim podcontroller-deployment.yaml
  • 内容如下:
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
  name: podcontroller-deployment # deployment的名称
  namespace: test # 命名类型
spec: # 详细描述
  replicas: 8 # 副本数量
  strategy: # 镜像更新策略
    type: RollingUpdate # 设置为滚动更新模式(不写也可以,默认就是滚动更新)
    rollingUpdate: #滚动更新配置,上面的replicas为8
      maxUnavailable: 25%  # 8*25%=2
      maxSurge: 25% # 8*25%=2
  selector: # 选择器,通过它指定该控制器可以管理哪些Pod
    matchLabels: # labels匹配规则
      app: nginx-pod
  template: # 模块 当副本数据不足的时候,会根据下面的模板创建Pod副本
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx # 容器名称
          image: nginx:1.17 # 容器需要的镜像地址
          ports:
            - containerPort: 80 # 容器所监听的端口
  • 执行配置文件:
[root@k8s-master ~]# kubectl apply -f podcontroller-deployment.yaml 
namespace/test created
deployment.apps/podcontroller-deployment created
  • 开启一个新的shell窗口动态监控deployment:(后面可以查看其Pod变化)
[root@k8s-master ~]# kubectl get deployments -n test -o wide -w
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment   8/8     8            8           16s   nginx        nginx:1.17   app=nginx-pod
  • 开始升级镜像:(如果拉取新镜像慢的话,可以去各个工作节点node,使用docker pull手动拉取)
[root@k8s-master ~]# kubectl set image deployment podcontroller-deployment nginx=nginx:1.22 -n test
deployment.apps/podcontroller-deployment image updated
  • 查看刚刚开的那个shell窗口:
[root@k8s-master ~]# kubectl get deployments -n test -o wide -w
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment   8/8     8            8           16s   nginx        nginx:1.17   app=nginx-pod
podcontroller-deployment   8/8     8            8           77s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   8/8     8            8           77s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   8/8     0            8           77s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   6/8     2            6           77s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   6/8     4            6           77s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     4            7           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   6/8     4            6           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   6/8     5            6           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     5            7           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     5            7           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     5            7           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   6/8     5            6           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   6/8     6            6           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     6            7           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   6/8     6            6           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   6/8     7            6           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     7            7           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     7            7           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     7            7           79s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   6/8     7            6           80s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   6/8     8            6           80s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     8            7           80s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     8            7           80s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   6/8     8            6           80s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     8            7           82s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     8            7           82s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   6/8     8            6           82s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   7/8     8            7           83s   nginx        nginx:1.22   app=nginx-pod
podcontroller-deployment   8/8     8            8           84s   nginx        nginx:1.22   app=nginx-pod

总结:对比重建更新Recreate我们可以看到滚动更新下的deployment始终都有Pod正常运行,在不影响服务的情况下进行升级,十分强大。

版本回退

kubernetes的deployment具有版本回退的功能,例如当我们从nginx:1.17(记录为版本1)升级到nginx:1.22(记录为版本2)后发现我们的程序不兼容这个nginx:1.22(版本2),那么此时我们可以使用到版本回退将现在的版本2->回退到版本1,此时我们的程序又恢复了正常。

命令格式:

# 版本升级相关功能
kubetl rollout 参数 deployment xxxxx  -n 命名空间
# 参数如下:
# status 显示当前升级的状态
# history 显示升级历史记录
# pause 暂停版本升级过程
# resume 继续已经暂停的版本升级过程
# restart 重启版本升级过程
# undo 回滚到上一级版本 (可以使用--to-revision回滚到指定的版本)
版本回退案例(实战)

案例过程:

1:创建一个名为podcontroller-deployment的Deployment并开启record功能。镜像版本为nginx:1.17,replicas为3。

2:对该Deployment的镜像从nginx:1.17升级到nginx:1.19。(此时kubectl rollout history就会多一条新版本记录,只有升级镜像才会被record到,扩缩容是不会被记录到的)

3:对该Deployment的镜像从nginx:1.19进行升级到nginx:1.22。

  • 1:创建配置文件:
vim podcontroller-deployment.yaml
  • 内容如下:
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
  name: podcontroller-deployment # deployment的名称
  namespace: test # 命名类型
spec: # 详细描述
  replicas: 3 # 副本数量
  revisionHistoryLimit: 5 # 保留历史版本,默认为10。(也就是保留前10个版本)
  paused: false # 暂停部署,默认是false 
  progressDeadlineSeconds: 600 # 部署超时时间(s),默认是600 
  strategy: # 镜像更新策略
    type: RollingUpdate # 设置为滚动更新模式(不写也可以,默认就是滚动更新)
    rollingUpdate: #滚动更新配置
      maxUnavailable: 25% 
      maxSurge: 25% 
  selector: # 选择器,通过它指定该控制器可以管理哪些Pod
    matchLabels: # labels匹配规则
      app: nginx-pod
  template: # 模块 当副本数据不足的时候,会根据下面的模板创建Pod副本
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx # 容器名称
          image: nginx:1.17 # 容器需要的镜像地址
          ports:
            - containerPort: 80 # 容器所监听的端口
  • 2:执行配置文件:(记得一定要开启record功能(–record=true),否则无法记录版本信息
[root@k8s-master ~]# kubectl apply -f podcontroller-deployment.yaml --record=true
namespace/test created
deployment.apps/podcontroller-deployment created
  • 3:查看Deployment:
[root@k8s-master ~]# kubectl get deployments -n test -o wide
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment   3/3     3            3           106s   nginx        nginx:1.17   app=nginx-pod
  • 4:查看版本历史信息:(一定要开启record功能,否则下面全是null)
[root@k8s-master ~]# kubectl rollout history deployment podcontroller-deployment -n test 
deployment.apps/podcontroller-deployment 
REVISION  CHANGE-CAUSE
1         kubectl apply --filename=podcontroller-deployment.yaml --record=true
  • 5:将nginx:1.17升级到nginx:1.19:
[root@k8s-master ~]# kubectl set image deployment podcontroller-deployment nginx=nginx:1.19 -n test
deployment.apps/podcontroller-deployment image updated
  • 6:立刻开启监听升级状态(rollout status):
[root@k8s-master ~]# kubectl rollout status deployment podcontroller-deployment -n test 
Waiting for deployment "podcontroller-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "podcontroller-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "podcontroller-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "podcontroller-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "podcontroller-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "podcontroller-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "podcontroller-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "podcontroller-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "podcontroller-deployment" successfully rolled out
  • 7:查看版本history:(可以发现多了一条新纪录2,这个记录就是刚刚我们升级的记录)
[root@k8s-master ~]# kubectl rollout history deployment podcontroller-deployment -n test 
deployment.apps/podcontroller-deployment 
REVISION  CHANGE-CAUSE
1         kubectl apply --filename=podcontroller-deployment.yaml --record=true
2         kubectl apply --filename=podcontroller-deployment.yaml --record=true
  • 8:查看deployment:(成功升级到nginx:1.19)
[root@k8s-master ~]# kubectl get deployments -n test -o wide
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment   3/3     3            3           9m10s   nginx        nginx:1.19   app=nginx-pod
  • 9:将nginx:1.19升级到nginx:1.22:
[root@k8s-master ~]# kubectl set image deployment podcontroller-deployment nginx=nginx:1.22 -n test
deployment.apps/podcontroller-deployment image updated
  • 10:查看deployment:
[root@k8s-master ~]# kubectl get deployments -n test -o wide
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment   3/3     3            3           19m   nginx        nginx:1.22   app=nginx-pod
  • 11:查看升级history:(当前处于版本3)
    • 版本1:nginx:1.17
    • 版本2:nginx:1.19
    • 版本3:nginx:1.22
[root@k8s-master ~]# kubectl rollout history deployment podcontroller-deployment -n test 
deployment.apps/podcontroller-deployment 
REVISION  CHANGE-CAUSE
1         kubectl apply --filename=podcontroller-deployment.yaml --record=true
2         kubectl apply --filename=podcontroller-deployment.yaml --record=true
3         kubectl apply --filename=podcontroller-deployment.yaml --record=true
  • 12:开始版本回退:(回退到上一个版本,不指定具体版本)
    • 不加上–to-revision的话,由于当前处于版本3,所以下面这行命令会回滚到版本2
# 不加上--to-revision的话,由于当前处于版本3,所以下面这行命令会回滚到版本2
kubectl rollout undo deployment podcontroller-deployment -n test
  • 13:查看版本history:
    • 可以看到版本2被挤下去了而版本3往上移动了一个位置新增了版本4,现在只有版本1、3、4。
    • 版本1:nginx:1.17
    • 版本3:nginx:1.22
    • 版本4:nginx:1.19
root@k8s-master ~]# kubectl rollout history deployment podcontroller-deployment -n test 
deployment.apps/podcontroller-deployment 
REVISION  CHANGE-CAUSE
1         kubectl apply --filename=podcontroller-deployment.yaml --record=true
3         kubectl apply --filename=podcontroller-deployment.yaml --record=true
4         kubectl apply --filename=podcontroller-deployment.yaml --record=true
  • 14:开始版本回退:(指定回退到版本1)
[root@k8s-master ~]# kubectl rollout undo deployment podcontroller-deployment -n test --to-revision=1
deployment.apps/podcontroller-deployment rolled back
  • 15:查看版本history:可以看到版本1被替换成5而版本3和4往上移动了一个位置,现在只有版本3、4、5。
    • 版本3:nginx:1.22
    • 版本4:nginx:1.19
    • 版本5:nginx:1.17
[root@k8s-master ~]# kubectl rollout history deployment podcontroller-deployment -n test 
deployment.apps/podcontroller-deployment 
REVISION  CHANGE-CAUSE
3         kubectl apply --filename=podcontroller-deployment.yaml --record=true
4         kubectl apply --filename=podcontroller-deployment.yaml --record=true
5         kubectl apply --filename=podcontroller-deployment.yaml --record=true
灰度发布
  • 灰度发布流程:
    • 当我们对Deployment进行镜像升级–滚动更新时,在一瞬间立刻暂停升级(kubectl rollout pause),此时就会出现一种情况,那就是一个Deployment有大部分的旧版本Pod,少部分新版本Pod,此时我们再测试一下这些新版本的Pod能否正常运行,如果可以正常运行的话就继续升级(kubectl rollout resume),如果不能够正常运行,则进行版本回退(kubectl rollout undo)。
灰度发布案例(实战1:灰度发布时新版本Pod可以正常运行下的场景)

案例1过程:

1:创建一个名为podcontroller-deployment的Deployment并开启record功能。镜像版本为nginx:1.17,replicas为3。

2:将这个Deployment从nginx:1.17升级到nginx:1.19并立刻暂停(灰度发布最重要的步骤

3:此时假设这个新版本Pod能够正常运行,此时我们就用kubectl rollout resume继续升级直到成功。

  • 1:创建配置文件:
vim podcontroller-deployment.yaml
  • 内容如下:
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
  name: podcontroller-deployment # deployment的名称
  namespace: test # 命名类型
spec: # 详细描述
  replicas: 3 # 副本数量
  revisionHistoryLimit: 5 # 保留历史版本,默认为10。(也就是保留前10个版本)
  paused: false # 暂停部署,默认是false 
  progressDeadlineSeconds: 600 # 部署超时时间(s),默认是600 
  strategy: # 镜像更新策略
    type: RollingUpdate # 设置为滚动更新模式(不写也可以,默认就是滚动更新)
    rollingUpdate: #滚动更新配置
      maxUnavailable: 25% 
      maxSurge: 25% 
  selector: # 选择器,通过它指定该控制器可以管理哪些Pod
    matchLabels: # labels匹配规则
      app: nginx-pod
  template: # 模块 当副本数据不足的时候,会根据下面的模板创建Pod副本
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx # 容器名称
          image: nginx:1.17 # 容器需要的镜像地址
          ports:
            - containerPort: 80 # 容器所监听的端口
  • 2:执行配置文件:(记得一定要开启record功能(–record=true),否则无法记录版本信息
[root@k8s-master ~]# kubectl apply -f podcontroller-deployment.yaml --record=true
namespace/test created
deployment.apps/podcontroller-deployment created
  • 3:查看Deployment:
[root@k8s-master ~]# kubectl get deployments -n test -o wide
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment   3/3     3            3           61s   nginx        nginx:1.17   app=nginx-pod
  • 4:进行灰度发布,升级镜像到nginx:1.19(最重要的操作)
[root@k8s-master ~]# kubectl set image deployment podcontroller-deployment nginx=nginx:1.19 -n test && kubectl rollout pause deployment podcontroller-deployment -n test
deployment.apps/podcontroller-deployment image updated
deployment.apps/podcontroller-deployment paused
  • 5:此时我们可以看到升级过程中已经被成功暂停了。
[root@k8s-master ~]# kubectl rollout status deployment podcontroller-deployment -n test 
Waiting for deployment "podcontroller-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
  • 6:查看deployment和ReplicaSet:
    • 从下面我们可以看出滚动更新是先创建一组新版本的Pod,创建成功之后再删除一组旧版本的Pod。
    • 执行了上面的灰度发布命令,就会出现下面这种情况。可以看到一共有4个Pod,其中3个是旧版本(nginx:1.17)的Pod,1个(UP-TO-DATE)是新版本(nginx:1.19)的Pod。
[root@k8s-master ~]# kubectl get deployments -n test -o wide
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment   4/3     1            4           13m   nginx        nginx:1.19   app=nginx-pod
[root@k8s-master ~]# kubectl get ReplicaSet -n test -o wide
NAME                                  DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment-59586bbf69   1         1         1       4m16s   nginx        nginx:1.19   app=nginx-pod,pod-template-hash=59586bbf69
podcontroller-deployment-6555988b6c   3         3         3       17m     nginx        nginx:1.17   app=nginx-pod,pod-template-hash=6555988b6c
  • 7:继续更新:
[root@k8s-master ~]# kubectl rollout resume deployment podcontroller-deployment -n test
deployment.apps/podcontroller-deployment resumed
灰度发布案例(实战2:灰度发布时新版本Pod不能够正常运行下的场景)

案例2过程:

1:执行完灰度发布案例1的全部过程。(此时nginx版本为1.19)

2:将这个Deployment从nginx:1.19升级到nginx:1.22并立刻暂停灰度发布最重要的步骤

3:此时假设这个新版本Pod不能正常运行,由于kubernetes不允许版本回滚一个pause暂停的deployment,所以我们要kubectl rollout resume继续升级,然后立刻就用kubectl rollout undo进行版本回退。

  • 1:进行灰度发布,升级镜像到nginx:1.22(最重要的操作)
kubectl set image deployment podcontroller-deployment nginx=nginx:1.22 -n test && kubectl rollout pause deployment podcontroller-deployment -n test
  • 2:查看deployment和ReplicaSet:
[root@k8s-master ~]# kubectl get deployments -n test -o wide
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment   4/3     1            4           21m   nginx        nginx:1.22   app=nginx-pod
[root@k8s-master ~]# kubectl get ReplicaSet -n test -o wide
NAME                                  DESIRED   CURRENT   READY   AGE    CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment-54549664f9   1         1         1       48s    nginx        nginx:1.22   app=nginx-pod,pod-template-hash=54549664f9
podcontroller-deployment-59586bbf69   3         3         3       9m1s   nginx        nginx:1.19   app=nginx-pod,pod-template-hash=59586bbf69
podcontroller-deployment-6555988b6c   0         0         0       22m    nginx        nginx:1.17   app=nginx-pod,pod-template-hash=6555988b6c
  • 3:查看版本history:
    • 版本1:nginx:1.17
    • 版本2:nginx:1.19
    • 版本3:nginx:1.22(目前我们处于这个版本,但是这个版本是灰度发布中,处于暂停阶段。)
[root@k8s-master ~]# kubectl rollout history deployment podcontroller-deployment -n test 
deployment.apps/podcontroller-deployment 
REVISION  CHANGE-CAUSE
1         kubectl apply --filename=podcontroller-deployment.yaml --record=true
2         kubectl apply --filename=podcontroller-deployment.yaml --record=true
3         kubectl apply --filename=podcontroller-deployment.yaml --record=true
  • 4:由于kubernetes不允许版本回滚一个pause暂停的deployment,所以我们要kubectl rollout resume继续升级。
[root@k8s-master ~]# kubectl rollout resume deployment podcontroller-deployment -n test
deployment.apps/podcontroller-deployment resumed
  • 5:然后立刻进行版本回退:(也就是回退到灰度发布前的版本,也就是版本2(nginx:1.19))
[root@k8s-master ~]# kubectl rollout undo deployment podcontroller-deployment -n test
deployment.apps/podcontroller-deployment rolled back
  • 6:查看deployment和ReplicaSet:(大功告成,现在全都已经回退到nginx:1.19版本了)
[root@k8s-master ~]# kubectl get deployments -n test -o wide 
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment   3/3     3            3           29m   nginx        nginx:1.19   app=nginx-pod
[root@k8s-master ~]# kubectl get ReplicaSet -n test -o wide 
NAME                                  DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES       SELECTOR
podcontroller-deployment-54549664f9   0         0         0       8m10s   nginx        nginx:1.22   app=nginx-pod,pod-template-hash=54549664f9
podcontroller-deployment-59586bbf69   3         3         3       16m     nginx        nginx:1.19   app=nginx-pod,pod-template-hash=59586bbf69
podcontroller-deployment-6555988b6c   0         0         0       29m     nginx        nginx:1.17   app=nginx-pod,pod-template-hash=6555988b6
删除Deployment
  • 方式1:配置文件删除
[root@k8s-master ~]# kubectl delete -f podcontroller-deployment.yaml 
namespace "test" deleted
deployment.apps "podcontroller-deployment" deleted
  • 方式2:通过deployment名称删除
[root@k8s-master ~]# kubectl delete deployments podcontroller-deployment -n test 
deployment.apps "podcontroller-deployment" deleted

❤️💛🧡本章结束,我们下一章见❤️💛🧡

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐