pod其他设置
Last updated
Last updated
Volume 可以为容器提供持久化存储,比如
更多挂载存储卷的方法参考 。
在使用私有镜像时,需要创建一个 docker registry secret,并在容器中引用。
创建 docker registry secret:
比如使用 Azure Container Registry(ACR):
容器中引用该 secret:
支持三种 RestartPolicy
Always:只要退出就重启
OnFailure:失败退出(exit code 不等于 0)时重启
Never:只要退出就不再重启
注意,这里的重启是指在 Pod 所在 Node 上面本地重启,并不会调度到其他 Node 上去。
环境变量为容器提供了一些重要的资源,包括容器和 Pod 的基本信息以及集群中服务的信息等:
(1) hostname
HOSTNAME
环境变量保存了该 Pod 的 hostname。
(2)容器和 Pod 的基本信息
(3) 集群中服务的信息
容器的环境变量中还可以引用容器运行前创建的所有服务的信息,比如默认的 kubernetes 服务对应以下环境变量:
支持三种 ImagePullPolicy
Always:不管镜像是否存在都会进行一次拉取
Never:不管镜像是否存在都不会进行拉取
IfNotPresent:只有镜像不存在时,才会进行镜像拉取
注意:
默认为 IfNotPresent
,但 :latest
标签的镜像默认为 Always
。
拉取镜像时 docker 会进行校验,如果镜像中的 MD5 码没有变,则不会拉取镜像数据。
生产环境中应该尽量避免使用 :latest
标签,而开发环境中可以借助 :latest
标签自动拉取最新的镜像。
通过设置 dnsPolicy 参数,设置 Pod 中容器访问 DNS 的策略
ClusterFirst:优先基于 cluster domain (如 default.svc.cluster.local
) 后缀,通过 kube-dns 查询 (默认策略)
Default:优先从 Node 中配置的 DNS 查询
通过设置 spec.hostIPC
参数为 true,使用主机的 IPC 命名空间,默认为 false。
通过设置 spec.hostNetwork
参数为 true,使用主机的网络命名空间,默认为 false。
通过设置 spec.hostPID
参数为 true,使用主机的 PID 命名空间,默认为 false。
通过 spec.hostname
参数实现,如果未设置默认使用 metadata.name
参数的值作为 Pod 的 hostname。
通过 spec.subdomain
参数设置 Pod 的子域名,默认为空。
比如,指定 hostname 为 busybox-2 和 subdomain 为 default-subdomain,完整域名为 busybox-2.default-subdomain.default.svc.cluster.local
,也可以简写为 busybox-2.default-subdomain.default
:
注意:
默认情况下,DNS 为 Pod 生成的 A 记录格式为 pod-ip-address.my-namespace.pod.cluster.local
,如 1-2-3-4.default.pod.cluster.local
上面的示例还需要在 default namespace 中创建一个名为 default-subdomain
(即 subdomain)的 headless service,否则其他 Pod 无法通过完整域名访问到该 Pod(只能自己访问到自己)
注意,必须为 headless service 设置至少一个服务端口(spec.ports
,即便它看起来并不需要),否则 Pod 与 Pod 之间依然无法通过完整域名来访问。
从 v1.9 开始,可以在 kubelet 和 kube-apiserver 中设置 --feature-gates=CustomPodDNS=true
开启设置每个 Pod DNS 地址的功能。
注意该功能在 v1.10 中为 Beta 版,v1.9 中为 Alpha 版。
对于旧版本的集群,可以使用 ConfigMap 来自定义 Pod 的 /etc/resolv.conf
,如
k8s中的Pod,除了显式写明pod.spec.Nodename的之外,一般是经历这样的过程
调度时仅仅使用了requests,而没有使用limits。而在运行的时候两者都使用了。
而在运行时,这些参数的整体发挥作用的途径如下
最后由操作系统内核来控制这些进程的资源限制
用一张表来描述里面的关系
docker参数
处理过程
cpuShares
如果requests.cpu为0且limits.cpu非0,以limits.cpu为转换输入值,否则从request.cpu为转换输入值。转换算法为:如果转换输入值为0,则设置为minShares == 2, 否则为*1024/100
oomScoreAdj
cpuQuota, cpuPeriod
由limits.cpu 转换而来,默认cpuQuota为100ms,而cpuPeriod为limits.cpu的核数 * 100ms,这是一个硬限制
memoryLimit
limits.memor
注意:配置了limit,没有配置request,默认会以limit的值来定义request
总结一下,说明4个参数在k8s里面的使用:
Kubernetes 通过 cgroups 限制容器的 CPU 和内存等计算资源,包括 requests(请求,调度器保证调度到资源充足的 Node 上,如果无法满足会调度失败)和 limits(上限)等:
spec.containers[].resources.limits.cpu
:CPU 上限,可以短暂超过,容器也不会被停止
spec.containers[].resources.limits.memory
:内存上限,不可以超过;如果超过,容器可能会被终止或调度到其他资源充足的机器上
spec.containers[].resources.limits.ephemeral-storage
:临时存储(容器可写层、日志以及 EmptyDir 等)的上限,超过后 Pod 会被驱逐
spec.containers[].resources.requests.cpu
:CPU 请求,也是调度 CPU 资源的依据,可以超过
spec.containers[].resources.requests.memory
:内存请求,也是调度内存资源的依据,可以超过;但如果超过,容器可能会在 Node 内存不足时清理
spec.containers[].resources.requests.ephemeral-storage
:临时存储(容器可写层、日志以及 EmptyDir 等)的请求,调度容器存储的依据
比如 nginx 容器请求 30% 的 CPU 和 56MB 的内存,但限制最多只用 50% 的 CPU 和 128MB 的内存:
注意
CPU 的单位是 CPU 个数,可以用 millicpu (m)
表示少于 1 个 CPU 的情况,如 500m = 500millicpu = 0.5cpu
,而一个 CPU 相当于
AWS 上的一个 vCPU
GCP 上的一个 Core
Azure 上的一个 vCore
物理机上开启超线程时的一个超线程
内存的单位则包括 E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki
等。
从 v1.10 开始,可以设置 kubelet ----cpu-manager-policy=static
为 Guaranteed(即 requests.cpu 与 limits.cpu 相等)Pod 绑定 CPU(通过 cpuset cgroups)。
在K8S中可以对两类资源进行限制:cpu和内存。
CPU的单位有:
正实数
,代表分配几颗CPU,可以是小数点,比如0.5
代表0.5颗CPU,意思是一颗CPU的一半时间。2
代表两颗CPU。
正整数m
,也代表1000m=1
,所以500m
等价于0.5
。
内存的单位:
正整数
,直接的数字代表Byte
k
、K
、Ki
,Kilobyte
m
、M
、Mi
,Megabyte
g
、G
、Gi
,Gigabyte
t
、T
、Ti
,Terabyte
p
、P
、Pi
,Petabyte
在K8S中,对于资源的设定是落在Pod里的Container上的,主要有两类,limits
控制上限,requests
控制下限。其位置在:
spec.containers[].resources.limits.cpu
spec.containers[].resources.limits.memory
spec.containers[].resources.requests.cpu
spec.containers[].resources.requests.memory
举例:
方法一虽然很好,但是其不是强制性的,因此很容易出现因忘记设定limits
/request
,导致Host资源使用过度的情形,因此我们需要一种全局性的资源限制设定,以防止这种情况发生。K8S通过在Namespace
设定LimitRange
来达成这一目的。
request
/limit
:如果配置里默认的request
/limit
,那么当Pod Spec没有设定request
/limit
的时候,会使用这个配置,有效避免无限使用资源的情况。
配置位置在:
spec.limits[].default.cpu
,default limit
spec.limits[].default.memory
,同上
spec.limits[].defaultRequest.cpu
,default request
spec.limits[].defaultRequest.memory
,同上
例子:
request
/limit
的约束我们还可以在K8S里对request
/limit
进行以下限定:
某资源的request
必须>=某值
某资源的limit
必须<=某值
这样的话就能有效避免Pod Spec中乱设limit
导致资源耗尽的情况,或者乱设request
导致Pod无法得到足够资源的情况。
配置位置在:
spec.limits[].max.cpu
,limit
必须<=某值
spec.limits[].max.memory
,同上
spec.limits[].min.cpu
,request
必须>=某值
spec.limits[].min.memory
,同上
例子:
为了确保容器在部署后确实处在正常运行状态,Kubernetes 提供了两种探针(Probe)来探测容器的状态:
LivenessProbe:探测应用是否处于健康状态,如果不健康则删除并重新创建容器
ReadinessProbe:探测应用是否启动完成并且处于正常服务状态,如果不正常则不会接收来自 Kubernetes Service 的流量
Kubernetes 支持三种方式来执行探针:
tcpSocket:对指定的容器 IP 及端口执行一个 TCP 检查,如果端口是开放的则表示探测成功,否则表示失败
可以通过给 Pod 增加 kubernetes.io/ingress-bandwidth
和 kubernetes.io/egress-bandwidth
这两个 annotation 来限制 Pod 的网络带宽
仅 kubenet 支持限制带宽
目前只有 kubenet 网络插件支持限制网络带宽,其他 CNI 网络插件暂不支持这个功能。
kubenet 的网络带宽限制其实是通过 tc 来实现的
可以通过 nodeSelector、nodeAffinity、podAffinity 以及 Taints 和 tolerations 等来将 Pod 调度到需要的 Node 上。
也可以通过设置 nodeName 参数,将 Pod 调度到指定 node 节点上。
比如,使用 nodeSelector,首先给 Node 加上标签:
接着,指定该 Pod 只想运行在带有 disktype=ssd
标签的 Node 上:
默认情况下,容器的 /etc/hosts
是 kubelet 自动生成的,并且仅包含 localhost 和 podName 等。不建议在容器内直接修改 /etc/hosts
文件,因为在 Pod 启动或重启时会被覆盖。
默认的 /etc/hosts
文件格式如下,其中 nginx-4217019353-fb2c5
是 podName:
从 v1.7 开始,可以通过 pod.Spec.HostAliases
来增加 hosts 内容,如
v1.8 + 支持给容器分配 HugePages,资源格式为 hugepages-<size>
(如 hugepages-2Mi
)。使用前要配置
开启 --feature-gates="HugePages=true"
在所有 Node 上面预分配好 HugePage ,以便 Kubelet 统计所在 Node 的 HugePage 容量
使用示例
注意事项
HugePage 资源的请求和限制必须相同
HugePage 以 Pod 级别隔离,未来可能会支持容器级的隔离
基于 HugePage 的 EmptyDir 存储卷最多只能使用请求的 HugePage 内存
使用 shmget()
的 SHM_HUGETLB
选项时,应用必须运行在匹配 proc/sys/vm/hugetlb_shm_group
的用户组(supplemental group)中
从 v1.8 开始,可以为 Pod 设置一个优先级,保证高优先级的 Pod 优先调度。
优先级调度功能目前为 Beta 版,在 v1.11 版本中默认开启。对 v1.8-1.10 版本中使用前需要开启:
--feature-gates=PodPriority=true
--runtime-config=scheduling.k8s.io/v1alpha1=true --admission-control=Controller-Foo,Controller-Bar,...,Priority
为 Pod 设置优先级前,先创建一个 PriorityClass,并设置优先级(数值越大优先级越高):
Kubernetes 自动创建了
system-cluster-critical
和system-node-critical
等两个 PriorityClass,用于 Kubernetes 核心组件。
为 Pod 指定优先级
当调度队列有多个 Pod 需要调度时,优先调度高优先级的 Pod。而当高优先级的 Pod 无法调度时,Kubernetes 会尝试先删除低优先级的 Pod 再将其调度到对应 Node 上(Preemption)。
注意:受限于 Kubernetes 的调度策略,抢占并不总是成功。
Sysctls 允许容器设置内核参数,分为安全 Sysctls 和非安全 Sysctls:
安全 Sysctls:即设置后不影响其他 Pod 的内核选项,只作用在容器 namespace 中,默认开启。包括以下几种
kernel.shm_rmid_forced
net.ipv4.ip_local_port_range
net.ipv4.tcp_syncookies
非安全 Sysctls:即设置好有可能影响其他 Pod 和 Node 上其他服务的内核选项,默认禁止。如果使用,需要管理员在配置 kubelet 时开启,如 kubelet --experimental-allowed-unsafe-sysctls 'kernel.msg*,net.ipv4.route.min_pmtu'
v1.6-v1.10 示例:
从 v1.11 开始,Sysctls 升级为 Beta 版本,不再区分安全和非安全 sysctl,统一通过 podSpec.securityContext.sysctls 设置,如
很多容器都是配置了 UTC 时区,与国内集群的 Node 所在时区有可能不一致,可以通过 HostPath 存储插件给容器配置与 Node 一样的时区:
Pod 的名字、命名空间、IP 以及容器的计算资源限制等可以以 的方式获取并存储到环境变量中。
由于环境变量存在创建顺序的局限性(环境变量中不包含后来创建的服务),推荐使用 来解析服务。
使用了一个非常复杂的算法把容器分为三类,详见,按优先级降序为:Guaranteed, Burstable, Best-Effort,和request.memory负相关,这个值越为负数越不容易被杀死
| docker参数 | 处理过程 | | ------------------- | ---------------------------------------- | | cpuShares | 如果requests.cpu为0且limits.cpu非0,以limits.cpu为转换输入值,否则从request.cpu为转换输入值。转换算法为:如果转换输入值为0,则设置为minShares == 2, 否则为*1024/100 | | oomScoreAdj | 使用了一个非常复杂的算法把容器分为三类,详见,按优先级降序为:Guaranteed, Burstable, Best-Effort,和request.memory负相关,这个值越为负数越不容易被杀死 | | cpuQuota, cpuPeriod | 由limits.cpu 转换而来,默认cpuQuota为100ms,而cpuPeriod为limits.cpu的核数 * 100ms,这是一个硬限制 | | memoryLimit | == limits.memory |
exec:在容器中执行一个命令,如果 返回 0
则表示探测成功,否则表示失败
httpGet:对指定的容器 IP、端口及路径执行一个 HTTP Get 请求,如果返回的 在 [200,400)
之间则表示探测成功,否则表示失败
nodeAffinity、podAffinity 以及 Taints 和 tolerations 等的使用方法请参考 。
用来保证一组 Pod 同时运行的数量,这些 Pod 需要使用 Deployment、ReplicationController、ReplicaSet 或者 StatefulSet 管理。