k8s 资源管理之 Pod

Posted 看,未来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了k8s 资源管理之 Pod相关的知识,希望对你有一定的参考价值。

文章目录

导读:k8s的资源管理

Kubernetes 的本质就是一个集群系统,用户可以在集群中部署各种服务。所谓的部署服务,其实就是在 Kubernetes 集群中运行一个个的容器,并将指定的程序跑在容器中。
Kubernetes 的最小管理单元是 Pod 而不是容器,所以只能将容器放在 Pod 中,而 Kubernetes 一般也不会直接管理 Pod ,而是通过 Pod 控制器来管理 Pod 的。
Pod 提供服务之后,就需要考虑如何访问 Pod 中的服务,Kubernetes 提供了 Service 资源实现这个功能。
当然,如果 Pod 中程序的数据需要持久化,Kubernetes 还提供了各种存储系统。


Pod

● Pod是kubernetes集群进行管理的最小单元,程序要运行必须部署在容器中,而容器必须存在于Pod中。
● Pod可以认为是容器的封装,一个Pod中可以存在一个或者多个容器。

为什么需要 Pod?

先分析一下容器的本质:

namespace做隔离

Cgroup做限制

rootfs做文件系统

三者相辅相成组成容器基本模型

但是,宏观的来说,容器的本质是系统中的一个进程。只不过这个进程启动时被附加了以上等等一些特殊的属性。

所谓容器只是一个恰当的说法。

就如系统中的大多数进程来说,不是单个进程独自工作,而是以“进程组”的方式“原则性”的组织在一起,互相协作,完成复杂任务。当然,它们之间也会共享一些资源,例如pid,namespace,存储等等。

在实际开发和运维中也是随处可见的这种问题,应用之间有深切的联系和依赖。

比如说,我要将一个应用容器化,这个应用由负责各个功能的5个进程组成,这时候,问题来了。

正是容器的局限性:单进程模型

单进程不是指容器中只能运行一个进程,而是容器无法去管理多个进程

例如,容器中有pid=1的进程,还有一个pid=5的进程,当这个pid=5的进程异常退出时,后续的垃圾回收等处理工作又由谁去做呢?

所以,这个应用的5个模块就必须分别制成5个容器,而且必须在同一个机器上运行。

随之而来的又是一个问题:

也就是容器调度问题,例如有两个容器调度节点node1和node2,可用内存分别为5G和4.5G,

每个容器分1G内存。由于5个容器必须在一台机器,正常全部调度到node1刚刚好,没有任何问题。

但是,因为是以容器为单位调度,有这样一些特殊情况。当前4个容器被调度到node2上时,空间只有0.5G,不足以运行最后一个容器,它有只能在node1运行,这就是以容器为调度单位的缺点。

当然也有解决方案:如Mesos中的资源囤积(resource hoarding),也就是所有调度任务都到达了才进行调度,也有谷歌Omega论文提出乐观调度,就是先不管冲突,而是在冲突之后通过一系列回滚机制解决冲突。

但这些都没有很完善的解决容器调度问题,但是在kubernetes中,这些问题都迎刃而解。

因为不再按照传统思维的将容器作为调度单位,kubernetes中的项目调度器是统一按照pod的资源需求做调度计算,也就是开始总结的那句话: pod是kubernetes项目的原子调度单位


pod结构

如图所示,一个pod包含了两类容器:

  • 用户容器
  • Pause容器,也常常被称为“根容器”(老版本叫做infra容器)

用户容器好理解,但是Pause容器,也就是根容器,他是做什么用的呢?

pause容器主要为每个用户容器提供以下功能:

① PID命名空间:Pod中的不同应用程序可以看到其他应用程序的进程ID。

② 网络命名空间:Pod中的多个容器能够访问同一个IP和端口范围。

③ IPC命名空间:Pod中的多个容器能够使用SystemV IPC或POSIX消息队列进行通信。

④ UTS命名空间:Pod中的多个容器共享一个主机名。

⑤ Volumes(共享存储卷):Pod中的各个容器可以访问在Pod级别定义的Volumes。


pod实现原理

一定要明白一点:pod只是一个逻辑上的概念

