K8S中Deployment控制器的概念、原理解读以及使用技巧

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
云解析 DNS,旗舰版 1个月
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: K8S中Deployment控制器的概念、原理解读以及使用技巧

1、Deployment控制器

Deployment官方文档:

https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

1.1 Deployment概述

Deployment是kubernetes中最常用的资源对象,为ReplicaSet和Pod的创建提供了一种声明式的定义方法,

在Deployment对象中描述一个期望的状态,Deployment控制器就会按照一定的控制速率把实际状态改成期望状态,

通过定义一个Deployment控制器会创建一个新的ReplicaSet控制器,通过ReplicaSet创建pod,删除Deployment控制器,

也会删除Deployment控制器下对应的ReplicaSet控制器和pod资源.

使用Deployment而不直接创建ReplicaSet是因为Deployment对象拥有许多ReplicaSet没有的特性,例如滚动升级和回滚。

扩展:声明式定义是指直接修改资源清单yaml文件,然后通过kubectl apply -f 资源清单yaml文件,就可以更改资源

Deployment控制器是建立在rs之上的一个控制器,可以管理多个rs,每次更新镜像版本,都会生成一个新的rs,

把旧的rs替换掉,多个rs同时存在,但是只有一个rs运行。

rs v1控制三个pod,删除一个pod,在rs v2上重新建立一个,依次类推,直到全部都是由rs v2控制,

如果rs v2有问题,还可以回滚,Deployment是建构在rs之上的,多个rs组成一个Deployment,但是只有一个rs处于活跃状态.

还有一个值得注意的地方是:在.spec.selector中定义的标签选择器必须能够匹配到spec.template.metadata.labels里定义的Pod标签,

否则Kubernetes将不允许创建ReplicaSet。

1.2 Deployment工作原理:如何管理rs和Pod?

Deployment可以使用声明式定义,直接在命令行通过纯命令的方式完成对应资源版本的内容的修改,

也就是通过打补丁的方式进行修改;Deployment能提供滚动式自定义自控制的更新;对Deployment来讲,

我们在实现更新时还可以实现控制更新节奏和更新逻辑。

互动:什么叫做更新节奏和更新逻辑呢?

比如说Deployment控制5个pod副本,pod的期望值是5个,但是升级的时候需要额外多几个pod,

那我们控制器可以控制在5个pod副本之外还能再增加几个pod副本;比方说能多一个,但是不能少,那么升级的时候就是先增加一个,

再删除一个,增加一个删除一个,始终保持pod副本数是5个;还有一种情况,最多允许多一个,最少允许少一个,也就是最多6个,

最少4个,第一次加一个,删除两个,第二次加两个,删除两个,依次类推,可以自己控制更新方式,

这种滚动更新需要加readinessProbe和livenessProbe探测,确保pod中容器里的应用都正常启动了才删除之前的pod。

启动第一步,刚更新第一批就暂停了也可以;假如目标是5个,允许一个也不能少,允许最多可以10个,那一次加5个即可;

这就是我们可以自己控制节奏来控制更新的方法。

通过Deployment对象,你可以轻松的做到以下事情:

1、创建ReplicaSet和Pod

2、滚动升级(不停止旧服务的状态下升级)和回滚应用(将应用回滚到之前的版本)

3、平滑地扩容和缩容

4、暂停和继续Deployment

2、Deployment资源清单文件编写技巧

#查看Deployment资源对象由哪几部分组成

[root@master01 ~]# kubectl explain deployment
KIND:     Deployment
VERSION:  apps/v1
DESCRIPTION:
     Deployment enables declarative updates for Pods and ReplicaSets.
FIELDS:
   apiVersion <string>  #该资源使用的api版本
   kind <string>            #创建的资源是什么?
   metadata <Object>       #元数据,包括资源的名字和名称空间
   spec <Object>           #定义容器的
   status <Object>       #状态,不可以修改
#查看Deployment下的spec字段
[root@master01 ~]# kubectl explain deployment.spec
KIND:     Deployment
VERSION:  apps/v1
RESOURCE: spec <Object>
DESCRIPTION:
     Specification of the desired behavior of the Deployment.
     DeploymentSpec is the specification of the desired behavior of the
     Deployment.
FIELDS:
    minReadySeconds <integer>

#Kubernetes在等待设置的时间后才进行升级

#如果没有设置该值,Kubernetes会假设该容器启动起来后就提供服务了

paused #暂停,当我们更新的时候创建pod先暂停,不是立即更新

progressDeadlineSeconds

#k8s 在升级过程中有可能由于各种原因升级卡住(这个时候还没有明确的升级失败),

比如在拉取被墙的镜像,权限不够等错误。那么这个时候就需要有个 deadline ,

在 deadline 之内如果还卡着,那么就上报这个情况,这个时候这个 Deployment 状态就被标记为 False,

并且注明原因。但是它并不会阻止 Deployment 继续进行卡住后面的操作。完全由用户进行控制。

replicas #副本数

revisionHistoryLimit #保留的历史版本,默认是10

