jjzjj

k8s如何滚动升级应用

jmuhe 2024-04-21 原文

本文基于《Kubernetes in Action》第9章整理。

在进入正文前,不得不感慨一下标签选择器的设计对解耦k8s各模块发挥的作用。k8s的service, replicaSet, 滚动升级,调度的亲缘性和污点容忍度都离不开标签选择器。标签选择器让k8s对资源的操作更加灵活。

手动进行滚动升级

我们先用如下的配置创建一个ReplicationController

apiVersion: v1
kind: ReplicationController
metadata:
  name: kubia-v1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: kubia
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      containers:
        - image: test:v1
          name: my-container

并创建一个service,其标签选择器是 “app: kubia”

现在我们想要更新镜像,可以执行如下步骤进行滚动升级。

  • 新建一个新的ReplicationController,如下所示
apiVersion: v1
kind: ReplicationController
metadata:
  name: kubia-v2
spec:
  replicas: 0
  selector:
    matchLabels:
      app: kubia
      deployment: 757d16 # 增加标签,用于标记此次的升级记录
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
        deployment: 757d16 # 增加标签,用于标记此次的升级记录
    spec:
      containers:
        - image: test:v2 # 修改镜像
          name: my-container
  • 为原pod和ReplicationController增加标签:deployment: 343der。此时,kubia-v1还是管理着原先的pod,kubia-v2新建的pod不会被kubia-v1管理。但是不论kubia-v1还是kubia-v2创建的pod,都会和之前建的service关联。
  • 逐步扩容kubia-v2,并逐步缩容kubia-v1,直至所有pod都是由kubia-v2管理,则此次滚动升级结束

上述的步骤,也是之前kubectl的roling-update命令执行的大概过程。

这个过程存在以下弊端

  1. 过程繁琐。需要多次和API服务器交互
  2. 是在客户端执行,因此无法保证一致性,如果在滚动升级过程中和API服务器的交互出现问题,则pod, rc等资源会处于中间状态
  3. 不符合k8s的设计理念。应该通过设置期望的状态而不是告诉需要做哪些事情

通过Deployment滚动升级

首先创建以下配置,命名为deployment.yaml

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: kubia
spec:
  replicas: 3
  progressDeadlineSeconds: 600 # 滚动升级失败的超时时间
  minReadySeconds: 10 # 需要容器就绪多久后才能认为可用,在可用前,滚动升级不会继续。这个可以用于控制滚动升级的速率
  strategy:
    rollingUpdate:
      maxSurge: 1 # 在期望副本数基础上,最多允许超出的pod实例数量,允许设置绝对值和百分比
      maxUnavailable: 25% # 相对于期望副本数,允许有多少pod实例处于不可用状态,允许设置绝对值和百分比
    type: RollingUpdate # 表示滚动升级。也可以配置成 Recreate,其会一次性删除所有旧版本的pod,然后创建新的pod
  selector:
    matchLabels:
      app: kubia
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      containers:
        - image: test:v1
          name: my-container

执行下面命令会创建Deployment

kubectl create -f deployment.yaml --record

--record会记录历史版本号,在回滚时会很有用

随后,这个deployment会创建一个ReplicaSet,然后新建的ReplicaSet再去创建pod,不过这个都不需要我们关注。所以,Deployment是比ReplicaSet更高级的资源,是用于协调多个ReplicaSet的。

修改pod模板才会触发滚动升级,因此修改deployment本身的配置,以及pod关联的ConfigMap等都不会触发滚动升级。当滚动升级开始的时候,会新建一个ReplicaSet,根据新的pod模板创建新的pod,并不断扩容新的ReplicaSet,缩容旧的ReplicaSet。过程类似上面介绍的手动滚动升级,区别是Deployment不会删除旧的ReplicaSet,因此可以方便的进行回滚。

滚动升级相关的命令是kubectl rollout,可以查看其都有哪些子命令

kubectl rollout history deployment my-deployment # 可以查看my-deployment的滚动升级历史
kubectl rollout pause deployment my-deployment # 可以暂停滚动升级
kubectl rollout resume deployment my-deployment # 可以恢复滚动升级
kubectl rollout status deployment my-deployment # 可以查看滚动升级中的状态
kubectl rollout undo deployment my-deployment --to-revision=1 # 回滚到指定版本

聊一下服务的上线

服务的上线是一个危险的动作,很多事故都是因为上线引起的。之所以危险,原因有很多,比如测试不到位,服务没有优雅退出,没有做好兼容等。所以对于服务的上线,需要足够的敬畏。

为了减少服务上线带来的事故,采取的措施一般有

  1. 封线。比如节假日前后,流量高峰期时一般不允许上线
  2. 周知。周知相关服务的负责人,让他们协助在服务上线期间一起观察服务有无异常
  3. 分阶段升级。比如第一次只升级其中一个实例,第二次升级3个实例,逐步放量,缓慢上线
  4. 做好观察。在服务上线期间,需要盯监控,关注告警,观察失败日志,在出现异常的时候第一时间会滚

有关k8s如何滚动升级应用的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  5. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  6. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  9. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  10. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

随机推荐