因为kubernetes真正处理的还是宿主机操作系统上容器的Namespace和Cgroup,也就是说没有所谓的pod边界或隔离环境。

所以说,pod就是一组共享了某些资源的容器

在一个pod中所有容器是共享一个Network Namespace的,根据声明的不同来实现不同的资源共享

但是容器间的复杂关系在容器上难以解决,所以kubernetes项目里,pod的实现借用了一个中间容器,也就是常常说的根容器

在pod中,根容器永远是第一个创建的容器,用户后面定义的容器会加入进pod的Network Namespace,从而在视图上容器都在pod里。

不妨在k8s中看看这个容器镜像:

[root@master ~]# docker images | grep pause
registry.aliyuncs.com/google_containers/pause                     3.2        80d28bedfe5d   15 months ago   683kB

#当然,主机上有多少个pod就能docker ps 过滤看到多少pause容器

pause镜像大小只有683k,它是由汇编语言写的镜像

在一个pod中的容器,它们的Namespace文件,是一样的

也就意味着:

  • pod内的容器可以使用localhost进行通信
  • 根容器能看到的网络资源,其他容器都能看到,也就是pod的网络资源和pod内的容器共享
  • 一个pod有一个ip地址,和pod对应的Network namespace的ip一致
  • pod的生命周期只与根容器有关,与pod内的容器无关
  • 从pod里的容器的视角来说,它们的流量进出可以看做是通过根容器完成的

pod 操作

1、当我们搭建成功集群之后,可以看到已经有几个 Pod 在运行中了,这是支持我们集群运行的重要组件:

kubectl get pods -A

在实习的时候不常用 -A,实在太多了,都是用 -n 筛选一下命名空间,比如这里就可以这样:

当然,有时候筛选过还是很多,可以用 grep 做正则表达式再筛选。

2、 创建一个 pod

kubectl run mynginx --image=nginx[:1.17.1] --port=80 [--namespace=dev]

这里的镜像它会去下载,如果本地没有的话。这里的本地指的是 k8s 存储镜像的地方。

3、 查看 pod 的详细信息

kubectl describe pod pod的名称 [-n 命名空间名称]

4、访问容器

kubectl get pods -n dev -o wide

获取到容器 IP。

使用配置文件形式

让我们以配置文件的形式复现一下上述操作:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
spec:
  containers:
  - image: nginx:1.17.1
    imagePullPolicy: IfNotPresent
    name: pod
    ports: 
    - name: nginx-port
      containerPort: 80
      protocol: TCP
kubectl create -f pod-nginx.yaml
kubectl delete -f pod-nginx.yaml

k8s 镜像拉取策略

注意看这一行:imagePullPolicy: IfNotPresent
k8s 有三个镜像拉取策略:

  • Always 镜像标签为latest或镜像不存在时总是从指定的仓库中获取镜像
  • IfNotPresent 仅当本地镜像缺失时方才从目标仓库下载镜像
  • Never 禁止从仓库下载镜像,即仅使用本地镜像

对于标签latest的镜像文件,其默认的镜像获取策略即为Always,而对于其他标签的镜像,其默认策略则为IfNotPresent。需要注意的是,使用私有仓库中的镜像时通常需要由Registry服务器完成认证后才能进行。认证过程要么需要在相关节点上交互式执行docker login命令来进行,要么就是将认证信息定义为专有的Secret资源,并配置Pod通过imagePullSecredtes字段调用此认证信息完成。


对于这个配置文件的写法,我特地做了个表格,不放出来可惜了。

Pod 配置文件速查表