selector -required- #标签选择器,选择它关联的pod

strategy #更新策略

template -required #定义的pod模板查看Deployment下的spec.strategy字段

[root@master01 ~]# kubectl explain deploy.spec.strategy
KIND:     Deployment
VERSION:  apps/v1
RESOURCE: strategy <Object>
DESCRIPTION:
     The deployment strategy to use to replace existing pods with new ones.
     DeploymentStrategy describes how to replace existing pods with new ones.
FIELDS:
   rollingUpdate  <Object>
   type <string>
     Type of deployment. Can be "Recreate" or "RollingUpdate". Default is
     RollingUpdate.
#支持两种更新,Recreate和RollingUpdate
#Recreate是重建式更新,删除一个更新一个

#RollingUpdate滚动更新,定义滚动更新方式,也就是pod能多几个,少几个
#查看Deployment下的spec.strategy.rollingUpdate字段
[root@master01 ~]# kubectl explain deploy.spec.strategy.rollingUpdate
KIND:     Deployment
VERSION:  apps/v1
RESOURCE: rollingUpdate <Object>
DESCRIPTION:
     Rolling update config params. Present only if DeploymentStrategyType =
     RollingUpdate.
     Spec to control the desired behavior of rolling update.
FIELDS:
   maxSurge <string>
#我们更新的过程当中最多允许超出的指定的目标副本数有几个; 
它有两种取值方式,第一种直接给定数量,第二种根据百分比,百分比表示原本是5个,
最多可以超出20%,那就允许多一个,最多可以超过40%,那就允许多两个
   maxUnavailable <string>
#最多允许几个不可用
假设有5个副本,最多一个不可用,就表示最少有4个可用

replicas: 5

maxSurge: 25% 5*25%=1.25 ->5+2=7

maxUnavailable: 25% 5%25%=1.25 -> 5-1=4

查看Deployment下的spec.template字段

#template为定义Pod的模板,Deployment通过模板创建Pod

[root@master01 ~]# kubectl explain deploy.spec.template
KIND:     Deployment
VERSION:  apps/v1
RESOURCE: template <Object>
DESCRIPTION:
     Template describes the pods that will be created.
     PodTemplateSpec describes the data a pod should have when created from a template
FIELDS:
   metadata <Object>  #定义模板的名字
   spec <Object>   
deployment.spec.template为Pod定义的模板,和Pod定义不太一样,template中不包含apiVersion和Kind属性,
要求必须有metadata。deployment.spec.template.spec为容器的属性信息,其他定义内容和Pod一致。

查看Deployment下的spec.template.spec字段

[root@master01 ~]# kubectl explain deploy.spec.template.spec
KIND:     Deployment
VERSION:  apps/v1
RESOURCE: spec <Object>
DESCRIPTION:
     Specification of the desired behavior of the pod. More info:
     https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
     PodSpec is a description of a pod.
FIELDS:
   activeDeadlineSeconds  <integer>
#activeDeadlineSeconds表示Pod 可以运行的最长时间,达到设置的该值后,Pod 会自动停止。
   affinity <Object>  #定义亲和性,跟直接创建pod时候定义亲和性类似
   automountServiceAccountToken <boolean> #身份认证相关的
   containers <[]Object> -required- #定义容器属性
   dnsConfig  <Object>  #设置Pod的DNS
dnsConfig:
    nameservers:
      - 192.xxx.xxx.6
    searches:
      - xianchao.svc.cluster.local
      - my.dns.search.xianchao
   dnsPolicy  <string> # dnsPolicy决定Pod 内预设的DNS 配置策略

None 无任何策略:使用自定义的策略
Default 默认:使用宿主机的dns配置,/etc/resolv.conf
ClusterFirst 集群DNS优先,与 Default 相反,会预先使用 kube-dns (或 CoreDNS ) 的信息当预设置参数写入到该 Pod 内的DNS配置。
ClusterFirstWithHostNet 集群 DNS 优先,并伴随着使用宿主机网络:同时使用 hostNetwork 与 kube-dns 作为 Pod 预设 DNS 配置。

   enableServiceLinks <boolean>
   ephemeralContainers  <[]Object> #定义临时容器

临时容器与其他容器的不同之处在于,它们缺少对资源或执行的保证,

并且永远不会自动重启,因此不适用于构建应用程序。

临时容器使用与常规容器相同的 ContainerSpec 段进行描述,但许多字段是不相容且不允许的。

临时容器没有端口配置,因此像 ports,livenessProbe,readinessProbe 这样的字段是不允许的。

Pod 资源分配是不可变的,因此 resources 配置是不允许的。


临时容器用途:

当由于容器崩溃或容器镜像不包含调试应用程序而导致 kubectl exec 无用时,临时容器对于交互式故故障排查很有用。

