天天看点

K8S:Pod资源管理

认识 Pod

Pod是Kubernetes的最基本操作单元,也是应用运行的载体,包含一个到多个密切相关的容器。整个Kubernetes系统都是围绕着Pod展开的,比如如何运行Pod、如何保证Pod的数量、如何访问Pod等。

特点:

·pod是对象;

最小的部署单元,最基本的管理单元;

一组容器的集合;(为便于管理,生产环境一般情况是放一个容器)

一个pod中的容器共享网络命名空间,相当于小型局域网;

pod是有生命周期的,所以是短暂的

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/busybox
    args:
    - /bin/sh
    --c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 30
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5
           

定义文件中Pod的主要要素如下:

1)apiVersion:Kubernetes的API版本声明,目前是v1。

2)kind:API对象的类型声明,当前类型是Pod。

3)metadata:设置Pod的元数据。

■ name:指定Pod的名称,Pod名称必须在namespace内唯一,需符合RFC1035规范。

■ namespace:命名空间,不指定时将使用名为“default”的命名空间。

■ labels:自定义标签属性列表。

可根据需要对所创建的Pod自定义标签,再利用Service或者ReplicationController的Label Selector来选择自定义的Pod。

4)spec:配置Pod的详细描述。

■ containers:Pod中运行的容器列表,数组形式,每一项定义一个容器。

■ name:指定容器的名称,在Pod的定义中唯一。

■ image:设置容器镜像名,在Node上如果不存在该镜像,则Kubelet会先下载。

■ command:设置容器的执行命令。

Pod容器的分类

官方网站:https://kubernetes.io/docs/concepts/workloads/pods/init-containers/

1: infrastructure container 基础容器

维护整个Pod网络空间

查看容器的网络
# docker ps -a 
registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0

在kubelet配置文件中已经定义好了
# cat /opt/kubernetes/cfg/kubelet
--pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0
           

基础容器跟着kubelet一起产生的

Kubelet创建好了之后 去提交申请给master,master同意证书许可颁发的时候,开始建基础容器,基础容器有了之后,在建初始化容器,加载完初始化容器,再加载业务容器

2:initcontainers 初始化容器

先于业务容器开始执行

在之前版本,初始化容器与业务容器是并行开启的,现在进行了改进

3:container 业务容器

业务容器就是真正提供服务的

app容器就是业务容器

apply和create都可以创建资源,不过 apply还可以更新资源

镜像拉取策略(image PullPolicy)

Pod被分配到Node之后会根据镜像下载策略进行镜像下载,因此,用户可以根据自身集群的特点来决定采用何种下载策略。无论何种策略,都要确保Node上有正确的镜像可用。

有以下3种:

IfNotPresent: 默认值,镜像在本地没有的时候才下载镜像。

Always: 每次创建Pod都会重新拉取一次镜像,每次都下载最新的镜像。

Never: Pod永远不会主动拉取这个镜像,只使用本地镜像,从不下载。

示例:

# vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: nginx
      image: nginx
      imagePullPolicy: Always
定义镜像拉取策略为Always
           

定义了镜像拉取策略是Always,也就是说,每次创建Pod都会重新拉取一次镜像

K8S:Pod资源管理
创建启动pod
# kubectl create -f pod1.yaml
查看pod状态
# kubectl get pods
详细查看pod创建过程
# kubectl describe pod mypod
           
K8S:Pod资源管理

详细查看pod创建过程

K8S:Pod资源管理

Pod 资源限制

出于安全考虑,生产环境中需要给资源进行限制,可通过CPU和内存两个方便做配置

官网解释:https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/

Pod和Container的资源请求和限制:

spec.containers[].resources.limits.cpu //cpu上限

spec.containers[].resources.limits.memory //内存上限

spec.containers[].resources.requests.cpu //创建时分配的基本CPU资源

spec.containers[].resources.requests.memory //创建时分配的基本内存资源