属性名称取值类型是否必选取值说明
apiVersion: v1StringRequried版本号,例如v1,版本号必须可以用 kubectl api-versions 查询到
kind: PodStringRequriedPod
metadata:ObjectRequried元数据
name: stringStringRequriedPod名称,需符合RFC 1035规范
namespace: stringStringRequriedPod所属的命名空间,默认为"default"
labels:List自定义标签
- name: stringString自定义标签名字
annotations:List自定义注释列表
- name: string
spec:ObjectRequriedPod中容器的详细定义
containers:ListRequriedPod中容器列表
- name: stringStringRequried容器名称,需符合RFC 1035规范
image: stringStringRequried容器的镜像名称
imagePullPolicy: [ Always|Never|IfNotPresent ]String获取镜像的策略,默认值为Alawys,Alawys表示每次都尝试下载镜像,IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
command: [string]List容器的启动命令列表,如不指定,使用打包时使用的启动命令
args: [string]List容器的启动命令参数列表
workingDir: stringString容器的工作目录
volumeMounts:List挂载到容器内部的存储卷配置
- name: stringString引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
mountPath: stringString存储卷在容器内mount的绝对路径,应少于512字符
readOnly: booleanBoolean是否为只读模式,默认为读写模式
ports:List需要暴露的端口库号列表
- name: stringString端口的名称
containerPort: intInt容器需要监听的端口号
hostPort: intInt容器所在主机需要监听的端口号,默认与Container相同
protocol: stringString端口协议,支持TCP和UDP,默认TCP
env:List容器运行前需设置的环境变量列表
- name: stringString环境变量名称
value: stringString环境变量的值
resources:Object资源限制和请求的设置
limits:Object资源限制的设置
cpu: stringStringCPU的限制,单位为core数,将用于docker run --cpu-shares参数
memory: stringString内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
requests:Object资源限制的设置
cpu: stringStringCPU请求,容器启动的初始可用数量
memory: stringString内存请求,容器启动的初始可用数量
livenessProbe:Object对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器,可设置的方法包括exec、httpGet和tcpSocket,对一个容器仅需设置其中一种健康检查方法
exec:Object对Pod容器内检查方式设置为exec方式
command: [string]Stringexec方式需要制定的命令或脚本
httpGet:Object对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket:Object对Pod内个容器健康检查方式设置为tcpSocket方式
port: number
initialDelaySeconds: 0Number容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 0Number对容器健康检查探测等待响应的超时时间,单位秒,默认1秒,若超过该超时时间设置,则认为该容器不健康,会重启该容器
periodSeconds: 0Number对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always | Never | OnFailure]StringPod的重启策略,(1)Always表示一旦不管以何种方式终止运行,kubelet都将重启它,(2)OnFailure表示只有Pod以非0退出码退出才重启,如果容器正常结束(退出码为0)kubelet将不会重启它,(3)Nerver:Pod终止后,kubelet将退出码报告给Master,不会再重启该Pod。
nodeSelector: obejectObject设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
imagePullSecrets:ObjectPull镜像时使用的secret名称,以name:secretkey格式指定
- name: string
hostNetwork: falseBoolean是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络,不再使用Docker网桥,该Pod将无法在同一宿主机上启动第2哥副本
volumes:List在该pod上定义共享存储卷列表
- name: stringString共享存储卷名称 ,在一个Pod中每个存储卷定义一个名称,应符合RFC 1035规范。容器定义部分的containers[].volumeMounts[].name将引用该共享存储卷的名称。Volume的类型包括:emptyDir、hostPath、gcePersistentDisk、awsElasticBlockStore、gitRepo、secret、nfs、iscsi、glusterfs、persistentVolumeClaim、rbd、flexVolume、cinder、cephfs、flocker、downwardAPI、fc、azureFile、configMap、vsphereVolume,可以定义多个Volume,每个Volume的name保持唯一。
emptyDir: Object类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
hostPath: stringObject类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: stringStringPod所在宿主机的目录,将被用于同期中mount的目录
secret:Object类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
scretname: string
items:
- key: string
path: string
configMap:Object类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: string
items:
- key: string
path: string

滚动更新 pod

  • 更新
kubectl replace -f hello-world-pod.yaml

但是由于Pod的很多属性没办法修改,比如容器镜像,这时候可以采用–force参数

  • 重建Pod
kubectl replace --force -f hello-world-pod.yaml


删除Pod

  • 通过kubectl delete删除指定Pod
kubectl delete pod hello-world
  • 通过kubectl delete批量删除全部Pod
kubectl delete pod --all

如果是由 kubectl run 直接构建的 pod,一删就没了。但是如果是由 deployment 构建的 pod,就没那么好删了,“deployment 详解” 的文正在赶来的路上。


