Kubernetes资源调度
在Kubernetes平台上,我们很少会直接创建一个Pod,在大多数情况下会通过Deployment、Statefulset、DaemonSet、Job等控制器完成对一组Pod副本的创建、调度及全生命周期的自动控制任务。
一、Replication Controller 和 ReplicaSet
Replication Controller(复制控制器,RC,几乎不用)和 ReplicaSet(复制集,RS)是两种简单部署 Pod的方式。因为在生产环境中,主要使用更高级的 Deployment 等方式进行 Pod 的管理和部署,所以只需要简单了解即可。
1. Replication Controller
不常用,已弃用
Replication Controller(简称 RC)可确保 Pod 副本数达到期望值,也就是 RC 定义的数量。换句话说,Replication Controller 可确保一个 Pod 或一组同类 Pod 总是可用。
如果存在的 Pod 大于设定的值,则 Replication Controller 将终止额外的 Pod。如果太小,Replication Controller 将启动更多的 Pod 用于保证达到期望值。与手动创建 Pod 不同的是,用Replication Controller 维护的 Pod 在失败、删除或终止时会自动替换。因此即使应用程序只需要一个 Pod,也应该使用 Replication Controller 或其他方式管理。Replication Controller 类似于进程管理程序,但是 Replication Controller 不是监视单个节点上的各个进程,而是监视多个节点上的多个 Pod。
定义一个 Replication Controller 的示例如下:
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
2. ReplicaSet
ReplicaSet (复制集,RS)是支持基于集合的标签选择器的下一代 Replication Controller,它主要用作Deployment 协调创建、删除和更新 Pod,和 Replication Controller 唯一的区别是,ReplicaSet 支持标签选择器。
采用正则表达式方式形式
在实际应用中,虽然 ReplicaSet 可以单独使用,但是一般建议使用 Deployment 来自动管理 ReplicaSet,除非自定义的 Pod 不需要更新或有其他编排等。
定义一个 ReplicaSet 的示例如下:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec: # RS的配置
# modify replicas according to your case
replicas: 3
selector:
matchLabels:
tier: frontend
matchExpressions:
- {
key: tier, operator: In, values: [frontend]}
template:
metadata:
labels:
app: guestbook
tier: frontend
spec: # Pod的配置
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v3
resources:
requests:
cpu: 100m
memory: 100Mi
env:
- name: GET_HOSTS_FROM
value: dns
# If your cluster config does not include a dns service, then to
# instead access environment variables to find service host
# info, comment out the 'value: dns' line above, and uncomment the
# line below.
# value: env
ports:
- containerPort: 80
Replication Controller 和 ReplicaSet 的创建删除和 Pod 并无太大区别,Replication Controller目前几乎已经不在生产环境中使用,ReplicaSet 也很少单独被使用,都是使用更高级的资源Deployment、DaemonSet、StatefulSet 进行管理 Pod。
二、有无服务状态说明
参考地址:
K8S: 有状态 vs 无状态服务 - 知乎 (zhihu.com)
1. 有状态服务
- 服务本身依赖或者存在局部的状态数据,这些数据需要自身持久化或者可以通过其他节点恢复。
- 一个请求只能被某个节点(或者同等状态下的节点)处理。
- 存储状态数据,实例的拓展需要整个系统参与状态的迁移。
- 在一个封闭的系统中,存在多个数据闭环,需要考虑这些闭环的数据一致性问题。
- 通常存在于分布式架构中。
有状态服务需要在本地存储持久化数据,典型的是分布式数据库的应用,分布式节点实例之间有依赖的拓扑关系.比如,主从关系. 如果K8S停止分布式集群中任 一实例pod,就可能会导致数据丢失或者集群的crash.
mysql 主写从读,就需要先恢复主
2. 无状态服务
- 服务不依赖自身的状态,实例的状态数据可以维护在内存中。
- 任何一个请求都可以被任意一个实例处理。
- 不存储状态数据,实例可以水平拓展,通过负载均衡将请求分发到各个节点。
- 在一个封闭的系统中,只存在一个数据闭环。
- 通常存在于单体架构的集群中。
无状态服务不会在本地存储持久化数据.多个服务实例对于同一个用户请求的响应结果是完全一致的.这种多服务实例之间是没有依赖关系,比如web应用,在k8s控制器 中动态启停无状态服务的pod并不会对其它的pod产生影响.
三、无状态应用管理 Deployment
Deployment一般用于部署无状态服务,这个也是最常用的控制器,因为企业内部现在都是以微服务为主,而微服务实现无状态化也是最佳实践,可以利用Deployment的高级功能做到无缝迁移、自动扩容缩容、自动灾难恢复、一键回滚等功能。
例如:
- Java
- Go
- Vue
- PHP等业务容器
- 其他需要任何状态的服务
Deployment被设计用来管理无状态服务的pod,每个pod完全一致。
- 无状态服务内的多个Pod创建的顺序是没有顺序的.
- 无状态服务内的多个Pod的名称是随机的.pod被重新启动调度后,它的名称与IP都会发生变化.
- 无状态服务内的多个Pod背后是共享存储的.
Deployment组件是为无状态服务而设计的,其中的Pod名称,主机名,存储都是随机,不稳定的,并且Pod的创建与销毁也是无序的。这个设计决定了无状态服务并 不适合数据库领域的应用。
如Redis集群,Redis是主从的架构,只能允许集群中出现一个主节点提供写,其它节点提供读能力。如果同时出现二个主节点后,必须会出现并发写的 操作,进一步导致集群写数据的不一致。
1. 创建 Deployment
部署过程示例:
在master01上执行命令,并不代表一定在master01上创建Pod,是在任意节点,自动选择比较优的节点。所以都要配置好网络等相关信息。
创建一个 Deployment:
apiVersion: apps/v1
kind: Deployment # Deployment类型
metadata:
name: nginx-deployment # Deployment名称
labels: # Deployment标签
app: nginx
spec: # Deployment配置
replicas: 3 # Deployment的副本
selector:
matchLabels:
app: nginx # Deployment管理的Pod标签
template: # Pod的定义
metadata:
labels: # Pod的标签
app: nginx
spec: # Pod的配置
containers:
- name: nginx
image: nginx:1.15.12
ports:
- containerPort: 80
注意:
从 Kubernetes 1.16 版本开始,彻底废弃了其他的 APIVersion,只能使用 apps/v1,1.16 以下的版本可以使用 extension 等。
示例解析:
-
nginx-deployment:Deployment的名称;
-
replicas: 创建Pod的副本数;
-
selector:定义Deployment如何找到要管理的Pod,与template的label(标签)对应,apiVersion为apps/v1必须指定该字段;selector和template标签写成一样的。
-
template字段包含以下字段:
- app: nginx使用label(标签)标记Pod;
- spec:表示Pod运行一个名字为nginx的容器;
- image:运行此Pod使用的镜像;
- Port:容器用于发送和接收流量的端口。
# 结果
[root@k8s-master01 pre]# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
cluster-test 1/1 1 1 170m
nginx-deployment 3/3 3 3 27m
[root@k8s-master01 pre]# kubectl get po
NAME READY STATUS RESTARTS AGE
cluster-test-66bb44bd88-pztch 1/1 Running 2 (49m ago) 170m
nginx-deployment-5c8578bf64-6s9tt 1/1 Running 0 3m39s
nginx-deployment-5c8578bf64-mn7kf 1/1 Running 0 28m
nginx-deployment-5c8578bf64-rzt9w 1/1 Running 0 28m
[root@k8s-master01 pre]# kubectl get po -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cluster-test-66bb44bd88-pztch 1/1 Running 2 (50m ago) 172m 172.16.195.2 k8s-master03 <none> <none>
nginx-deployment-5c8578bf64-6s9tt 1/1 Running 0 5m24s 172.16.32.131 k8s-master01 <none> <none>
nginx-deployment-5c8578bf64-mn7kf 1/1 Running 0 30m 172.16.85.195 k8s-node01 <none> <none>
nginx-deployment-5c8578bf64-rzt9w 1/1 Running 0 30m 172.16.58.194 k8s-node02 <none> <none>
直接获取deployment的yaml文件:
# kubectl create deploy nginx --image=registry.cn-beijing.aliyuncs.com/dotbalo/nginx:1.15.12-alpine --replicas=3 -oyaml --dry-run=client >nginx-deploy.yaml
使用 kubectl create 创建此 Deployment:
# kubectl create -f dp-nginx.yaml
deployment.apps/nginx-deployment created
使用 kubectl get 或者 kubectl describe 查看此 Deployment 的状态:
[root@k8s-master01 pre]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
cluster-test 1/1 1 1 3h
nginx-deployment 3/3 3 3 38m
# ➢ NAME:集群中Deployment的名称;
# ➢ READY:Pod就绪个数和总副本数;
# ➢ UP-TO-DATE:显示已达到期望状态的被更新的副本数;
# ➢ AVAILABLE:显示用户可以使用的应用程序副本数,当前为3,说明目前达到期望的Pod;
# ➢ AGE:显示应用程序运行的时间。
[root@k8s-master01 pre]# kubectl get rs
NAME DESIRED CURRENT READY AGE
cluster-test-66bb44bd88 1 1 1 179m
nginx-deployment-5c8578bf64 3 3 3 36m
[root@k8s-master01 pre]# kubectl get po
NAME READY STATUS RESTARTS AGE
cluster-test-66bb44bd88-pztch 1/1 Running 2 (57m ago) 179m
nginx-deployment-5c8578bf64-6s9tt 1/1 Running 0 12m
nginx-deployment-5c8578bf64-mn7kf 1/1 Running 0 36m
nginx-deployment-5c8578bf64-rzt9w 1/1 Running 0 36m
# 从Pod的名字可以看出来是由三部分组成
# deployment的名字 + ReplicaSet(复制集,rs)+Pod名字
此时删除一个Pod,会自动生产一个Pod,达到期望值。,因为replicas副本是3
可以使用 rollout 命令查看整个 Deployment 创建的状态:
[root@k8s-master01 pre]# kubectl rollout status deployment/nginx-deployment
deployment "nginx-deployment" successfully rolled out
# 当新建或者重置的时候,可以查进度
[root@k8s-master01 pre]# kubectl rollout status deployment/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 4 of 5 updated replicas are available...
deployment "nginx-deployment" successfully rolled out
[root@k8s-master01 pre]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
cluster-test 1/1 1 1 3h6m
nginx-deployment 3/3 3 3 44m
# 当 rollout 结束时,再次查看此 Deployment,可以看到 AVAILABLE 的数量和 yaml 文件中定义的 replicas 相同:**
按标签筛选:查看此 Deployment 当前对应的 ReplicaSet:
[root@k8s-master01 pre]# kubectl get rs -l app=nginx
NAME DESIRED CURRENT READY AGE
nginx-deployment-5c8578bf64 3 3 3 45m
# ➢ DESIRED:应用程序副本数;
# ➢ CURRENT:当前正在运行的副本数;
当 Deployment 有过更新,对应的 RS 可能不止一个,可以通过-o yaml
获取当前对应的 RS是哪个,其余的 RS 为保留的历史版本,用于回滚等操作。
查看此 Deployment 创建的 Pod,可以看到 Pod 的 hash 值 5c8578bf64 和上述 Deployment 对应的 ReplicaSet 的 hash 值一致:
[root@k8s-master01 pre]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-5c8578bf64-6s9tt 1/1 Running 0 22m app=nginx,pod-template-hash=5c8578bf64
nginx-deployment-5c8578bf64-mn7kf 1/1 Running 0 46m app=nginx,pod-template-hash=5c8578bf64
nginx-deployment-5c8578bf64-rzt9w 1/1 Running 0 46m app=nginx,pod-template-hash=5c8578bf64
删除deploy命令
# kubectl delete -f nginx-deploy.yaml
更新deploy命令
[root@k8s-master01 pre