Pod中如何管理多个容器
Pod中可以同时运行多个进程(作为容器运行)协同工作。同一个Pod中的容器会自动的分配到同一个 node 上。同一个Pod中的容器共享资源、网络环境和依赖,它们总是被同时调度。
注意在一个Pod中同时运行多个容器是一种比较高级的用法。只有当你的容器需要紧密配合协作的时候才考虑用这种模式。例如,你有一个容器作为web服务器运行,需要用到共享的volume,有另一个“sidecar”容器来从远端获取资源更新这些文件,如下图所示:
Pod中可以共享两种资源:网络和存储。
-
网络:每个Pod都会被分配一个唯一的IP地址。Pod中的所有容器共享网络空间,包括IP地址和端口。Pod内部的容器可以使用
localhost互相通信。Pod中的容器与外界通信时,必须分配共享网络资源(例如使用宿主机的端口映射)。
- 存储:可以Pod指定多个共享的Volume。Pod中的所有容器都可以访问共享的volume。Volume也可以用来持久化Pod中的存储资源,以防容器重启后文件丢失。
Pod容器分类
•Infrastructure Container:基础容器,维护整个Pod网络空间
•InitContainers:初始化容器,先于业务容器开始执行
•Containers:业务容器,并行启动
kubernetes中pod创建流程
Pod是Kubernetes中最基本的部署调度单元,可以包含container,逻辑上表示某种应用的一个实例。例如一个web站点应用由前端、后端及数据库构建而成,这三个组件将运行在各自的容器中,那么我们可以创建包含三个container的pod。
具体的创建步骤包括:
(1)客户端提交创建请求,可以通过API Server的Restful API,也可以使用kubectl命令行工具。支持的数据类型包括JSON和YAML。 (2)API Server处理用户请求,存储Pod数据到etcd。 (3)调度器通过API Server查看未绑定的Pod。尝试为Pod分配主机。 (4)过滤主机 (调度预选):调度器用一组规则过滤掉不符合要求的主机。比如Pod指定了所需要的资源量,那么可用资源比Pod需要的资源量少的主机会被过滤掉。 (5)主机打分(调度优选):对第一步筛选出的符合要求的主机进行打分,在主机打分阶段,调度器会考虑一些整体优化策略,比如把容一个Replication Controller的副本分布到不同的主机上,使用最低负载的主机等。 (6)选择主机:选择打分最高的主机,进行binding操作,结果存储到etcd中。 (7)kubelet根据调度结果执行Pod创建操作: 绑定成功后,scheduler会调用APIServer的API在etcd中创建一个boundpod对象,描述在一个工作节点上绑定运行的所有pod信息。运行在每个工作节点上的kubelet也会定期与etcd同步boundpod信息,一旦发现应该在该工作节点上运行的boundpod对象没有更新,则调用Docker API创建并启动pod内的容器。
调度约束
https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
scheduler组件
k8s调度器会将pod调度到资源满足要求并且评分最高的node上。
我们可以使用多种规则比如:
1.设置cpu、内存的使用要求
2.增加node的label,并通过pod.Spec.NodeSelector进行强匹配;
3.直接设置pod的nodeName,跳过调度直接下发。
k8s 1.2加入了一个实验性的功能:affinity。意为亲和性。这个特性的设计初衷是为了替代nodeSelector,并扩展更强大的调度策略。
调度器的工作机制是这样的
一、预备工作 1、缓存所有的node节点,记录他们的规格:cpu、内存、磁盘空间、gpu显卡数等; 2、缓存所有运行中的pod,按照pod所在的node进行区分,统计每个node上的pod request了多少资源。request是pod的QoS配置。 3、list & watch pod资源,当检查到有新的Pending状态的pod出现,就将它加入到调度队列中。 4、调度器的worker组件从队列中取出pod进行调度。 二、调度过程 1、先将当前所有的node放入队列; 2、执行predicates算法,对队列中的node进行筛选。这里算法检查了一些pod运行的必要条件,包括port不冲突、cpu和内存资源QoS(如果有的话)必须满足、挂载volume(如果有的话)类型必须匹配、nodeSelector规则必须匹配、硬性的affinity规则(下文会提到)必须匹配、node的状态(condition)必须正常,taint_toleration硬规则(下文会提到)等等。 3、执行priorities算法,对队列中剩余的node进行评分,这里有许多评分项,各个项目有各自的权重:整体cpu,内存资源的平衡性、node上是否有存在要求的镜像、同rs的pod是否有调度、node affinity的软规则、taint_toleration软规则(下文会提到)等等。 4、最终评分最高的node会被选出。即代码中suggestedHost, err := sched.schedule(pod)一句(plugin/pkg/scheduler/scheduler.go)的返回值。 5、调度器执行assume方法,该方法在pod调度到node之前,就以“该pod运行在目标node上” 为场景更新调度器缓存中的node 信息,也即预备工作中的1、2两点。这么做是为了让pod在真正调度到node上时,调度器也可以同时做后续其他pod的调度工作。 6、调度器执行bind方法,该方法创建一个Binding资源,apiserver检查到创建该资源时,会主动更新pod的nodeName字段。完成调度
nodeSelector用于将Pod调度到匹配Label的Node上
将标签附加到node
[root@k8s-master1 ~]# kubectl label nodes 192.168.0.126 env_role=dev node/192.168.0.126 labeled [root@k8s-master1 ~]# kubectl label nodes 192.168.0.125 env_role=test node/192.168.0.125 labeled [root@k8s-master1 ~]# kubectl get nodes --show-labels NAME STATUS ROLES AGE VERSION LABELS 192.168.0.125 Ready <none> 2d4h v1.13.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,env_role=test,kubernetes.io/hostname=192.168.0.125 192.168.0.126 Ready <none> 2d4h v1.13.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,env_role=dev,kubernetes.io/hostname=192.168.0.126
将nodeSelector字段添加到pod配置中
[root@k8s-master1 ~]# vim pod2.yaml apiVersion: v1 kind: Pod metadata: name: nginx
labels:
app: nginx spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent nodeSelector: env_role: dev [root@k8s-master1 ~]# kubectl create -f pod2.yaml pod/nginx created
查看pod
[root@k8s-master1 ~]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 115s [root@k8s-master1 ~]# kubectl describe pod nginx Name: nginx Namespace: default Priority: 0 PriorityClassName: <none> Node: 192.168.0.126/192.168.0.126 Start Time: Fri, 21 Dec 2018 14:07:49 +0800 Labels: <none> Annotations: <none> Status: Running IP: 172.17.92.2 Containers: nginx: Container ID: docker://8c7e442cc83b6532b3bda707f389fa371861d173e9395149bbede9e166bf559c Image: nginx Image ID: docker-pullable://nginx@sha256:1a0043cfb1987774c6981c41e49f758c58ace64c30e1c4ecff5cedff0b5c88da Port: <none> Host Port: <none> State: Running Started: Fri, 21 Dec 2018 14:07:50 +0800 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-7vs6s (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: default-token-7vs6s: Type: Secret (a volume populated by a Secret) SecretName: default-token-7vs6s Optional: false QoS Class: BestEffort Node-Selectors: env_role=dev Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m11s default-scheduler Successfully assigned default/nginx to 192.168.0.126 Normal Pulled 2m11s kubelet, 192.168.0.126 Container image "nginx" already present on machine Normal Created 2m10s kubelet, 192.168.0.126 Created container Normal Started 2m10s kubelet, 192.168.0.126 Started container