在 Kubernetes 中,一个重要的概念就是 Pod(豆英),Kubernetes 并不是直接管理容器的,他的最小管理单元叫做 Pod。
一、什么是 Pod
Pod 是一个或多个容器的组合。这些容器共享存储、网络和命名空间,以及运行规范。在 Pod中,所有容器都被统一安排和调度,并运行在共享的上下文中。对于具体应用而言,Pod 是它们的逻辑主机,Pod 包含业务相关的多个应用容器。所以,Pod 是一组具有共享命名空间、IP 地址和端口的容器的集合。
备注:
共享上下文是一种基于线程的内存位置
1:从使用的角度来看
在实际的使用时,单个容器是无法单独来支撑我们的应用的,往往需要很多微服务才能组成一个系统,并且还会存在A服务依赖B服务,B服务需要和C服务共用某个目录。另外,在使用裸容器时,很难实现对容器内进行健康检査以及横向扩容等操作,而 Pod 可以轻松解决这些问题。
2:从 Kubernetes 的角度来看
Docker 只是容器 Runtime(运行时)的一种们还有很多容器 Runtime,比如 Rkt、CRI-0等,而 Kubernetes 作为目前最流行的容器编排工具,需要支持各个 Runtime 并且不依赖于底层Runtime 的实现技术,于是就抽象出了 Pod 这个概念,用于管理多个紧密相连的符合 CRI 标准的容器。
Pod 可以简单的理解为一组、一个或多个容器,每个 Pod 还包含一个 Pause 容器,Pause 容器是 Pod 的父容器,主要负责僵尸进程的回收管理。同时,通过 Pause 容器可以使同一个 Pod里面的不同容器共享存储、网络、PID、IPC 等,容器之间可以使用 Localhost:Port 的方式相瓦访问,可以使用 volume 实现数据共享。根据 Docker 的构造,Pod 可以被创建为一组具有共享命名空卷、IP 地址和端口的容器。
Pod 有两个必须知道的特点:
- 网络:每一个 Pod 都会被指派一个唯一的 Ip 地址,在 Pod 中的每一个容器共享网络命名空间,包括 Ip 地址和网络端口。在同一个 Pod 中的容器可以同 1ocahost 进行互相通信。当 Pod中的容器需要与 Pod 外的实体进行通信时,则需要通过端口等共享的网络资源。
- 存储:Pod 能够被指定共享存储卷的集合,在Pod中所有的容器能够访问共享存储卷,允许这些容器共享数据。存储卷也允许在一个 Pod 持久化数据,以防止其中的容器需要被重启。
3:Pod 的状态
(1)kubectl 命令创建 pod
kubectl run nginx--image=nginx:1.7.9 --labels="app=nginx"
(2)查看 pod
kubectlget pods -n default
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 78s
(3)显示 Pod的更多信息
kubectl get pod nginx -o wide
NAME READY STATUS RESTARTS AGE Ip NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 54s 10.244.58.195 k8s-node02 <none> <none>
(4)查看 pod日志
curl 10.244.58.195
kubectl logs nginx
(5)以yaml格式显示 Pod 详细信息
kubectl get pod nginx -o yaml
(6)显示资源的详细描述信息
kubectl describe pod nginx
备注:
- kubectl get:常用于査看同一资源类型的一个或多个资源对象,可以使用-0 参数自定义输出格式。
- kubectl describe:侧重于描述指定资源的各方面的详细信息,不仅会返回节点信息,还会返回在其上运行的 Pod 的摘要、节点事件等信息。
(7)在 Pod 的容器中执行命令
kubectl exec nginxc nginx-- date
备注:
- -c:指定 Pod 中容器的名字
(8)登录到 Pod 中的容器中
kubectl exec -it nginx-c nginx -- bash
备注:
kubectl exec -it nginx --bash
如果登录的时候不指定容器,就登录到 Pod 中的第一个容器中。
(9)在线编辑运行中的资源对象
kubectl edit pod nginx
(10)将 pod 的端口映射到宿主机
kubectl port-forward --address 0.0.0.0 pod/nginx 8080:80
Forwarding from 0.0.0.0:8080->80
其他主机访问测试:
curl 192.168.10.101:8080
注意:
此命令会在前台运行,此时就可以在其他客户端用该 k8s 主机的 IP 地址和 8080 的端口号进行访问了,Ctr1+c停止,但停止后就没有这个映射了。
(11)在宿主机和 Pod 的容器之间拷贝文件
kubectl cp nginx:etc/fstab /opt/aaa.txt
kubectl cp /opt/aaa.txt nginx:etc/bbb.txt
(12)Pod 的状态
kubectl get pods -n default
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 29m
可以看到此时的 Pod 的状态是 Running,Pod 的状态不仅仅只有 Running,常见的其他状态如表所示:
状态 | 说明 |
Pending(挂起) | Pod 已经被 Kubernetes 系统接收,但是仍有一个或多个容器未被创建,可以通过 kubectl describe 查看处于Pending 状态的原因。 |
Running(运行中) | Pod 已经被绑定到一个节点上,并且所有的容器都已经被创建,而且至少有一个是运行的状态、正在启动或者重启,可以通过 kubectl logs 查看 Pod 的日志。 |
Succeeded | 所有容器执行成功,并终止,并且不会再次重启,可以通过kubectl logs 査看 Pod 的日志 |
Failed(失败) | 所有容器都已终止,并且至少一个容器以失败的方式终止,也就是说这个容器要么以非零状态退出,要么被系统终止,可以通过 logs 和 describe 査看 Pod 的日志和状态 |
Unknown(未知) | 通常是由于通信问题造成的无法获得 Pod 的状态 |
ImagePullBackOff ErrImagePull | 镜像拉取失败,一般是由于镜像不存在、网络不通或者需要登录认证引起的,可以使用 describe 命令查看具体的原因 |
CrashLoopBackoff | 容器启动失败,可以通过 logs 命令查看具体的原因,一般为启动命令不正确、健康检査不通过等原因 |
OOMKilled | 容器内存溢出,一般是容器的内存 Limit 设置的过小,或者程序本身有内存溢出,可以通过 logs 查看程序的启动日志 |
Terminating | Pod 正在被删除,可以通过 describe 查看状态 |
SysctlForbiden | Pod 自定义了内核配置,但 kubect1 没有添加内核配置或配置的内核参数不支持,可以通过 describe 查看具体原因 |
Completed | 容器内部主进程退出,一般计划任务执行结束会显示该该状态,此时可以通过 logs 查看容器日志 |
ContainerCreating | Pod 正在创建,一般正在下载镜像,或者有配置不当的地方可以通过 describe 查看具体原因 |
(13)删除 Pod
kubectl delete pod nginx
二、Pod 探针
在生产环境中,进程正常启动并不代表应用能正常处理请求,所以合理的设计应用的健康检查尤其重要。在使用裸机或裸容器部署时,一般很难对应用做很完善的健康检査,而 Pod 提供的探针可以很方便的用来检测容器的应用是否正常。目前探针有3种检测方式,可以根据不同的场景选择合适的健康检查方式。检查方式如表所示:
上述的检查方式可以被周期性的执行,每次检查容器后可能得到的容器状态如表所示:
Pod 探针有三类,分别是:livenessProbe(存活探针)、readinessProbe(就绪探针)、startupProbe(启动探针)。
- livenessProbe (存活探针):判断容器是否正常运行,如果失败则杀掉容器(不是 pod),再根据重启策略决定是否重启容器
- readinessProbe(就绪探针):判断容器是否能够进入ready 状态,探针失败则进入noready 状态,并从service 的endpoints 中剔除此容器
- startupProbe(启动探针): 判断容器内的应用是否启动成功,在 success 状态前,其它探针都处于无效状态
三、Pod 镜像拉取策略和重启策略
在发布应用或者更改控制器配置时,会触发Pod 的滚动更新,此时针对容器的镜像有不同的拉取方式。如表所示:
指定拉取策略:
kubectl run nginx --image=nginx:1.7.9 --labels="app=nginx" --image-pull-policy=Never
Pod 进行部署或者运行时,难免会出现故障,对于故障。,Pod也有不同的处理方式,如表所示:
指定重启策略:
kubectl delete pod nginx
kubectl run nginx --image=nginx:1.7.9 --labels="app=nginx" --restart=OnFailure
四、创建一个简单的 Pod
1:编写一个简单的 Pod
vim nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
2:编写 Pod 配置文件 frontend-localredis-pod.yaml
cat <<E0F>frontend-localredis-pod.yam1
apiVersion: v1
kind: Pod
metadata:
name: redis-php
labels:
name: redis-php
spec:
containers:
- name: frontend
image: kubeguide/guestbook-php-frontend:localredis
imagePullPolicy: IfNotPresent
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 1
ports:
- containerPort: 80
- name: redis
image: kubeguide/redis-master
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6379
restartPolicy: OnFailure
EOF
备注:
##必选,版本号apiVersion:v1
kind: Pod##必选,资源类型
metadata:##必选,元数据
name: redis-php##必选,Pod 名称
labels :##自定义的 pod 标签列表
##标签值name:redis-php
##必选,Pod 中容器的详细信息spec:
##必选,Pod 中的容器列表containers:
##必选,自定义的容器名称- name:frontend
image:kubeguide/guestbook-php-frontend:localredis##必选,容器的镜像名称
imagePullPolicy:IfNotPresent##镜像拉取策略
设置存活探针livenessProbe:
tcpsocket:##测试某端口是否可以连接
##指定要测试的端口port:80
initialDelaySeconds:1 #指定 kubelet 在执行第一次探测前应该等待1秒,即第一次探测是在容器启动后的第2秒才开始执行。默认是0秒,最小值是0
periodseconds:3#指定了 kubelet 应该每 3 秒执行一次存活探测。默认是 10 秒。最小值是 1
timeoutSeconds:1##当探测失败时,Kubernetes 将在放弃之前重试的次数。存活探测情况下的放弃就意味着重新启动容器。就绪探测情况下的放弃Pod 会被打上未就绪的标签。默认值是 3。最小值是 1
##需要暴露的端口号列表ports:
##容器需要监听的端口号-containerPort:80
name:redis##另一个容器的名字
image:kubeguide/redis-master##另一个容器的镜像
##需要暴露的另一个容器的端口列表ports:
containerPort:6379##容器需要监听的端口号
##重启策略restartPolicy:onFailure
3:Pod 文件语法
(1)Pod 文件的一级属性
一级属性主要包含5部分:
- apiVersion<string>版本,由 kubernetes 内部定义,版本号必须可以用 kubectlapi-versions 查询到
- kind<string>类型,由 kubernetes 内部定义,版本号必须可以用 kubect1api-resources 查询到
- metadata<Object>元数据,主要是资源标识和说明,常用的有 name、namespace、labels
- spec<Object>描述,这是配置中最重要的一部分,里面是对各种资源配置的详细述
- status<Object>状态信息,里面的内容不需要定义,由kubernetes 自动生成
(2)spec(规格)属性
在一级属性中,spec是研究的重点,它的常见子属性有:
- containers<[]Object>容器列表,用于定义容器的详细信息
- nodeName<String>根据 nodeName 的值将 pod 调度到指定的 Node 节点上
- nodeselector <map[]>根据 Nodeselector 中定义的信息选择将该 Pod 调度到包含这些label的Node 上
- hostNetwork<boolean〉是否使用主机网络模式,默认为 false,如果设置为 true,表示使用宿主机网络
- volumes<[]0bject>存储卷,用于定义 Pod 上面挂在的存储信息
- restartPolicy<string>重启策略,表示 Pod 在遇到故障的时候的处理策略
(3)通过 kubectl explain 命令来查看每种资源的可配置项
kubectl explain pod
kubectl explain deployment
kubectl explain service
kubectl explain pod.metadata
kubectl explain pod.spec.containers
备注:
查看某种资源可以配置的一级属性
# kubectl explain 资源类型
查看属性的子属性
# kubectl explain 资源类型,属性
4:运行 kubectl create 命令创建此 Pod
kubectl create -f frontend-localredis-pod.yaml
5:查看已经创建的 Pod
kubectl get pods
NAME READY STATUS RESTARTS AGE
redis-php 2/2 Running 0 119s
6:查看 pod 详细创建信息
kubectl describe pod redis-php
7:删除 pod
kubectl delete -f frontend-localredis-pod.yaml
五、Pod 的基本用法
1:编写 pod 文件,将两个容器放在同一个 pod 中
cat <<EOF>nginx-php.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-php
labels:
name: nginx-php
spec:
containers:
- name: nginx-app
image: nginx:1.7.9
ports:
- containerPort: 80
- name: php-app
image: bitnami/php-fpm
imagePullPolicy: Never
ports:
- containerPort: 9000
EOF
2:部署 nginx的 pod 文件
kubectl apply -f nginx-php.yaml
kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-php 2/2 Running 0 28s
备注:
此时可以看到 pod 中有两个容器处于 running 状态中
3:查看 pod 的详细信息
kubectl describe pod nginx-php
4:暴露端口
kubectl expose pod nginx-php --port=8080 --target-port=80 --type=NodePort --name=nginx-php
5:查看端口映射
kubectl get pod,svc nginx-php -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
pod/nginx-php 2/2 Running 0 2m35s 172.25.244.199 k8s-master01 <none> <none> service/nginx-php NodePort 10.99.26.98
<none> 8080:32598/TcP 2m24s name=nginx-php
6:测试访问
用外部主机,访问master 的ip 地址:映射的端口
http://192.168.10.101:32598/
7:删除 pod
kubectl delete -f nginx-php.yaml
六、静态 pod
静态 Pod 是由 kubelet 进行管理的仅存在于各个 Node 上的 Pod。他们不能通过 API Server进行管理,无法于 Replicationcontroller、Deployment 或者 Daemonset 进行关联,并且kubelet 无法对他们进行健康检査。静态 Pod 总是由 kubelet 创建的,并且总在 kubelet 所在的 Node 上运行。
1:编写 yamal 文件
cat<<E0F>/etc/kubernetes/manifests/nginx-pod.yaml
apiVersion:v1
kind: Pod
metadata:
name: nginx
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
EOF
2:不需执行部署命令,过一会,查看 pod
kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-php 2/2 Running 4(18m ago)20m
static-web-k8s-master01 1/1 Running 0 20s
3:删除静态 pod 的方法
rm -rf /etc/kubernetes/manifests/nginx-pod.yaml
备注:
不能用如下语句删除
kubectl delete pod static-web-k8s-master01
这样删除,会让 pod 处于 pending 状态,但无法删除
七、Pod 启动阶段(相位 phase)
Pod 创建完之后,一直到持久运行起来,中间有很多步骤,也就有很多出错的可能,因此会有很多不同的状态
1:pod 的启动过程包含的步骤
- 调度到某台 node 上。kubernetes 根据一定的优先级算法选择一台 node 节点将其作为Pod 运行的 node
- 拉取镜像
- 挂载存储配置等
- 运行起来。如果有健康检查,会根据检查的结果来设置其状态
2: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 事件
kubectl describe TYPE NAME PREFIX
- 査看 Pod 日志(Failed 状态下)
kubectl logs <POD NAME>[-c Container NAME]
- 进入 Pod(状态为running,但是服务没有提供)
kubectl exec it <POD NAME> bash
- 查看集群信息
kubectl get nodes
- 发现集群状态正常
kubectl cluster-info
- 査看 kubelet 日志发现
journalctl -xefu kubelet