静态 Pod

(这个部分目前来看,但当涉猎)

什么是 Static Pod

静态 Pod 在指定的节点上由 kubelet 守护进程直接管理,不需要 API 服务器监管。 与由控制面管理的 Pod(例如,[Deployment]) 不同;kubelet 监视每个静态 Pod(在它崩溃之后重新启动)。

静态 Pod 永远都会绑定到一个指定节点上的 [Kubelet]。

kubelet 会尝试通过 Kubernetes API 服务器为每个静态 Pod 自动创建一个 [镜像 Pod]。 这意味着节点上运行的静态 Pod 对 API 服务来说是可见的,但是不能通过 API 服务器来控制。 Pod 名称将把以连字符开头的节点主机名作为后缀。

最常见的 Static Pod

  • etcd
  • kube-apiserver
  • kube-controller-manager
  • kube-scheduler

创建静态Pod有两种方式:配置文件方式和HTTP方式。

配置文件方式

可以通过kubelet的启动参数查看kubelet扫描静态Pod配置文件的路径,如下:

可以到kubelet是由这个配置文件进行启动的,在通过查看此配置文件,内容如下:

apiVersion: kubelet.config.k8s.io/v1beta1
.....
.....
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s

其中staticPodPath: /etc/kubernetes/manifests就是正在运行的kubelet需要监控的配置文件所在的目录,kubelet会定期扫描该目录,并根据该目录下的.yaml或.json文件进行创建操作。

在目录/etc/kubernetes/manifests中放入static-web.yaml文件,内容如下:

---

apiVersion: v1
kind: Pod
metadata:
   name: static-web
   labels:
     name: static-web
spec:
    containers:
    - name: static-web
      image: nginx
      ports:
      - name: web
        containerPort: 80

等待一会儿,查看本机中已经启动的容器:

[root@k8s-node0 ~]# docker ps|grep static-web
85fd075aaddd        nginx                                               "/docker-entrypoint.…"   About an hour ago   Up About an hour                        k8s_static-web_static-web-k8s-node0_default_d9890f08374e33f99c31a2a034276178_0

可以看到一个Nginx容器已经被kubelet成功创建了出来。

到Master上查看Pod列表,可以看到这个static pod:

[root@k8s-master ~]# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
nginx-f89759699-gn2wn   1/1     Running   1          17h
static-web-k8s-node0    1/1     Running   0          12s

由于静态Pod无法通过API Server直接管理,所以在Master上尝试删除这个Pod时,会使其变成Pending状态,且不会被删除。

[root@k8s-master ~]# kubectl delete pod static-web-k8s-node0
pod "static-web-k8s-node0" deleted
[root@k8s-master ~]# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
nginx-f89759699-gn2wn   1/1     Running   1          18h
static-web-k8s-node0    0/1     Pending   0          2s

删除该Pod的操作只能是到其所在Node上将其定义文件static-web.yaml从/etc/kubernetes/manifests目录下删除。

[root@k8s-node0 ~]# rm /etc/kubernetes/manifests/static_pod_web_nginx.yaml
rm: remove regular file ‘/etc/kubernetes/manifests/static_pod_web_nginx.yaml’? y
[root@k8s-node0 ~]# docker ps|grep static-web
[root@k8s-node0 ~]# docker ps|grep static-web

在Master上查看这个Pod:

[root@k8s-master ~]# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
nginx-f89759699-gn2wn   1/1     Running   1          18h

HTTP方式

通过设置kubelet的启动参数–manifest-url或kubelet的配置文件加上此配置项,kubelet将会定期从该URL地址下载Pod的定义文件,并以.yaml或.json文件的格式进行解析,然后创建Pod。其实现方式与配置文件方式是一致的。


关于 Pod 的内容还没结束,Pod 的内容实在是太多了。

以上是关于k8s 资源管理之 Pod的主要内容,如果未能解决你的问题,请参考以下文章

08—K8S之Deployment 资源

08—K8S之Deployment 资源

08—K8S之Deployment 资源

08—K8S之Deployment 资源

k8s自主式pod之应用策略规则

K8s 之 Pod 高级用法