探索云原生技术之容器编排引擎-Kubernetes/K8S详解(5)
探索云原生技术之容器编排引擎-Kubernetes/K8S详解。Kubernetes是Google开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。在生产环境中部署一个应用程序时,通常要部署该应用的多个实例以便对应用请求进行负载均衡。........................
基本理论介绍
什么是云原生
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 AutoScaler:HPA和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
❤️💛🧡本章结束,我们下一章见❤️💛🧡
更多推荐
所有评论(0)