深入剖析k8s中常见的控制器

本文是《深入剖析k8s》学习笔记的第三篇,主要对k8s中的控制器进行分析和讲解。

pod是k8s操作的最小单元,操作pod的工作都是由控制器controller完成的,对应k8s中的组件就是kube-controller-manager,其下常见的控制器类型有:

  • Deployment,无状态容器控制器,通过控制ReplicaSet来控制pod;应用场景web应用;
  • StatefulSet,有状态容器控制器,保证pod的有序和唯一,pod的网络标识和存储在pod重建前后一致;应用场景主从架构;
  • DeamonSet,守护容器控制器,确保所有节点上有且仅有一个pod;应用场景监控;
  • Job,普通任务容器控制器,只会执行一次;应用场景离线数据处理;
  • CronJob,定时任务容器控制器,定时执行;应用场景通知、备份;

控制器的yaml文件一般分为两个部分,上半部分是关于控制器的定义,下半部分是关于被控制对象,也就是pod的定义:

## 上半部分,定义控制器
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  # 管理标签为app=nginx的pod
  selector:
    matchLabels:
      app: nginx
  # 确保被管理的对象数量始终为3
  replicas: 3
  ## 下半部分,定义被控制的对象,也就是pod
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

Deployment、ReplicaSet、Pod三者之间是一种层层控制的关系,ReplicaSet通过控制器模式来保证pod的数量永远等于指定的个数,而Deployment同样也通过控制器的模式来操作ReplicaSet。如此,Deployment可以很方便地实现如下两个特性(并不只是Deployment控制器的功能):

  • 水平收缩,通过修改replicas副本数量,Deployment将指令传递给ReplicaSet,由ReplicaSet来实现pod的水平收缩;
  • 滚动更新,Deployment会创建一个新的ReplicaSet来逐一新建新版本的pod,旧的ReplicaSet也逐渐将旧版本的pod副本数量降低到0;好处就是如果新版本的pod创建过程中出现问题,滚动更新会中断,旧版本的pod也会停止销毁,此时还能对外提供旧版本的服务,不会导致业务中断;当然,我们还可以通过如下的更新策略字段来控制新版本滚动更新的范围,实现金丝雀发布或者灰度发布的目的:
    • partition,StatefulSet控制器拥有该属性,表示编号大于等于该值的pod才会更新为新的版本;
    • maxSurge,Deployment拥有该属性,更新时同一时间新建pod的数量占总数量的百分比,默认25%;
    • MaxUnavailable,Deployment拥有该属性,更新时同一时间可以删除pod的数量占总数量的百分比,默认25%;
    • pods,Deployment拥有该属性,表示可以一次性更新的pod数量;

StatefulSet主要是为了满足需要维持应用之间拓扑状态、稳定应用各自的网络状态、保持应用各自存储状态的情形而设计的。

  • 拓扑状态,即多个pod之间存在启动依赖关系,比如主从架构中,从节点肯定要依赖并晚于主节点才能启动,且写请求一定只能转发给主节点,这种情况下,Deployment就无法解决。StatefulSet之所以能满足该场景,是因为其给所有pod进行了编号,编号以StatefulSet Name-index命名,比如mystatefulset-0、mystatefulset-1,每个pod按照编号递增,永不重复。这些pod的创建是顺序同步进行的,前面的pod没有进入到running状态,后面的pod就会一直pending。
  • 网络状态,所有pod都进入running之后,各自都会有固定不变的网络身份,即他们的hostname,和它们的pod编号名称一样,固定不变是指无论重新创建多少次,各个pod的网络身份始终一致。这样通过headless service方式访问每个pod的地址就始终固定不变,比如mystatefulset-0.servicename、mystatefulset-1.servicename,如此StatefulSet就保证了pod网络标识的稳定性。
  • 存储状态,每个pod挂载pvc时,也会给pvc命名,命名规则为pvc-StatefulSet Name-index,比如mypvc-mystatefulset-0、mypvc-mystatefulset-1,无论pod重新创建与否,每个pod与其对应的pvc始终都会处于绑定状态。如此StatefulSet就保证了存储状态的稳定性。

DaemonSet控制器确保k8s集群中的每个节点有且仅有一个定义的pod运行。那么它是如何实现这个功能的呢?

  • 从etcd中获取所有node的信息,循环遍历每个node,没有守护容器的就新建,超过1个的就删除,正好就1个的就表示正常;
  • 通过nodeAffinity节点亲和性来保证每个守护pod只会在和其亲和的节点上被调度运行;
  • 通过tolerations声明,允许守护pod可以在被标记为污点的Node上调度运行;

建议在设置DaemonSet控制器时,限制守护pod的资源占用上线,避免守护容器过度占用宿主机的资源,影响用户容器的正常运行。

前面所说的Deployment、StatefulSet、DaemonSet都是一种Long Running Task,即长在线业务,这些应用一旦运行起来,除非出错或者停止,它的容器进程会一直保持在running的状态。然而现实中有种业务是执行完成就结束,不需要一直在线运行的,这种业务被称为离线业务,Batch Job,就是我们接下来要介绍的Job和CronJob。

如下是一个Job的yaml定义代码,它也是直接管理pod,其中的部分字段含义如下:

  • restartPolicy,指pod中的任务执行失败时的重启策略;
    • Never,表示pod不要重启,但是会创建新的pod来替换旧的pod执行任务;
    • OnFailure,pod不会变化,但是会尝试重启pod中的容器;
  • spec.backoffLimit,任务失败的最大重试次数,每次重试的时间间隔是按照指数级增加的,比如10s、20s、40s......
  • spec.activeDeadlineSeconds,任务最大可运行时间,到了这个时间,Job中还未结束的pod都会被强制停止;

apiVersion: batch/v1
kind: Job
metadata:
  name: test-job
spec:
 # 定义pod模板
  template:
    spec:
      # 定义pod中容器
      containers:
      - name: test01
        image: resouer/ubuntu-bc 
        # 需要在容器中执行的任务,执行完毕就退出
        command: ["sh", "-c", "echo 'scale=10000; 4*a(1)' | bc -l "]
      # pod的重启策略,通常有Never和OnFailure
      restartPolicy: Never
  # 任务失败重试次数,默认为6
  backoffLimit: 4

Job还支持任务的并行执行,主要通过如下两个参数来控制并行的策略:

  • spec.parallelism,任务并行度,定义一个Job同时最多可以启动pod的数量;
  • spec.completions,任务数,定义一个Job总共需要完成多少个pod的数量;

CronJob是Job的控制器,通过控制Job来控制pod,只是比Job多了调度cron表达式的功能。它所用的cron表达式是unix cron风格的,支持5位,分别代表分、时、日、月、星期,比如*/1 * * * *就表示每隔1分钟就创建一个Job,但是并不限制已经创建Job的结束时间,所以可能就会出现多个Job同时在运行的情况,此时可以通过如下的字段来进行约束:

  • spec.concurrencyPolicy,定义Job的调度策略;
    • Allow,允许多个Job同时运行;
    • Forbid,不允许多个Job同时运行,该创建周期被跳过;
    • Replace,新周期创建的Job会替换旧的还没有执行完成的Job;
  • spec.startingDeadlineSeconds,指定若干秒内,某个Job如果执行100次都失败,就会停止再次创建这个Job;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容