hostAliases <[]Object> #在pod中增加域名解析的
  hostAliases:
  – ip: "10.1.2.2"
    hostnames:
    – "mc.local"
    – "rabbitmq.local"
  – ip: "10.1.2.3"
    hostnames:
    – "redis.local"
    – "mq.local"
   hostIPC  <boolean> #使用主机IPC
   hostNetwork  <boolean>  #是否使用宿主机的网络
   hostPID  <boolean> #可以设置容器里是否可以看到宿主机上的进程。True可以
   hostname <string>
   imagePullSecrets <[]Object>
   initContainers <[]Object> #定义初始化容器
   nodeName <string>  #定义pod调度到具体哪个节点上
   nodeSelector <map[string]string> #定义节点选择器
   overhead <map[string]string> #overhead是1.16引入的字段,在没有引入 Overhead 之前,
   只要一个节点的资源可用量大于等于 Pod 的 requests 时,这个 Pod 就可以被调度到这个节点上。
   引入 Overhead 之后,只有节点的资源可用量大于等于 Overhead 加上 requests 的和时才能被调度上来。
   preemptionPolicy <string>
   priority <integer>
   priorityClassName  <string>
   readinessGates <[]Object> 
   restartPolicy  <string>   #Pod重启策略
   runtimeClassName <string>
   schedulerName  <string>
   securityContext  <Object> #是否开启特权模式
     privileged: true  #开启特权模式
   serviceAccount <string>
   serviceAccountName <string>
   setHostnameAsFQDN  <boolean>
   shareProcessNamespace  <boolean>
   subdomain  <string>
   terminationGracePeriodSeconds  <integer>
#在真正删除容器之前,K8S会先发终止信号(kill -15 {pid})给容器,默认30s
   tolerations  <[]Object>  #定义容忍度
   topologySpreadConstraints  <[]Object
   volumes  <[]Object>  #挂载存储卷

3、查看控制器的历史版本

[root@master01 ~ ]# kubectl rollout --help
Manage the rollout of a resource.
  
 Valid resource types include:

  *  deployments
  *  daemonsets
  *  statefulsets

Examples:
  # Rollback to the previous deployment
  kubectl rollout undo deployment/abc
  
  # Check the rollout status of a daemonset
  kubectl rollout status daemonset/foo

Available Commands:
  history     View rollout history
  pause       Mark the provided resource as paused
  restart     Restart a resource
  resume      Resume a paused resource
  status      Show the status of the rollout
  undo        Undo a previous rollout

kubectl rollout restart 也是删除旧pod,重新建pod

查看Deployment有几个历史版本

[root@master01 ~]# kubectl rollout history deployment myapp-v1

#回滚到某个版本

[root@master01 ~]# kubectl rollout undo deployment myapp-v1 --to-revision=1
deployment.apps/myapp-v1 rolled back
[root@master01 ~]# kubectl rollout history deployment myapp-v1
deployment.apps/myapp-v1 
REVISION  CHANGE-CAUSE
2         <none>
3         <none>


4、自定义滚动更新策略

maxSurge和maxUnavailable用来控制滚动更新的更新策略

取值范围

数值

  1. maxUnavailable: [0, 副本数]
  2. maxSurge: [0, 副本数]
    注意:两者不能同时为0。
    比例
  3. maxUnavailable: [0%, 100%] 向下取整,比如10个副本,5%的话==0.5个,但计算按照0个;
  4. maxSurge: [0%, 100%] 向上取整,比如10个副本,5%的话==0.5个,但计算按照1个;
    注意:两者不能同时为0。
    建议配置
  5. maxUnavailable == 0
  6. maxSurge == 1
    这是我们生产环境提供给用户的默认配置。即“一上一下,先上后下”最平滑原则:1个新版本pod ready(结合readiness)后,才销毁旧版本pod。此配置适用场景是平滑更新、保证服务平稳,但也有缺点,就是“太慢”了。

总结:

maxUnavailable:和期望的副本数比,不可用副本数最大比例(或最大值),这个值越小,越能保证服务稳定,更新越平滑;

maxSurge:和期望的副本数比,超过期望副本数最大比例(或最大值),这个值调的越大,副本更新速度越快。

创建 Deployment 的时候使用了–record参数可以记录命令,我们可以很方便的查看每次 revision 的变化。查看单个revision 的详细信息:

kubectl rollout history deployment nginx-test --revision=3

–record 的作用是将当前命令记录到 revision 记录中,这样我们就可以知道每个 revison 对应的是哪个配置文件。

通过 kubectl rollout history deployment httpd 查看 revison 历史记录。

历史记录是一1、2、3的,并没有具体的版本号,只是对应yaml文件名,可以不按版本号作为命名的一部分,这样可以方便观察。

CHANGE-CAUSE 就是 --record 的结果。如果要回滚到某个版本,比如 revision 1,

可以执行命令 kubectl rollout undo deployment httpd --to-revision=1:

可以查看rollout history来获取

其实rollout history中记录revison是和ReplicaSets 一一对应,

如果我们手动删除了某个ReplicaSet对应到rollout history 就会被删除,也就是说无法rollout到这revison,

同样我们还可以查看一个revison的详细信息

5、K8S自动伸缩

使用 autoscaler 自动设置在kubernetes集群中运行的pod数量(水平自动伸缩)。

