目录
1 概述
1.1 为什么要有Pod
- 对于一个简单的微服务部署架构而言,至少要包含:web、app、数据库等等这些微服务。微服务之间存在调用关系,而服务本身也有多节点部署、生命周期管理的需求。基于上述需求,需要让这些服务共享同一个网络栈以及数据卷,还需要管理好这些容器的生命周期。
- 其实,传统“单容器部署”的方式其实可以满足上述的需求,只不过自动化程度太低了,工程师不但要做一些重复性的操作,还要面对容器生命周期管理、调度的棘手问题。基于上述的问题,Kubernetes-Pod出现了。
- Pod是Kubernetes创建和管理的最小单元,一个Pod由一个容器或多个容器组成,这些容器共享存储、网络。
1.2 Pod特点
- 一个Pod可以理解为是一个应用实例,用来提供服务
- Pod中的容器在一个Node上
- Pod中容器共享网络、存储资源
- Kubernetes直接管理的是Pod,而不是容器
1.3 Pod用法
- 运行单个容器:最常见的用法,在这种情况下,可以将Pod看做是单个容器的抽象封装(类似于容器)
- 运行多个容器:封装多个紧密耦合且需要共享资源的应用程序
如果有如下需求,可以在一个Pod中运行多个容器(实际应用较少):
- 两个应用之间发生文件交互
- 两个应用需要通过127.0.0.1或者socket通信
- 两个应用需要发生频繁的调用
2 pod资源共享实现机制
Pod内资源共享机制共享机制总体如下图所示:
2.1 共享网络
- Pod在创建时,会先创建 Infra Container 容器,该容器专门用来维护Pod的网络。
- 之后在Pod中创建其他容器时,都将新创建的容器连接到Infra Container 的网络命名空间中,从而解决了同一个Pod中不同容器之间的网络共享问题。
2.2 共享存储
容器之间通过数据卷共享存储(两个容器部署在同一台宿主机上,数据卷也是该宿主机上的一个目录)
3 Pod常用管理命令
Pod常用管理命令如下,然后本节基于这些命令,简单的验证一下Pod中容器的资源共享情况。
3.1 Pod常用管理命令
#创建Pod(yaml文件中一个Pod可定义多个容器):
kubectl apply -f <pod的.yaml文件名字>
#查看集群中有哪些Pod(-w参数实时查看):
kubectl get pods
#查看某一个Pod的详细信息
kubectl describe pod <Pod名称>
#查看Pod中某一个容器的日志:
kubectl logs <Pod名称> [-c CONTAINER]
#进入Pod中某一个容器的终端(busybox 用 -- sh):
kubectl exec <Pod名称> [-c CONTAINER] -- bash
#删除Pod:
kubectl delete pod <Pod名称>
3.2 测试Pod中容器共享网络情况
1 测试Pod网络共享
#1、定义Pod的yaml文件
vi pod1.yaml
#文件中复制如下内容并保存(之所以busybox多了一个command参数,是因为busybox这个进程一旦启动就会自动退出,作为容器的主进程是不能退出的,否则容器也不能正常运行,所以需要加一个指令不让它退出)
apiVersion: v1
kind: Pod
metadata:
labels:
app: test
name: pod-net-test
namespace: default
spec:
containers:
- image: busybox
name: test
command: ["/bin/sh","-c","sleep 360000"]
- image: nginx
name: web
#2、创建Pod
kubectl apply -f pod1.yaml
#3、进入busybox容器终端(yaml中容器名字叫test)
kubectl exec -it pod-net-test -c test -- sh
#4、查看busybox容器端口(发现了80端口,按理说单独部署busybox应该没有80端口才对,看来busybox容器和nginx容器的网络已经通了,但是这个案例不够直接,主要是nginx这个容器中能用的指令太少了)
netstat -antp
3.3 测试Pod中容器共享存储情况
#1、定义Pod的yaml文件
vi pod2.yaml
#文件中复制如下内容并保存(添加了数据卷字段)
labels:
app: test
name: pod-volume-test
namespace: default
spec:
containers:
- image: busybox
name: test
command: ["/bin/sh","-c","sleep 360000"]
volumeMounts:
- name: log
mountPath: /data
- image: nginx
name: web
volumeMounts:
- name: log
mountPath: /data
volumes:
- name: log
emptyDir: {}
#2、创建Pod
kubectl apply -f pod2.yaml
#3、先进入nginx容器终端(进入nginx容器终端后,在数据卷目录 /data 下随便创建一个文件)
kubectl exec -it pod-volume-test -c web -- bash
#4、再进入到busybox容器中(同样进入到数据卷目录 /data 下,发现存在之前在另外一个容器中创建的文件)
kubectl exec -it pod-volume-test -c test -- sh
3.4 Pod状态分类
kubectl get pods指令可查看当前集群中Pod的状态
- Pending:Pod未调度或已经调度正在拉取镜像
- Runing:Pod已经运行
- Failed:Pod内容器运行停止
- Success:Pod内容器运行成功结束
- Unknown:Master与Node失联,Pod状态无法正常获取到
4 Pod健康检查与重启策略
部署在Pod中的容器可能会发生状态的改变,因此需要时刻监视这些容器的状态,一旦出现问题,及时重启,本节介绍的就是这个事情。整体架构如下:
4.1 健康检查
健康检查指的是对Pod中容器的检查,健康检查有以下3种类型:
- livenessProbe(存活检查):如果检查失败,将杀死容器,根据Pod的restartPolicy来操作。
- readinessProbe(就绪检查):如果检查失败,Kubernetes会把Pod从service endpoints中剔除。
- startupProbe(启动检查)
上述三种检查类型支持以下3种具体的检查方法:
- exec:执行Shell命令返回状态码是0为成功。
- httpGet:发送HTTP请求,返回200-400范围状态码为成功。
- tcpSocket:发起TCP Socket建立成功。
4.2 重启策略
- Always:当容器终止退出后,总是重启容器,默认策略。
- OnFailure:当容器异常退出(退出状态码非0)时,才重启容器。
- Never:当容器终止退出,从不重启容器。
4.3 验证Pod的健康检查与重启策略执行情况
(1)验证存活检查及重启
执行以下操作:
#1、创建一个Pod的yaml文件
vi exec-liveness.yaml
#2、文件中编辑如下内容
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: pod-check
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600 #创建文件、休眠30秒、删除文件、休眠600秒
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5 #启动容器后多少秒进行健康检查
periodSeconds: 5 #以后间隔多少秒检查一次
#3、创建Pod
kubectl apply -f exec-liveness.yaml
#4、Pod创建完毕后30秒内输入如下指令,一切正常,然而超过35s后马上出发健康检查条件,Pod中容器被重启
kubectl describe pod pod-check
#5、再查看pod信息,发现容器确实被重启了
kubectl get pod pod-check
上述操作过程描述如下:
Pod中容器在创建的同时会创建一个 /tmp/healthy文件,而该Pod的健康检查机制就是每隔5秒检查容器中该文件是否存在,不存在则删除容器。在容器启动的前30秒,一切正常,然后那个文件被删除掉,再过5秒,健康检查发现文件被删除于是马上停止运行Pod中的容器,此时Pod的重启策略被激活,该容器又被重新启动 。
(2)其他健康检查验证
上面的例子只是介绍了通过exec指令进行存活检查的例子。然而健康检查一共有3种,检查方法也有3种!对于其他的健康检查验证案例请参考官网文档:Pod健康检查例子
5 Pod注入环境表变量
有时候容器需要用到Pod的变量信息,比如某个微服务(容器)需要知道当前Pod在哪个节点上,从而把节点IP注册到注册中心中。于是对于这样的需要求,可以把一些容器可能用到的变量信息存到Pod的yaml文件中,这样容器就能直接使用了。
如下例子介绍了如何往Pod的yaml文件中存入变量信息以及如何从Pod的容器中提取这些变量:
#1、创建一个Pod的yaml文件
vi pod-vars.yaml
#2、粘贴如下内容
apiVersion: v1
kind: Pod
metadata:
name: pod-envars
spec:
containers:
- name: test
image: busybox
command: [ "sh", "-c", "sleep 36000"]
env:
- name: MY_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: ABC
value: "123456"
#3、进入busybox容器内
kubectl exec -it pod-envars sh
#4、查询变量MY_POD_IP的值
echo $MY_POD_IP
#5、查询变量ABC的值
echo $ABC
6 Init初始化容器
6.1 Pod中的容器类型
- Infrastructure Container:基础容器,维护整个Pod网络空间
- InitContainers:初始化容器,先于业务容器开始执行
- Containers:业务容器,并行启动
6.2 Init Container简介
- 支持大部分应用容器配置,但不支持健康检查
- 优先应用容器执行
6.3 Init Container 应用场景
- 环境检查:例如确保应用容器依赖的服务启动后再启动应用容器
- 初始化配置:例如给应用容器准备配置文件等
6.4 演示
为了更加了解Init Container,接下来的操作做了这样一个事情:
创建一个Pod,该Pod中定义了2个容器,第一个容器是init容器(创建优先于应用容器,专门做一些初始化的工作,从而帮助到应用容器),第二个容器是普通的应用容器(部署nginx)
init容器容器在创建时下载了一些资源到共享目录下,然后应用容器可以从共享目录下获取到该资源。
#1、创建一个Pod的yaml文件
vi pod-initcontainer.yaml
#2、粘贴如下内容
#Pod中2个容器download、nginx,其中download的创建优先级要高于nginx
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
#从/www.baidu.com下载页面并保存到容器的 /opt/index.html 路径下
initContainers:
- name: download
image: busybox
command:
- wget
- "-O"
- "/opt/index.html"
- http://www.baidu.com
volumeMounts:
- name: wwwroot
mountPath: "/opt"
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: wwwroot
mountPath: /usr/share/nginx/html
volumes:
- name: wwwroot
emptyDir: {}
#3、进入nginx容器中
kubectl exec -it init-demo -- bash
#4、进入到nginx容器的共享数据卷目录中
cd /usr/share/nginx/html
#5、查看名字为download的容器下载的内容在nginx容器中是否存在
ls