目录:
(1)k8s指南-概述
(2)k8s指南-架构
(3)k8s指南-工作负载(1)
(4)k8s指南-工作负载(2)
(5)k8s指南-工作负载(3)
(6)k8s指南-工作负载(4)
(7)k8s指南-Service
(8)k8s指南-Ingress
(9)k8s指南-DNS与服务发现
(10)K8S指南-平滑升级与自动扩缩容
ReplicaSet是无状态的工作负载,其目的是维护一组在任何时候都处于运行状态的pod副本的稳定集合。
ReplicaSet
ReplicaSet是通过一组字段来定义的,包括一个用来识别pod的选择符、一个用来标明期望副本数量和pod模板等。下面是一个ReplicaSet示例:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# 按你的实际情况修改副本数
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v3
事实上,一般不会直接使用ReplicaSet,而是用Deployment。Deployment是一个更高级的概念,它管理ReplicaSet,并向pod提供声明式的更新和其他功能。
ReplicaSet通过选择符来获取pod,它所获得的pod都在其ownerReferences字段中包含了ReplicaSet信息。查看前文中通过deployment创建的pod的的YAML:
kubectl get pod/nginx-deployment-66b957f9d-nxtmb -o yaml
可以看到如下信息:
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: nginx-deployment-66b957f9d
uid: 258330af-a097-402c-9054-97c38dd1f324
resourceVersion: "312558"
uid: 1744870f-4b9f-451d-bbf6-1d9becbc610e
这里的属主ReplicaSet正是deployment管理的ReplicaSet,通过kubectl get rs
可以看到。
非模板pod的获得
在前文中我们创建了nginx-deployment,在这个deployment中期望的副本数是3,如下所示:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-66b957f9d-nxtmb 1/1 Running 0 167m
nginx-deployment-66b957f9d-pjpk5 1/1 Running 0 167m
nginx-deployment-66b957f9d-rfqfm 1/1 Running 0 167m
这些pod都是deployment管理的ReplicaSet创建的,其属主是nginx-deployment-66b957f9d
。
下面直接创建裸pod,bare_pod.yaml如下所示:
apiVersion: v1
kind: Pod
metadata:
name: pod1
labels:
app: nginx
spec:
containers:
- name: c1
image: nginx:1.16.1
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
labels:
app: nginx
spec:
containers:
- name: c2
image: nginx:1.16.1
直接创建:
kubectl apply -f bare_pod.yaml
创建完成后查看所有的pods:
NAME READY STATUS RESTARTS AGE
nginx-deployment-66b957f9d-nxtmb 1/1 Running 0 3h
nginx-deployment-66b957f9d-pjpk5 1/1 Running 0 3h
nginx-deployment-66b957f9d-rfqfm 1/1 Running 0 3h
pod1 1/1 Running 0 5m58s
pod2 1/1 Running 0 5m58s
查看nginx-deployment管理的rs,即nginx-deployment-66b957f9d:kubectl describe rs nginx-deployment-66b957f9d
,可以得到如下信息:
Selector: app=nginx,pod-template-hash=66b957f9d
Labels: app=nginx
pod-template-hash=66b957f9d
我们使用edit命令在pod1的标签中添加pod-template-hash=66b957f9d,再次查看pods,发现pod1不见了:
NAME READY STATUS RESTARTS AGE
nginx-deployment-66b957f9d-nxtmb 1/1 Running 0 24h
nginx-deployment-66b957f9d-pjpk5 1/1 Running 0 24h
nginx-deployment-66b957f9d-rfqfm 1/1 Running 0 24h
pod2 1/1 Running 0 21h
查看rs信息kubectl describe rs nginx-deployment-66b957f9d
,可以看到如下描述:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulDelete 106s replicaset-controller Deleted pod: pod1
这是因为pod1修改标签后,rs通过选择符获取到了pod1。而rs的期望副本数是3,原有的三个pod加上pod1之后会超过期望值,因此pod1才会被删除以保证rs管理的pod数量符合期望值。
如果先裸创建一个pod,再通过rs创建其他pod,且裸创建的pod标签与rs的选择符一致,则裸创建的这个pod会占用期望副本的数量
使用ReplicaSet
删除ReplicaSet
要删除ReplicaSet和它的所有pod,可以使用delete命令。默认情况下,垃圾收集器自动删除所有依赖的pod。
注意,如果删除deployment管理的rs,如上文中nginx-deployment所生成的rs,是不能够直接删除的。Deployment会重新生成一个相同名称的rs并扩容pod。
当然也可以只删除ReplicaSet而不影响它的各个pod,方法是用delete命令并设置--cascade=orphan
选项。
如果只删除了rs,并创建一个拥有同样选择器的rs来替换它。即使新的rs的模板与原来的不一样,已有的pod也不会更新。
隔离pod
可以通过改变标签来从ReplicaSet中移除pod,这种技术可以用来从服务中摘除有问题的pod以便进行排错和数据恢复。
扩缩ReplicaSet
通过更新.spec.replicas
字段,ReplicaSet可以被轻松地进行扩缩容。
降低pod数量时,ReplicaSet控制器通过对所有可用的pod进行排序来选择要被删除的pod。算法如下:
- 首先选择剔除悬挂(Pending且不可调度)的pod
- 如果设置了
controller.kubernetes.io/pod-deletion-cost
注解,则注解值极较小的优先被剔除 - 所处节点上副本数较多的pod优先于所处节点上副本数量少的
- 如果pod的创建时间不同,创建时间近的优先剔除
如果以上比较结果都相同,则随机选择
Pod删除开销
功能特性: Kubernetes v1.22 [beta]。
通过使用controller.kubernetes.io/pod-deletion-cost
注解,可以对ReplicaSet缩容时要先删除哪些pod设置偏好。
此注解要设置到pod上,取值范围为[-2147483647, 2147483647],代表的是删除同一ReplicaSet中其他pod相比较而言的开销,越小则越容易被删除。
Pod如果未设置此注解,则默认为0。如果注解值非法,则API服务器会拒绝相应的pod。此功能处于Beta阶段,默认被启用。
ReplicaSet作为水平的Pod自动扩缩容目标
ReplicaSet也可以作为水平的Pod扩缩器(HPA)的目标。也就是说,ReplicaSet可以被HPA自动扩缩。下面是一个示例:
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: frontend-scaler
spec:
scaleTargetRef:
kind: ReplicaSet
name: frontend
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 50
通过kubectl apply命令可以对名为frontend的ReplicaSet进行扩缩容设置。或者也可以使用kubectl autoscale命令完成相同的操作:
kubectl autoscale rs frontend --max=10 --min=3 --cpu-percent=50
ReplicaSet的替换方案
Deployment
Deployment是一个可以拥有ReplicaSet并使用声明式方式在服务器端完成对pod滚动更新的对象。尽管ReplicaSet可以独立使用,但实际上其主要用途是提供给Deployment作为编排Pod创建、删除和更新的一种机制。
当使用Deployment时,你不必去关心如何管理它所创建的ReplicaSet,而是由Deployment自己管理。
Job
用Job代替ReplicaSet,可以用于一些期望自行终止的Pod。
DaemonSet
对于管理那些提供主机级别功能(如主机监控和主机日志)的容器,就要用DaemonSet而不用ReplicaSet,这些Pod的寿命与主机寿命有关:这些pod需要先于主机上的其他Pod运行,并且在机器准备重新启动/关闭时安全地终止。
DaemonSet
DaemonSet即是守护进程工作负载,负责管理节点上运行的守护进程。DaemonSet的一些典型用法:
- 在每个节点上运行集群守护进程
- 在每个节点上运行日志收集守护进程
- 在每个节点上运行监控守护进程
一种简单的用法是为每种类型的守护进程在所有的节点上都启动一个DaemonSet。稍微复杂点的用法是为同一种守护进程部署多个DaemonSet,每个具有不同的标志,并且对不同的硬件类型具有不同的内存和CPU要求。
DaemonSet Spec
创建DaemonSet
下面是一个示例:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
tolerations:
# 这些容忍度设置是为了让该守护进程集在控制平面节点上运行
# 如果你不希望自己的控制平面节点运行 Pod,可以删除它们
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
与所有其他Kubernetes配置一样,DaemonSet也需要apiversion、kind和metadata字段。DaemonSet对象的名称必须是一个合法的DNS子域名。
DaemonSet也需要.spec
节区。
Pod模板与选择符
与其他工作负载一样,.spec
中需要template
模板,用来描述生成pod的信息。还需要指定合理的标签,以供选择器来筛选。
在DaemonSet中的Pod模板必须具有一个值为Always
的RestartPolicy
,当该值未指定时,默认是Always
。
一旦DaemonSet创建成功,其选择器.sepc.selector
就不能修改。选择器有多个条件时,按逻辑与操作处理。
仅在某些节点上运行Pod
如果指定了 .spec.template.spec.nodeSelector
,DaemonSet 控制器将在能够与Node选择算符匹配的节点上创建 Pod。 类似这种情况,可以指定 .spec.template.spec.affinity
,DaemonSet 控制器将在能够与节点亲和性匹配的节点上创建 Pod。 如果根本就没有指定,则 DaemonSet Controller 将在所有节点上创建 Pod。
更新DaemonSet
如果节点的标签被修改,DaemonSet将立刻向新匹配的节点添加Pod,并删除不匹配的节点上的Pod。
你可以修改DaemonSet创建的pod,不过并非所有的字段都可更新。
你可以删除一个DaemonSet,对应的pod也会被删除。如果使用--cascade-orhpan
选项,则pod会被保留。接下来如果使用相同选择器创建新的DaemonSet,则新的DaemonSet会收养已有的pod。如果有pod需要被替换,DaemonSet会根据其updateStrategy
来替换。
DaemonSet的替代方案
init脚本
可以使用初始化脚本直接在节点上启动守护进程(如使用init
、upstartd
、systemd
)。但大多数情况下这是不推荐的,不如使用DaemonSet。
静态Pod
通过在一个指定的、受kubelet监视的目录下编写文件创建pod也是可行的。这类pod被称为静态Pod。不像DaemonSet,静态Pod不受kubectl和其他Kubernetes API客户端管理,静态pod不依赖于API服务器,这使得它们在启动引导新集群的情况下非常有用。此外,静态Pod在将来可能会被废弃。
Deployment
DaemonSet与Deployment非常类似,都能创建pod,并且pod中的进程都不希望被终止(如Web服务器、存储服务器)。
建议为无状态的服务使用Deployment。对这些服务而言。对副本数量进行扩缩容、平滑升级,比精确控制Pod运行在某个主机上重要得多。当需要Pod副本总是运行在全部或特定主机上,并且当该DaemonSet提供了节点级别的功能(允许其他pod在该节点上正确运行)时,才应该使用DaemonSet。例如,网络插件通常包含一个以DaemonSet运行的组件。这个DaemonSet组件确保它所在节点的网络正常工作。
参考资料
[1]. https://kubernetes.io/zh/docs/concepts/overview/
[2]. https://blog.csdn.net/weichuangxxb/article/details/103754021