指定Deployment、ReplicaSet或ReplicationController,并创建已经定义好资源的自动伸缩器。

使用自动伸缩器可以根据需要自动增加或减少系统中部署的pod数量。$ autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [–min=MINPODS] --max=MAXPODS [–cpu-percent=CPU] [flags]

示例

使用默认的自动伸缩策略,指定目标CPU使用率,使其Pod数量在2到10之间。

kubectl autoscale deployment/nginx-test --min=2 --max=10

使其Pod的数量介于1和5之间,CPU使用率维持在80%。

kubectl autoscale deploy/nginx-test --max=5 --cpu-percent=80

kubectl autoscale deployment netdisk --min=2 --max=5 --cpu-percent=80

为部署netdisk创建一个自动伸缩器,目标CPU利用率设置为80%,副本数量介于2和5之间。

通过kubectl get hpa可以列出自动伸缩器,通过kubectl describe hpa能够获得自动伸缩器的详细说明。

最后,可以使用kubectl delete hpa删除自动缩放器。

此外,还有一个特殊kubectl autoscale命令可以轻松创建HorizontalPodAutoscaler。

6、动态控制副本数量

命令语法

scale [–resource-version=version] [–current-replicas=count] --replicas=COUNT (-f FILENAME | TYPE NAME)

kubectl scale命令通过调整正在运行的容器的数量来立即缩放应用程序。这是增加部署副本数量的最快、最简单的方法,可用于应对服务高峰以及日常维护变更。