如果运行Pod的节点有足够的可用资源,则容器有可能使用比该request资源指定的资源更多的资源。但是,容器不能使用超出其资源的范围limit。

示例:

以下Pod具有两个容器。每个容器都有0.25 cpu的请求和64MiB(2 26字节)的内存。每个容器的限制为0.5 cpu和128MiB的内存。可以说Pod的请求为0.5 cpu和128 MiB的内存,限制为1 cpu和256MiB的内存。

# vim pod2.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"
    - name: wp
    image: wordpress
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
           
K8S:Pod资源管理
# kubectl apply -f pod2.yaml
# kubectl get pods
# kubectl get pods -o wide
           

创建一个pod资源 frontend,分配到node2节点

K8S:Pod资源管理

Node2节点:

查看两个容器 状态

# docker ps -a | greo wordpress
# docker ps -a | grep mysql
           

Master1节点:

详细查看创建过程
# kubectl describe pod frontend
查看资源状态
# kubectl describe nodes 192.168.195.150

           
K8S:Pod资源管理

以上每个数据是两个容器的总和

特定资源类型的 Pod资源请求/限制是Pod中每个Container的该类型资源请求/限制的总和。

重启策略restartPolicy

RestartPolicy:设置Pod的重启策略。

该Pod内容器的重启策略可选值为Always、OnFailure以及Never,默认值为Always。Pod重启策略选择Always时,容器一旦终止运行,无论容器是如何终止的,Kubelet都将重启它。Pod重启策略选择OnFailure时,只有容器以非零退出码终止时Kubelet才会重启该容器。如果容器正常结束(退出码为0),则Kubelet将不会重启它。Pod重启策略选择Never时,容器终止后Kubelet将退出码报告给Master,不再重启它。

(注意: k8s 中不支持重启Pod资源,只有删除重建)

1: Always: 当容器终止退出后,总是重启容器,默认策略

2: OnFailure: 当容器异常退出(退出状态码非0)时,重启容器

3: Never: 当容器终止退出,从不重启容器。

示例1:

不指定重启策略 ,查看他的默认策略是否是Always,看重启状态

Master1节点:
# cd demo
# vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - /bin/sh
    --c
    - sleep 30; exit 3
           

创建完容器之后,休眠30秒,异常退出,非0值,就会进行重启

# kubectl apply -f pod3.yaml

查看到重启次数加1
# kubectl get pods -w
..........
foo  	1/1 		Running  	0  	12s
foo 		0/1		Error		0	43s
foo		1/1		Running		1	44s
foo		0/1		Error 		1	74s
foo		0/1	CrashloopBackoff	1	85s

# kubectl get pods
foo		1/1 		CrashloopBackoff		2		 99s
           

查看到重启次数变为2,并且会一直重启,验证了默认重启策略是Always: 当容器终止退出后,总是重启容器

K8S:Pod资源管理

这个资源如果不删,会一直反复重启

#kubectl delete -f pod3.yaml

示例2:

重启策略为Never

修改重启策略
# vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 10
  restartPolicy: Never

# kubectl apply -f pod3.yaml

完成状态不会进行重启
# kubectl get pods
foo		0/1 		Completed		0		 99s
           
K8S:Pod资源管理

完成状态不会进行重启

K8S:Pod资源管理

健康状态检查

许多长时间运行的应用程序最终会转换为损坏的状态,除非重新启动,否则无法恢复。Kubernetes提供了活动性探针来检测和纠正这种情况。

健康检查:又称为探针( Probe)

注意: 规则可以同时定义

livenessProbe:如果检查失败,将杀死容器,根据Pod的restartPolicy来操作。

ReadinessProbe:如果检查失败,kubernetes 会把Pod从service endpoints中剔除。

Probe支持三种检查方法:

httpGet:发送http请求,返回200-400范围状态码为成功。

exec:执行Shell命令返回状态码是0为成功。

tcpSocket:发起TCP Socket建立成功

