《Kubernetes 入门:深刻了解 Pod 》最先发布在 blog.hdls.me/15346044250…html
Pod 做为 k8s 的基本调度单元,是 k8s 的核心资源所在。本文从 Pod 的使用、控制、调度、应用配置等方面入手,全方面讲解 k8s 如何发布和管理应用。node
对长时间运行容器的要求是:其主程序须要一直在前台运行。kubelet 建立包含这个容器的 Pod 以后运行完命令,即认为 Pod 执行结束,接着当即销毁该 Pod ,根据 RS 中定义的 Pod 副本数量,会当即再生成一个新 Pod ,会进入无限循环。json
属于一个 Pod 的多个容器应用之间仅需经过 localhost 通讯,一组容器被绑定在了一个环境中。api
在同一个 Pod 中的容器共享 Pod 级别的 Volume,而每一个容器便可各自进行挂载,将 Volume 挂载为容器内部须要的目录。bash
静态 pod 是指由 kubelet 管理的仅存在特定 Node 上的 Pod。它们不能经过 APIServer 管理,没法与 RS 等进行关联。网络
建立静态 Pod 的方式:app
静态 pod 的建立方式有两种,分别为配置文件方式和 HTTP 方式。性能
配置文件方式ui
设置 kubelet 的启动参数 --config,指定 kubelet 须要监控的配置文件所在目录,kubelet 按期扫描该目录,根据目录中的 .yaml 或 .json 文件建立操做。因为没法经过 APIServer 对静态 pod 进行直接管理,在 Master 节点上尝试删除这个 Pod 将会将其变成 pending 状态,不会删除;若须要删除该 pod 须要在其所在 Node 上,将其定义文件从 /etc/kubelet.d 目录下删除。url
HTTP 方式
设置 kubelet 的启动参数 --manifest-url ,kubelet 按期从该 URL 地址下载 Pod 的定义文件,并以 .yaml 或 .json 文件的格式解析,而后建立 Pod。实现方式与配置文件方式一致。
应用部署的一个最佳实践是将应用所需的配置信息与程序分离,好处是能够实现应用程序被更好的服用,经过不一样的配置也能实现更灵活的功能。ConfigMap 是 k8s 统一的集群配置管理方案。
生成为容器的环境变量,设置容器启动命令的启动参数,以 Volume 形式挂载为容器内部的文件或目录,以 key:value 的形式保存,既能够表示变量的值,也能够表示一个完整配置文件的内容。 blog.cdn.updev.cn
经过 yaml 文件的方式:书写好 yaml 文件后, kubectl create -f ***.yaml
命令便可建立 ConfigMap。
直接使用 kubectl create configmap
命令行的方式:能够根据目录、文件或字面值建立 ConfigMap。
--from-file
参数从目录中建立kubectl create configmap <map-name> --from-file=config-files-dir
复制代码
其中, <map-name>
表明 ConfigMap 的名字,config-files-dir
表明目录。建立出来的 ConfigMap 的 key 即为文件名。
--from-file
参数从文件中建立,并自定义 keykubectl create configmap <map-name> --from-file=<my-key-name>=<path-to-file>
复制代码
其中, my-key-name
为自定义 key,path-to-file
表明文件。
--from-literal
参数从文件中建立,并指定字面值kubectl create configmap <map-name> --from-literal=<key>=<value>
复制代码
其中, <key>=<value>
表明指定的键值对。
下面就是容器中的应用如何使用 ConfigMap 的方法,主要有环境变量方式和挂载 Volume 方式。
在 Deployment 的 yaml 的 container 中定义 env ,格式以下:
env:
- name: HDLS_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: hdls
复制代码
意为:该容器中环境变量 HDLS_KEY
的值取自名为 special-config
的 ConfigMap 中,key 为 hdls
。
须要在 Pod 的 yaml 的 container 中定义 volumeMounts (引用 volume 名和挂载到容器内的目录),且在 volumes 中定义须要挂载的 volume 名和 ConfigMap 等信息。以下:
apiVersion: v1
kind: Pod
metadata:
name: hdls-pod
spec:
containers:
- name: hdls-container
image: ...
ports:
- containerPort: 8080
volumeMounts: # 在 container 中定义 volumeMounts
- name: hdls-server # 引用的 volume 名
mountPath: /configfiles # 挂载到容器中的目录
volumes:
- name: hdls-server # pod 中挂载的 Volume 名
configMap:
name: special-config # 使用 ConfigMap “special-config”
...
复制代码
咱们在调度、管理 Pod 时,须要熟悉 Pod 在整个生命周期的各个状态,而设置 Pod 的重启策略也是基于对 Pod 的各类状态的了解。
Pod 的全部状态总共有 5 种,分别以下:
Pending : APIServer 已经建立该 Pod ,但 Pod 内还有容器的镜像没有建立或正在下载; Running : Pod 中全部的容器均已建立,且至少有一个容器处于运行、正在启动、正在重启状态; Succeeded : Pod 中全部容器已成功退出,且不会重启; Failed : Pod 中所求容器均已退出,但至少有一个容器处于失败状态; Unknown : 因为某种缘由没法获取该 Pod 的状态,可能因为网络不顺畅所致。
Pod 的重启策略有 3 种,默认值为 Always。
Always : 容器失效时,kubelet 自动重启该容器; OnFailure : 容器终止运行且退出码不为0时重启; Never : 不论状态为什么, kubelet 都不重启该容器。
kubelet 重启失效容器的时间间隔以 sync-frequency 乘以 2n 来计算,最长延迟 5 分钟,并在成功重启后的 10 分钟重置该时间。
Pod 的重启策略与控制方式有关,每种控制器对 Pod 的重启策略要求以下:
RS 和 DaemonSet:必须设置为 Always Job:OnFailure 或 Never kubelet (静态 Pod):Pod 失效时自动重启,且不进行健康检查
Pod 的健康检查分别两种:存活检查和就绪检查,分别使用 LivenessProbe 探针和 ReadinessProbe 探针。
用于判断容器是否存活,一旦检测到容器不健康, kubelet 即杀掉该容器,并根据重启策略作相应处理,若是容器不包含 LivenessProbe 探针,kubelet 认为其返回值永远是 success。
用于判断容器是否启动完成,便是否 ready 状态,一旦检测到失败,则 Pod 的状态被改写,并将该 Pod 的 Endpoint 从 Service 的转发 Endpoint 中删除。
ExecAction :在容器内执行一个命令,若是该命令的返回码为0,代表容器健康; TCPSocketAction :经过容器的 IP 和端口号执行 TCP 检查,若是能创建 TCP 链接,代表容器健康; HTTPGetAction :经过容器的 IP 地址、端口号及路径调用 HTTP Get 方法,若是返回码 >=200 ,且 <400,认为容器健康。
以上每种探测方式都须要设置的参数: initialDelaySeconds:延迟检查的时间,单位为s timeoutSeconds:健康检查发送后等待响应的超时时间,单位为s periodSeconds:执行周期
Pod 实为 k8s 中的最小调度单元,只是容器的载体,其自己没法完成自动调度的功能。 k8s 采用了 RS、Deployment、DaemonSet、Job 等方式实现 Pod 的调度和自动控制。
RS 的主要功能之一就是自动部署一个容器应用的多份副本,及持续监控副本的数量。而 RS/RC 在 k8s 中通常不多单独使用,都是在 Deployment 中使用,而 Deployment 是 k8s 引入的一个更好解决 Pod 编排问题的概念,经过 Deployment 咱们能够随时知道 Pod 的调度状况。
在 Pod 的定义中,能够采用 NodeSelector 或 NodeAffinity 两种方式进行调度。
Pod 调度是经过 Master 上的 Scheduler 负责实现的,原理是经过 Node 标签和 Pod 的 nodeSelector 属性匹配。
NodeSelector 定向调度的过程为:经过 kubectl label 给目标 Node 打上标签;在 Pod 的定义上加上 nodeSelector 的设置。须要注意的是,一旦 Pod 指定了 nodeSelector ,若集群中不存在匹配的 Node ,即便有空闲的 Node,也不会调度。
经过 kubectl
进行打标签的方法:
kubectl label nodes <node-name> <label-key>=<label_value>
复制代码
在 Pod 中指定 nodeSelector:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hdls
spec:
template:
metadata:
name: hdls-pod
spec:
containers:
- name: hdls-container
image: ...
ports:
- containerPort: 8080
nodeSelector:
<label-key>: <label_value>
复制代码
NodeAffinity 意为 Node 亲和性的调度策略,是替换 NodeSelector 的下一代调度策略。在 NodeSelector 的基础上增长了 In/NotIn/Exists/DoesNotExsist/Gt/Lt 等操做。
设置亲和性: requiredDuringSchedulingRequiredDuringExecution:相似于 NodeSelector ,在 Node 不知足条件时,系统从该 Node 上移除以前调度上的 Pod ; requiredDuringSchedulingIgnoredDuringExecution:在 Node 不知足条件时,系统不必定从该 Node 上移除以前调度上的 Pod; preferredDuringSchedulingIgnoredDuringExecution:指定在知足条件的 Node 中,哪些 Node 更优先地调度;同时,Node 不知足条件时,不必定从该 Node 上移除以前调度上的 Pod。
DaemonSet 是 Kubernetes 1.2 版本中新增的一种资源对象,用于确保所有(或指定的某些)Node 上运行一个 Pod 副本。其 Pod 调度策略与 RC 相似。
使用场景:
Job 是 Kubernetes 1.2 版本中新增的支持批处理的资源对象。批处理任务一般并行或串行启动多个计算进程去处理一批工做项(work item),处理完后整个 Job 结束。
考虑到批处理的并行问题,Job 被分为如下几种类型:
在实际生产系统中,服务扩容是个不容忽视的场景。在 k8s 中,有两种方式来实现 Pod 的扩容和缩容,分别为 RC 的 Scale 机制和 HPA (Horizontal Pod Autoscaler)。
经过 kebectl
命令可设置 Pod 的副本数:
kubectl scale rc <rc-name> --replicas=3
复制代码
经过 --replicas=<num>
参数将 Pod 的副本数手动调高,便可完成 Pod 的扩容;相应的,将该参数设置为较低的数,系统将 kill 掉一些运行中的 Pod ,以实现应用集群缩容。
HPA (Horizontal Pod Autoscaler) 是 Kubernetes v1.1 新增的控制器,用以实现基于 CPU 使用率进行自动 Pod 扩缩容的功能。HPA 基于 Master 的 kube-controller-manager 服务启动参数 --horizontal-pod-autoscaler-sync-period 定义的时长(默认为 30 秒),周期性的检测目标 Pod 的 CPU 使用率,并在知足条件时对 RC 或 Deployment 中的 Pod 副本数进行调整,以符合用户定义的平均 Pod CPU 使用率。PodCPU 使用率来源于 heapster 组件,因此须要预先安装好 heapster。
建立 HPA 时可使用 kubectlautoscale
命令或使用 yaml 配置文件。在建立 HPA 以前,须要确保已经存在一个 RC 或 Deployment 对象,且该 RC 或 Deployment 中的 Pod 必须定义 resources.requests.cpu 的资源请求值。
在实际生产环境中,应用的升级也是一个很重要的场景。在集群规模较大时,先所有中止再逐步升级的方式会致使较长时间内服务不可用,升级工做就成了一个不小的挑战。 k8s 提供了滚动升级功能来解决这个问题。
滚动升级经过执行 kubectl rolling-update
命令一键完成。整个过程为:
须要注意的是,新旧 RC 必须在同一 namespace 下。
若采用 yaml 配置文件来实现滚动升级,须要先手动建立一个新的 RC yaml,且 yaml 文件中须要注意的是:
再运行 kubectl
命令完成滚动升级:
kubectl rolling-update <RC-name> -f <new-RC-yaml>
复制代码
若不使用 yaml 配置文件,可直接用 kubectl rolling-update
命令,加上 --image
参数指定新版镜像名。
kubectl rolling-update <RC-name> --image=<image-name>
复制代码
与使用配置文件的方式不一样,该方法执行的结果是旧的 RC 被删除,新的 RC 仍使用旧的 RC 名,且完成升级后,新 RC 多一个 key 为 “deployment”(这个名字可经过 --deployment-label-key
参数进行修改) 的 Label ,值为 RC 的内容进行 Hash 计算后的值。
最后,若 Pod 须要回滚,可中断更新操做,执行 kubectl rolling-update-rollback
完成 Pod 版本的回滚。