草庐IT

【云原生 | 从零开始学Kubernetes】十五、k8s核心技术-Deployment 控制器

cloud、泡泡 2023-04-09 原文

该篇文章已经被专栏《从零开始学k8s》收录
上一篇文章:k8s核心技术-Controller 点击跳转


Deployment 控制器

什么是Deployment 控制器

  • Deployment控制器可以部署无状态应用
  • 管理Pod和ReplicaSet
  • 部署,滚动升级等功能
  • 应用场景:web服务,微服务

Deployment表示用户对K8S集群的一次更新操作。Deployment是一个比RS( Replica Set, RS) 应用模型更广的 API 对象,可以是创建一个新的服务,更新一个新的服务,也可以是滚动升级一个服务。滚动升级一个服务,实际是创建一个新的RS,然后逐渐将新 RS 中副本数增加到理想状态,将旧RS中的副本数减少到0的复合操作。

这样一个复合操作用一个RS是不好描述的,所以用一个更通用的Deployment来描述。以K8S的发展方向,未来对所有长期伺服型的业务的管理,都会通过Deployment来管理。

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 处于活跃状态.

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

简单使用Deployment

但是我们可以尝试使用上面的代码创建一个镜像【只是尝试,不会创建】

kubectl create deployment web --image=nginx --dry-run -o yaml > nginx.yaml

然后输出一个yaml配置文件 nginx.yml ,配置文件如下所示

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: web
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
status: {}

我们看到的 selector 和 label 就是我们Pod 和 Controller之间建立关系的桥梁

使用YAML创建Pod

通过刚刚的代码快速创建Pod镜像

kubectl apply -f nginx.yaml

但是因为这个方式创建的,我们只能在集群内部进行访问,所以我们还需要对外暴露端口

kubectl expose deployment web --port=80 --type=NodePort --target-port=80 --name=web1

关于上述命令,有几个参数

  • –port:就是我们内部的端口号
  • –target-port:就是暴露外面访问的端口号
  • –name:名称
  • –type:类型

同理,我们一样可以导出对应的配置文件

kubectl expose deployment web --port=80 --type=NodePort --target-port=80 --name=web1 -o yaml > web1.yaml

得到的web1.yaml如下所示

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: "2022-07-11T07:21:58Z"
  labels:
    app: web
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:labels:
          .: {}
          f:app: {}
      f:spec:
        f:externalTrafficPolicy: {}
        f:ports:
          .: {}
          k:{"port":80,"protocol":"TCP"}:
            .: {}
            f:port: {}
            f:protocol: {}
            f:targetPort: {}
        f:selector:
          .: {}
          f:app: {}
        f:sessionAffinity: {}
        f:type: {}
    manager: kubectl
    operation: Update
    time: "2022-07-11T07:21:58Z"
  name: web-5dcb957ccc-246f9
  namespace: default
  resourceVersion: "49814"
  selfLink: /api/v1/namespaces/default/services/web-5dcb957ccc-246f9
  uid: 05dbb353-3b46-4907-a6fe-7f345d178d93
spec:
  clusterIP: 10.105.31.251
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30438
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: web
  sessionAffinity: None
  type: NodePort
status:
  loadBalancer: {}

然后我们可以通过下面的命令来查看对外暴露的服务

kubectl get pods,svc

然后我们访问对应的url,即可看到 nginx了 http://192.168.11.139:32639/

升级回滚和弹性伸缩

  • 升级: 假设从版本为1.14 升级到 1.15 ,这就叫应用的升级【升级可以保证服务不中断】
  • 回滚:从版本1.15 变成 1.14,这就叫应用的回滚
  • 弹性伸缩:我们根据不同的业务场景,来改变Pod的数量对外提供服务,这就是弹性伸缩

应用升级和回滚

首先我们先创建一个 1.14版本的Pod

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: web
    spec:
      containers:
      - image: nginx:1.14
        name: nginx
        resources: {}
status: {}

我们先指定版本为1.14,然后开始创建我们的Pod

kubectl apply -f nginx.yaml

然后我们查看pods,nginx在node2,过去使用docker images命令,就能看到我们成功拉取到了一个 1.14版本的镜像

nginx                                1.14                295c7be07902        3 years ago         109MB

我们使用下面的命令,可以将nginx从 1.14 升级到 1.15

kubectl set image deployment web nginx=nginx:1.15

在我们执行完命令后,能看到升级的过程

[root@k8smaster node]# kubectl get pods
NAME                    READY   STATUS              RESTARTS   AGE
web-65b7447c7-9rp9v     1/1     Running             0          107s
web-7d9697b7f8-fdtbv    0/1     ContainerCreating   0          21s
[root@k8smaster node]# kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
nginx-f89759699-5qdtn   1/1     Running   2          14d
web-7d9697b7f8-fdtbv    1/1     Running   0          37s
  • 首先是开始的nginx 1.14版本的Pod在运行,然后 1.15版本的在创建
  • 然后在1.15版本创建完成后,就会暂停1.14版本
  • 最后把1.14版本的Pod移除,完成我们的升级

