文章目录
- pod生命周期
- pod启动阶段
- 故障排除步骤:
- 存储卷
- emptyDir存储卷
- hostPath存储卷
- nfs共享存储卷
- 总结:
pod生命周期
pod启动阶段
-
一般来说,pod 这个过程包含以下几个步骤:
- 调度到某台 node 上。kubernetes 根据一定的优先级算法选择一台 node 节点将其作为 Pod 运行的 node
- 拉取镜像
- 挂载存储配置等
- 容器运行起来。如果有健康检查,会根据检查的结果来设置其状态
-
phase 的可能状态有:
- Pending:表示APIServer创建了Pod资源对象并已经存入了etcd中,但是它并未被调度完成(比如还没有调度到某台node上),或者仍然处于从仓库下载镜像的过程中。
- Running:Pod已经被调度到某节点之上,并且Pod中所有容器都已经被kubelet创建。至少有一个容器正在运行,或者正处于启动或者重启状态(也就是说Running状态下的Pod不一定能被正常访问)。
- Succeeded:有些pod不是长久运行的,比如job、cronjob,一段时间后Pod中的所有容器都被成功终止,并且不会再重启。需要反馈任务执行的结果。
- Failed:Pod中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止,比如 command 写的有问题。
- Unknown:表示无法读取 Pod 状态,通常是 kube-controller-manager 无法与 Pod 通信。Pod 所在的 Node 出了问题或失联,从而导致 Pod 的状态为 Unknow
-
如何删除 Unknown 状态的 Pod ?
- 从集群中删除有问题的 Node。使用公有云时,kube-controller-manager 会在 VM 删除后自动删除对应的 Node。 而在物理机部署的集群中,需要管理员手动删除 Node(kubectl delete node <node_name>)。
- 被动等待 Node 恢复正常,Kubelet 会重新跟 kube-apiserver 通信确认这些 Pod 的期待状态,进而再决定删除或者继续运行这些 Pod。
- 主动删除 Pod,通过执行 kubectl delete pod <pod_name> --grace-period=0 --force 强制删除 Pod。但是这里需要注意的是,除非明确知道 Pod 的确处于停止状态(比如 Node 所在 VM 或物理机已经关机),否则不建议使用该方法。特别是 StatefulSet 管理的 Pod,强制删除容易导致脑裂或者数据丢失等问题。
故障排除步骤:
- 查看Pod事件
kubectl get pods -o wide
kubectl describe TYPE NAME_PREFIX
- 查看Pod日志(Failed状态下)
kubectl logs <POD_NAME> [-c Container_NAME] -p
- 进入Pod(状态为running,但是服务没有提供)
kubectl exec –it <POD_NAME> bash
##在pod中添加一个临时容器进行调试
kubectl debug -it pod_name --image=nginx --target=目标容器
neenter在宿主机中进入到pod的命名空间
- 查看集群信息
kubectl get nodes
- 发现集群状态正常
kubectl cluster-info
- 查看kubelet日志发现
journalctl -xefu kubelet
存储卷
emptyDir存储卷
- 当Pod被分配给节点时,首先创建emptyDir卷,并且只要该Pod在该节点上运行,该卷就会存在。
- 正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入emptyDir卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。
- 当出于任何原因从节点中删除 Pod 时,emptyDir中的数据将被永久删除
- 数据容器共享,数据没有持久化
mkdir /opt/volumes
cd /opt/volumes
vim pod-emptydir.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-emptydir
namespace: default
labels:
app: myapp
tier: frontend
spec:
containers:
- name: myapp
image: nginx:1.14
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
#定义容器挂载内容
volumeMounts:
#使用的存储卷名称,如果跟下面volume字段name值相同,则表示使用volume的这个存储卷
- name: html
#挂载至容器中哪个目录
mountPath: /usr/share/nginx/html/
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: html
#在容器内定义挂载存储名称和挂载路径
mountPath: /data/
command: ['/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done']
#定义存储卷
volumes:
#定义存储卷名称
- name: html
#定义存储卷类型
emptyDir: {}
apiVersion: v1
kind: Pod
metadata:
name: pod-emptydir
namespace: default
labels:
app: myapp
spec:
containers:
- name: myapp
image: nginx:1.14
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: html
mountPath: /data/
command: ['/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done']
volumes:
- name: html
emptyDir: {}
kubectl apply -f pod-emptydir.yaml
##分别进入两个容器中,查看对应的容器中的文件
kubectl exec -it pod-emptydir -c busybox sh
kubectl exec -it pod-emptydir -c myapp sh
hostPath存储卷
- hostPath卷将 node 节点的文件系统中的文件或目录挂载到集群中。
- hostPath可以实现持久存储,但是在node节点故障时,也会导致数据的丢失
- 把Node节点上的目录/文件挂载到容器中,可实现持久化数据存储。
- 但是存储空间会受到Node节点的单机限制,Node节点故障数据就会丢失,且Pod不能实现跨节点共享数据
apiVersion: v1
kind: Pod
metadata:
name: pod-hostpath
namespace: default
spec:
containers:
nodeName: node02
- name: myapp
image: nginx:1.14
#定义容器挂载内容
volumeMounts:
#使用的存储卷名称,如果跟下面volume字段name值相同,则表示使用volume的这个存储卷
- name: html
#挂载至容器中哪个目录
mountPath: /usr/share/nginx/html
#读写挂载方式,默认为读写模式false
readOnly: false
#volumes字段定义了paues容器关联的宿主机或分布式文件系统存储卷
volumes:
#存储卷名称
- name: html
#路径,为宿主机存储路径
hostPath:
#在宿主机上目录的路径
path: /data/pod/volume1
#定义类型,这表示如果宿主机没有此目录则会自动创建,权限为755
type: DirectoryOrCreate
apiVersion: v1
kind: Pod
metadata:
name: pod-hostpath
namespace: default
spec:
nodeName: node02
containers:
- name: myapp
image: nginx:1.14
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: false
volumes:
- name: html
hostPath:
path: /data/pod/volume1
type: DirectoryOrCreate
nfs共享存储卷
- 使用nfs服务将共享存储设备空间挂载到容器中,可实现持久化数据存储,且Pod能实现跨节点共享数据
##创建nfs共享存储
systemctl stop firewalld
setenforce 0
rpm -q rpcbind
rpm -q nfs-utils
##创建共享目录
mkdir -p /data/volumes
##创建共享配置
vim /etc/exports
/data/volumes 192.168.242.0/24(rw,no_root_squash,sync)
##重启服务
systemctl enable --now rpcbind nfs
##查看共享
showmount -e 192.168.242.71
apiVersion: v1
kind: Pod
metadata:
name: pod-vol-nfs
namespace: default
spec:
containers:
- name: myapp
image: nginx:1.14
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: false
volumes:
- name: html #指定名称
nfs: #指定存储卷类型
path: /data/volumes #共享目录
server: 192.168.242.71 #nfs服务器地址或者server
总结:
-
Pod 的启动过程:
- 通过 scheduler 根据调度算法选择一台在最适合的 Node节点运行 Pod
- 拉取镜像
- 挂载 存储卷 等
- 创建并运行容器
- 根据容器的探针探测结果设置 Pod 状态
-
Pod 生命周期的 5 种状态
- pending :Pod已经创建,但是处于包括Pod还未完成调度到Node节点的过程或者处于镜像拉取过程中、存储卷挂载失败等情况
- running : Pod中至少有一个容器正在运行
- succeeded :Pod中的所有容器都已经成功退出,且不再重启。(Completed)
- failed : Pod中的所有容器都已终止,且至少有一个容器异常退出。(Error)
- unknown : Master节点的 controller-manager 无法获取 Pod 的状态,通常是因为 Master节点与 Pod 所在的 Node 节点通信失联导致的
-
Pod遵循预定义的生命周期,起始于Pending阶段,如果至少其中有一个主要容器正常启动,则进入Running阶段,之后取决于Pod中是否有容器以失败状态结束而进入Succeeded或者Failed阶段。
-
K8S 中的排障手段
kubectl get pods #查看Pod运行状态
kubectl describe <资源类型|pods> <资源名称>
#查看资源的详细信息和事件
kubectl logs <pod名称> [-c <容器名>] [-p] #查看容器的进程日志
kubectl exec -it <pod名称> [-c <容器名>] sh|bash #进入Pod容器,查看容器内部相关状态信息
kubectl debug -it <pod名称> --image=<临时容器的镜像名> --target=<目标容器>
#在Pod中创建临时容器进入目标容器进行调试
- 在Pod容器的宿主机使用nsenter转换网络等命名空间,直接在宿主机进入目标容器的命名空间进行调试
kubectl get nodes #查看Node节点的运行状态
kubectl get cs #查看Master组件的状态
kubectl cluster-info #查看集群信息
journalctl -u kubelet -f #跟踪查看Kubelet进程日志
- K8S 的 存储卷 volumes
- emptyDir:可实现Pod中的容器之间共享目录数据,但emptyDir存储卷没有持久化数据的能力,存储卷会随着Pod生命周期结束而一起删除
- hostPath:将Node节点上的目录/文件挂载到Pod容器的指定目录中,有持久化数据的能力,但只能在单个Node节点上持久化数据,不能实现跨Node节点的Pod共享数据
- nfs:使用NFS服务将存储卷挂载到Pod容器的指定目录中,有持久化数据的能力,且也能实现跨Node节点的Pod共享数据