官网:https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/

探针支持的3种检查方式的用法示例如下

Master1节点:

示例1:

探针检查pod资源状态

exec方式:

将创建一个Pod,该Pod可基于k8s.gcr.io/busybox图像运行容器 。

定义了健康检查的livenessProbe规则

# vim pod4.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 30
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5
           

periodSeconds字段:指定kubelet应该每5秒执行一次活动性探测。

initialDelaySeconds字段:告诉kubelet在执行第一个探测之前应等待5秒钟

为了执行探测,kubelet cat /tmp/healthy在目标容器中执行命令。

如果命令成功执行,则返回0,并且kubelet认为该容器处于活动状态且健康。

如果命令返回非零值,则kubelet将杀死容器并重新启动它。

在容器寿命的前30秒内,有一个/tmp/healthy文件。因此,

在前30秒内,该命令cat /tmp/healthy将返回成功代码。

30秒后,cat /tmp/healthy返回失败代码。

# kubectl apply -f pod4.yaml

查看重启状态的变化
# kubectl get pods -w

# kubectl get pods
           
K8S:Pod资源管理

会反复进行 运行关闭重启容器,这就是 健康检查中的livenessProbe规则

K8S:Pod资源管理

示例2:

定义活动HTTP请求

另一种活动性探针使用HTTP GET请求。这是基于k8s.gcr.io/liveness 映像运行容器的Pod的配置文件。

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/liveness
    args:
    - /server
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
        httpHeaders:
        - name: Custom-Header
          value: Awesome
      initialDelaySeconds: 3
      periodSeconds: 3
           

在配置文件中,可以看到Pod具有单个容器。

该periodSeconds字段指定kubelet应该每3秒执行一次活动性探测。

该initialDelaySeconds字段告诉kubelet在执行第一个探测之前应等待3秒。

为了执行探测,kubelet将HTTP GET请求发送到在容器中运行并正在侦听端口8080的服务器。

如果服务器/healthz路径的处理程序返回成功代码,则kubelet会认为该容器处于活动状态并且运行状况良好。

如果处理程序返回失败代码,则kubelet将杀死容器并重新启动它。

任何大于或等于200且小于400的代码均表示成功。其他任何代码均指示失败。

您可以在server.go中查看服务器的源代码 。

在容器/healthz处于活动状态的前10秒钟中,处理程序返回状态200。此后,处理程序返回状态500。

容器启动后三秒钟,kubelet将开始执行运行状况检查。因此,前几次健康检查将成功。但是10秒钟后,运行状况检查将失败,并且kubelet将终止并重新启动容器。

示例3:

定义TCP活动度探针

第三种类型的活动性探针使用TCP套接字。使用此配置,kubelet将尝试在指定端口上打开容器的套接字。如果可以建立连接,则认为该容器运行状况良好,如果不能建立连接,则视为故障。

apiVersion: v1
kind: Pod
metadata:
  name: goproxy
  labels:
    app: goproxy
spec:
  containers:
  - name: goproxy
    image: k8s.gcr.io/goproxy:0.1
    ports:
    - containerPort: 8080
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20
           

TCP检查的配置与HTTP检查非常相似。

容器启动后5秒钟内,kubelet将发送第一个就绪探测器。这将尝试连接到goproxy端口8080上的容器。

如果探测成功,则Pod将标记为就绪。kubelet将继续每10秒运行一次此检查。

容器启动后15秒钟,kubelet将运行第一个活动探针。如果活动探针失败,则将重新启动容器。

exec用的比较多,先写规则,在写探测方法

http和tcp两种方式探测,容易带来日志访问统计误差,所以不常用

调度约束,指定分配调度

Kubernetes通过watch的机制进行每个组件的协作,每个组件之间的设计实现了解耦。

watch机制是APIserver触发的

K8S:Pod资源管理

K8S调度过程:

1: 客户要创建资源时,会发给APIserver,APIserver会把pod资源的属性信息发给etcd,写入到etcd;

