一. Controller:控制器
什么是控制器
kubernetes中内建了很多controller(控制器),这些相当于一个状态机,用来控制pod的具体状态和行为。
部分控制器类型如下:
ReplicationController 和 ReplicaSet
Deployment
DaemonSet
StatefulSet
Job/CronJob
HorizontalPodAutoscaler
Pod是K8s集群中所有业务类型的基础,可以看作运行在K8s集群中的小机器人,不同类型的业务就需要不同类型的小机器人去执行。目前K8s中的业务主要可以分为长期伺服型(long-running)、批处理型(batch)、节点后台支撑型(node-daemon)和有状态应用型(stateful application);分别对应的小机器人控制器为Deployment、Job、DaemonSet和PetSet
。
1.Replication Controller和ReplicaSet:RC,RS
https://kubernetes.io/zh/docs/concepts/workloads/controllers/replicationcontroller/
3. Deployment(常用)
https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/
4. service
4. Statefulset
5. Daemonset
6. Job
1. Rc,Rs
Replication Controller:副本控制器复制控制器(selector =
或者 selector !=
)
- 确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会
自动创建新的pod来替代
; - 而异常多出来的容器也会自动回收。设置期望的Pod
副本数为 3
- 只
适用于长期服型的业务类型
,比如控制小机器人提供高可用的Web服务。
ReplicaSet:副本控制集,
- 和副本控制器的区别是:对选择器的支持(
selector选择器
还支持in notin),也可以独立实现, - 如今被 Deployment 作为
协调Pod
创建,删除的新机制, - 当使用 Deployment 时,不必担心还要管理它们创建的 ReplicaSet,Deployment 会拥有并管理它们的 ReplicaSet。
Deployment:部署 比rs更高一级的控制器
,
- 除了有rs的功能之外,还有很多高级功能,,比如说最重要的:
滚动升级、回滚等
- Deployment 表示用户对K8s集群的一次更新操作。Deployment是一个比RS应用模式更广的API对象,
- 滚动升级一个服务,实际是创建一个新的RS,然后逐渐将新RS中副本数增加到理想状态,将旧RS中的副本数减小到0的复合操作;
- 这样一个复合操作用一个RS是不太好描述的,所以用一个更通用的Deployment来描述。以K8s的发展方向,未来对所有长期伺服型的的业务的管理,都会通过Deployment来管理。
https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/
RS 通过标签(matchLabels
)来管理 Pod
- 删除RS,Pod也会被删除
apiVersion: apps/v1 #api版本定义
kind: ReplicaSet #定义资源类型为ReplicaSet
metadata: #元数据定义
name: frontend
namespace: default
spec: # ReplicaSet的规格定义
replicas: 3 #定义副本数量为3个
selector: #标签选择器,定义匹配Pod的标签
matchLabels: # RS通过labels来确定某个Pod是否归该RS管,即RS通过标签来监控Pod
tier: frontend
template: #Pod的模板定义,与上面Pod的定义一致
metadata: #Pod的元数据定义
name: myapp-pod #自定义Pod的名称
labels: #定义Pod的标签,需要和上面的标签选择器内匹配规则中定义的标签一致,可以多出其他标签
tier: frontend
spec: #Pod的规格定义
containers: #容器定义
- name: mynginx #容器名称
image: hub.zyx.com/library/nginx:v1 #容器镜像
imagePullPolicy: IfNotPresent #拉取镜像的规则
env:
- name: GET_HOSTS_FROM
value: dns
ports: #暴露端口
- name: http #端口名称
containerPort: 80
修改 labels
kubectl label pod frontend-5lgj9 tier=abc --overwrite=true
2.2 Deployment (重点)
deployment 是一个三级结构,deployment 管理 replicaset
,replicaset 管理 pod
Deployment 是在 Pod 这个抽象上更为上层的一个抽象,它可以定义一 组 Pod 的副本数目
、以及这个 Pod 的版本
。一般大家用 Deployment 这个抽象来做应用的真正的管理,而 Pod 是组成 Deployment 最小的 单元。 Kubernetes 是通过 Controller控制器去维护 Deployment 中 Pod 的数目,它也会去帮助 Deployment 自动恢复失败 的 Pod
。
比如说我可以定义一个 Deployment,这个 Deployment 里面需要两个 Pod , 当 一 个 Pod 失 败 的 时 候 , 控 制 器 就 会 监 测 到 , 它 重 新 把 Deployment 中的 Pod 数目从一个恢复到两个,通过再去新生成一个 Pod。通过控制器,我们也会帮助完成发布的策略。比如说进行滚动升级, 进行重新生成的升级,或者进行版本的回滚
。
滚动更新:会创建一个新副本的rs1,旧的rs的pod减少一个时,rs1会新加一个,直到全部增减完成
Deployment的定义与Replica Set的定义类似,只是API声明与Kind类型不同
Deployment实例:支持selector
选择器
[root@k8s-master controller]# pwd
/root/k8s_practice/controller
[root@k8s-master controller]# cat nginx-deployment-1.17.1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
# 重点关注该字段
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.cn-beijing.aliyuncs.com/google_registry/nginx:1.17.1
ports:
- containerPort: 80
[root@k8s-master controller]#
[root@k8s-master controller]# cat nginx-deployment-1.17.5.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
# 重点关注该字段
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.cn-beijing.aliyuncs.com/google_registry/nginx:1.17.5
ports:
- containerPort: 80
查看devlopment
kubectl get deployment -o wide
查看pod
查看RS
kubectl get rs -o wide
kubectl get rs -o wide --show-labels
selector 字段定义 Deployment 如何查找要管理的 Pods
。 在这种情况下,会选择在 template(Pod)模板中定义的标签labels(app: nginx)。但更复杂的选择规则是可能的,只要 template (Pod) 模板本身满足规则。
重点说明
1、ReplicaSet 的名称始终被格式化为[DEPLOYMENT-NAME]-[RANDOM-STRING]。随机字符串是随机生成,并使用 pod-template-hash 作为选择器和标签。
2、Deployment 控制器将 pod-template-hash 标签添加到 Deployment 创建或使用的每个 ReplicaSet 。此标签可确保 Deployment 的子 ReplicaSets 不重叠。因此不可修改。
3、注意Deployment、ReplicaSet和Pod三者的名称关系
2.3 更新Devlopment
动态的,一边更新,一边杀死旧的
例如:将nginx版本更新
# 方式一如下【可使用】:
kubectl set image deployment/nginx-deployment nginx=registry.cn-beijing.aliyuncs.com/google_registry/nginx:1.17.5 --record
# 方式二如下【推荐★★★★★】
kubectl apply -f nginx-deployment-1.17.5.yaml --record
# --record 参数可以记录命令,通过 kubectl rollout history deployment/nginx-deployment 可查询
查看更新状态
[root@k8s-master controller]# kubectl rollout status deployment/nginx-deployment
# 如没有更新完成,则显示更新过程直到更新成功
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out
# 如已更新完毕,直接显示更新成功
deployment "nginx-deployment" successfully rolled out
然后用命令查看Deployment、ReplicaSet、Pod
信息
2.4 devlopment回滚(重点)
- yaml文件方式
针对应用的每个镜像版本,都有对应deploy的yaml文件。不管是升级还是回滚都已轻松应
nginx-deployment-1.17.6.yaml
nginx-deployment-1.18.yaml
nginx-deployment-1.19.1.yaml
- 命令行方式
问题产生
:假设在更新 Deployment 时犯了一个拼写错误,将镜像名称命名写错
[root@k8s-master controller]# kubectl get pod -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
nginx-deployment-844d7bbb7f-pctwr 0/1 ImagePullBackOff
回滚到以前稳定的 Deployment 版本
查看以前的版本
[root@k8s-master controller]# kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 kubectl apply --filename=nginx-deployment.yaml --record=true
2 kubectl set image deployment/nginx-deployment nginx=registry.cn-beijing.aliyuncs.com/google_registry/nginx:1.17.5 --record=true
查看修改历史的详细信息
kubectl rollout history deployment/nginx-deployment --revision=2
开始回回滚
# 回滚到上一版本
[root@k8s-master controller]# kubectl rollout undo deployment/nginx-deployment
# 回滚到指定历史版本
[root@k8s-master controller]# kubectl rollout undo deployment/nginx-deployment --to-revision=2
暂停 deployment 的更新
kubectl rollout pause deployment/nginx-deployment
2.5 扩容、缩容
也就是修改pod数量--replicas=10
[root@k8s-master controller]# kubectl scale deployment/nginx-deployment --replicas=10
deployment.apps/nginx-deployment scaled
[root@k8s-master controller]# kubectl get deploy -o wide --show-labels
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR LABELS
nginx-deployment 10/10 10 10 17h nginx registry.cn-beijing.aliyuncs.com/google_registry/nginx:1.17.5 app=nginx app=nginx
[root@k8s-master controller]#
[root@k8s-master controller]# kubectl get rs -o wide --show-labels
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR LABELS
nginx-deployment-55c7bdfb86 0 0 0 17h nginx registry.cn-beijing.aliyuncs.com/google_registry/nginx:1.17 app=nginx,pod-template-hash=55c7bdfb86 app=nginx,pod-template-hash=55c7bdfb86
nginx-deployment-56d78686f5 10 10 10 17h nginx registry.cn-beijing.aliyuncs.com/google_registry/nginx:1.17.5 app=nginx,pod-template-hash=56d78686f5 app=nginx,pod-template-hash=56d78686f5
nginx-deployment-76b9d6bcf5 0 0 0 17h nginx registry.cn-beijing.aliyuncs.com/google_registry/nginx:1.17.1 app=nginx,pod-template-hash=76b9d6bcf5 app=nginx,pod-template-hash=76b9d6bcf5
nginx-deployment-844d7bbb7f 0 0 0 17h nginx registry.cn-beijing.aliyuncs.com/google_registry/nginx:1.1710 app=nginx,pod-template-hash=844d7bbb7f app=nginx,pod-template-hash=844d7bbb7f
[root@k8s-master controller]#
[root@k8s-master controller]# kubectl get pod -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
nginx-deployment-56d78686f5-4v5mj 1/1 Running 0 44s 10.244.2.64 k8s-node02 <none> <none> app=nginx,pod-template-hash=56d78686f5
nginx-deployment-56d78686f5-8m7mx 1/1 Running 0 44s 10.244.4.60 k8s-node01 <none> <none> app=nginx,pod-template-hash=56d78686f5
nginx-deployment-56d78686f5-c7wlb 1/1 Running 0 44s 10.244.4.59 k8s-node01 <none> <none> app=nginx,pod-template-hash=56d78686f5
nginx-deployment-56d78686f5-jg5lt 1/1 Running 0 44s 10.244.2.63 k8s-node02 <none> <none> app=nginx,pod-template-hash=56d78686f5
nginx-deployment-56d78686f5-jj58d 1/1 Running 0 11m 10.244.4.56 k8s-node01 <none> <none> app=nginx,pod-template-hash=56d78686f5
nginx-deployment-56d78686f5-k2kts 1/1 Running 0 11m 10.244.4.57 k8s-node01 <none> <none> app=nginx,pod-template-hash=56d78686f5
nginx-deployment-56d78686f5-qltkv 1/1 Running 0 44s 10.244.2.61 k8s-node02 <none> <none> app=nginx,pod-template-hash=56d78686f5
nginx-deployment-56d78686f5-r7vmm 1/1 Running 0 11m 10.244.2.60 k8s-node02 <none> <none> app=nginx,pod-template-hash=56d78686f5
nginx-deployment-56d78686f5-rxlpm 1/1 Running 0 44s 10.244.2.62 k8s-node02 <none> <none> app=nginx,pod-template-hash=56d78686f5
nginx-deployment-56d78686f5-vlzrf 1/1 Running 0 44s 10.244.4.58 k8s-node01 <none> <none> app=nginx,pod-template-hash=56d78686f5
kubectl get deployment -o wide
参数说明:
NAME:列出集群中 Deployments 的名称
READY:已就绪副本数/期望副本数
UP-TO-DATE:显示已更新和正在更新中的副本数
AVAILABLE:显示应用程序可供用户使用的副本数
AGE:显示运行的时间
kubectl get rs -o wide
参数说明:
NAME:列出集群中 ReplicaSet的名称
DESIRED:期望副本数
CURRENT:当前副本数
READY:已就绪副本数
AGE:运行时间
2.6 清理策略Policy
可以在 Deployment 中设置 .spec.revisionHistoryLimit,以指定保留多少该 Deployment 的 ReplicaSets数量。其余的将在后台进行垃圾回收。默认情况下,是10
注意:此字段设置为 0 将导致清理 Deployment 的所有历史记录,因此 Deployment 将无法通过命令行回滚。
二. 服务(Service)四层
Service是建立在一组Pod对象之上的资源对象,在前面提过,它是通过标签选择器选择一组Pod对象,并为这组Pod对象定义一个统一的固定访问入口(通常是一个IP地址),如果K8S存在DNS附件(如coredns)它就会在Service创建时为它自动配置一个DNS名称,用于客户端进行服务发现。
RC、RS和Deployment只是保证了支撑服务的微服务Pod的数量,但是没有解决如何访问这些服务的问题。
一个Pod只是一个运行服务的实例,随时可能在一个节点上停止,在另一个节点以一个新的IP启动一个新的Pod,因此不能以确定的IP和端口号提供服务
。
要稳定地提供服务需要服务发现和负载均衡能力。服务发现完成的工作,是针对客户端访问的服务,找到对应的的后端服务实例。
在K8s集群中,客户端需要访问的服务就是Service对象。每个Service会对应一个集群内部有效的虚拟IP,集群内部通过虚拟IP访问一个服务。
在K8s集群中微服务的负载均衡是由Kube-proxy实现的。
Kube-proxy是K8s集群内部的负载均衡器。它是一个分布式代理服务器,在K8s的每个节点上都有一个;这一设计体现了它的伸缩性优势,需要访问服务的节点越多,提供负载均衡能力的Kube-proxy就越多,高可用节点也随之增多。与之相比,我们平时在服务器端做个反向代理做负载均衡,还要进一步解决反向代理的负载均衡和高可用问题。
二. StatefulSet(控制器)
kubectl get statefulset -A
kubectl get sts -A
StatefulSet 是用来管理有状态
应用的工作负载 API 对象。
StatefulSet 作为 Controller 为 Pod 提供唯一的标识。它可以保证部署和 scale 的顺序
一个完整的 StatefulSet 应用由三个部分组成:
1… headless service
(无头服务)、用来定义 Pod 网络标识( DNS domain);
2… StatefulSet controller
、
3… volumeClaimTemplate(PVC)
。存储卷申请模板,创建 PVC,指定 pvc 名称大小,将自动创建 pvc,且 pvc 必须由存储类供应;
StatefulSet
:定义具体应用,名为 Nginx,有三个 Pod 副本,并为每个 Pod 定义了一个域名部署 statefulset
。
个域名的格式为:
FQDN:$(podname).(headless server name).namespace.svc.cluster.local
StatefulSet 中的 Pod 拥有一个具有黏性的、独一无二
的身份标识。这个标识基于 StatefulSet 控制器分配给每个 Pod 的唯一顺序索引。Pod 的名称的形式为- 。例如:web的StatefulSet 拥有两个副本,所以它创建了两个 Pod:web-0和web-1
。
和 Deployment 相同的是,StatefulSet 管理了基于相同容器定义的一组 Pod。但和 Deployment 不同的是,StatefulSet 为它们的每个 Pod 维护了一个固定的 ID
。这些 Pod 是基于相同的声明来创建的,但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID
。
使用场景StatefulSet 对于需要满足以下一个或多个需求的应用程序很有价值:
- 稳定的、唯一的网络标识符,即Pod重新调度后其PodName和HostName不变【当然
IP是会变的
】 - 稳定的、持久的存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC实现
- 有序的、优雅的部署和缩放
- 有序的、自动的滚动更新
稳定意味着 Pod 调度或重调度的整个过程是有持久性
的。
如果应用程序不需要任何稳定的标识符或有序的部署、删除或伸缩,则应该使用由一组无状态的副本控制器
提供的工作负载来部署应用程序,比如使用 Deployment 或者 ReplicaSet 可能更适用于无状态应用部署需要。
限制
1、给定 Pod 的存储必须由 PersistentVolume
驱动 基于所请求的 storage class 来提供,或者由管理员预先提供。
2、删除或者收缩StatefulSet 并不会删除它关联的存储卷
。这样做是为了保证数据安全,它通常比自动清除 StatefulSet 所有相关的资源更有价值。
3、StatefulSet 当前需要 headless 服务 来负责 Pod 的网络标识。你需要负责创建此服务。
4、当删除 StatefulSets 时,StatefulSet 不提供任何终止 Pod 的保证。为了实现 StatefulSet 中的 Pod 可以有序和优雅的终止,可以在删除之前将 StatefulSet 缩放为 0。
5、在默认 Pod 管理策略(OrderedReady) 时使用滚动更新,可能进入需要人工干预才能修复的损坏状态
StatefulSet 是为了解决有状态服务
的问题(对应 Deployments 和 ReplicaSets 是为无状态服务而设计),其应用场景包括:
-
稳定的持久化存储
,即 Pod 重新调度后还是能访问到相同的持久化数据,基于 PVC 来实现 -
稳定的网络标志
,即 Pod 重新调度后其 PodName 和 HostName 不变,基于Headless Service(即没有 Cluster IP 的 Service)来实现 -
有序部署,有序扩展
,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从 0 到 N-1,在下一个 Pod 运行之前所有之前的 Pod 必须都是 Running 和 Ready 状态),基于 init containers 来实现 -
有序收缩,有序删除
(即从 N-1 到 0)
1. 有序索引
对于具有 N 个副本的 StatefulSet,StatefulSet 中的每个 Pod 将被分配一个整数序号,从 0 到 N-1,该序号在 StatefulSet 上是唯一的。
StatefulSet 中的每个 Pod 根据 StatefulSet 中的名称和 Pod 的序号来派生出它的主机名。组合主机名的格式为$(StatefulSet 名称)-$(序号)
。
2. 部署和扩缩保证
对于包含 N 个 副本的 StatefulSet,当部署 Pod 时,它们是依次创建的,顺序为 0~(N-1)
。
当删除 Pod 时,它们是逆序终止的,顺序为 (N-1)~0
。
在将缩放操作应用到 Pod 之前,它前面的所有 Pod 必须是 Running 和 Ready 状态。
在 Pod 终止之前,所有的继任者必须完全关闭。
StatefulSet 不应
将 pod.Spec.TerminationGracePeriodSeconds 设置为 0
。这种做法是不安全的,要强烈阻止。
部署顺序
在下面的 nginx 示例被创建后,会按照 web-0、web-1、web-2 的顺序部署三个 Pod。在 web-0 进入 Running 和 Ready 状态前不会部署 web-1。在 web-1 进入 Running 和 Ready 状态前不会部署 web-2。
如果 web-1 已经处于 Running 和 Ready 状态,而 web-2 尚未部署,在此期间发生了 web-0 运行失败,那么 web-2 将不会被部署,要等到 web-0 部署完成并进入 Running 和 Ready 状态后,才会部署 web-2。
收缩顺序
如果想将示例中的 StatefulSet 收缩为 replicas=1,首先被终止的是 web-2。在 web-2 没有被完全停止和删除前,web-1 不会被终止。当 web-2 已被终止和删除;但web-1 尚未被终止,如果在此期间发生 web-0 运行失败,那么就不会终止 web-1,必须等到 web-0 进入 Running 和 Ready 状态后才会终止 web-1。
示例
# headless service
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None # 通过指定 clusterIP 为 None 实现 headless service
selector:
app: nginx # (A) A,B,C 三处要相同,根据 label 来匹配哪些 pod 归无头服务管
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # (B) A,B,C 三处要相同,根据 label 匹配决定哪些 pod 归StatefulSet管
serviceName: "nginx" # 指定 Service 名称(上面创建的,一定要是个无头服务)
replicas: 3 # 副本数
template:
metadata:
labels:
app: nginx # (C) A,B,C 三处要相同,label标签
spec:
containers: # 容器信息
- name: nginx
image: wangyanglinux/myapp:v2
ports:
- containerPort: 80 # 释放的端口
name: web # 端口名字
volumeMounts: # 挂载
- name: www
mountPath: /usr/share/nginx/html # 容器内目录
volumeClaimTemplates: # 卷请求声明模板(pvc模板)
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ] # 指定要请求的卷的访问模式
storageClassName: "nfs" # 指定要请求的卷的类名,只有与 PV 中的storageClassName 相同时,才会匹配
resources:
requests:
storage: 1Gi # 指定要请求的卷大小必须满足 1G
[root@k8s-master controller]# pwd
/root/k8s_practice/controller
[root@k8s-master controller]# cat statefulset.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: http
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # has to match .spec.template.metadata.labels
serviceName: "nginx"
replicas: 3 #默认只有1个
template:
metadata:
labels:
app: nginx # has to match .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10 # 默认30秒
containers:
- name: nginx
image: registry.cn-beijing.aliyuncs.com/google_registry/nginx:1.17
ports:
- containerPort: 80
name: http
启动并查看
kubectl apply -f statefulset.yaml
kubectl get service -o wide
kubectl get statefulset -o wide
kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-0 1/1 Running 0 16m 10.244.2.95 k8s-node02 <none> <none>
web-1 1/1 Running 0 16m 10.244.3.103 k8s-node01 <none> <none>
web-2 1/1 Running 0 16m 10.244.3.104 k8s-node01 <none> <none>
StatefulSet 中的pod是有序的。有N个副本,那么序列号为0~(N-1)
3. statefulSet域名相关信息
创建临时pod,用于查看上面statefulset创建pod的域名信息
[root@k8s-master test]# pwd
/root/k8s_practice/test
[root@k8s-master test]# cat myapp_demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-demo
namespace: default
labels:
k8s-app: myapp
spec:
containers:
- name: myapp
image: registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: httpd
containerPort: 80
protocol: TCP
创建
kubectl apply -f myapp_demo.yaml
查看
kubectl get pod -o wide | grep 'myapp'
myapp-demo 1/1 Running 0 3m24s 10.244.2.101 k8s-node02 <none> <none>
进入pod查看
# 进入一个k8s管理的myapp镜像容器。
[root@k8s-master test]# kubectl exec -it myapp-demo sh
/ # nslookup 10.244.2.95
nslookup: can't resolve '(null)': Name does not resolve
Name: 10.244.2.95
Address 1: 10.244.2.95 web-0.nginx.default.svc.cluster.local
/ #
/ #
/ # nslookup 10.244.3.103
nslookup: can't resolve '(null)': Name does not resolve
Name: 10.244.3.103
Address 1: 10.244.3.103 web-1.nginx.default.svc.cluster.local
/ #
/ #
/ # nslookup 10.244.3.104
nslookup: can't resolve '(null)': Name does not resolve
Name: 10.244.3.104
Address 1: 10.244.3.104 web-2.nginx.default.svc.cluster.local
/ #
/ #
##### nginx.default.svc.cluster.local 为service的域名信息
/ # nslookup nginx.default.svc.cluster.local
nslookup: can't resolve '(null)': Name does not resolve
Name: nginx.default.svc.cluster.local
Address 1: 10.244.3.104 web-2.nginx.default.svc.cluster.local
Address 2: 10.244.3.103 web-1.nginx.default.svc.cluster.local
Address 3: 10.244.2.95 web-0.nginx.default.svc.cluster.local
4. StatefulSet网络标识与PVC
有上文可得如下信息:
1、匹配StatefulSet的Pod name(网络标识)的模式为
:$(statefulset名称)-$(序号)
,比如StatefulSet名称为web,副本数为3。则为:web-0、web-1、web-2
2、StatefulSet为每个Pod副本创建了一个DNS域名
,这个域名的格式为:$(podname).(headless service name),
也就意味着服务之间是通过Pod域名来通信而非Pod IP。当Pod所在Node发生故障时,Pod会被漂
移到其他Node上,Pod IP会发生改变,但Pod域名不会变化
3、StatefulSet使用Headless服务来控制Pod的域名,这个Headless
服务域名的为:$(service name).$(namespace).svc.cluster.local
,其中 cluster.local 指定的集群的域名
4、根据volumeClaimTemplates,为每个Pod创建一个PVC
,PVC的命令规则为:$(volumeClaimTemplates name)-$(pod name)
,比如volumeClaimTemplates为www,pod name为web-0、web-1、web-2;那么创建出来的PVC为:www-web-0、www-web-1、www-web-2
5、删除Pod不会删除对应的PVC
,手动删除PVC将自动释放PV。
三. DaemonSet(控制器)
DaemonSet 确保 k8s 集群所有的节点都运行一个相同的 pod 副本。当有节点加入集群时,会为他们新增一个 Pod。当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod
Daemonset 典型的应用场景
-
在集群的每个节点上运行
集群存储
,比如:glusterd 或 ceph。 -
在每个节点上运行
日志收集
组件,比如:flunentd 、 logstash、filebeat 等。 -
在每个节点上运行
监控组件
,比如:Prometheus、 Node Exporter 、collectd 等。
DaemonSet 与 Deployment 的区别
- Deployment 部署的副本 Pod 会分布在各个 Node 上,每个 Node 都可能
运行好几个副本
。 - DaemonSet 的不同之处在于:每个 Node 上最多
只能运行一个副本
。
备注
:DaemonSet 中的 Pod 可以使用 hostPort,从而可以通过节点 IP 访问到 Pod;因为DaemonSet模式下Pod不会被调度到其他节点。使用示例如下:
ports:
- name: httpd
containerPort: 80
#除非绝对必要,否则不要为 Pod 指定 hostPort。 将 Pod 绑定到hostPort时,它会限制 Pod 可以调度的位置数;DaemonSet除外
#一般情况下 containerPort与hostPort值相同
hostPort: 8090 #可以通过宿主机+hostPort的方式访问该Pod。例如:pod在/调度到了k8s-node02【172.16.1.112】,那么该Pod可以通过172.16.1.112:8090方式进行访问。
protocol: TCP
DaemonSet 资源清单文件编写技巧
节点可能是所有集群节点,也可能是通过nodeSelector
选定的一些特定节点。典型的后台支撑型服务包括,存储,日志和监控等在每个节点上支持K8s集群运行的服务。
apiVersion: apps/v1 #api版本定义
kind: DaemonSet #定义资源类型为DaemonSet
metadata: #元数据定义
name: daemonset-nginx #daemonset控制器名称
namespace: default #名称空间
labels: #设置daemonset的标签
app: daemonset
spec: #DaemonSet控制器的规格定义
selector: #指定匹配pod的标签
matchLabels: #指定匹配pod的标签
app: daemonset-nginx #注意:这里需要和template中定义的标签一样
template: #Pod的模板定义
metadata: #Pod的元数据定义
name: nginx
labels: #定义Pod的标签,需要和上面的标签一致,可以多出其他标签
app: daemonset-nginx
spec: #Pod的规格定义
containers: #容器定义
- name: nginx-pod #容器名字
image: hub.zyx.com/library/nginx:v1 #容器镜像
ports: #暴露端口
- name: http #端口名称
containerPort: 80 #暴露的端口
可以看到两个节点上各运行一个
:
[root@k8s-master01 yaml]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
daemonset-nginx-js4tc 1/1 Running 0 82s 10.244.1.21 k8s-node01 <none> <none>
daemonset-nginx-kkc5q 1/1 Running 0 9s 10.244.2.21 k8s-node02 <none> <none>
实现:日志收集
实现:pod 的滚动更新
查看 daemonset 的滚动更新策略
# kubectl explain ds.spec.updateStrategy
KIND: DaemonSet
VERSION: apps/v1
RESOURCE: updateStrategy <Object>
DESCRIPTION:
An update strategy to replace existing DaemonSet pods with new pods.
DaemonSetUpdateStrategy is a struct used to control the update strategy for
a DaemonSet.
FIELDS:
rollingUpdate <Object>
Rolling update config params. Present only if type = "RollingUpdate".
type <string>
Type of daemon set update. Can be "RollingUpdate" or "OnDelete". Default is
RollingUpdate.
#查看 rollingUpdate 支持的更新策略
]# kubectl explain ds.spec.updateStrategy.rollingUpdate
KIND: DaemonSet
VERSION: apps/v1
RESOURCE: rollingUpdate <Object>
DESCRIPTION:
Rolling update config params. Present only if type = "RollingUpdate".
Spec to control the desired behavior of daemon set rolling update.
FIELDS:
maxUnavailable <string>#表示 rollingUpdate 更新策略只支持 maxUnavailabe,先删除在更新;因为我们不支持一个
节点运行两个 pod,因此需要先删除一个,在更新一个。
#更新镜像版本,可以按照如下方法:
kubectl set image daemonsets fluentd-elasticsearch *=ikubernetes/filebeat:5.6.6-alpine -n kube-system
kubectl set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N [options]
五. Job和CronJob(控制器)
1. job
Job 控制器用于管理 Pod 对象运行一次性
任务,比方说我们对数据库备份,可以直接在 k8s 上启动一个 mysqldump 备份程序,也可以启动一个 pod,这个 pod 专门用来备份用的,备份结束 pod 就可以终止了,不需要重启,而是将 Pod 对象置于"Completed"(完成)状态,若容器中的进程因错误而终止,则需要按照重启策略配置确定是否重启,对于 Job 这个类型的控制器来说,需不需要重建 pod 就看任务是否完成,完成就不需要重建,没有完成就需要重建 pod
批处理业务与长期伺服业务的主要区别
- 批处理业务的运行有头有尾,
- 长期伺服业务在用户不停止的情况下永远运行。
Job管理的Pod根据用户的设置把任务成功完成就自动退出了。
4. Job负责批处理任务
:即仅执行一次
的任务,它保证批处理任务的一个或多个pod成功结束
Job创建一个或多个Pod,并确保指定数量的Pod成功终止。Pod成功完成后,Job将跟踪成功完成的情况。当达到指定的成功完成次数时,任务(即Job)就完成了。删除Job将清除其创建的Pod。
一个简单的情况是创建一个Job对象,以便可靠地运行一个Pod来
。如果第一个Pod发生故障或被删除(例如,由于节点硬件故障或节点重启),则Job对象将启动一个新的Pod。
当然还可以使用Job并行运行多个Pod。
特殊说明:
spec.template
格式同 Pod
- 容器的
restartPolicy
仅支持Never
或OnFailure
,因为 Job 就是批处理任务,执行完自动退出, - 如果是
Always
,只要退出就重启
OnFailure
:失败退出(exit code不等于0)时重启
Never
:只要退出就不再重启
单个 Pod 时,默认 Pod 成功运行后(返回码为 0) Job 即结束
.spec.completions
:标志Job结束需要成功运行的 Pod 个数,默认为 1
.spec.parallelism
:标志并行运行的 Pod 的个数,默认为 1
.spec.activeDeadlineSeconds
:标志失败 Pod 的重试最大时间,超过这个时间不会继续重试
可以通过以下 3 种方式来判断一个 Job 是否已完成:
-
.status.completion Time
是否为空。Job 完成时该字段会被设置成 Job 完成的时间,否则为空 -
.spec.completions
和.status.succeeded
是否相等,即对比期望完成数和已成功数,当二者相等时,表示 Job 已经完成 -
.status.conditions[0].type
:type 为 Complete 和 Failed 时,分别表示 Job 执行成功和失败
容器失败分两种情况
.spec.template.spec.restartPolicy = "OnFailure"
:容器失败后会不断重启,直到成功(退出码为 0).spec.template.spec.restartPolicy = "Never"
:容器不会重启
apiVersion: batch/v1 # kubectl explain job 查看 job 版本
kind: Job
metadata:
name: pi
spec:
template:
metadata:
name: pi
spec:
containers:
- name: pi
image: perl
command: ["perl","-Mbignum=bpi","-wle","print bpi(2000)"] # 通过 perl 进行圆周率计算,输出小数点后2000位
restartPolicy: Never # 重启策略
job使用场景
Job 三种使用场景:
1、非并行任务:只启一个 pod,pod 成功,job 正常结束
2、并行任务同时指定成功个数:.spec.completions 为指定成功个数,可以指定也可以不指定.spec.parallelism(指定>1,会有多个任务并行运行)。当成功个数达到.spec.completions,任务结束。
3、有工作队列的并行任务:.spec.completions 默认为 1,.spec.parallelism 为大于 0 的整数。此时并行启动多个 pod,只要有一个成功,任务结束,所有 pod 结束
适用场景:
Job 不是设计用来完成通信密集型的并行程序,如科学计算领域常见的场景。它支持并行地处理一组独立但相关的 work item,如发送邮件,渲染帧,转码文件和扫描 NoSql 数据库中的 key
相关配置:
.spec.completions:完成该 Job 需要执行成功的 Pod 数
.spec.parallelism:能够同时运行的 Pod 数
.spec.backoffLimit:允许执行失败的 Pod 数,默认值是 6,0 表示不允许 Pod 执行失败。如果Pod 是 restartPolicy 为 Nerver,则失败后会创建新的 Pod,如果是 OnFailed,则会重启 Pod,不管是哪种情况,只要 Pod 失败一次就计算一次,而不是等整个 Pod 失败后再计算一个。当失败的次数达到该限制时,整个 Job 随即结束,所有正在运行中的 Pod 都会被删除。
.spec.activeDeadlineSeconds: Job 的超时时间,一旦一个 Job 运行的时间超出该限制,则 Job失败,所有运行中的 Pod 会被结束并删除。该配置指定的值必须是个正整数。不指定则不会超时
2. CronJob 定时任务
创建是基于时间调度的 Jobs
一个 CronJob 对象就像 crontab (cron table) 文件中的一行。它用 Cron 格式进行编写,并周期性地在给定的调度时间执行 Job。
- 管理基于时间的 Job,即:
- 在给定时间点只运行一次
- 周期性地在给定时间点运行
-
使用前提条件:当前使用的 Kubernetes 集群,版本 >= 1.8(对 CronJob)。
-
典型的用法:
-
在给定的时间点调度 Job 运行
-
创建周期性运行的 Job,例如:数据库备份、发送邮件
CronJob 限制
创建 Job 操作应该是 幂等的
。
CronJob 仅负责创建与其调度时间相匹配的 Job,而 Job 又负责管理其代表的 Pod。
CronJob字段
.spec.schedule
:调度,必需字段,指定任务运行周期
,格式同 Cron
.spec.jobTemplate
:Job 模板,必需字段,指定需要运行的任务,格式同 Job
.spec.startingDeadlineSeconds
:启动 Job 的期限(秒级别),该字段是可选的。如果因为任何原因而错过了被调度的时间,那么错过执行时间的 Job 将被认为是失败的。如果没有指定,则没有期限
.spec.concurrencyPolicy
:并发策略,该字段也是可选的。它指定了如何处理被 Cron Job 创建的 Job 的并发执行。只允许指定下面策略中的一种:
- Allow (默认):允许并发运行 Job
- Forbid :禁止并发运行,如果前一个还没有完成,则直接跳过下一个
- Replace :取消当前正在运行的 Job,用一个新的来替换
注意:当前策略只能应用于同一个 Cron Job 创建的 Job。如果存在多个 Cron Job,它们创建的 Job 之间总是允许并发运行。
.spec.suspend
:挂起,该字段也是可选的。如果设置为 true ,后续所有执行都会被挂起。它对已经开始执行的 Job 不起作用。默认值为 false 。
.spec.successfulJobsHistoryLimit
和 .spec.failedJobsHistoryLimit
:历史限制,是可选的字段。它们指定了可以保留多少完成和失败的 Job。默认情况下,它们分别设置为 3 和 1 。设置限制的值为 0 ,相关类型的 Job 完成后将不会被保留。
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args: # 运行命令,输出当前时间
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
[root@k8s-master01 yaml]# kubectl get cronjob
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 <none> 29s
[root@k8s-master01 yaml]# kubectl get job
NAME COMPLETIONS DURATION AGE
hello-1603320660 1/1 108s 2m4s
hello-1603320720 0/1 64s 64s
hello-1603320780 0/1 4s 4s
# 删除 CronJob
kubectl delete deployment/nginx-deployment
使用 CronJob 定期备份 MySQL 数据
CronJob 所描述的,定时任务。
1、在给定时间点只运行一次
2、在给定时间点周期性地运行
一个 CronJob 对象类似于 crontab (cron table)文件中的一行。它根据指定的预定计划周期性地运行一个 Job。在这里简单的说一下 cron,是指 unix 中 cron 表达式。
比如:"*/1 * * * *"
,这个Cron 表达式里*/1
中 *表示从 0 开始,/ 表示"每",1 表示偏移量,所以它的意思是:从 0 开始,每 1个时间单位执行一次。Cron 表达式中五个部分分别代表:分钟,时,日,月,周。
所以上述这句Cron 表达式的意思是:从当前开始,每分钟执行一次。那么我们可以利用这个机制来指定创建 mysql备份任务的对象:
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: mysqldump
spec:
schedule: "50 15 * * *"
jobTemplate:
spec:
completions: 1
template:
spec:
restartPolicy: Never
volumes:
- name: mysql-master-script
hostPath:
path: /root/app/mysql/shell
- name: mysql-master-backup
hostPath:
path: /root/app/db/backup
- name: local-time
hostPath:
path: /etc/localtime
containers:
- name: mysqldump-container
image: nacos/nacos-mysql-master:latest
volumeMounts:
- name: mysql-master-script
mountPath: /var/db/script
- name: local-time
mountPath: /etc/localtime
- name: mysql-master-backup
mountPath: /var/db/backup
command:
- "sh"
- "/var/db/script/mysqldump.sh"