K8S:几种资源调度方式-RC/RS/Deployment/StatefulSet/DaemonSet
学习自:k8s资源调度-RC/RS/Deployment/StatefulSet/DaemonSet - 知乎
使用Deployment、StatefulSet部署应用__GalenZhang888的博客-CSDN博客
剖析 Kubernetes 控制器:Deployment、ReplicaSet 和 StatefulSet 的功能与应用场景_51CTO博客
前言
下文会经常提到状态一词:
Deployment用于部署无状态服务,是最常用的控制器。
STS(StatefulSet)是有状态集,常用于部署有状态且需要有序启动的应用程序。
这里的状态是什么意思?
有状态:如Redis这种,存在主从节点,会选举出一个M节点工作。
无状态:所有节点地位平等,多台同时协作工作。
Replication Controller(RC)
RC通过Label控制Pod的创建和销毁,它可以保证任何时候都有指定数量的Pod副本在运行。这一点通过RC的yaml中的spec.replicas来确定。
如果存在的Pod>replicas,那么RC会终止多余的Pod。反之会启动更多的Pod来保证达到期望值。
因此在管理Pod时,哪怕应用程序只需要一个Pod,也建议用RC这种自动管理方式来管理Pod。RC所管理的Pod不限于某个Node,而是监视K8S集群的多个Node上的多个Pod。
一个RC的yaml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | apiVersion: v1 kind: ReplicationController metadata: name: nginx spec: replicas: 3 #副本数 selector: app: nginx template: metadata: name: nginx labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 |
ReplicaSet(RS)
RS可以视为RC的优化版,除了具有RC的功能——协调创建、删除、更新Pod之外,与RC唯一的区别在于:RS支持灵活的Label Selector,RC的LS只支持选择某个确定标签,而RS可以以集合的方式选择标签(通过spec.selector.matchExpressions进行),使用这种集合方式可以实现RollingUpdate。
后续的Deployment也是通过RS实现了Pod副本的自动控制功能。
RS的yaml示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | apiVersion: apps/v1 kind: ReplicaSet metadata: name: frontend labels: app: test version: v2 spec: replicas: 3 selector: matchLabels: version: v2 matchExpressions: #集合式标签选择器,允许同时有v1和v2两个版本的pod。 - {key: version, operator: In, values: [v1,v2]} template: metadata: labels: app: test version: v2 spec: containers: - name: nginx image: nginx:1.15.2 resources: requests: cpu: 100m memory: 100Mi env: - name: IS_env value: env ports: - containerPort: 80 |
RC和RS是两种简单部署Pod的方式。
它们在创建、删除Pod时的区别不大,生产中也比较少用到,通常使用较为高级的Deployment等进行Pod管理。
Deployment
为了更好地解决Pod编排问题,K8S从1.2版本开始引入了Deployment,在其内部使用了RS来实现这个目的。
Deployment相比RC的优势在于可以随时知道Pod部署进度,即当前容器正处于Pod创建、调度、绑定、启动的哪个阶段。
它一般用于管理维护企业内部无状态的微服务,如springboot、configserver。可以管理多个Pod副本无缝迁移、自动扩缩容、灾难恢复、一键回滚等功能。
一个Deployment的yaml文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | apiVersion: apps/v1 kind: Deployment metadata: annotations: deployment.kubernetes.io/revision: "1" creationTimestamp: "2021-06-16T07:49:17Z" generation: 1 labels: #deploy自身的标签 app: nginx name: nginx namespace: test-wang spec: progressDeadlineSeconds: 600 replicas: 1 #副本数 revisionHistoryLimit: 10 #保留历史记录的次数,设置为0的话,不保留历史数据 # minReadySeconds: 0 #可选参数,指定新创建的Pod在没有任何容器崩溃的情况下视为Ready最小的秒数,< br >默认为0,即一旦被创建就视为可用。 selector: #匹配RS,一旦创建就不建议修改,否则RS会脱离deploy的掌控 matchLabels: app: nginx strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate < br >#更新deployment的方式 1.RollingUpdate:滚动更新(默认),可以指定< br >maxSurge(超过期望值的最大Pod数,默认25%)和maxUnavailable(最大不可用数量,默认25%)< br >2.Recreate 重建 先删除旧的Pod,在创建新的Pod template: metadata: #匹配Pod,要和匹配RS的一致 creationTimestamp: null labels: app: nginx spec: #和Pod的一致。 containers: - image: nginx:1.15.2 imagePullPolicy: IfNotPresent name: nginx resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 |
deployment常用的命令
1、get:查询
1 2 3 | kubectl get deploy -n test-wang -o wide NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR nginx 1/1 1 1 5m23s nginx nginx:1.15.2 app=nginx |
参数-n后跟节点的名字
返回项:
NAME:名称
READY:Pod状态,已经准备和所需的Pod副本数
UP-TO-DATE:最新版本的Pod副本数,指示在RollingUpdate的过程中,有多少Pod已经成功升级
AVAILABLE:已经可用的Pod副本数,即存活的Pod数
AGE:应用程序运行的时间
CONTAINERS:容器名称
IMAGES:镜像
SELECTOR:该Deploy所管理的Pod的Label
2、create:创建
1 | kubectl create -f XXX.yaml |
3、set image:更新
1 | kubectl set image deploy nginx nginx=nginx:1.15.3 |
4、rollout:回滚、查看历史版本
1 2 3 4 5 6 7 | kubectl rollout history deploy nginx #查看历史版本 kubectl rollout undo deploy nginx #回滚到上一个版本 kubectl rollout history deploy nginx #查看历史记录 kubectl rollout history deploy nginx --revision=3 #查看某个版本的详细信息 kubectl rollout undo deploy nginx --to-revision=3 #回滚到某个版本 kubectl rollout pause deployment nginx #暂停 kubectl rollout resume deploy nginx #恢复 |
StatefulSet(STS)
STS是有状态集,常用于部署有状态且需要有序启动的应用程序。
STS管理的Pod都有稳定、唯一的网络标识,可以用来发现其他成员。
它控制的Pod副本的启停顺序都是受控的,操作第n个Pod时,需要前n-1个Pod都是Ready状态。
它管理的Pod采用稳定的持久化存储,删除时不会删除相关的存储卷,这些卷使用K8S其他资源管理。
例如生产环境中,可以用StatefulSet来部署需要持久化的RabbitMQ、Redis、Kafka集群。这些集群有一些共同特点:每个节点都有固定身份,并且可以通过身份相互通信,规模固定,不随意变动,Pod都是有状态,通常会持久化数据到永久存储,当磁盘损坏时某个节点无法正常运行,使集群功能受损。
StatefulSet和Deploy类似,一个STS也同样管理着相同容器规范的Pod。区别在于STS为每个Pod维护了一个持久标识符,在重新调度时也会保留,一般格式为StatefuleSetName-Number。例如某个STS的名为Redis,指定创建3个Pod,那么创建出来的Pod名为Redis-0、Redis-1、Redis-2。
STS创建的Pod间,一般采用Headless Service进行通信,它与普通Service的区别在于Headless Service没有ClusterIP,而是用自定义的EndPoint进行通信。Headless的格式和STS管理的Pod名字格式类似:
1 | statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local |
- statefulSetName:STS的名字
- 0..N-1:Pod序号
- serviceName:Headless Service的名字
- namepsace:Service所在命名空间
- cluster.local:集群域
以一个Redis的例子说明STS的作用
某个项目需要部署主从模式Redis,可以使用STS,因为STS启动Pod时,需要前置Pod已经启动;由于STS中的Pod标识固定,因此用户可以通过标识判断Pod角色。
例如某个STS名为redis-ms,用它来部署主从架构的Redis,第一个容器启动时的标识符redis-ms-0,并且Pod内的主机名也为redis-ms-0,此时就能根据主机名判断,当主机名为redis-ms-0的容器作为Redis的M节点,其余为S节点。那么S连接M时就可以用不会更改的M的Headless Service,此时S的配置文件如下:
port 6379
slaveof redis-ms-0.redis-ms.public-service.svc.cluster.local 6379
tcp-backlog 511
timeout 0
tcp-keepalive 0
注意第二行slaveof,reids-ms-0.xxx.xxx.local就是M的Headless Service,在同一命名空间下只需要写为redis-ms-0.redis-ms即可,后半截可以省略。
STS注意事项
1、一般STS会用于有以下需求的应用程序中:
- 需要稳定、独一无二的网络标识符;
- 需要持久化数据;
- 需要有序、优雅的部署、扩展;
- 需要有序的RollingUpdate。
如果应用程序不需要稳定标识符、有序扩展,应该使用无状态的控制器部署,例如Deployment或RS。
2、Pod所用的存储必须由PersistentVolume Provisioner(持久化卷配置器)根据请求配置StorageClass,或者由管理员预先配合,当然也可以不配置存储。
3、为了确保数据安全,删除、缩放STS不会删除与STS关联的卷,可以手动选择性地删除PVC和PV;
4、STS采用Headless Service负责Pod的网络身份和通信,需要提前创建该服务;
5、删除一个STS,不保证对Pod的终止,要在STS中实现Pod的有序、正常终止,可以在删除前将STS的副本缩减为0。
STS的yaml文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | apiVersion: v1 kind: Service metadata: name: nginx #Service定义了一个名字为Nginx的Headless Service,k8s所创建的Service格式为nginx-0.nginx.default.svc.cluster.local,其他的类似 namespace: test-k8s labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None #设置None后不会有clusterIP,但是可以通过无头服务访问到它,不强制要求设置None,可以避免资源的浪费 selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web # StatefulSet定义了一个名字为web的StatefulSet,replicas表示部署Pod的副本数,本实例为2,当StatefulSet控制器创建Pod时,它会添加一个标签statefulset.kubernetes.io/pod-name,该标签的值为Pod的名称,用于匹配Service。 namespace: test-k8s spec: serviceName: "nginx" replicas: 2 selector: #在StatefulSet中必须设置Pod选择器用来匹配其标签(.spec.template.metadata.labels)。在1.8版本之前,如果未配置该字段,将被设置为默认值,在1.8版本之后,如果未指定匹配Pod Selector,则会导致StatefulSet创建错误 matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web |
sts的常见操作和特性
1、通过get查看STS的Pod,可以发现名称都是xxx-0、xxx-1,如果用exec进去,会发现主机名称也和Pod一致,是固定的。
如果用get查询service,会发现它没有Ip地址
2、扩容sts时,只有web0创建好了才能创建web1,web2,中间任何一个过程出问题都会导致下一个Pod创建失败。
如果在扩容时,删除了中间的某个Pod,那么会先把这个Pod新建再完成后续创建。
缩容时,是从序号较大的开始,如果在该过程中某个序号较小的挂了,那么会等它变为Reday再继续。
3、删除
级联删除:删除sts时删除Pod(默认)
非级联删除:删除STS时不删除Pod
1 | kubectl delete sts web --cascade=false |
DaemonSet(DS)
DS,守护进程集,在所有节点或匹配的节点上都部署一个Pod。
使用DS的场景:
- 运行集群存储的Daemon,例如ceph或glusterd;
- 节点的CNI网络插件,calico
- 节点日志的收集:fluentd、filebeat
- 节点监控:node exporter
- 服务暴露:部署一个ingress nginx
DS的yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | apiVersion: apps/v1 kind: DaemonSet metadata: labels: app: nginx name: nginx namespace: test-k8s spec: revisionHistoryLimit: 10 selector: matchLabels: app: nginx updateStrategy: #滚动更新策略 rollingUpdate: maxUnavailabel: 1 #滚动更新时最大不可用数目 type: RollingUpdate template: metadata: creationTimestamp: null labels: app: nginx spec: containers: - image: nginx:1.15.2 imagePullPolicy: IfNotPresent name: nginx resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
2020-10-09 struct.error: unpack requires a buffer of 26 bytes
2020-10-09 自己创建bmp图像