2: etcd记载完成后,会返回记载完成指令给APIserver;

3: APIserver触发watch机制,发给scheduler信息,我要创建pod资源,请你给我调度分配;

4: scheduler进行评分,通过调度算法 算出来的,并把即将要绑定的pod所在的node节点IP等信息,返回给APIserver;

5: APIserver调动etcd,写入pod和nodeIP等信息,etcd记载完成,再返回状态给APIserver;

6: APIserver又会通过watch机制,分配到指定node节点当中,通过kubelet绑定对应的node节点,分配对应的pod地址,下载镜像是触发docker run 找到docker下载基础镜像,完成后 容器状态反馈给kubelet;

7: kubelet把容器启动状态信息, 返回给APIserver;

8: APIserver再次调用etcd,把状态信息写入到etcd中;etcd记载完成,再返回状态给APIserver;

Etcd 3个阶段:

记录pod的元信息基本属性

记录pod分配的node节点信息

记录pod的状态信息

调度约束的两种方式

nodeName: 用于将Pod调度到指定的Node名称上 (跳过调度器直接分配)

nodeSelector: 用于将Pod调度到匹配Label的Node上

示例1:nodeName方式

# vim pod5.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-example
  labels:
    app: nginx
spec:
  nodeName: 192.168.195.150
  containers:
  - name: nginx
    image: nginx:1.15
           
K8S:Pod资源管理
# kubectl apply -f pod5.yaml
# kubectl get pods

详细查看创建过程
# kubectl describe pod pod-example
           

可看到 没有经过scheduler调度器

K8S:Pod资源管理

示例2:nodeSelector 方式

给对应的node设置标签分别为kgc=a和kgc=b

# cd demo
# kubectl label nodes 192.168.195.150 kgc=a
node/192.168.195.150 labeled
# kubectl label nodes 192.168.195.151 kgc=b
node/192.168.195.151 labeled

查看标签
# kubectl get nodes --show-labels
           
K8S:Pod资源管理

修改 pod5.yaml文件,改为 nodeSelector 调度约束方式

先把上面的pod资源删除
#  kubectl delete -f pod5.yaml
pod "pod-example" deleted

然后进行修改:
# vim pod5.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-example
labels:
app: nginx
spec:
nodeSelector:
  kgc: b
containers: 
- name: nginx
image: nginx:1.15
           
K8S:Pod资源管理

重新创建并运行pod资源

# kubectl apply -f pod5.yaml
# kubectl get pods -o wide

查看详细事件(通过事件可以观察经过调度器分配)
# kubectl describe pod pod-example
           

通过nodeSelector调度约束方式,通过调度器Schedular进行调度分配到 指定分配node节点

K8S:Pod资源管理
pod资源状态故障排查:
描述
Pending Pod已经被创建,但是一个或者多个容器还未创建,这包括Pod调度阶段,以及容器镜像的下载过程。Pod创建已经提交到Kubernetes。 但是 因为某种原因而不能顺利创建。例如下载镜像慢,调度不成功。
Running Pod已经被调度到Node,所有容器已经创建,并且至少一个容器在运行或者正在重启。Pod已经绑定到一个节点,并且已经创建了所有容器。至少有一个容器正在运行中,或正在启动或重新启动。
Succeeded Pod中的所有容器都已成功终止Pod中所有容器正常退出。,不会重新启动。
Failed Pod的所有容器均已终止,且至少有一个容器已在故障中终止。容器要么以非0状态退出,要么被系统终止。
Unknown 由于某种原因apiserver无法获得Pod的状态,通常是由于Master与 Pod所在主机kubelet通信时出错。

通常先进行以下检查

查看pod事件
kubectl describe TYPE NAME_PREFIX

查看pod日志(Failed 状态下)
kubectl logs POD_NAME

进入pod (状态为running,但是服务没有提供)
kubectl exec -it POD_NAME bash