我们在下载 1.15版本,容器就处于ContainerCreating状态,然后下载完成后,就用 1.15版本去替换1.14版本了,这么做的好处就是:升级可以保证服务不中断

我们到我们的node2节点上,查看我们的 docker images;

能够看到,我们已经成功拉取到了 1.15版本的nginx了

查看升级状态

下面可以,查看升级状态

kubectl rollout status deployment web

查看历史版本

我们还可以查看历史版本

kubectl rollout history deployment web

应用回滚

我们可以使用下面命令,完成回滚操作,也就是回滚到上一个版本

kubectl rollout undo deployment web

然后我们就可以查看状态

kubectl rollout status deployment web

同时我们还可以回滚到指定版本

kubectl rollout undo deployment web --to-revision=2

弹性伸缩

弹性伸缩,也就是我们通过命令一下创建多个副本

kubectl scale deployment web --replicas=10

能够清晰看到,我们一下创建了10个副本

写在最后

创作不易,如果觉得内容对你有帮助,麻烦给个三连关注支持一下我!如果有错误,请在评论区指出,我会及时更改!
目前正在更新的系列:从零开始学k8s
感谢各位的观看,文章掺杂个人理解,如有错误请联系我指出~

有关【云原生 | 从零开始学Kubernetes】十五、k8s核心技术-Deployment 控制器的更多相关文章

  1. Ruby Readline 在向上箭头上使控制台崩溃 - 2

    当我在Rails控制台中按向上或向左箭头时,出现此错误:irb(main):001:0>/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/rb-readline-0.4.2/lib/rbreadline.rb:4269:in`blockin_rl_dispatch_subseq':invalidbytesequenceinUTF-8(ArgumentError)我使用rvm来管理我的ruby​​安装。我正在使用=>ruby-2.0.0-p247[x86_64]我使用bundle来管理我的gem,并且我有rb-readline(0.4.2)(人们推荐的最少

  2. ruby-on-rails - 带 Spring 锁的 Rails 4 控制台 - 2

    我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.

  3. ruby-on-rails - openshift 上的 rails 控制台 - 2

    我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新ruby​​gems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems

  4. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  5. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  6. ruby-on-rails - 在 Rails 控制台中使用 asset_path - 2

    在我的Character模型中,我添加了:字符.rbbefore_savedoself.profile_picture_url=asset_path('icon.png')end但是,对于数据库中已存在的所有角色,它们的profile_picture_url为nil。因此,我想进入控制台并遍历所有这些并进行设置。在我试过的控制台中:Character.find_eachdo|c|c.profile_picture_url=asset_path('icon.png')end但这给出了错误:NoMethodError:undefinedmethod`asset_path'formain:O

  7. ruby-on-rails - 带有 Pry 的 Rails 控制台 - 2

    当我进入Rails控制台时,我已将pry设置为加载代替irb。我找不到该页面或不记得如何将其恢复为默认行为,因为它似乎干扰了我的Rubymine调试器。有什么建议吗? 最佳答案 我刚发现问题,pry-railsgem。忘记了它的目的是让“railsconsole”打开pry。 关于ruby-on-rails-带有Pry的Rails控制台,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/question

  8. ruby - 将全局 $stdout 重新分配给控制台 - ruby - 2

    我正在尝试将$stdout设置为临时写入一个文件,然后返回到一个文件。test.rb:old_stdout=$stdout$stdout.reopen("mytestfile.out",'w+')puts"thisgoesinmytestfile"$stdout=old_stdoutputs"thisshouldbeontheconsole"$stdout.reopen("mytestfile1.out",'w+')puts"thisgoesinmytestfile1:"$stdout=old_stdoutputs"thisshouldbebackontheconsole"这是输出。r

  9. ruby-on-rails - Ruby 流量控制 : throw an exception, 返回 nil 还是让它失败? - 2

    我在思考流量控制的最佳实践。我应该走哪条路?1)不要检查任何东西并让程序失败(更清晰的代码,自然的错误消息):defself.fetch(feed_id)feed=Feed.find(feed_id)feed.fetchend2)通过返回nil静默失败(但是,“CleanCode”说,你永远不应该返回null):defself.fetch(feed_id)returnunlessfeed_idfeed=Feed.find(feed_id)returnunlessfeedfeed.fetchend3)抛出异常(因为不按id查找feed是异常的):defself.fetch(feed_id

  10. ruby-on-rails - ruby 新手,有人可以帮我从控制台破译这个错误吗? - 2

    我真的只是不确定这意味着什么或我应该做什么才能让网页在我的本地主机上运行。现在它只是显示一个错误,上面写着“我们很抱歉,但出了点问题。”当我运行railsserver并在chrome中打开localhost:3000时。这是控制台输出:StartedGET"/users/sign_in"for127.0.0.1at2013-07-0512:07:07-0400ProcessingbyDevise::SessionsController#newasHTMLCompleted500InternalServerErrorin55msNoMethodError(undefinedmethod`

随机推荐