k8s 中所有的内容都抽象为资源,资源实例化之后,叫做对象
集群资源分类:
也可以使用命令:kubectl explain
来查看详细属性
例如:
kubectl explain pod
kubectl explain pod.spec
参数名 | 字段类型 | 说明 | 默认值 |
---|---|---|---|
apiVersion |
String | 这里是指的是K8S API的版本,目前基本上是v1,可以用 kubectl api-versions 或者 kubectl explain pod 命令查询 |
|
kind |
String | 这里指的是yaml文件定义的资源类型和角色,比如: Pod | |
metadata |
Object | 元数据对象,固定值就写metadata | |
metadata.name|String |
元数据对象的名字,这里由我们编写,比如命名Pod的名字 | ||
metadata.namespace |
String | 元数据对象的命名空间,由我们自身定义 | default |
metadata.labels |
map[string]string | 键值数据,常被用作挑选条件 | |
spec |
Object | 详细定义对象,固定值就写Spec | |
spec.containers[]|List |
这里是Spec对象的容器列表定义,是个列表 | ||
spec.containers[].name |
String | 这里定义容器的名字 | |
spec.containers[].image |
String | 这里定义要用到的镜像名称,如果镜像的标签是 latest,每次使用该镜像都会从远程下载 |
参数名 | 字段类型 | 说明 | 默认值 |
---|---|---|---|
spec.containers[].name | String | 定义容器的名字 | 随机指定 |
spec.containers[].image | String | 定义要用到的镜像名称,如果镜像的标签是 latest,每次使用该镜像都会从远程下载 | |
spec.containers[].imagePullPolicy | String | 定义镜像拉取策略,有Always、 Never、IfNotPresent三个值可选 (1) Always: 意思是每次都尝试重新拉取镜像 (2) Never: 表示仅使用本地镜像 (3) IfNotPresent: 如果本地有镜像就使用本地镜像,没有就拉取在线镜像 |
Always |
spec.containers[].command[] | List | 指定容器启动命令,因为是数组可以指定多个 | 默认使用镜像打包时使用的启动命令 |
spec.containers[].args[] | List | 指定容器启动命令参数,因为是数组可以指定多个 | |
spec.containers[].workingDir | String | 指定容器的工作目录 | |
spec.containers[].volumeMounts[] | List | 指定容器内部的存储卷配置 | |
spec.containers[].volumeMounts[].name | String | 指定可以被容器挂载的存储卷的名称 | |
spec.containers[].volumeMounts[].mountPath | String | 指定可以被容器挂载的存储卷的路径 | |
spec.containers[].volumeMounts[].readOnly | Boolean | 设置存储卷路径的读写模式,ture 或者 false | false |
spec.containers[].ports[] | List | 指定容器需要用到的端口列表 | |
spec.containers[].ports[].name | String | 指定端口名称 | |
spec.containers[].portsl].containerPort | String | 指定容器需要监听的端口号 | |
spec.containers[].ports[].hostPort | String | 指定容器所在主机需要监听的端口号,默认跟上面containerPort相同, 注意设置了hostPort同一台主机无法启动该容器的相同副本(因为主机的端口号不能相同,这样会冲突) | |
spec.containers[].ports[].protocol | String | 指定端口协议,支持TCP和UDP | TCP |
spec.containers[].env[] | List | 指定容器运行前需设置的环境变量列表 | |
spec.containers[].env[].name | String | 指定环境变量名称 | |
spec.containers[].env[].value | String | 指定环境变量值 | |
spec.containers[].resources | Object | 指定资源限制和资源请求的值(这里开始就是设置容器的资源上限) | |
spec.containers[].resources.limits | Object | 指定设置容器运行时资源的运行上限 | |
spec.containers[].resources.limits.cpu | String | 指定CPU的限制,单位为core数,将用于docker run --Cpu-shares参数 (这里前面文章Pod资源限制有讲过) | |
spec.containers[].resources.limits.memory | String | 指定MEM内存的限制,单位为MIB、GiB | |
spec.containers[].resources.requests | Object | 指定容器启动和调度时的限制设置 | |
spec. containers[].resources.requests.cpu | String | CPU请求,单位为core数,容器启动时初始化可用数量 | |
spec. containers[].resources.requests .memory | String | 内存请求,单位为MIB、GiB, 容器启动的初始化可用数量 |
参数名 | 字段类型 | 说明 | 默认值 |
---|---|---|---|
spec.restartPolicy | String | 定义Pod的重启策略,可选值为Always、OnFailure、Never 1.AIways:Pod 一旦终止运行,则无论容器是如何终止的,kubelet服务都将重启它。 2.OnFailure:只有Pod以非零退出码终止时,kubelet才会重启该容器。如果容器正常结束(退出码为0),则kubelet将不会重启它。 3. Never:Pod终止后,kubelet将退出码报告给Master,不会重启该Pod |
Always |
spec.nodeSelector | Object | 定义Node的Label过滤标签,以key:value格式指定 | |
spec.imagePullSecrets | Object | 定义pull镜像时使用secret名称,以name:secretkey格式指定 | |
spec.hostNetwork | Boolean | 定义是否使用主机网络模式。设置true表示使用宿主机网络,不使用docker网桥,同时设置了true将无法在同一台宿主机上启动第二个副本 | false |
spec.restartPolicy 仅指通过同一节点上的 kubelet 重新启动容器。失败的容器由 kubelet 以五分钟为上限的指数退避延迟(10秒,20秒,40 秒…)重新启动,并在成功执行十分钟后重置。如 Pod 文档 中所述,一旦绑定到一个节点,Pod 将 永远不会重新绑定到另一个节点。
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: app
image: hub.zyx.com/library/myapp:v1
- name: test
image: hub.zyx.com/library/myapp:v1
kubectl apply -f pod.yaml
kubectl describe pod myapp-pod # describe 查看容器信息
kubectl logs myapp-pod test # 查看 pod 中指定容器的日志
kubectl get pod -o wide/json/yaml # 以指定的格式输出
kubectl delete podName
kubectl create -f pod.yaml
因为 Init 容器具有与应用程序容器分离的单独镜像,所以它们的启动相关代码具有如下优势:
它们可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的
它们可以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建镜像没必要FROM另一个镜像,只需要在安装过程中使用类似sed、awk、python或dig这样的工具。
应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像。
Init 容器使用 LinuxNamespace,所以相对应用程序容器来说具有不同的文件系统视图。因此,它们能够具有访问 Secret 的权限,而应用程序容器则不能。
它们必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以Init容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法,直到满足了一组先决条件。
在 Pod 启动过程中,Init 容器会按顺序在网络和数据卷初始化之后启动。每个容器必须在下一个容器启动之前成功退出(网络和数据卷初始化是在 pause)
如果由于运行时或失败退出,将导致容器启动失败,它会根据 Pod 的 restartPolicy
指定的策略进行重试。例如,如果 Pod 的 restartPolicy 设置为 Always,Init容器失败时会不断重试,直到达到他的最大上限为止
在所有的 Init 容器没有成功之前,Pod 将不会变成 Ready 状态。Init 容器的端口将不会在 Service 中进行聚集。正在初始化中的 Pod 处于 Pending 状态,但应该会将 Initializing 状态设置为true
如果 Pod 重启,所有 Init 容器必须重新执行
对 Init 容器 spec 的修改(kubectl edit pod)被限制在容器 image 字段,修改其他字段都不会生效(不会自动重启)。更改 Init 容器的image 字段,会自动重启该 Init 容器,相当于重启 Pod
Init 容器具有应用容器的所有字段。除了 readinessProbe
(就绪检测),因为 Init 容器无法定义不同于完成(completion)的就绪(readiness)之外的其他状态。这会在验证过程中强制执行
在 Pod 中的每个 app 和 Init 容器的名称必须唯一;与任何其它容器共享同一个名称,会在验证时抛出错误(同一个 Pod 中 Init 的端口是可以相同的)
编写资源清单,创建 init-pod.yaml:
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers: # 这是主容器
- name: myapp-container
image: busybox # 如果镜像的标签是 latest 且下载策略是 Always,每次使用该镜像都会从远程下载
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers: # 这是 init 容器
- name: init-myservice
image: busybox
# 循环检测 myservice 域名是否能被解析,如果可以解析,退出循环
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox
# 循环检测 mydb 是否能被解析,如果可以解析,退出循环
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
启动 pod 并查看日志
[root@k8s-master01 ~]# kubectl create -f init-pod.yaml
pod/myapp-pod created
[root@k8s-master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 9s
# 查看详细信息及日志:
kubectl describe pod myapp-pod
kubectl logs myapp-pod -c init-myservice
创建 service.yaml,启动名为 myservice 的 service
kind: Service
apiVersion: v1
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
[root@k8s-master01 ~]# kubectl create -f service.yaml
service/myservice created
# 可以看到,Init 容器成功启动了一个
[root@k8s-master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:1/2 0 25m
# 查看详细信息及日志:
kubectl describe pod myapp-pod
kubectl logs myapp-pod -c init-myservice
kubectl get svc # 查看刚创建的 Service (svc 是 Service 的简写)
同理,创建 db.yaml,启动名为 mydb 的 service
kind: Service
apiVersion: v1
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
[root@k8s-master01 ~]# kubectl create -f db.yaml
service/mydb created
# 稍等片刻,发现 pod Running
[root@k8s-master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 34m
探针是由每一个 Node 上的 kubelet 对容器执行的定期诊断。要执行诊断,kubelet 调用由容器实现的 Handler。有三种类型的处理程序:
每次探测都将获得以下三种结果之一:
探测方案也有两种:
livenessProbe: 生存检测
readinessProbe: 就绪检测
区别:readinessProbe 检测成功之后,主容器才能宣布对外能够正常访问,否则状态都是 Failure。而 livenessProbe 跟随着容器的整个生命周期,会循环检测容器中的资源是否可用。
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-pod
namespace: default
spec:
containers:
- name: readiness-httpget-container
image: wangyanglinux/myapp:v1
imagePullPolicy: IfNotPresent
readinessProbe: # 就绪检测
httpGet: # httpGet 检测方案
port: 80 # 端口 80
path: /index1.html # 请求文件
initialDelaySeconds: 1 # 初始化检测的延时,容器启动 1 之后再开始检测
periodSeconds: 3 # 重试的检测时间
可以看到,容器在运行(Running),但是没有 Ready:
[root@k8s-master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness-httpget-pod 0/1 Running 0 12s
# 查看日志信息,显示 HTTP 请求状态码为 404
[root@k8s-master01 ~]# kubectl describe pod readiness-httpget-pod
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Unhealthy 75s (x22 over 2m18s) kubelet, localhost.localdomain Readiness probe failed: HTTP probe failed with statuscode: 404
手动进入容器,添加 index1.html 之后:
# 进入容器, 如果 POD 中有多个容器,则需要 -c 指定容器名
# kubectl exec (POD | TYPE/NAME) [-c CONTAINER] [flags] -- COMMAND [args...] [options]
kubectl exec readiness-httpget-pod -it -- /bin/sh
# 添加文件
cd /usr/share/nginx/html/
echo "123" > index1.html
exit
# 查看 Pod,已经 READY
[root@k8s-master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness-httpget-pod 1/1 Running 0 6m25s
模板说明:pod 创建,容器初始化完成后,创建文件后休眠 60 秒后删除该文件,存活检测在容器创建后延时 1s 进行检测,重试时间间隔 3s。
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec-pod
namespace: default
spec:
containers:
- name: liveness-exec-container
image: busybox
imagePullPolicy: IfNotPresent
# 创建一个文件,休眠 60s,然后把该文件删除
command: ["/bin/sh","-c","touch /temp/live ; sleep 60 ; rm -rf /temp/live; sleep 3600"]
livenessProbe: # 存活检测
exec:
# 检测该文件是还存在, 如果存在,返回值为 0
command: ["test","-e","/temp/live"]
initialDelaySeconds: 1 # 容器启动后延时 1s 再开始检测
periodSeconds: 3 # 每隔 3s 检测一次
容器启动时会创建 /temp/live
文件,60s 之后删除该文件。当 livenessProbe
发现文件不存在,就会重启容器,重启后的容器 60秒之后又会删除 /temp/live
文件,所以容器不断被重启,
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget-pod
namespace: default
spec:
containers:
- name: liveness-httpget-container
image: wangyanglinux/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
livenessProbe:
httpGet:
port: http # http 和 80 等价
path: /index1.html
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 10 # 最大超时时间
创建一个 pod,镜像文件是 nginx,存活检测镜像容器中的 nginx(80),使用 tcp 连接,端口指定8080,当探测结果失败时(不可访问),重启容器
apiVersion: v1
kind: Pod
metadata:
name: liveness-tcp-pod
namespace: default
spec:
containers:
- name: liveness-tcp-container
image: wangyanglinux/myapp:v1
imagePullPolicy: IfNotPresent
livenessProbe:
initialDelaySeconds: 1
timeoutSeconds: 5
periodSeconds: 3
tcpSocket:
port: 8080 # nginx 是 80 端口
Pod hook(钩子)是由 Kubernetes 管理的 kubelet 发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。可以同时为 Pod 中的所有容器都配置 hook
Hook 的类型包括两种:
p exec:执行一段命令 p HTTP:发送HTTP请求
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-start-stop-pod
namespace: default
spec:
containers:
- name: readiness-start-stop-container
image: nginx
imagePullPolicy: IfNotPresent
lifecycle:
postStart:
exec:
command: ["/bin/sh","-c","echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/bin/sh","-c","echo Hello from the postStop handler > /usr/share/message"]
Pod 的 status
字段是一个 PodStatus
对象,PodStatus
中有一个 phase
字段。
Pod 的相位(phase)是 Pod 在其生命周期中的简单宏观概述。该阶段并不是对容器或 Pod 的综合汇 总,也不是为了做为综合状态机
Pod 相位的数量和含义是严格指定的。除了本文档中列举的状态外,不应该再假定 Pod 有其他的 phase 值
下面是 phase
可能的值:
Pending
):Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间 包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间Running
):该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容 器正在运行,或者正处于启动或重启状态Succeeded
):Pod 中的所有容器都被成功终止(返回码为0),并且不会再重启Failed
):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止Unknown
):因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败Kubernetes 中内建了很多 controller(控制器),这些相当于一个状态机,用来控制 Pod 的具体状态和行为
RC (ReplicationController )主要的作用就是用来确保容器应用的副本数始终保持在用户定义的副本数 。即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收
Kubernetes 官方建议使用 RS(ReplicaSet ) 替代 RC (ReplicationController ) 进行部署,RS 跟 RC 没有本质的不同,只是名字不一样,并且 RS 支持集合式的 selector (标签)
通过命令行查看详细的 ReplicaSet 清单定义规则:
kubectl explain rs kubectl explain rs.spec.template
重点:
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
# 创建 RS
[root@k8s-master01 yaml]# kubectl create -f rs.yaml
# 查看创建的 rs
[root@k8s-master01 yaml]# kubectl get rs
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 23m
# 查看rs创建的 3 个 Pod,
[root@k8s-master01 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
frontend-cbxp2 1/1 Running 0 23m
frontend-qnfcd 1/1 Running 0 23m
frontend-qqngq 1/1 Running 0 23m
# 删除 Pod后,RS会自动重建 Pod,维持设置的副本数(3),通过 Pod 后的随机值可以看出,Pod是重新创建的
[root@k8s-master01 yaml]# kubectl delete pod --all
pod "frontend-cbxp2" deleted
pod "frontend-qnfcd" deleted
pod "frontend-qqngq" deleted
[root@k8s-master01 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
frontend-5lgj9 1/1 Running 0 14s
frontend-gxhrv 1/1 Running 0 14s
frontend-rwhc5 1/1 Running 0 14s
# 查看Pod的标签
[root@k8s-master01 yaml]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
frontend-5lgj9 1/1 Running 0 5m20s tier=frontend
frontend-gxhrv 1/1 Running 0 5m20s tier=frontend
frontend-rwhc5 1/1 Running 0 5m20s tier=frontend
# 修改其中一个Pod的标签
[root@k8s-master01 yaml]# kubectl label pod frontend-5lgj9 tier=abc --overwrite=true
pod/frontend-5lgj9 labeled
# RS会通过匹配 labels 来确定哪些 Pod 是自己管理的
# 当改变了 frontend-5lgj9 的 labels 时,该 Pod 已经不归 frontend 这个 RS 管了,所以 RS 又重新创建了一个Pod
[root@k8s-master01 yaml]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
frontend-5lgj9 1/1 Running 0 84m tier=abc
frontend-7fbp8 1/1 Running 0 4s tier=frontend
frontend-gxhrv 1/1 Running 0 84m tier=frontend
frontend-rwhc5 1/1 Running 0 84m tier=frontend
# 删除RS,Pod也会被删除
[root@k8s-master01 yaml]# kubectl delete rs frontend
[root@k8s-master01 yaml]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
frontend-5lgj9 1/1 Running 0 98m tier=abc
可以直接通过vim
编辑清单文件修改replicas
字段,也可以通过kubect edit
命令去编辑。kubectl
还提供了一个专用的子命令scale
用于实现应用规模的伸缩,支持从资源清单文件中获取新的目标副本数量,也可以直接在命令行通过“--replicas”
选项进行读取。
#修改rs配置文件
# kubectl edit rs frontend
#修改Pod副本数量提升为5个
# 删除rs,并删除管理的pod
kubectl delete rs [rs名字]
# 删除rs,不删除管理的pod “--cascade=false”选项,取消级联关系。
kubectl delete rs [rs名字] --cascade=false
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义 (declarative) 方法,用来替代以前的ReplicationController 来方便的管理应用。典型的应用场景包括
- ① 定义 Deployment 来创建 Pod 和 ReplicaSet
- ② 滚动升级和回滚应用
- ③ 扩容和缩容
- ④ 暂停和继续 Deployment
通过命令行查看详细的 Deployment 清单定义规则:
kubectl explain deployment kubectl explain deployment.spec.template
apiVersion: apps/v1 #api版本定义
kind: Deployment #定义资源类型为Deploymant
metadata: #元数据定义
name: nginx-deployment #deployment控制器名称
namespace: default #名称空间
spec: #deployment控制器的规格定义
replicas: 3 #定义deployment副本数量为2个
selector: #标签选择器,定义匹配Pod的标签
matchLabels:
app: nginx-deployment
template: #Pod的模板定义
metadata: #Pod的元数据定义
labels: #定义Pod的标签,和上面的标签选择器标签一致,可以多出其他标签
app: nginx-deployment
spec: #Pod的规格定义
containers: #容器定义
- name: nginx #容器名称
image: hub.zyx.com/library/nginx:v1 #容器镜像
ports: #暴露端口
- name: http #端口名称
containerPort: 80
kubectl get deployment
命令所显示的字段有:
NAME
:Deployment 的名称。READY
:显示应用程序的可用的副本数。显示的模式是“就绪个数/期望个数”。UP-TO-DATE
:显示为了达到期望状态已经更新的副本数。AVAILABLE
:显示应用可供用户使用的副本数。AGE
:显示应用程序运行的时间。# 创建Deployment对象
# --record 可以方便的查看 revision 的变化(roolout 被触发(spec.template被更改)就会创建一个 revision)
kubectl apply -f deployment.yaml --record
[root@k8s-master01 yaml]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 4m30s
[root@k8s-master01 yaml]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-645ccc47cc 3 3 3 4m32s
[root@k8s-master01 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-645ccc47cc-885sz 1/1 Running 0 4m37s
nginx-deployment-645ccc47cc-k5jcm 1/1 Running 0 4m37s
nginx-deployment-645ccc47cc-rwnk5 1/1 Running 0 4m37s
kubectl scale deployment nginx-deployment --replicas=5
修改 Pod
模板相关的配置参数便能完成 Deployment
控制器资源的更新。由于是声明式配置,因此对 Deployment
控制器资源的修改尤其适合使用 apply
和 patch
命令来进行;如果仅只是修改容器镜像,set image
命令更为易用。
kubectl set image deployment/[deployment名称] [容器名称]=[镜像名称]
kubectl set image deployment/nginx-deployment nginx=wangyanglinux/myapp:v2
# 可以看到原来的 RS 已经停用并做为备份,并创建了新的 RS
[root@k8s-master01 yaml]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-645ccc47cc 0 0 0 3h45m
nginx-deployment-6c67f64d64 5 5 4 8s
.spec.revisonHistoryLimit
项来指定 deployment
最多保留多少 revision
历史记录。默认的会保留所有的 revision
;如果将该项设置为 0
,Deployment
就不允许回退了# 回到上一个版本
kubectl rollout undo deployment/nginx-deployment
# 查看当前的更新状态
# 如果 rollout 成功完成, 该命令将返回一个 0 值的 Exit Code
kubectl rollout status deployments/nginx-deployment
# echo $? # 输出 0
# 查看当前版本(自定义 Pod 的输出)
kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
# 通过该命令查看更新历史记录,Pod 模板被修改就会创建一个 revision
kubectl rollout history deployment/nginx-deploy
# 查询结果,创建 Deployment 时加上 --record 才会显示CHANGE-CAUSE
# REVISION CHANGE-CAUSE
# 1 kubectl apply --filename=deployment.yaml --record=true
# 2 kubectl apply --filename=deployment.yaml --record=true
# 回滚到指定版本
kubectl rollout undo deployment/nginx-deployment --to-revision=1
# 暂停 deployment 的更新
kubectl rollout pause deployment/nginx-deployment
Deployment
可确保在更新时仅关闭一定数量的 Pod
。默认情况下,它确保至少所需 Pods
75% 处于运行状态(最大不可用比例为 25%)。
Deployment
还确保仅所创建 Pod
数量只可能比期望 Pods
数高一点点。 默认情况下,它可确保启动的 Pod
个数比期望个数最多多出 25%(最大峰值 25%)。
如果旧的 Pod 创建还没有达到期望数时(如期望数是 5,但现在只创建了3个),就更新了 Pod。在这种情况下,Deployment 会立即杀掉已创建的旧 Pod,并开始创建新 Pod。它不会等到所有的旧 Pod 都创建完成后才开始创建新 Pod
例如,如果仔细查看上述 Deployment (kubectl describe deployment
),将看到它首先创建了一些新的 Pod,然后删除了一些旧的 Pods。并且创建新的 Pods 创建没有到达 25% ,它不会杀死老 Pods,直到有足够的数量新的 Pods 已经出现。 然后开始杀死老 Pods ,在足够数量的旧 Pods 被杀死前并没有创建新 Pods。它确保至少 4 个 Pod 可用,同时最多总共 7 个 Pod 可用。
确保全部(或者一些)Node 上运行一个 Pod 的副本(同一个 Node 上运行多个 Pod 需要多个 DaemonSet)。当有 Node 加入集群时,也会为他们新增一个Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod
使用 DaemonSet 的一些典型用法:
① 运行集群存储 daemon,例如在每个 Node 上运行glusterd、ceph
② 在每个 Node 上运行日志收集 daemon,例如fluentd、logstash
③ 在每个 Node 上运行监控 daemon,例如Prometheus Node Exporter、collectd、Datadog 代理、New Relic 代理,或 Ganglia gmond
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>
job负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个pod成功结束
特殊说明:
restartPolicy
仅支持 Never
或 OnFailure
,因为 Job 就是批处理任务,执行完自动退出,如果是 Always,那么就会不断的执行.spec.completions
:标志Job结束需要成功运行的 Pod 个数,默认为 1.spec.parallelism
:标志并行运行的 Pod 的个数,默认为 1.spec.activeDeadlineSeconds
:标志失败 Pod 的重试最大时间,超过这个时间不会继续重试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,即:
使用前提条件:当前使用的 Kubernetes 集群,版本 >= 1.8(对 CronJob)。
典型的用法:
在给定的时间点调度 Job 运行
创建周期性运行的 Job,例如:数据库备份、发送邮件
.spec.schedule
:调度,必需字段,指定任务运行周期,格式同 Cron
.spec.jobTemplate
:Job 模板,必需字段,指定需要运行的任务,格式同 Job
.spec.startingDeadlineSeconds
:启动 Job 的期限(秒级别),该字段是可选的。如果因为任何原因而错过了被调度的时间,那么错过执行时间的 Job 将被认为是失败的。如果没有指定,则没有期限
.spec.concurrencyPolicy
:并发策略,该字段也是可选的。它指定了如何处理被 Cron Job 创建的 Job 的并发执行。只允许指定下面策略中的一种:
Allow
(默认):允许并发运行 JobForbid
:禁止并发运行,如果前一个还没有完成,则直接跳过下一个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
创建 Job 操作应该是 幂等的。
CronJob 仅负责创建与其调度时间相匹配的 Job,而 Job 又负责管理其代表的 Pod。
StatefulSet
作为 Controller 为 Pod 提供唯一的标识。它可以保证部署和 scale 的顺序
一个完整的 StatefulSet
应用由三个部分组成: headless service
(无头服务)、StatefulSet controller
、volumeClaimTemplate
(PVC)。
Headless Service
:用来定义 Pod 网络标识( DNS domain);volumeClaimTemplates
:存储卷申请模板,创建 PVC,指定 pvc 名称大小,将自动创建 pvc,且 pvc 必须由存储类供应;StatefulSet
:定义具体应用,名为 Nginx,有三个 Pod 副本,并为每个 Pod 定义了一个域名部署 statefulset。为什么需要
headless service
无头服务?
在用Deployment
时,每一个Pod
名称是没有顺序的,是随机字符串,因此是 Pod 名称是无序的,但是在statefulset
中要求必须是有序 ,每一个pod
不能被随意取代,pod 重建后 pod 名称还是一样的。而pod IP
是变化的,所以是以 Pod 名称来识别。pod 名称是 pod 唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个 Pod 一个唯一的名称 。
除此之外,
StatefulSet
在Headless Service
的基础上又为StatefulSet
控制的每个Pod
副本创建了一个DNS
域名,这个域名的格式为:
$(podname).(headless server name)
FQDN:$(podname).(headless server name).namespace.svc.cluster.local
为什么需要
volumeClaimTemplate
?
对于有状态的副本集都会用到持久存储,对于分布式系统来讲,它的最大特点是数据是不一样的,所以各个节点不能使用同一存储卷,每个节点有自已的专用存储,但是如果在Deployment
中的Pod template
里定义的存储卷,是所有副本集共用一个存储卷,数据是相同的,因为是基于模板来的;而statefulset
中每个Pod
都要自已的专有存储卷,所以statefulset
的存储卷就不能再用 Pod 模板来创建了,于是statefulSet
使用volumeClaimTemplate
,称为卷申请模板,它会为每个Pod
生成不同的pvc
,并绑定pv
,从而实现各 pod 有专用存储。这就是为什么要用volumeClaimTemplate
的原因。
StatefulSet
清单实例# 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
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)
Hroizontal Pod Autoscaling
kubectl create 和 kubectl apply区别
K8S的apiVersion版本说明
使用 kubectl explain pod
查看版本