在本文中,我们将了解如何使用kubectl scale来扩展一个简单的Kubernetes Deployment,同时,我们还将更深入的了解该命令相关的各种参数。最终形成kubectl scale的最佳实践,以及一些用于调整 Kubernetes 副`本数的替代方法。

kubectl scale用例

kubectl scale用于更改Kubernetes deployment, replica set, replication controller和 statefulset 等对象的副本数码。当我们增加副本数时,Kubernetes将启动新的Pod来扩我们的服务。降低副本数将导致 Kubernetes 优雅地终止一些 pod,从而释放集群资源。

我们可以运行kubectl scale来手动调整应用程序的副本数,以响应不断变化的服务容量需求。增加的流量负载可以通过增加副本数来处理,提供更多的应用程序实例来服务用户流量。当业务突发降低的时候,可以减少副本的数量。这有助于通过避免使用不需要的资源来降低成本。

使用 kubectl

kubectl scale最基本的用法是这样的:

$ kubectl scale --replicas=3 deployment/demo-deployment

kubectl scale deploy openaccountadmin --replicas=0 -n openaccount

kubectl scale deploy openaccountadmin --replicas=1 -n openaccount

条件缩放

有时我们可能想要扩展资源,但前提是已经有特定数量的副本在运行。这可以避免意外覆盖以前的副本,例如集群中其他用户所做的更改。

在命令中包含–current-replicas标志可以达到效果:

$ kubectl scale --current-replicas=3 --replicas=5 deployment/demo-deployment

deployment.apps/demo-deployment scaled

此示例将演示deployment扩展到五个副本,但前提是当前有三个副本正在运行。

–current -replicas值始终完全匹配;我们不能将条件表示为“小于”或“大于”特定计数。

扩展多个资源

当我们提供多个名称作为参数时, kubectl scale命令可以一次缩放多个资源。每个资源都将缩放到由–replicas标志设置的相同副本计数。

$ kubectl scale --replicas=5 deployment/app deployment/database

deployment.apps/app scaled

deployment.apps/database scaled

此命令将应用程序和数据库deployment扩展到每个五个副本。

我们可以通过提供–all标志来扩展特定类型的每个资源,例如此示例以扩展默认命名空间中的所有部署:

$ kubectl scale --all --replicas=5 --namespace=default deployment

deployment.apps/app scaled

deployment.apps/database scaled

这会选择当前活动命名空间内的每个匹配资源。缩放的对象显示在命令的输出中。

更改超时

–timeout标志设置 Kubectl 在放弃缩放操作之前将等待的时间。

默认情况下,没有等待期。该标志接受可读的时间值,例如5m或1h:

$ kubectl scale --replicas=5 --timeout=1m deployment/demo-deployment

如果无法立即完成缩放更改,这可以让我们避免长时间的终端挂起。

尽管kubectl scale是一个命令式命令,但在将新 pod 调度到节点时,对缩放的更改有时可能需要几分钟才能完成。

7、生产环境如何实现蓝绿部署?

7.1、什么是蓝绿部署?

蓝绿部署中,一共有两套系统:一套是正在提供服务系统,标记为“绿色”;

另一套是准备发布的系统,标记为“蓝色”。

两套系统都是功能完善的、正在运行的系统,只是系统版本和对外服务情况不同。

开发新版本,要用新版本替换线上的旧版本,

在线上的系统之外,搭建了一个使用新版本代码的全新系统。

这时候,一共有两套系统在运行,正在对外提供服务的老系统是绿色系统,新部署的系统是蓝色系统。

蓝色系统不对外提供服务,用来做什么呢?

用来做发布前测试,测试过程中发现任何问题,

可以直接在蓝色系统上修改,不干扰用户正在使用的系统。(注意,两套系统没有耦合的时候才能百分百保证不干扰)

蓝色系统经过反复的测试、修改、验证,确定达到上线标准之后,直接将用户切换到蓝色系统:

切换后的一段时间内,依旧是蓝绿两套系统并存,

但是用户访问的已经是蓝色系统。

这段时间内观察蓝色系统(新系统)工作状态,如果出现问题,直接切换回绿色系统。

当确信对外提供服务的蓝色系统工作正常,

不对外提供服务的绿色系统已经不再需要的时候,蓝色系统正式成为对外提供服务系统,成为新的绿色系统。

原先的绿色系统可以销毁,将资源释放出来,用于部署下一个蓝色系统。

7.2、蓝绿部署的优势和缺点

优点:

1、更新过程无需停机,风险较少

2、回滚方便,只需要更改路由或者切换DNS服务器,效率较高

缺点:

1、成本较高,需要部署两套环境。如果新版本中基础服务出现问题,会瞬间影响全网用户;如果新版本有问题也会影响全网用户。

2、需要部署两套机器,费用开销大

3、在非隔离的机器(Docker、VM)上操作时,可能会导致蓝绿环境被摧毁风险

4、负载均衡器/反向代理/路由/DNS处理不当,将导致流量没有切换过来情况出现

7.3 通过k8s实现线上业务的蓝绿部署

下面实验需要的镜像包在课件,把镜像压缩包上传到k8s的各个工作节点

[root@node02 ~]# docker load -i myapp-lan.tar.gz

[root@node01 ~]# docker load -i myapp-lv.tar.gz

Kubernetes不支持内置的蓝绿部署。目前最好的方式是创建新的deployment,然后更新应用程序的service以指向新的deployment部署的应用

1.创建绿色部署环境(基于第一版代码做的镜像运行的pod)

[root@master01 deploy ]#vim lv.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-v1
  namespace: blue-green
spec:
  replicas: 3
  selector:
   matchLabels:
    app: myapp
    version: v2
  template:
   metadata:
    labels:
     app: myapp
     version: v2
   spec:
    containers:
    - name: myapp
      image: janakiramm/myapp:v2
      imagePullPolicy: IfNotPresent
      ports:
      - containerPort: 80

[root@master01 deploy ]#kubectl create ns blue-green
namespace/blue-green created
[root@master01 deploy ]#kubectl apply -f lv.yaml 
deployment.apps/myapp-v1 created
[root@master01 deploy ]#
[root@master01 deploy ]#kubectl get pods -n blue-green
NAME                      READY   STATUS    RESTARTS   AGE
myapp-v1-5898574c-64tbk   1/1     Running   0          9s
myapp-v1-5898574c-hc7sk   1/1     Running   0          9s
myapp-v1-5898574c-zw4nd   1/1     Running   0          9s
[root@master01 deploy ]#kubectl get pods -n blue-green --show-labels
NAME                      READY   STATUS    RESTARTS   AGE   LABELS
myapp-v1-5898574c-64tbk   1/1     Running   0          62s   app=myapp,pod-template-hash=5898574c,version=v2
myapp-v1-5898574c-hc7sk   1/1     Running   0          62s   app=myapp,pod-template-hash=5898574c,version=v2
myapp-v1-5898574c-zw4nd   1/1     Running   0          62s   app=myapp,pod-template-hash=5898574c,version=v2

创建前端service

[root@master01 deploy ]#vim service_lanlv.yaml 
apiVersion: v1
kind: Service
metadata:
  name: myapp-lan-lv
  namespace: blue-green
  labels:
    app: myapp
spec:
  type: NodePort
  ports:
  - port: 80
    nodePort: 30062
    name: http
  selector:
    app: myapp
    version: v2

更新服务:

[root@master01 deploy ]#kubectl apply -f service_lanlv.yaml 
service/myapp-lan-lv created

[root@master01 deploy ]#kubectl get svc -n blue-green
NAME           TYPE       CLUSTER-IP        EXTERNAL-IP   PORT(S)        AGE
myapp-lan-lv   NodePort   192.168.182.131   <none>        80:30062/TCP   18s

在浏览器访问http://k8s-master节点ip:30062 显示如下:

绿色的界面:

Welcome to vNext of the web application

This application will be deployed on Kubernetes.

2.创建蓝色部署环境(新上线的环境,要替代绿色环境)

[root@master01 deploy ]#cat lan.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-v2
  namespace: blue-green
spec:
  replicas: 3
  selector:
   matchLabels:
    app: myapp
    version: v1
  template:
   metadata:
    labels:
     app: myapp
     version: v1
   spec:
    nodeName: node02
    containers:
    - name: myapp
      image: janakiramm/myapp:v1
      imagePullPolicy: IfNotPresent
      ports:
      - containerPort: 80


[root@master01 deploy ]#kubectl apply -f lan.yaml 
deployment.apps/myapp-v2 created
[root@master01 deploy ]#kubectl get pods -n blue-green
NAME                        READY   STATUS    RESTARTS   AGE
myapp-v1-5898574c-64tbk     1/1     Running   0          8m16s
myapp-v1-5898574c-hc7sk     1/1     Running   0          8m16s
myapp-v1-5898574c-zw4nd     1/1     Running   0          8m16s
myapp-v2-7799d7c9bb-cgrxz   1/1     Running   0          12s
myapp-v2-7799d7c9bb-hdmjr   1/1     Running   0          12s
myapp-v2-7799d7c9bb-qrv9s   1/1     Running   0          12s

修改service_lanlv.yaml 配置文件,修改标签,让其匹配到蓝程序(升级之后的程序)

[root@master01 deploy ]#cat service_lanlv.yaml 
apiVersion: v1
kind: Service
metadata:
  name: myapp-lan-lv
  namespace: blue-green
  labels:
    app: myapp
spec:
  type: NodePort
  ports:
  - port: 80
    nodePort: 30062
    name: http
  selector:
    app: myapp
    version: v1
[root@master01 deploy ]#kubectl apply -f service_lanlv.yaml 
service/myapp-lan-lv configured

[root@master01 deploy ]#kubectl get svc -n blue-green
NAME           TYPE       CLUSTER-IP        EXTERNAL-IP   PORT(S)        AGE
myapp-lan-lv   NodePort   192.168.182.131   <none>        80:30062/TCP   2d15h

在浏览器访问http://k8s-master节点ip:30062 显示如下:

蓝色的界面:

Welcome to V1 of the web application

This application will be deployed on Kubernetes.

实验完成之后,把资源先删除,以免影响后面实验:

[root@master01 deployment]# kubectl delete -f lan.yaml 
[root@master01 deployment]# kubectl delete -f lv.yaml 
[root@master01 deployment]# kubectl delete -f service_lanlv.yaml

8、通过k8s完成线上业务的金丝雀发布

8.1 金丝雀发布简介

金丝雀发布的由来:17 世纪,英国矿井工人发现,金丝雀对瓦斯这种气体十分敏感。

空气中哪怕有极其微量的瓦斯,金丝雀也会停止歌唱;当瓦斯含量超过一定限度时,

虽然人类毫无察觉,金丝雀却早已毒发身亡。

当时在采矿设备相对简陋的条件下,工人们每次下井都会带上一只金丝雀作为瓦斯检测指标,以便在危险状况下紧急撤离。

金丝雀发布(又称灰度发布、灰度更新):金丝雀发布一般先发1台,或者一个小比例,

例如2%的服务器,主要做流量验证用,也称为金丝雀 (Canary) 测试 (国内常称灰度测试)。

100个pod:

更新了一个pod:用的新的代码做的镜像

99个pod:没有更新

简单的金丝雀测试一般通过手工测试验证,复杂的金丝雀测试需要比较完善的监控基础设施配合,

通过监控指标反馈,观察金丝雀的健康状况,作为后续发布或回退的依据。

如果金丝测试通过,则把剩余的V1版本全部升级为V2版本。如果金丝雀测试失败,则直接回退金丝雀,发布失败。

优点:灵活,策略自定义,可以按照流量或具体的内容进行灰度(比如不同账号,不同参数),出现问题不会影响全网用户

缺点:没有覆盖到所有的用户导致出现问题不好排查

8.2 在k8s中实现金丝雀发布

打开一个标签1监测更新过程

[root@master01 deploy ]#kubectl get pods -l app=myapp -n blue-green -w
NAME                      READY   STATUS              RESTARTS   AGE
myapp-v1-5898574c-jzdcw   0/1     ContainerCreating   0          10s
myapp-v1-5898574c-lq5mm   0/1     ContainerCreating   0          9s
myapp-v1-5898574c-qnr26   0/1     ContainerCreating   0          9s
myapp-v1-5898574c-jzdcw   0/1     ContainerCreating   0          26s
myapp-v1-5898574c-lq5mm   0/1     ContainerCreating   0          25s
myapp-v1-5898574c-qnr26   0/1     ContainerCreating   0          25s
myapp-v1-5898574c-jzdcw   1/1     Running             0          28s
myapp-v1-5898574c-lq5mm   1/1     Running             0          27s
myapp-v1-5898574c-qnr26   1/1     Running             0          28s

打开另一个标签2执行如下操作:

[root@master01 ~ ]#kubectl set image deployment myapp-v1 myapp=nginx  -n blue-green && kubectl rollout pause deployment myapp-v1 -n blue-green
deployment.apps/myapp-v1 image updated
deployment.apps/myapp-v1 paused

回到标签1观察,显示如下:

[root@master01 deploy ]#kubectl get pods -l app=myapp -n blue-green -w
NAME                      READY   STATUS    RESTARTS   AGE
myapp-v1-5898574c-69rls   1/1     Running   0          113s
myapp-v1-5898574c-bchnr   1/1     Running   0          113s
myapp-v1-5898574c-jvpgt   1/1     Running   0          113s
myapp-v1-7bcddfd466-thjpp   0/1     Pending   0          0s
myapp-v1-7bcddfd466-thjpp   0/1     ContainerCreating   0          0s
myapp-v1-7bcddfd466-thjpp   0/1     ContainerCreating   0          1s
myapp-v1-7bcddfd466-thjpp   1/1     Running             0          103s

注:上面的解释说明把myapp这个容器的镜像更新到nginx版本 更新镜像之后,创建一个新的pod就立即暂停,

这就是我们说的金丝雀发布;如果暂停几个小时之后没有问题,那么取消暂停,就会依次执行后面步骤,把所有pod都升级。

可以看到目前有4个pod,前面三个pod镜像还是原来的镜像,后面一个是新创建的。通过service代理

请求会分别代理给这四个pod。如果查看日志有报错,则把这个pod删除就行。若运行没问题,就解除暂停

[root@master01 ~ ]#kubectl get po -n blue-green -owide
NAME                        READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
myapp-v1-5898574c-69rls     1/1     Running   0          8m11s   172.29.55.18   node01   <none>           <none>
myapp-v1-5898574c-bchnr     1/1     Running   0          8m11s   172.29.55.16   node01   <none>           <none>
myapp-v1-5898574c-jvpgt     1/1     Running   0          8m11s   172.29.55.17   node01   <none>           <none>
myapp-v1-7bcddfd466-thjpp   1/1     Running   0          6m15s   172.29.55.19   node01   <none>           <none>

请求原来的pod,返回时原来的服务 green:

[root@master01 ~ ]#curl 172.29.55.18
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Sample Deployment</title>
  <style>
    body {
      color: #ffffff;
      background-color: green;
      font-family: Arial, sans-serif;
      font-size: 14px;
    }

访问新建的pod,返回新页面

[root@master01 ~ ]#curl 172.29.55.19
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

这样就多出一个pod,用来测试新版本。如果暂停几个小时之后没有问题,那么取消暂停,就会依次执行后面步骤,把所有pod都升级。

解除暂停:

回到标签1继续观察:

打开标签2执行如下:

[root@master01 ~ ]#kubectl rollout resume deployment myapp-v1 -n blue-green

deployment.apps/myapp-v1 resumed

在标签1可以看到如下一些信息,下面过程是把余下的pod里的容器都更的版本:

[root@master01 deploy ]#kubectl get pods -l app=myapp -n blue-green -w
NAME                      READY   STATUS    RESTARTS   AGE
myapp-v1-5898574c-69rls   1/1     Running   0          113s
myapp-v1-5898574c-bchnr   1/1     Running   0          113s
myapp-v1-5898574c-jvpgt   1/1     Running   0          113s
myapp-v1-7bcddfd466-thjpp   0/1     Pending   0          0s
myapp-v1-7bcddfd466-thjpp   0/1     ContainerCreating   0          0s
myapp-v1-7bcddfd466-thjpp   0/1     ContainerCreating   0          1s
myapp-v1-7bcddfd466-thjpp   1/1     Running             0          103s
myapp-v1-7bcddfd466-c8wfd   0/1     Pending             0          0s
myapp-v1-5898574c-jvpgt     1/1     Terminating         0          12m
myapp-v1-7bcddfd466-c8wfd   0/1     ContainerCreating   0          0s
myapp-v1-5898574c-jvpgt     1/1     Terminating         0          12m
myapp-v1-7bcddfd466-c8wfd   0/1     ContainerCreating   0          1s
myapp-v1-5898574c-jvpgt     0/1     Terminating         0          12m
myapp-v1-5898574c-jvpgt     0/1     Terminating         0          12m
myapp-v1-5898574c-jvpgt     0/1     Terminating         0          12m
myapp-v1-7bcddfd466-c8wfd   1/1     Running             0          2s
myapp-v1-5898574c-69rls     1/1     Terminating         0          12m
myapp-v1-7bcddfd466-gncs2   0/1     Pending             0          0s
myapp-v1-7bcddfd466-gncs2   0/1     ContainerCreating   0          0s
myapp-v1-5898574c-69rls     1/1     Terminating         0          12m
myapp-v1-7bcddfd466-gncs2   0/1     ContainerCreating   0          1s
myapp-v1-7bcddfd466-gncs2   1/1     Running             0          1s
myapp-v1-5898574c-69rls     0/1     Terminating         0          12m
myapp-v1-5898574c-bchnr     1/1     Terminating         0          12m
myapp-v1-5898574c-69rls     0/1     Terminating         0          12m
myapp-v1-5898574c-69rls     0/1     Terminating         0          12m
myapp-v1-5898574c-bchnr     1/1     Terminating         0          12m
myapp-v1-5898574c-bchnr     0/1     Terminating         0          12m
myapp-v1-5898574c-bchnr     0/1     Terminating         0          12m
myapp-v1-5898574c-bchnr     0/1     Terminating         0          12m

可以看到replicaset控制器有2个了,原来的已经不再使用

[root@master01 ~ ]#kubectl get rs -n blue-green
NAME                  DESIRED   CURRENT   READY   AGE
myapp-v1-5898574c     0         0         0       13m
myapp-v1-7bcddfd466   3         3         3       11m
[root@master01 ~ ]#kubectl get pods -n blue-green
NAME                        READY   STATUS    RESTARTS   AGE
myapp-v1-7bcddfd466-c8wfd   1/1     Running   0          2m1s
myapp-v1-7bcddfd466-gncs2   1/1     Running   0          119s
myapp-v1-7bcddfd466-thjpp   1/1     Running   0          12m

查看历史版本:

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

欢迎大家关注留言,博主也会根据粉丝的需求,推出大家需要的题材博客,谢谢大家!!!


相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
10天前
|
Kubernetes 监控 调度
【赵渝强老师】K8s的DaemonSet控制器
DaemonSet控制器确保每个节点上运行一个Pod副本,适用于监控、日志收集等场景。通过示例创建DaemonSet并查看Pod信息,展示了其自动扩展和回收的能力。视频讲解和代码示例详细说明了DaemonSet的使用方法和调度机制。
|
10天前
|
Kubernetes 调度 容器
【赵渝强老师】K8s中Job控制器单工作队列的串行方式
Kubernetes中的Job控制器用于管理一次性任务,确保任务完成后不再重启。本文介绍了Job的工作原理、运行方式及示例,包括创建Job、查看Job和Pod信息等步骤,并附有视频讲解。
|
10天前
|
Kubernetes 双11 容器
【赵渝强老师】Kubernetes中的控制器
Kubernetes通过控制器管理Pod的生命周期,以应对不同场景需求,如Deployment、DaemonSet、Job等。控制器可自动调整Pod数量和重启故障Pod,确保系统稳定运行。视频讲解和详细内容见下文。
|
1月前
|
Kubernetes 持续交付 微服务
深入浅出:理解 Kubernetes 核心概念
Kubernetes 是一个由 Google 开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。它已成为微服务架构下的行业标准。本文深入浅出地介绍了 Kubernetes 的核心概念和组件,包括 Master 和 Node 组件、Pod、Service、Deployment 等,并提供了基本操作示例和实战应用,帮助你更好地管理和利用容器环境。
|
10天前
|
Kubernetes 应用服务中间件 nginx
【赵渝强老师】K8s中的Deployment控制器
Kubernetes中的Deployment用于部署无状态应用程序,管理Pod的数量、更新方式和资源限制。通过创建和管理ReplicaSet,Deployment可以实现Pod的自动扩缩容、滚动更新和回滚。本文介绍了Deployment的基本概念,并通过一个具体的示例演示了如何使用Deployment创建、更新和管理Pod。
|
10天前
|
存储 Kubernetes 调度
【赵渝强老师】K8s中Deployment控制器与StatefulSet控制器的区别
K8s中的Deployment控制器用于管理无状态应用程序,关注Pod数量、更新方式等;而StatefulSets控制器则管理有状态应用程序,提供持久存储和唯一标识符,适用于需要稳定网络标识符和持久化存储的场景。两者的主要区别在于是否维护状态和顺序。
|
10天前
|
存储 Kubernetes 调度
【赵渝强老师】K8s的有状态控制器StatefulSet
在Kubernetes中,StatefulSets用于部署有状态应用程序,提供持久存储和唯一标识符。与Deployment不同,StatefulSets确保Pod的标识符在重新调度后保持不变,适用于需要稳定网络标识符和持久存储的场景。本文介绍了StatefulSets的创建、扩容与缩容、更新与回滚等操作,并提供了具体示例和视频讲解。
|
10天前
|
Kubernetes Linux 调度
【赵渝强老师】K8s的周期性任务控制器CronJob
本文介绍了K8s中的CronJob控制器,它类似于Linux的crontab命令,用于管理和调度定时作业。CronJob可以设置在未来某一时间运行作业一次或在指定时间点重复运行作业。文章通过一个示例展示了如何创建和使用CronJob控制器,包括创建配置文件、应用配置、查看Pod信息和日志等步骤。同时,还解释了CronJob的时间表示方式及其限制。
|
10天前
|
Kubernetes 调度 容器
【赵渝强老师】K8s的Job控制器多工作队列的并行方式
Kubernetes Job 是一次性任务控制器,用于控制 Pod 中的容器执行特定任务。本文介绍了 Job 控制器的工作原理、运行方式及多工作队列并行执行的示例。示例中创建了 5 个作业,以 3 个队列并行执行,整个过程需 2 分钟。文中还提供了详细的 YAML 文件配置和执行命令。
|
18天前
|
存储 Kubernetes 调度
K8S中的核心概念
【10月更文挑战第26天】云原生环境下的安全问题易被忽视,导致潜在风险。应用层渗透测试和漏洞扫描是检测安全的关键,尤其是对于CVE漏洞的修复。然而,常见误解认为安全由外部防护处理且不易引入问题。

推荐镜像

更多