容器与pod资源对象
为什么Kubernetes要引入pod的概念,而不直接操作Docker容器
首先我们要明确一个概念,Kubernetes并不是只支持Docker这一个容器运行时,通过我的另一篇文章什么是Kubernetes的CRI-容器运行时接口介绍的内容,我们知道Kubernetes通过CRI这个抽象层,支持除Docker之外的其他容器运行时,比如rkt甚至支持客户自定义容器运行时。
- 第一个原因:借助CRI这个抽象层,使得Kubernetes不依赖于底层某一种具体的容器运行时实现技术,而是直接操作pod,pod内部再管理多个业务上紧密相关的用户业务容器,这种架构便于Kubernetes做扩展。
- 第二个原因,我们假设Kubernetes没有pod的概念,而是直接管理容器,那么一组容器作为一个单元,假设其中一个容器死亡了,此时这个单元的状态应该如何定义呢?应该理解成整体死亡,还是个别死亡?
这个问题不易回答的原因,是因为包含了这一组业务容器的逻辑单元,没有一个统一的办法来代表整个容器组的状态,这就是Kubernetes引入pod的概念,并且每个pod里都有一个Kubernetes系统自带的pause容器的原因,通过引入pause这个与业务无关并且作用类似于Linux操作系统守护进程的Kubernetes系统标准容器,以pause容器的状态来代表整个容器组的状态。
- 第三个原因:pod里所有的业务容器共享pause容器的IP地址,以及pause容器mount的Volume,通过这种设计,业务容器之间可以直接通信,文件也能够直接彼此共享。
Pod资源清单
下面是Pod的资源清单:
apiVersion: v1 #必选,版本号,例如v1
kind: Pod #必选,资源类型,例如 Pod
metadata: #必选,元数据
name: string #必选,Pod名称
namespace: string #Pod所属的命名空间,默认为"default"
labels: #自定义标签列表
- name: string
spec: #必选,Pod中容器的详细定义
containers: #必选,Pod中容器列表
- name: string #必选,容器名称
image: string #必选,容器的镜像名称
imagePullPolicy: [ Always|Never|IfNotPresent ] #获取镜像的策略
command: [string] #容器的启动命令列表,如不指定,使用打包时使用的启动命令
args: [string] #容器的启动命令参数列表
workingDir: string #容器的工作目录
volumeMounts: #挂载到容器内部的存储卷配置
- name: string #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符
readOnly: boolean #是否为只读模式
ports: #需要暴露的端口库号列表
- name: string #端口的名称
containerPort: int #容器需要监听的端口号
hostPort: int #容器所在主机需要监听的端口号,默认与Container相同
protocol: string #端口协议,支持TCP和UDP,默认TCP
env: #容器运行前需设置的环境变量列表
- name: string #环境变量名称
value: string #环境变量的值
resources: #资源限制和请求的设置
limits: #资源限制的设置
cpu: string #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
memory: string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
requests: #资源请求的设置
cpu: string #Cpu请求,容器启动的初始可用数量
memory: string #内存请求,容器启动的初始可用数量
lifecycle: #生命周期钩子
postStart: #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
preStop: #容器终止前执行此钩子,无论结果如何,容器都会终止
livenessProbe: #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
exec: #对Pod容器内检查方式设置为exec方式
command: [string] #exec方式需要制定的命令或脚本
httpGet: #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket: #对Pod内个容器健康检查方式设置为tcpSocket方式
port: number
initialDelaySeconds: 0 #容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 0 #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always | Never | OnFailure] #Pod的重启策略
nodeName: <string> #设置NodeName表示将该Pod调度到指定到名称的node节点上
nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上
imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定
- name: string
hostNetwork: false #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
volumes: #在该pod上定义共享存储卷列表
- name: string #共享存储卷名称 (volumes类型有很多种)
emptyDir: {
} #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
hostPath: string #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: string #Pod所在宿主机的目录,将被用于同期中mount的目录
secret: #类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
scretname: string
items:
- key: string
path: string
configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: string
items:
- key: string
path: string
#小提示:
# 在这里,可通过一个命令来查看每种资源的可配置项
# kubectl explain 资源类型 查看某种资源可以配置的一级属性
# kubectl explain 资源类型.属性 查看属性的子属性
[root@k8s-master01 ~]# kubectl explain pod
KIND: Pod
VERSION: v1
FIELDS:
apiVersion <string>
kind <string>
metadata <Object>
spec <Object>
status <Object>
[root@k8s-master01 ~]# kubectl explain pod.metadata
KIND: Pod
VERSION: v1
RESOURCE: metadata <Object>
FIELDS:
annotations <map[string]string>
clusterName <string>
creationTimestamp <string>
deletionGracePeriodSeconds <integer>
deletionTimestamp <string>
finalizers <[]string>
generateName <string>
generation <integer>
labels <map[string]string>
managedFields <[]Object>
name <string>
namespace <string>
ownerReferences <[]Object>
resourceVersion <string>
selfLink <string>
uid <string>
在kubernetes中基本所有资源的一级属性都是一样的,主要包含5部分:
apiVersion <string>
版本,由kubernetes内部定义,版本号必须可以用 kubectl api-versions 查询到kind <string>
类型,由kubernetes内部定义,版本号必须可以用 kubectl api-resources 查询到metadata <Object>
元数据,主要是资源标识和说明,常用的有name、namespace、labels等spec <Object>
描述,这是配置中最重要的一部分,里面是对各种资源配置的详细描述status <Object>
状态信息,里面的内容不需要定义,由kubernetes自动生成
在上面的属性中,spec是接下来研究的重点,继续看下它的常见子属性:
containers <[]Object>
容器列表,用于定义容器的详细信息nodeName <String>
根据nodeName的值将pod调度到指定的Node节点上nodeSelector <map[]>
根据NodeSelector中定义的信息选择将该Pod调度到包含这些label的Node 上hostNetwork <boolean>
是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络volumes <[]Object>
存储卷,用于定义Pod上面挂在的存储信息restartPolicy <string>
重启策略,表示Pod在遇到故障的时候的处理策略
管理pod中的容器
镜像及其获取策略
kubernetes支持用户自定义镜像文件的获取策略,例如在网络资源较为紧张时可以禁止从仓库中获取镜像文件等。容器的imagePullPolicy字段用于为其指定镜像获取策略,它的值可以包括以下几种
- Always:镜像标签为latest或镜像不存在时总是从指定的仓库中获取镜像
- IfNotPresent:仅当本地镜像缺失时方才从目标仓库下载镜像
- Never:禁止从仓库下载镜像,即仅使用本地镜像
默认值说明:
如果镜像tag为具体版本号, 默认策略是:IfNotPresent
如果镜像tag为:latest(最终版本) ,默认策略是always
[root@k8s-master1 ~]# cat pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-example
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Always
[root@k8s-master1 ~]# kubectl apply -f pod1.yaml
pod/pod-example configured
暴露端口
Docker的网络模型中,使用默认网络的容器化应用需要通过NAT将其暴露到外部网络中才能被其他节点之上的容器客户端所访问。然而kubernetes系统的网络模型中,各pod的ip地址处于同一网络平面上,无论是否为容器指定了要暴露的端口,都不会影响集群中其他节点之上的pod客户端对其进行访问,这就意味着,任何监听在非lo接口的端口都可以通过pod网络直接被请求
- 指定暴露端口为tcp的80,并将之命名为http
[root@k8s-master1 ~]# cat pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-example
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 80
protocol: TCP
[root@k8s-master1 ~]# kubectl delete pods pod-example
pod "pod-example" deleted
[root@k8s-master1 ~]# kubectl apply -f pod1.yaml
pod/pod-example created
[root@k8s-master1 ~]# curl 10.244.3.9 -I
HTTP/1.1 200 OK
Server: nginx/1.21.1
Date: Mon, 16 Aug 2021 16:18:22 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 06 Jul 2021 14:59:17 GMT
Connection: keep-alive
ETag: "60e46fc5-264"
Accept-Ranges: bytes
自定义运行的容器化应用
由docker镜像启动容器时运行的应用程序在相应的Dokcerfile中由ENTRYPOINT指令进行定义,传递给程序的参数则通过CMD指令指定,ENTRYPOINT指令不存在时,CMD可用于同时指定程序及其参数。
容器的command字段能够指定不同于镜像默认运行的应用程序,并且可以同时使用args字段进行参数传递,他们将覆盖镜像中的默认定义。
[root@k8s-master1 ~]# cat pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-example
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 80
protocol: TCP
command: ["/bin/sh"]
args: ["-c","while true;do sleep 30;done"]
[root@k8s-master1 ~]# kubectl delete pods pod-example
pod "pod-example" deleted
[root@k8s-master1 ~]# kubectl apply -f pod1.yaml
pod/pod-example created
[root@k8s-master1 ~]# kubectl get pods pod-example -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-example 1/1 Running 0 33s 10.244.3.10 k8s-node2 <none> <none>
创建pod-command.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-command
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;"]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q2TICaPq-1651206830823)(04.kubernetes pod资源/image-20210617224457945.png)]
command,用于在pod中的容器初始化完毕之后运行一个命令。
稍微解释下上面命令的意思:
“/bin/sh”,“-c”, 使用sh执行命令
touch /tmp/hello.txt; 创建一个/tmp/hello.txt 文件
while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done; 每隔3秒向文件中写入当前时间
# 创建Pod
[root@k8s-master01 pod]# kubectl create -f pod-command.yaml
pod/pod-command created
# 查看Pod状态
# 此时发现两个pod都正常运行了
[root@k8s-master01 pod]# kubectl get pods pod-command -n dev
NAME READY STATUS RESTARTS AGE
pod-command 2/2 Runing 0 2s
# 进入pod中的busybox容器,查看文件内容
# 补充一个命令: kubectl exec pod名称 -n 命名空间 -it -c 容器名称 /bin/sh 在容器内部执行命令
# 使用这个命令就可以进入某个容器的内部,然后进行相关操作了
# 比如,可以查看txt文件的内容
[root@k8s-master01 pod]# kubectl exec pod-command -n dev -it -c busybox /bin/sh
/ # tail -f /tmp/hello.txt
14:44:19
14:44:22
14:44:25
特别说明:
通过上面发现command已经可以完成启动命令和传递参数的功能,为什么这里还要提供一个args选项,用于传递参数呢?这其实跟docker有点关系,kubernetes中的command、args两项其实是实现覆盖Dockerfile中ENTRYPOINT的功能。
1 如果command和args均没有写,那么用Dockerfile的配置。
2 如果command写了,但args没有写,那么Dockerfile默认的配置会被忽略,执行输入的command
3 如果command没写,但args写了,那么Dockerfile中配置的ENTRYPOINT的命令会被执行,使用当前args的参数
4 如果command和args都写了,那么Dockerfile的配置被忽略,执行command并追加上args参数
pod资源限制
在kubernetes上,可由容器或Pod请求或消费的计算资源指的是cpu和内存。cpu属于可压缩型资源,即资源额度可按需收缩,而内存则是不可压缩型资源,对其执行收缩操作可能会导致某种程度的问题。
资源隔离属于容器级别,cpu和内存资源的配置需要在Pod中的容器上进行,每种资源均可由requests属性定义其请求的确保可用值,即容器运行可能用不到这些额度的资源,但用到时必须确保由如此多的资源可用,而limits属性则用于限制资源的可用的最大值。
Pod和Container的资源请求和限制:
• spec.containers[].resources.limits.cpu
• spec.containers[].resources.limits.memory
• spec.containers[].resources.requests.cpu
• spec.containers[].resources.requests.memory
- 定义资源请求和限制
[root@k8s-master1 ~]# cat pod-stress-ng.yaml
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
-