第一章:工作负载
- 工作负载是运行的 Kubernetes 上的一个应用程序。
- 一个应用很复杂,可能由单个组件或者多个组件共同完成。我们可以用一组 Pod 来描述一个应用,也就是一个工作负载,而 Pod 是一组容器。
- 换言之,工作负载控制一组 Pod ,Pod 控制一组容器(如:Deployment【工作负载】部署 3 个副本的 nginx-pod ,每个 nginx-pod 里面是真正的 nginx 容器)。
工作负载能让 Pod 拥有自愈能力。我们主要研究不同的工作负载如何控制 Pod 的行为。
第二章:Pod
2.1 什么是 Pod ?
- Pod 是一组(一个多多个)容器的集合(Pod 就像是豌豆荚,而容器就像是豌豆荚中的豌豆)。这些容器共享存储、网络等。
- 实际开发中,我们一般不直接创建 Pod ,而是创建一个工作负载(如:Deployment等),让它们来创建 Pod 。
Pod 的特点:
- ① Pod 对容器有自愈能力(自我恢复能力),Pod 可以自动重启失败的容器。
- ② Pod 自己不能恢复自己,Pod 被删除了就没有了,但是有时我们希望如果 Node 节点宕机了,这些 Pod 还可以在其他节点重新启动。
- ③ Pod 中可以有一个容器,也可以有多个容器。
- ④ 如果 Pod 中有多个容器协同工作(通常而言,都是有关系了),我们将提供服务的称为主容器,另外的容器称为 SideCar 。
- ⑤ Pod 天生为其成员容器提供了两种共享资源:
网络
和存储
。
- 一个 Pod 由一个 Pause 容器设置整个 Pod 里面的所有容器的网络、名称空间等信息。
2.2 Pod 的使用
- 可以使用 Deployment 等各种工作负载的 yaml 文件创建 Pod ,也可以直接创建 Pod 。
- Pod 的模板如下:
apiVersion: v1
kind: Pod
metadata:
name: "nginx-pod" # pod 的名称
namespace: default
labels:
app: "nginx" # 标签
spec:
containers:
- name: nginx # 容器的名称
image: "nginx:1.20.2" # 镜像的名称
resources: # 资源限制
limits:
cpu: 200m
memory: 500Mi
requests:
cpu: 100m
memory: 200Mi
env: # 环境变量
- name: hello
value: world
ports: # 端口
- containerPort: 80 # 容器的端口
name: nginx # 容器端口的名称
volumeMounts: # 卷挂载
- name: localtime
mountPath: /etc/localtime
volumes: # 卷声明,下面的这种方式相当于 Docker 的具名卷
- name: localtime
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
restartPolicy: Always
- 示例:多容器协同
vim k8s-multi-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: multi-pod
labels:
app: multi-alpine-pod
spec:
containers:
- name: nginx
image: nginx:1.20.2
volumeMounts: # 声明卷挂载
- name: nginx-volume
mountPath: /usr/share/nginx/html
- name: alpine
image: alpine
command:
- /bin/sh
- -c
- while true; do sleep 1 ;echo $(date "+%Y-%m-%d-%H:%M:%S") > /app/index.html ;done;
volumeMounts: # 声明卷挂载
- name: nginx-volume
mountPath: /app
volumes:
- name: nginx-volume
emptyDir: {} # 相当于 Docker 中的匿名挂载,会在外部创建一个位置
restartPolicy: Always
kubectl apply -f k8s-multi-pod.yaml
温馨提示:如果想进多容器协同的 Pod 中查看指定容器,使用这样的命令:kubectl exec -it Pod的名称 -c Pod中的容器名 -- COMMAND
。
2.3 Pod 的初始化容器
初始化容器是在 Pod 的主容器启动之前要运行的容器,主要是做一些主容器的前置工作,它具有两大特征:
- ① 初始化容器
必须运行完成直至结束
,如果某个初始化容器运行失败,那么 Kubernetes 需要重启它直至成功完成。 - ② 初始化容器必须按照定义的顺序执行,当且仅当前一个成功之后,后面的一个才能运行。
- ① 初始化容器
初始化容器有很多的应用场景,下面列出的是最常见的几个:
- 提供主容器镜像中不具备的工具程序或自定义代码。
- 初始化容器要先于应用容器串行启动并运行完成,因此可用于延后应用容器的启动直至其依赖的条件得到满足。
- 示例:
vim k8s-pod-lifecycle.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-lifecycle
labels:
app: pod-lifecycle
spec:
volumes:
- name: context-vol
emptyDir: {}
initContainers: # Pod 在启动 containers 之前,先要运行 initContainers 中的所有容器
- name: nginx-init
image: alpine # 必须有终结的那个时刻,一般不要用一直启动的镜像
command: ["/bin/sh","-c","echo 2222 > /app/index.html;sleep 15;"]
volumeMounts:
- mountPath: /app
name: context-vol
securityContext:
privileged: true # 使用特权模式运行容器,需要慎用!!!
containers:
- name: nginx
image: nginx:1.20.2
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /usr/share/nginx/html
name: context-vol
restartPolicy: Always
kubectl apply -f k8s-pod-lifecycle.yaml
2.4 Pod 的临时容器(了解)
2.4.1 概述
- 临时容器是一种特殊的容器,该容器可以在现有的 Pod 中临时运行,以便完成我们发起的操作,比如故障排查。我们应该使用临时容器来检查服务,而不是用临时容器来构建应用程序。
- Pod 是 Kubernetes 集群进行管理的最小单元,由于 Pod 是一次性且可以替换的,因此 Pod 一旦被创建,就无法将容器加入到Pod 中。而且,我们通常使用 Deployment 来删除并替换Pod。但是,有的时候我们需要检查现有 Pod 的状态,比如对难以复现的故障进行排查。在这些场景中,可以在现有 Pod 中运行临时容器来检查其状态并运行任意命令。
临时容器在目前的 Kubernetes 版本是 beta 。
2.4.2 什么是临时容器?
临时容器和其他容器的不同之处在于,它们缺少对资源或执行的保证,并且永远不会自动重启,因此不适合用来构建应用程序。临时容器使用和常规容器相同的
ContainerSpec
来描述,但是许多字段是不兼容或者不允许的。- 临时容器没有端口配置,因此像
ports
、livenessProbe
、readinessProbe
这样的字段是没有的。 - Pod 的资源分配是不可变的,因此
resources
这样的配置临时容器也是没有的。 - ……
- 临时容器没有端口配置,因此像
- 临时容器是使用
ephemeralcontainers
来进行创建的,而不是直接添加到pod.spec
中,所以是无法使用kubectl edit
来添加一个临时容器。 - 和常规容器一样,将临时容器添加到Pod后,不能更改或删除临时容器。
2.4.3 临时容器的用途
- 当由于容器奔溃或容器镜像不包含调试工具而导致
kubectl exec
无用的时候,临时容器对于交互式故障排查非常有用。 - 比如,像
distroless 镜像
允许用户部署最小的容器镜像,从而减少攻击面并减少故障和漏洞的暴露。由于distroless 镜像
不包含 Shell 或任何的调试工具,因此很难单独使用kubectl exec
命令进行故障排查。 - 使用临时容器的时候,启用 进程名字空间共享 很有帮助,可以查看其他容器中的进程。
2.4.4 开启临时容器
- 查询临时容器是否开启:
kubelet -h | grep EphemeralContainers
- 在 Master 节点(192.168.65.100)和 Node 节点(192.168.65.101、192.168.65.102)修改 kubectl 的参数:
vi /etc/sysconfig/kubelet
# 修改增加--feature-gates EphemeralContainers=true
KUBELET_EXTRA_ARGS="--cgroup-driver=systemd --feature-gates EphemeralContainers=true"
KUBE_PROXY_MODE="ipvs"
vi /var/lib/kubelet/config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 0s
cacheUnauthorizedTTL: 0s
cgroupDriver: systemd
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMinimumGCAge: 0s
kind: KubeletConfiguration
logging: {}
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
rotateCertificates: true
runtimeRequestTimeout: 0s
shutdownGracePeriod: 0s
shutdownGracePeriodCriticalPods: 0s
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
# 修改部分
featureGates:
EphemeralContainers: true
- 加载配置文件以便重启 kubelet :
systemctl daemon-reload
systemctl stop kubelet
systemctl start kubelet
- 在 Master 节点(192.168.65.100)修改 kube-apiserver.yaml 和 kube-scheduler.yaml :
vi /etc/kubernetes/manifests/kube-apiserver.yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 192.168.65.100:6443
creationTimestamp: null
labels:
component: kube-apiserver
tier: control-plane
name: kube-apiserver
namespace: kube-system
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=192.168.65.100
- --allow-privileged=true
- --authorization-mode=Node,RBAC
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-admission-plugins=NodeRestriction
- --enable-bootstrap-token-auth=true
- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
- --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
- --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
- --etcd-servers=https://127.0.0.1:2379
- --insecure-port=0
- --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
- --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
- --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
- --requestheader-allowed-names=front-proxy-client
- --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
- --requestheader-extra-headers-prefix=X-Remote-Extra-
- --requestheader-group-headers=X-Remote-Group
- --requestheader-username-headers=X-Remote-User
- --secure-port=6443
- --service-account-issuer=https://kubernetes.default.svc.cluster.local
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-account-signing-key-file=/etc/kubernetes/pki/sa.key
- --service-cluster-ip-range=10.96.0.0/16
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
# 修改部分
- --feature-gates=EphemeralContainers=true
vi /etc/kubernetes/manifests/kube-scheduler.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
component: kube-scheduler
tier: control-plane
name: kube-scheduler
namespace: kube-system
spec:
containers:
- command:
- kube-scheduler
- --authentication-kubeconfig=/etc/kubernetes/scheduler.conf
- --authorization-kubeconfig=/etc/kubernetes/scheduler.conf
- --bind-address=127.0.0.1
- --kubeconfig=/etc/kubernetes/scheduler.conf
- --leader-elect=true
- --port=0
# 修改部分
- --feature-gates=EphemeralContainers=true
2.4.5 使用临时容器在线 debug
- ① 创建一个 Pod :
vim k8s-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
shareProcessNamespace: true # 这个配置非常重要,一定要配置
containers:
- name: nginx
image: nginx:1.17.1
kubectl apply -f k8s-pod.yaml
- ② 创建 ec.json 文件,内容如下:
{
"apiVersion": "v1",
"kind": "EphemeralContainers",
"metadata": {
"name": "nginx" // 指定 Pod 的名称
},
"ephemeralContainers": [{
"command": [
"sh"
],
"image": "busybox", // 如果是 JRE ,当然使用 JDK 作为临时容器了
"imagePullPolicy": "IfNotPresent",
"name": "debugger",
"stdin": true,
"tty": true,
"terminationMessagePolicy": "File"
}]
}
注意:json 文件目前是没有注释的。
- ③ 应用临时容器:
# /api/v1/namespaces/default/pods/[pod的名称]/ephemeralcontainers
kubectl replace --raw /api/v1/namespaces/default/pods/nginx/ephemeralcontainers -f ec.json
2.5 重启策略
在容器探测中,一旦容器探测出现了问题,Kubernetes 就会对容器所在的 Pod 进行重启,其实这是由 Pod 的重启策略决定的,Pod 的重启策略有 3 种,分别如下:
- Always:容器失效时,自动重启该容器(默认值)。
- OnFailure:容器终止运行且退出码不为 0 时重启。
- Never:不论状态如何,都不重启该容器。
- 重启策略适用于 Pod 对象中的所有容器,首次需要重启的容器,将在其需要的时候立即进行重启,随后再次重启的操作将由 kubelet 延迟一段时间后进行,且反复的重启操作的延迟时长以此为 10s 、20s 、40s 、80s 、160s 和 300s ,300s 是最大的延迟时长。
- 示例:
apiVersion: v1
kind: Pod
metadata:
name: pod-restart-policy
namespace: dev
labels:
user: xudaxian
spec:
containers: # 容器配置
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
restartPolicy: Always # 重启策略
2.6 钩子函数
- 钩子函数能够感知自身生命周期中的事件,并在相应的时刻到来时运行用户指定的程序代码。
Kubernetes 在主容器启动之后和停止之前提供了两个钩子函数:
- postStart:容器创建之后执行,如果失败会重启容器。
- preStop:容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作。
钩子处理器支持使用下面的三种方式定义动作:
exec 命令:在容器内执行一次命令。
…… lifecycle: postStart: exec: command: - cat - /tmp/healthy ……
tcpSocket:在当前容器尝试访问指定的 socket 。
…… lifecycle: postStart: tcpSocket: port: 8080 ……
httpGet:在当前容器中向某 url 发起 HTTP 请求(应用程序使用此种方式最多)。
…… lifecycle: postStart: httpGet: path: / #URI地址 port: 80 #端口号 host: 192.168.109.100 #主机地址 scheme: HTTP #支持的协议,http或者https ……
- 示例:
apiVersion: v1
kind: Pod
metadata:
name: pod-hook-exec
namespace: default
labels:
user: xudaxian
spec:
containers: # 容器配置
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
resources:
limits:
cpu: "2"
memory: "10Gi"
requests:
cpu: "1"
memory: "10Mi"
lifecycle: # 生命周期配置
postStart: # 容器创建之后执行,如果失败会重启容器
exec: # 在容器启动的时候,执行一条命令,修改掉Nginx的首页内容
command: ["/bin/sh","-c","echo postStart ... > /usr/share/nginx/html/index.html"]
preStop: # 容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作
exec: # 在容器停止之前停止Nginx的服务
command: ["/usr/sbin/nginx","-s","quit"]
2.7 Probe 探针机制(健康检查机制)
2.7.1 概述
- probe 是由 kubelet 对容器执行的定期诊断。 要执行诊断,kubelet 既可以在容器内执行代码,也可以发出一个网络请求。
针对运行中的容器,
kubelet
可以选择是否执行以下三种探针,以及如何针对探测结果作出反应:startupProbe(启动探针):
- kubelet 使用启动探针,来检测应用是否已经启动。如果启动就可以进行后续的探测检查。慢容器一定指定启动探针。一直在等待启动。
- 启动探针一旦成功就不在执行(只会成功执行一次),存活探针和就绪探针将接着持续运行。
livenessProbe(存活探针):
- kubelet 使用存活探针,来检测容器是否正常存活。(有些容器可能产生死锁【应用程序在运行,但是无法继续执行后面的步骤】),如果检测失败就会重新启动这个容器。
readinessProbe(就绪探针):
- kubelet 使用就绪探针,来检测容器是否准备好了可以接收流量。当一个 Pod 内的所有容器都准备好了,才能把这个 Pod 看作就绪了。用途就是:Service后端负载均衡多个Pod,如果某个Pod还没就绪,就会从service负载均衡里面剔除。
Probe 的配置项:
- initialDelaySeconds:容器启动后要等待多少秒后存活和就绪探测器才被初始化,默认是 0 秒,最小值是 0。
- periodSeconds:执行探测的时间间隔(单位是秒),默认是 10 秒,最小值是 1。
- successThreshold:探测器在失败后,被视为成功的最小连续成功数,默认值是 1。存活和启动探针的这个值必须是 1。
- failureThreshold:当探测失败时,Kubernetes 的重试次数,存活探测情况下的放弃就意味着重新启动容器, 就绪探测情况下的放弃 Pod 会被打上未就绪的标签。默认值是 3。
- timeoutSeconds:探测的超时后等待多少秒,默认值是 1 秒,最小值是 1。
- Probe 的探测方式:exec 、httpGet(应用程序使用此种方式最多)、tcpSocket。
2.7.2 应用示例
- 示例:
apiVersion: v1
kind: Pod
metadata:
name: nginx-prode
labels:
app: nginx-prode
spec:
containers:
- name: nginx
image: nginx:1.20.2
imagePullPolicy: IfNotPresent
startupProbe: # 启动探针
exec:
command: # 返回不是 0 ,就是探测失败
- /bin/sh
- -c
- sleep 30;abc
initialDelaySeconds: 1 # 探测延迟,RUNNING 后指定 20 秒后才执行探测,默认为 0 秒。
periodSeconds: 5 # 执行探测的时间间隔(单位是秒),默认为 10 秒。
successThreshold: 1 # 成功阈值:连续几次成功才算成功。探测器在失败后,被视为成功的最小连续成功数。默认值是 1 ,存活和启动探针的这个值必须是 1。最小值是 1。
failureThreshold: 3 # 失败阈值:连续几次失败才算失败。当探测失败时,Kubernetes 的重试次数。 存活探测情况下的放弃就意味着重新启动容器。 就绪探测情况下的放弃 Pod 会被打上未就绪的标签。默认值是 3。最小值是 1。
timeoutSeconds: 5 # 探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。
2.7.3 微服务
- SpringBoot(2.3+) 已经支持了 Kubernetes 的探针机制,只需要添加
spring-boot-starter-actuator
依赖,并在 application.yml 中配置如下内容:
server: # 服务器配置
shutdown: graceful # 开启优雅停机
spring:
lifecycle:
timeout-per-shutdown-phase: 30s #设置缓冲时间 默认30s
management:
endpoint:
health:
probes:
enabled: true
show-details: always
endpoints:
web:
exposure:
include: '"*"'
health:
livenessState:
enabled: true
readinessState:
enabled: true
- 存活探针的路径是:
/actuator/health/liveness
。- 就绪探针的路径是:
/actuator/health/readiness
。
apiVersion: v1
kind: Pod
metadata:
name: nginx-prode
labels:
app: nginx-prode
spec:
terminationGracePeriodSeconds: 30 # 优雅停机时间
containers:
- name: nginx
image: nginx:1.20.2
imagePullPolicy: IfNotPresent
livenessProbe: # 就绪探针
httpGet:
path: /actuator/health/liveness
port: 8080
scheme: HTTP
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
scheme: HTTP
第三章:ReplicaSet(rs)
3.1 概述
- ReplicaSet 的主要作用是保证一定数量的 Pod 能够正常运行,它会持续监听这些 Pod 的运行状态,一旦 Pod 发生故障,就会重启或重建。同时它还支持对 Pod 数量的扩缩容。
注意:ReplicaSet 没有镜像升级的功能,如果要模拟这一功能,需要手动将 rs 删除,然后修改 yaml 文件,再创建新的 Pod 。
- ReplicaSet 的资源清单文件:
apiVersion: apps/v1 # 版本号
kind: ReplicaSet # 类型
metadata: # 元数据
name: # rs名称
namespace: # 所属命名空间
labels: #标签
app: rs
spec: # 规格,期望的状态
replicas: 3 # 副本数量
selector: # 选择器,通过它指定该控制器管理哪些pod matchLabels 和 matchExpressions 二者选其一
matchLabels: # Labels匹配规则
app: nginx-pod
matchExpressions: # Expressions匹配规则
- {key: app, operator: In, values: [nginx-pod]}
template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
3.2 创建 ReplicaSet
- 创建 ReplicaSet :
vi k8s-rs.yaml
apiVersion: apps/v1 # 版本
kind: ReplicaSet # 类型
metadata: # 元数据
name: nginx-rs # 名称
labels: # 标签
app: nginx
spec: # 规格,期望的状态
replicas: 3 # 副本数量
selector: # selector 选择器,通常而言,和 template 模板中的 labels 保持一致
matchLabels:
app: nginx
template: # Pod 模板,原来怎么编写 Pod ,这里也怎么写。
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.1
kubectl apply -f k8s-rs.yaml
3.3 扩缩容
- 方式一:使用
kubectl edit
命令,修改spec:replicas:n
即可:
kubectl edit rs nginx-rs
- ② 方式二:使用
scale
命令使用扩缩容,后面加上--replicas=n
直接指定目标数量即可:
kubectl scale rs nginx-rs --replicas=2
- ③ 修改 yaml 文件中 spec.replicas 字段,随后使用
kubectl apply -f xxx.yaml
命令即可:
vim k8s-rs.yaml
...
spec: # 规格,期望的状态
replicas: 5 # 副本数量
...
kubectl apply -f k8s-rs.yaml
3.4 模拟镜像升级
- 先删除 rs ,更新 rs 中 Pod 的模板,再重新创建 rs:
kubectl delete -f k8s-rs.yaml
vim k8s-rs.yaml
...
spec: # 规格,期望的状态
replicas: 3 # 副本数量
selector: # selector 选择器,通常而言,和 template 模板中的 labels 保持一致
matchLabels:
app: nginx
template: # Pod 模板,原来怎么编写 Pod ,这里也怎么写。
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.20.2
...
kubectl apply -f k8s-rs.yaml
注意:此种方式在实际开发中并不可取,它的原理是先删除所有的 Pod ,然后创建新的 Pod ,如果我在 k8s-rs.yaml 文件中的 Pod 的镜像写错,那么之前的 Pod 已经没了,不满足滚动更新的原则(新建一批 Pod ,删除一批 Pod ,直到新建的所有 Pod 替换原有的所有 Pod ,类似于人民战争时期我党采取的策略:根据不同的情况,争取一批、打倒一批),所以推荐使用 Deployment 代替 ReplicaSet 。
3.5 删除 ReplicaSet
- 方式一:通过
kubectl delete
命令:
# --cascade=false 删除 rs 的同时保留 Pod
kubectl delete rs rs的名称 [-n 命名空间] [--cascade=false]
kubectl delete rs nginx-rs
- 方式二:通过 yaml 文件:
kubectl delete -f k8s-rs.yaml
第四章:Deployment(deploy)
4.1 概述
- 为了更好的解决服务编排的问题,Kubernetes 在v1.2版本开始,引入了 Deployment 控制器。值得一提的是,Deployment 控制器并不直接管理 Pod,而是通过管理 ReplicaSet 来间接管理 Pod ,即:Deployment 管理 ReplicaSet,ReplicaSet 管理 Pod 。所以 Deployment 的功能比 ReplicaSet 强大。
- Deployment 的资源清单:
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
name: # rs名称
namespace: # 所属命名空间
labels: #标签
controller: deploy
spec: # 详情描述
replicas: 3 # 副本数量
revisionHistoryLimit: 3 # 保留历史版本,默认为10
paused: false # 暂停部署,默认是false
progressDeadlineSeconds: 600 # 部署超时时间(s),默认是600
strategy: # 策略
type: RollingUpdate # 滚动更新策略
rollingUpdate: # 滚动更新
maxSurge: 30% # 最大额外可以存在的副本数,可以为百分比,也可以为整数 maxUnavailable: 30% # 最大不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
selector: # 选择器,通过它指定该控制器管理哪些pod
matchLabels: # Labels匹配规则
app: nginx-pod
matchExpressions: # Expressions匹配规则
- {key: app, operator: In, values: [nginx-pod]}
template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
4.2 Deployment 的更新原理
- 仅当 Deployment 的 Pod 模板(spec.template)发生改变的时候(如:模板的标签或容器镜像被更新),才会触发 Deployment 上线,其他更新(如:Deployment 的扩缩容等操作)均不会触发上线动作。
- 上线动作:创建新的 ReplicaSet,准备就绪后,替换旧的 ReplicaSet(此时不会删除,因为 revisionHistoryLimit 指定了保留几个版本)。
4.3 创建Deployment
- 创建 Deployment :
vi k8s-deploy.yaml
apiVersion: apps/v1 # 必须字段
kind: Deployment # 必须字段
metadata: # 必须字段
name: nginx-deployment # 部署的 deployment 的名称
namespace: default # 名称空间
labels: # 标签
app: nginx-deployment
spec: # 规格,期望状态,必须字段
selector: # 选择器,用来帮助 Deployment 来筛选 Pod,必须字段
matchLabels: # 匹配标签
app: nginx # 通常而言,和 template 中的 metadata.labels 保持一致
template: # Pod 的模板,必须字段
metadata: # Pod 的 metadata(元数据)
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
restartPolicy: Always
kubectl apply -f k8s-deploy.yaml
watch -n 1 kubectl get deploy,rs,pod
4.4 扩缩容
- 方式一:使用 K
ubectl edit
命令,修改spec:replicas:n
即可:
kubectl edit deployment nginx-deployment
- 方式二:使用
scale
命令实现扩缩容:
kubectl scale deploy nginx-deployment --replicas=3
- 方式三:修改 yaml 文件中 spec.replicas 字段,随后使用
kubectl apply -f xxx.yaml
命令即可:
vim k8s-deploy.yaml
...
spec: # 规格,期望状态,必须字段
replicas: 2 # 副本数
...
kubectl apply -f k8s-deploy.yaml
4.5 镜像升级
4.5.1 概述
- Deployment 支持两种镜像更新策略:
重建更新
和滚动更新
,可以通过strategy
字段进行配置:
strategy: # 指定新的Pod替代旧的Pod的策略,支持两个属性
type: # 指定策略类型,支持两种策略 Recreate:在创建出新的Pod之前会先杀掉所有已经存在的Pod RollingUpdate:滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本的Pod
rollingUpdate:# 当type为RollingUpdate的时候生效,用于为rollingUpdate设置参数,支持两个属性:
maxUnavailable:# 用来指定在升级过程中不可用的Pod的最大数量,默认为25%。
maxSurge: # 用来指定在升级过程中可以超过期望的Pod的最大数量,默认为25%。
- Deployment 的默认的镜像更新策略是 RollingUpdate(滚动更新),实际开发的时候,使用默认镜像更新策略即可。
4.5.2 重建更新
- 设置镜像更新策略为重建更新:
vi k8s-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
labels:
app: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
revisionHistoryLimit: 15 # 旧副本集保留的数量,即可回滚的数量。默认为 10 。
progressDeadlineSeconds: 600 # 处理的最终期限,如果超过了这个指定的时间就会给集群汇报错误。默认为 600s 。
paused: false # 暂停更新,默认为 false 。
strategy: # 更新策略
type: Recreate # Recreate:在创建出新的Pod之前会先杀掉所有已经存在的Pod
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
restartPolicy: Always
kubectl apply -f k8s-deploy.yaml
- 方式一:使用
kubectl set image
命令:
kubectl set image deployment nginx-deployment nginx=nginx:1.20.2
- 方式二:修改 yaml 文件,使用
kubectl apply -f xxx.yaml
命令即可:
vi k8s-deploy.yaml
...
spec:
replicas: 3
selector:
matchLabels:
app: nginx
revisionHistoryLimit: 15 # 旧副本集保留的数量,即可回滚的数量。默认为 10 。
progressDeadlineSeconds: 600 # 处理的最终期限,如果超过了这个指定的时间就会给集群汇报错误。默认为 600s 。
paused: false # 暂停更新,默认为 false 。
strategy: # 更新策略
type: Recreate # Recreate:在创建出新的Pod之前会先杀掉所有已经存在的Pod
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.20.2 # 镜像更新
imagePullPolicy: IfNotPresent
restartPolicy: Always
...
kubectl apply -f k8s-deploy.yaml
4.5.3 滚动更新
- 设置镜像更新策略为滚动更新:
vi k8s-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
labels:
app: nginx-deployment
spec:
replicas: 6
selector:
matchLabels:
app: nginx
revisionHistoryLimit: 15 # 旧副本集保留的数量,即可回滚的数量。默认为 10 。
progressDeadlineSeconds: 600 # 处理的最终期限,如果超过了这个指定的时间就会给集群汇报错误。默认为 600s 。
paused: false # 暂停更新,默认为 false 。
strategy: # 更新策略
type: RollingUpdate # 滚动更新
rollingUpdate:
maxSurge: 25% # 最大增量:一次最多新建几个 Pod,可以写数字或百分比,maxUnavailable 为 0 的时候,maxSurge 不能为 0 。
maxUnavailable: 25% # 最大不可用量:最大不可用的 Pod,可以写数字或百分比
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
restartPolicy: Always
kubectl apply -f k8s-deploy.yaml
- 方式一:使用
kubectl set image
命令:
kubectl set image deployment nginx-deployment nginx=nginx:1.20.2
- 方式二:修改 yaml 文件,使用
kubectl apply -f xxx.yaml
命令即可:
vim k8s-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
labels:
app: nginx-deployment
spec:
replicas: 6
selector:
matchLabels:
app: nginx
revisionHistoryLimit: 15 # 旧副本集保留的数量,即可回滚的数量。默认为 10 。
progressDeadlineSeconds: 600 # 处理的最终期限,如果超过了这个指定的时间就会给集群汇报错误。默认为 600s 。
paused: false # 暂停更新,默认为 false 。
strategy: # 更新策略
type: RollingUpdate # 滚动更新
rollingUpdate:
maxSurge: 25% # 最大增量:一次最多新建几个 Pod,可以写数字或百分比,maxUnavailable 为 0 的时候,maxSurge 不能为 0 。
maxUnavailable: 25% # 最大不可用量:最大不可用的 Pod,可以写数字或百分比
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.20.2 # 镜像升级
imagePullPolicy: IfNotPresent
restartPolicy: Always
kubectl apply -f k8s-deploy.yaml
4.6 版本回退
- Deployment 支持版本升级过程中的暂停、继续功能以及版本回退等诸多功能:
kubetl rollout 参数 deploy xx # 支持下面的选择
# status 显示当前升级的状态
# history 显示升级历史记录
# pause 暂停版本升级过程
# resume 继续已经暂停的版本升级过程
# restart 重启版本升级过程
# undo 回滚到上一级版本 (可以使用--to-revision回滚到指定的版本)
- 创建 Deployment :
vi k8s-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
labels:
app: nginx-deployment
spec:
replicas: 6
selector:
matchLabels:
app: nginx
revisionHistoryLimit: 15 # 旧副本集保留的数量,即可回滚的数量。默认为 10 。
progressDeadlineSeconds: 600 # 处理的最终期限,如果超过了这个指定的时间就会给集群汇报错误。默认为 600s 。
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
restartPolicy: Always
kubectl apply -f k8s-deploy.yaml --record
- 查看版本升级历史记录:
kubectl rollout history deployment nginx-deployment
- 镜像升级:
kubectl set image deployment nginx-deployment nginx=nginx:1.17.2 --record
kubectl set image deployment nginx-deployment nginx=nginx:1.20.2 --record
- 查看版本升级历史记录:
kubectl rollout history deployment nginx-deployment
- 版本回退:
# 可以使用-to-revision=1回退到1版本,如果省略这个选项,就是回退到上个版本,即2版本
kubectl rollout undo deployment nginx-deployment --to-revision=1
kubectl rollout undo deployment nginx-deployment
Deployment 之所以能够实现版本的回退,就是通过记录下历史的 ReplicaSet 来实现的,一旦想回滚到那个版本,只需要将当前版本的 Pod 数量降为 0 ,然后将回退版本的 Pod 提升为目标数量即可。
4.7 金丝雀发布
4.7.1 概述
- 滚动更新也是有缺点的:滚动更新短时间就直接结束了,不能直接控制新老版本的存活时间;而金丝雀发布却可以实现这样的功能。
- 金丝雀的发布流程如下:
- ① 将 service 的标签设置为 app=nginx ,这就意味着集群中的所有标签是 app=nginx 的 Pod 都会加入负载均衡网络。
- ② 使用 Deployment v=v1 app=nginx 去筛选标签是 app=nginx 以及 v=v1 的 所有 Pod。
- ③ 同理,使用 Deployment v=v2 app=nginx 去筛选标签是 app=nginx 以及 v=v2 的所有 Pod 。
- ④ 逐渐加大 Deployment v=v2 app=nginx 控制的 Pod 的数量,根据轮询负载均衡网络的特点,必定会使得此 Deployment 控制的 Pod 的流量增大。
- ⑤ 当测试完成后,删除 Deployment v=v1 app=nginx 即可。
4.7.2 金丝雀发布
- 准备 v1 版本的 Deployment:
vi k8s-v1-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy-v1
labels:
app: nginx-deploy-v1
spec:
replicas: 3
selector:
matchLabels:
app: nginx
v: v1
template:
metadata:
name: nginx
labels:
app: nginx
v: v1
spec:
containers:
- name: nginx
image: nginx:1.17.2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
restartPolicy: Always
kubectl apply -f k8s-v1-deploy.yaml
- 创建 v2 版本的 Deployment :
vi k8s-v2-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy-v2
labels:
app: nginx-deploy-v2
spec:
replicas: 4
selector:
matchLabels:
app: nginx
v: v2
template:
metadata:
name: nginx
labels:
app: nginx
v: v2
spec:
initContainers:
- name: alpine
image: alpine
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","echo 2222 > /app/index.html;"]
volumeMounts:
- mountPath: /app
name: app
containers:
- name: nginx
image: nginx:1.17.2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts:
- name: app
mountPath: /usr/share/nginx/html
volumes:
- name: app
emptyDir: {}
restartPolicy: Always
kubectl apply -f k8s-v2-deploy.yaml
- 创建 Service :
vi k8s-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: canary-svc
spec:
selector:
app: nginx
type: NodePort
ports:
- port: 80 # svc 的访问端口
name: canary-nginx
targetPort: 80 # Pod 的访问端口
protocol: TCP
nodePort: 31009 # 在机器上开端口,浏览器访问
kubectl apply -f k8s-svc.yaml
- 测试:
curl 192.168.65.100:31009
当然,这仅仅是金丝雀发布的简单演示罢了,实际开发中,还需要结合 Jenkins 的 Pipeline 才行!
4.8 删除 Deployment
- 方式一:通过
kubectl delete
命令:
# --cascade=false 删除 deploy 的同时保留 Pod
kubectl delete deployment deploy的名称 [-n 命名空间] [--cascade=false]
kubectl delete deployment nginx-deployment
- 方式二:通过 yaml 文件:
kubectl delete -f k8s-deploy.yaml
第五章:HPA
5.1 概述
- 我们已经可以通过手动执行
kubectl scale
命令实现Pod的扩缩容,但是这显然不符合 Kubernetes 的定位目标–自动化和智能化。Kubernetes 期望可以通过监测Pod的使用情况,实现 Pod 数量的自动调整,于是就产生了 HPA 这种控制器。 - HPA 可以获取每个 Pod 的利用率,然后和 HPA 中定义的指标进行对比,同时计算出需要伸缩的具体值,最后实现 Pod 的数量的调整。其实 HPA 和之前的 Deployment 一样,也属于一种 Kubernetes 资源对象,它通过追踪分析目标Pod的负载变化情况,来确定是否需要针对性的调整目标 Pod 的副本数。
5.2 安装 metrics-server(v0.6.1)
- 获取 metrics-server (网速不行,请点这里components.yaml):
wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.1/components.yaml
- 修改 components.yaml :
vim components.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: metrics-server
name: metrics-server
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: metrics-server
strategy:
rollingUpdate:
maxUnavailable: 0
template:
metadata:
labels:
k8s-app: metrics-server
spec:
containers:
- args:
- --cert-dir=/tmp
- --secure-port=4443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
- --metric-resolution=15s
# 修改部分
- --kubelet-insecure-tls # 使用非安全的协议
image: bitnami/metrics-server:0.6.1 # k8s.gcr.io/metrics-server/metrics-server:v0.6.1
- 安装:
kubectl apply -f components.yaml
- 查看是否安装成功:
kubectl top nodes --use-protocol-buffers
kubectl top pods --use-protocol-buffers
5.3 HPA 监控 CPU使用率
- 创建 Deployment 和 Service :
vim k8s-hpa-deploy-svc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
resources: # 资源限制
requests:
cpu: "100m" # 100m 表示100 milli cpu,即 0.1 个CPU
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx
type: NodePort
ports:
- port: 80 # svc 的访问端口
name: nginx
targetPort: 80 # Pod 的访问端口
protocol: TCP
nodePort: 30010 # 在机器上开端口,浏览器访问
kubectl apply -f k8s-hpa-deploy-svc.yaml
- 创建 HPA :
vim k8s-hpa.yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: k8s-hpa
spec:
minReplicas: 1 # 最小 Pod 数量
maxReplicas: 10 # 最大 Pod 数量
targetCPUUtilizationPercentage: 3 # CPU 使用率指标,即 CPU 超过 3%(Pod 的 limit 的 cpu ) 就进行扩容
scaleTargetRef: # 指定要控制的Nginx的信息
apiVersion: apps/v1
kind: Deployment
name: nginx-deploy
- 测试:
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://192.168.65.100:30010; done"
- 当然,HPA 目前也可以监控内存等指标,但是,目前是 beta 版。
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: pc-hpa
namespace: dev
spec:
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 90
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 90
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deploy
第六章:DaemonSet
6.1 概述
DaemonSet 控制器确保所有(或一部分)的节点都运行了一个指定的 Pod 副本。
- 每当向集群中添加一个节点时,指定的 Pod 副本也将添加到该节点上。
- 当节点从集群中移除时,Pod 也就被垃圾回收了。
- 删除一个 DaemonSet 可以清理所有由其创建的 Pod。
DaemonSet 的典型应用场景:
- ① 在每个节点上运行集群的存储守护进程,如:glusterd、ceph。
- ② 在每个节点上运行日志收集守护进程,如:fluentd、logstash。
- ③ 在每个节点上运行监控守护进程,如:Prometheus Node Exporter、Sysdig Agent、collectd、Dynatrace OneAgent、APPDynamics Agent、Datadog agent、New Relic agent、Ganglia gmond、Instana Agent 等
- DaemonSet 的资源清单:
apiVersion: apps/v1 # 版本号
kind: DaemonSet # 类型
metadata: # 元数据
name: # 名称
namespace: #命名空间
labels: #标签
controller: daemonset
spec: # 详情描述
revisionHistoryLimit: 3 # 保留历史版本
updateStrategy: # 更新策略
type: RollingUpdate # 滚动更新策略
rollingUpdate: # 滚动更新
maxUnavailable: 1 # 最大不可用状态的Pod的最大值,可用为百分比,也可以为整数
selector: # 选择器,通过它指定该控制器管理那些Pod
matchLabels: # Labels匹配规则 matchLabels 和 matchExpressions 任选其一
app: nginx-pod
matchExpressions: # Expressions匹配规则
- key: app
operator: In
values:
- nginx-pod
template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
6.2 部署 DaemonSet
- 创建 DaemonSet:
vim k8s-ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: ds
namespace: default
labels:
app: ds
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
# tolerations: # 污点,后面讲
# - key: node-role.kubernetes.io/master
# effect: NoSchedule
containers:
- name: nginx
image: nginx:1.20.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: localtime
mountPath: /etc/localtime
terminationGracePeriodSeconds: 30
volumes:
- name: localtime
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
kubectl apply -f k8s-ds.yaml
- 删除:
kubectl delete -f k8s-ds.yaml
第七章:StatefulSet(sts)
7.1 概述
- Stateful 翻译为
有状态的
。 - Deployment 部署的应用称为
无状态应用
,StatefulSet 部署的应用称为有状态应用
。 - 无状态应用:网络可能会变(IP 地址)、存储可能会变(卷)、顺序可能会变(启动的顺序)。应用场景:业务代码,如:使用 SpringBoot 开发的商城应用的业务代码。
- 有状态应用:网络不变、存储不变、顺序不变。应用场景:中间件,如:MySQL 集群、Zookeeper 集群、Redis 集群、MQ 集群。
7.2 StatefulSet 使用场景和限制
对于有如何要求的应用程序,StatefulSet 非常适合。
- ① 稳定、唯一的网络标识(dnsname),必须配置 HeadlessService(无头服务):StatefulSet 通过和其相关的无头服务为每个 Pod 提供 DNS 解析条目。假设无头服务的 DNS 条目为
$(service name).$(namespace).svc.cluster.local
,那么 Pod 的解析条目就是$(pod name).$(service name).$(namespace).svc.cluster.local
,并且每个 Pod 都是唯一的。
- ① 稳定、唯一的网络标识(dnsname),必须配置 HeadlessService(无头服务):StatefulSet 通过和其相关的无头服务为每个 Pod 提供 DNS 解析条目。假设无头服务的 DNS 条目为
- ② 稳定、持久的存储:每个 Pod 始终对应各自的存储路径(PersistantVolumeClaimTemplate)。
- ③ 有序的、优雅的部署和缩放:按顺序地增加副本、减少副本,并在减少副本时执行清理。
- ④ 有序的、自动的滚动更新:按顺序自动地执行滚动更新。
限制:
- 给定 Pod 的存储必须由 PersistentVolume 驱动 基于所请求的 storage class 来提供,或者由管理员预先提供。
- 删除或者收缩 StatefulSet 并不会删除它关联的存储卷。 这样做是为了保证数据安全,它通常比自动清除 StatefulSet 所有相关的资源更有价值。
- StatefulSet 当前需要
无头服务
来负责 Pod 的网络标识。我们需要负责创建此服务。 - 当删除 StatefulSets 时,StatefulSet 不提供任何终止 Pod 的保证。 为了实现 StatefulSet 中的 Pod 可以有序地且体面地终止,可以在删除之前将 StatefulSet 缩放为 0。
- 在默认
Pod 管理策略
(OrderedReady) 时使用 滚动更新,可能进入需要人工干预
才能修复的损坏状态。
7.3 部署 StatefulSet
- 创建 StatefulSet :
vi k8s-sts.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: stateful-nginx
namespace: default
spec:
selector:
matchLabels:
app: ss-nginx
serviceName: nginx-svc # 服务名称,这个字段需要和 service 的 metadata.name 相同
replicas: 3 # 副本数
template:
metadata:
labels:
app: ss-nginx
spec:
containers:
- name: nginx
image: nginx:1.20.2
---
# 将 StatefulSet 加入网络
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
selector:
app: ss-nginx
type: ClusterIP
clusterIP: None # 不分配 ClusterIP ,形成无头服务,整个集群的 Pod 能直接访问,但是浏览器不可以访问。
ports:
- name: nginx
protocol: TCP
port: 80
targetPort: 80
kubectl apply -f k8s-sts.yaml
- 新建一个 Pod ,在 Pod 中访问 sts 创建的 Pod 以及无头服务:
kubectl run -it test --image=nginx /bin/sh
curl stateful-nginx-0.nginx-svc
curl stateful-nginx-1.nginx-svc
curl stateful-nginx-2.nginx-svc
curl nginx-svc
- 删除 StatefulSet :
kubectl delete -f k8s-sts.yaml
7.4 Pod 的管理策略
- StatefulSet 的 Pod 的管理策略(podManagementPolicy)分为:OrderedReady(有序启动,默认值) 和 Parallel(并发一起启动)。
...
spec:
podManagementPolicy: OrderedReady # 控制 Pod 创建、升级以及扩缩容逻辑。Parallel(并发一起启动) 和
...
- 示例:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: stateful-nginx
namespace: default
spec:
podManagementPolicy: OrderedReady # 控制 Pod 创建、升级以及扩缩容逻辑。Parallel(并发一起启动) 和 OrderedReady(有序启动), 默认是 OrderedReady
selector:
matchLabels:
app: ss-nginx
serviceName: nginx-svc
replicas: 3
template:
metadata:
labels:
app: ss-nginx
spec:
containers:
- name: nginx
image: nginx:1.20.2
---
# 将 StatefulSet 加入网络
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
selector:
app: ss-nginx
type: ClusterIP
clusterIP: None
ports:
- name: nginx
protocol: TCP
port: 80
targetPort: 80
7.5 分区更新
StatefulSet 的更新策略:
- OnDelete:删除之后才更新。
- RollingUpdate:滚动更新,如果是此更新策略,可以设置更新的索引(默认值)。
...
spec:
updateStrategy: # 更新策略
type: RollingUpdate # OnDelete 删除之后才更新;RollingUpdate 滚动更新
rollingUpdate:
partition: 0 # 更新索引 >= partition 的 Pod ,默认为 0
...
- 示例:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: stateful-nginx
namespace: default
spec:
updateStrategy: # 更新策略
type: RollingUpdate # OnDelete 删除之后才更新;RollingUpdate 滚动更新
rollingUpdate:
partition: 0 # 更新索引 >= partition 的 Pod ,默认为 0
selector:
matchLabels:
app: ss-nginx
serviceName: nginx-svc
replicas: 3
template:
metadata:
labels:
app: ss-nginx
spec:
containers:
- name: nginx
image: nginx:1.20.2
---
# 将 StatefulSet 加入网络
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
selector:
app: ss-nginx
type: ClusterIP
clusterIP: None
ports:
- name: nginx
protocol: TCP
port: 80
targetPort: 80
第八章:Job
8.1 概述
- Job 主要用于负责批量处理短暂的一次性任务。
Job 的特点:
- 当 Job 创建的 Pod 执行成功结束时,Job 将记录成功结束的 Pod 数量。
- 当成功结束的 Pod 达到指定的数量时,Job 将完成执行。
- 删除 Job 对象时,将清理掉由 Job 创建的 Pod 。
- Job 可以保证指定数量的 Pod 执行完成。
- Job 的资源清单:
apiVersion: batch/v1 # 版本号
kind: Job # 类型
metadata: # 元数据
name: # 名称
namespace: #命名空间
labels: # 标签
controller: job
spec: # 详情描述
completions: 1 # 指定Job需要成功运行Pod的总次数,默认为1
parallelism: 1 # 指定Job在任一时刻应该并发运行Pod的数量,默认为1
activeDeadlineSeconds: 30 # 指定Job可以运行的时间期限,超过时间还没结束,系统将会尝试进行终止
backoffLimit: 6 # 指定Job失败后进行重试的次数,默认为6
manualSelector: true # 是否可以使用selector选择器选择Pod,默认为false
ttlSecondsAfterFinished: 0 # 如果是 0 表示执行完Job 时马上删除。如果是 100 ,就是执行完 Job ,等待 100s 后删除。TTL 机制由 TTL 控制器 提供,ttlSecondsAfterFinished 字段可激活该特性。当 TTL 控制器清理 Job 时,TTL 控制器将删除 Job 对象,以及由该 Job 创建的所 有 Pod 对象。
selector: # 选择器,通过它指定该控制器管理那些Pod,非必须字段
matchLabels: # Labels匹配规则
app: counter-pod
matchExpressions: # Expressions匹配规则
- key: app
operator: In
values:
- counter-pod
template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板
metadata:
labels:
app: counter-pod
spec:
restartPolicy: Never # 重启策略只能设置为Never或OnFailure
containers:
- name: counter
image: busybox:1.30
command: ["/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 20;done"]
关于模板中的重启策略的说明:
- 如果设置为OnFailure,则Job会在Pod出现故障的时候重启容器,而不是创建Pod,failed次数不变。
- 如果设置为Never,则Job会在Pod出现故障的时候创建新的Pod,并且故障Pod不会消失,也不会重启,failed次数+1。
- 如果指定为Always的话,就意味着一直重启,意味着Pod任务会重复执行,这和Job的定义冲突,所以不能设置为Always。
注意
:
- 所有的 Job 类型的 Pod 不需要阻塞式镜像,如:nginx 等。
- Job 类型的 Pod 需要运行完成后就停止的镜像,如:alpine、busybox 等。
- Deployment 类型的 Pod 需要阻塞式镜像。
8.2 部署 Job
- 新建 Job :
vi k8s-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: job-01
labels:
app: job-01
spec:
# backoffLimit: 6 # 指定 Job 失败后进行重试的次数,默认为 6 ;换言之,Job 失败 6 次后,就认为失败。
# activeDeadlineSeconds: 30 # 指定 Job 可以运行的时间期限,超过时间还没结束,系统将会尝试进行终止。
completions: 4 # 指定 Job 需要成功运行 Pod 的总次数,默认为 1
template: # Pod 模板
metadata:
name: pod-job-test
labels:
app: job-01
spec:
containers:
- name: alpine
image: alpine # 坑:所有的 Job 类型的 Pod 不需要阻塞式镜像,如:nginx 等。Job 类型的 Pod 需要运行完成后就停止的镜像,如:alpine、busybox 等。
command: ["/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;done"]
restartPolicy: Never
kubectl apply -f k8s-job.yaml
- 删除 Job :
kubectl delete -f k8s-job.yaml
第九章:CronJob
9.1 概述
- CronJob 控制器以 Job 控制器为其管控对象,并借助它管理 Pod 资源对象,Job 控制器定义的作业任务在其控制器资源创建之后便会立即执行,但 CronJob 可以以类似 Linux 操作系统的周期性任务作业计划的方式控制器运行时间点及重复运行的方式,换言之,CronJob 可以在特定的时间点反复去执行 Job 任务。
- CronJob 的资源清单:
apiVersion: batch/v1beta1 # 版本号
kind: CronJob # 类型
metadata: # 元数据
name: # 名称
namespace: #命名空间
labels:
controller: cronjob
spec: # 详情描述
schedule: # cron格式的作业调度运行时间点,用于控制任务任务时间执行
concurrencyPolicy: # 并发执行策略
failedJobsHistoryLimit: # 为失败的任务执行保留的历史记录数,默认为1
successfulJobsHistoryLimit: # 为成功的任务执行保留的历史记录数,默认为3
jobTemplate: # job控制器模板,用于为cronjob控制器生成job对象,下面其实就是job的定义
metadata: {}
spec:
completions: 1 # 指定Job需要成功运行Pod的总次数,默认为1
parallelism: 1 # 指定Job在任一时刻应该并发运行Pod的数量,默认为1
activeDeadlineSeconds: 30 # 指定Job可以运行的时间期限,超过时间还没结束,系统将会尝试进行终止
backoffLimit: 6 # 指定Job失败后进行重试的次数,默认为6
template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板
spec:
restartPolicy: Never # 重启策略只能设置为Never或OnFailure
containers:
- name: counter
image: busybox:1.30
command: [ "/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 20;done" ]
schedule:cron表达式,用于指定任务的执行时间。
*/1 * * * *
:表示分钟 小时 日 月份 星期。- 分钟的值从 0 到 59 。
- 小时的值从 0 到 23 。
- 日的值从 1 到 31 。
- 月的值从 1 到 12 。
- 星期的值从 0 到 6,0 表示星期日。
- 多个时间可以用逗号隔开,范围可以用连字符给出:
*
可以作为通配符,/
表示每...
concurrencyPolicy:并发执行策略
- Allow:运行 Job 并发运行(默认)。
- Forbid:禁止并发运行,如果上一次运行尚未完成,则跳过下一次运行。
- Replace:替换,取消当前正在运行的作业并使用新作业替换它。
9.2 部署 CronJob
- 新建 CronJob :
vi k8s-cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: cronjob-test
namespace: default
spec:
schedule: "*/1 * * * *"
jobTemplate: # job 控制器模板,用于为 cronjob 控制器生成 job 对象,下面其实就是 job 的定义
spec:
template:
spec:
containers:
- name: hello
image: busybox
args: ['/bin/sh', '-c', 'date; echo Hello from the Kubernetes cluster']
restartPolicy: Never
kubectl apply -f k8s-cronjob.yaml
- 删除 CronJob :
kubectl delete -f k8s-cronjob.yaml
[...]Kubernetes 概念 Kubernetes(v1.21)工作负载 Kubernetes(v1.21)配置和存储Kubernetes(v1.21)网络Kubernetes(v1.21)调度原理Kubernetes(v1.21)安全K8s - Ingress 限流K8s-Pod重启策略Kubernetes滚动更新解决Mac/Windows版Desktop Docker中自带的K8s无法访问pod[...]