本篇是关于k8s的Pod,主要包括Pod和容器的使用、Pod的控制和调度管理、应用配置管理等内容。
Pod的定义
Pod是k8s的核心概念一直,就名字一样,是k8s中一个逻辑概念。Pod是docekr容器的集合,每个Pod中至少有一个Pause容器和业务容器。和docker容器关注单个可用的资源不同,Pod更多在应用层的角度,将多个docker容器组合来实现作为一个应用,它是k8s中最小的资源单位。
结合docker本身容器的特性,Pod中所有容器都是共享资源,如磁盘、网络、CPU、内存等,同时,一个Pod共用一个网络。
以下的yaml格式的Pod定义文件:
apiVersion: v1
kind: Pod
metadata:
name: string
namespace: string
labels:
- name: string
annotations:
- name: string
spec:
containers:
- name: string
image: string
imagePullPolicy: [Always | Never | IfNotPresent]
command: [string]
args: [string]
workingDir: string
volumeMounts: string
- name: string
mountPath: string
readOnly: boolean
ports:
- name: string
containerPort: int
hostPort: int
protocol: string
env:
- name: string
value: string
resources:
limits:
cpu: string
memory: string
requests:
cpu: string
memory: string
livenessProbe:
exec:
command: [string]
httpGet:
path: string
port: number
scheme: string
httpHeaders:
- name: string
value: string
tcpSocket:
port: number
initialDelaySeconds: 0
timeoutSeconds: 0
periodSeconds: 0
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always | Never | OnFailure]
nodeSelector: object
imagePullSecrets:
- name: string
hostNetwork: false
volumes:
- name: string
emptyDir: {}
hostPath:
path: string
secret:
secretName: string
items:
- key: string
value: string
configMap:
name: string
items:
- key: string
- path: string
注:k8s的Pod启动命令不能是后台执行的,不然k8s会不断创建新的Pod而陷入无限循环中。如果docker镜像的命令无法改造为前台执行,可以使用开源工具Supervisor。或是 && tail -f xx 这样的组合命令。
静态Pod
静态Pod是由Kubelet进行管理的的仅存在于特定Node上的Pod。它们不能通过API Server进行管理,也无法和ReplicationController、Deployment或者DaemonSet进行关联,kubelet也不乏对它们进行健康检查。静态Pod总是由kubelet创建,也由kubelet来销毁。同时也只运行在该kubelet所在的Node上。
创建静态Pod由两种方式:配置文件和HTTP。
1.配置文件方式
静态文件存放的位置在kubelet的配置文件中定义,由参数staticPodPath指定,如果k8s集群由kubeadm搭建,那默认存储在目录/etc/kubernetes/manifests
下。我们定义配置文件static-nginx.yaml
:
apiVersion: v1
kind: Pod
metadata:
name: static-nginx
labels:
name: static-nginx
spec:
containers:
- name: static-nginx
image: nginx
ports:
- name: nginx
containerPort: 80
不需要使用命令创建,等他一会,kubelet会自动创建Pod
[root@k8s-master ~]# kubectl get pods
static-nginx-k8s-master 1/1 Running 0 12m
注:如果一段时间还是没有生成Pod,可以查看日志文件 /var/log/messages
删除Pod不是使用命令kubelet delete ...
,而是直接删除/etc/kubernetes/manifests/static-nginx.yaml
,kubelet自动会删除Pod。
2.HTTP方式
kubelet会定时根据参数--manifest-url
来下载镜像并生成静态Pod。
注:比较巧妙地方的是kubeadm安装地管理节点 kube-apiserver、kube-sheduler、kube-controller-manager 组件都是静态的Pod。
Pod共享volume
之前说过,同一个Pod中的容器能共享Volume,那怎么将Volume共享给Pod呢。
关键在于配置文件中的spec.containers[].volumeMounts
和spec.volumes[]
参数,例如Pod中容器之间共享一个emptyDir的目录,名为logs,配置文件就可以这样:
apiVersion: v1
kind: Pod
metadata:
name: volume-pod
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: logs
mountPath: /usr/local/nginx/logs
- name: busybox
image: busybox
volumeMounts:
- name: logs
mountPath: /logs
volumes:
- name: logs
emptyDir: {}
这样一来,容器nginx和busybox就共享一个目录,且各自挂载的路径也不同。重点是用volumes
定义要共享的volume,再在containers上使用volumeMounts
参数来使用。
Pod ConfigMap
k8s 在 1.2版本时提供了一种统一的集群配置管理方案,就是ConfigMap,利用不同配置和不同容器分离开的方式,让复杂容器管理简单化。
ConfigMap的用法
ConfigMap供容器使用的典型用法如下:
- 生成为容器内的环境变量。
- 设置容器启动命令的启动参数(需设置为环境变量)。
- 以 Volume 的形式挂载为容器内部的文件或目录。
ConfigMap的创建
1.yaml文件方式
# cm.appvars.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-appvars
data:
apploglevel: info
appdatadir: /var/data
指定命令创建:
kubectl create -f cm-appvars.yaml
查看命令就用:
kubectl get configMap -o json
或者key:value也可以使用配置文件的别名和文件的内容。
data:
key-serverxml: |
......
......
key-properties: "key=...
....
"
注意格式问题。
2.kubelet命令行创建
直接通过kubectl create configmap
也可以创建ConfigMap,可以使用参数--from-file
或--from-literal
指定内容。
通过--from-file
参数从文件中创建,可以指定key的名称,可以在一个命令中创建包含多个key的ConfigMap,语法为:
kubectl create configmap NAME --from-file=[key=]source --from-file=[key=]source
通过--from-file
参数从目录中进行创建,该目录的每个配置文件名都被设置为key,文件的内容被设置为value,语法为:
kubectl create configmap NAME --from-file=config-files-dir
通过--file-literal
从文本中进行创建、直接将指定的key#=value#创建为ConfigMap的内容,语法为:
kubectl create configmap NAME --from-literal=key1=value1 --from-literal=key2=value2
ConfigMap的使用
ConfigMap的使用也有几种方式。
1.环境变量
apiVersion: v1
kind: Pod
metadata:
name: cm-test-pod
spec:
containers:
- name: cm-test
image: buysbox
env:
- name: APPLOGLEVEL # 定义环境变量名称
valueFrom: # key "apploglevel" 对应的值
configMapKeyRef:
name: cm-appvars # 环境变量的值取自 cm-appvars 中
key: apploglevel # key 为 "apploglevel"
- name: APPDATADIR
valueFrom:
configMapKeyRef:
name: cm-appvars
key: appdatadir
restartPolicy: Never
要点是环境变量中使用valueFrom
参数指定configMapKeyRef
2.volumeMount的方式
...
spec:
containers:
- name: cm-test-app
image: busybox
volumeMounts:
- name: serverxml # 引用volume名
mountPath: /configfiles # 挂载到容器内的目录
volumes:
- name: serverxml
configMap:
name: cm-appconfigfiles # 使用 ConfigMap "cm-appconfigfiles"
items:
- key: key-serverxml # key=key-serverxml
path: server.xml # value将server.xml文件名进行挂载
如果在引用 ConfigMap 时不指定 items,则使用 volumeMount 方式在容器内的目录中为每个 item 生成一个文件名为 key 的文件。
ConfigMap 的限制条件
使用 ConfigMap 的限制条件如下:
- ConfigMap 必须在 Pod 之前创建。
- ConfigMap 也可以定义为属于某个 Namespace。 只有处于相同 Namespace 中的 Pod 可以引用它。
- ConfigMap 中的配额管理还未能实现。
- 静态Pod无法引用 ConfigMap。
- 在 Pod 对 ConfgMap 进行挂载(volumeMount)操作时,容器内部只能挂载为“目录”,无法挂载为“文件”。在挂载到容器内部后,目录中将包含 ConfigMap 定义的每个 item,如果该目录下原先还有其他文件,则容器内的该目录将会被挂载的 ConfigMap 进行覆盖。如果应用程序需要保留原来的其他文件,则需要进行额外的处理。可以通过将 ConfigMap 挂载到容器内部的临时目录,在通过启动脚本将配置文件复制或者链接到应用所用的实例配置目录下。
Pod生命周期和重启策略
Pod的状态
状态值 | 描述 |
---|---|
Peding | API Server 已经创建该Pod,但Pod内还有一个或多个容器的镜像没有创建,包括正在下载镜像的过程 |
Running | Pod内所有容器均已创建,且至少有一个容器处于运行状态、正在启动状态或正在重启状态 |
Succeeded | Pod内所有容器均成功执行退出,且不会再重启 |
Failed | Pod内所有容器均已退出,但至少有一个容器退出为失败状态 |
Unknown | 由于某种原因无法获取该Pod的状态,可能由于容器通信不畅导致 |
Pod的RestartPolicy重启策略:
- Always:当容器失效时,有Kubelet自动重启容器。
- OnFailure:当容器终止运行且退出码不为0,由kubelet自动重启该容器。
- Never:不论容器运行状态如何,kubelet都不会启动该容器。
每种控制器对Pod的重启策略不同:
- RC和DaemonSet:必须设置为 Always,需要保证该容器持续运行。
- Job:OnFailure或Never,确保容器执行完成后不再重启。
- kubelet:在Pod失效时自动重启它,不论RestartPolicy设置为什么值,并且也不会对Pod进行健康检查。
Pod健康检查
Pod的健康状态检查可以通过两类探针来检查:LivenessProbe 和 ReadinessProbe。
- LivenessProbe:用于判断容器是否存活(running 状态),如果LivenessProbe探针探测到容器不健康,则kubelet将杀掉该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针返回值永远是“Success”。
- ReadinessProbe:用于判断容器是否自动完成(ready 状态),可以接收请求。 如果ReadinessProbe探针检测到失败,则Pod的状态将被修改。Endpoint Controller将从Service的Endpoint中删除包含该容器所在Pod的Endpoint。
kubelet定期执行LivenessProbe探针来诊断容器的健康状况。LivenessProbe有三种实现方式。
ExecAction:在容器内部执行一个命令,如果该命令的返回码为0,则表明容器健康。
...
spec:
containers:
- name: liveness
...
livenessProbe:
exec:
command:
- cat
- /tmp/health
initialDelaySeconds: 15 # 探针初始化检测时间间隔,单位为秒
timeoutSeconds: 1 # 返回超时时间,单位为秒。如果超时kubelet会重启容器
TCPSocketAction:通过容器的IP地址和端口号执行TCP检查,如果能够建立TCP连接。则表明容器健康。
...
spec:
containers:
- name: liveness
...
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 15 # 探针初始化检测时间间隔,单位为秒
timeoutSeconds: 1 # 返回超时时间,单位为秒
HTTPGetAction:通过容器的IP地址、端口号及路径调用HTTP Get方法,如果响应的状态码大于等于200且小于等于400,则认为容器状态健康。
...
spec:
containers:
- name: liveness
...
livenessProbe:
httpGet:
path: /_status/healthz
port: 80
initialDelaySeconds: 15 # 探针初始化检测时间间隔,单位为秒
timeoutSeconds: 1 # 返回超时时间,单位为秒
Pod调度
在k8s中,Pod在大部分场景在都只是容器的载体而已,通常需要通过RC、Deployment、DaemonSet、Job等对象来完成Pod的调度与自动控制功能。
RC、Deployment全自动调度
RC的主要功能之一就是自动部署一个容器应用的多份副本,以及持续监控副本的数量,在集群内始终保持用户指定的副本数量。
Pod的调度策略除了有系统内置的Node调度算法,还可以在Pod的定义中使用NodeSelector或者NodeAffinity来指定满足条件的Node进行调度。