文章目录
- [K8s Pod 资源进阶](#K8s Pod 资源进阶)
-
- [pod 资源限制](#pod 资源限制)
- 资源限制实战
- [Pod 服务质量Qos](#Pod 服务质量Qos)
- [Downward API](#Downward API)
-
- 可注入的元数据信息
- 环境变量方式注入元数据
- 存储卷方式注入元数据
- [为注册服务注入Pod 名称](#为注册服务注入Pod 名称)
- [为 JVM 注入堆内存限制](#为 JVM 注入堆内存限制)
K8s Pod 资源进阶
pod 资源限制
资源限制的方法:
- Requests: 申请的资源大小; 刚创建时,申请1G内存,找到符合的节点,然后调度上去;
- Limits: 限制运行过程中的最大使用量; 限制2G,当达到2G就没办法在继续使用了;
限制资源种类。常用有 cpu 和 memory 资源,也可以用来限制 nvidia.com/gpu 资源。限制gpu资源需要先安装对应插件,gpu 的限制方案和cpu 基本一致
Pod资源限制:
- CPU/GPU: 可压缩资源,超载,响应慢;
- 内存: 不可被压缩的资源,超载,触发OOM机制;杀死Pod;看 QOS
限制资源单位
-
CPU: 1 核CPU 等于 1000 毫核, 1 核心 = 1000 millicpu(1 Core = 1 m)。 k8s 不允许设置精度小于1m 的CPU 资源。 因此当 CPU 单位小于 1 时, 只能用豪核心表示
-
memory: 内存的基本单位是字节数(Bytes),也可以加上国际单位,十进制的 E、P、T、G、M、K、m,或二进制 Ei、Pi、Ti、Gi、Mi、Ki
1 MB = 1000 KB = 1000000 Bytes
1 Mi = 1024 KB = 1038576 bytes
资源限制实战
yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-resource
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1" ] # 告知容器尝试分配 150 MiB 内存
resources:
requests:
cpu: "100m" # 申请 0.1 Core cpu 资源 设置高了。没有可调度node, pod 会一直处于pending 状态
memory: "100Mi" # 申请 100 Mi 内存 设置高了 pending
limits:
cpu: "200m" # 最多使用 0.2 Core cpu 超了会影响效率
memory: "200Mi" # 最多使用 200 Mi 内存 使用超过设置 会导致 status 为 OOMKilled 内存溢出(OOM) 杀死容器
Pod 服务质量Qos
QoS(Quality of Service),译作 "服务质量保证", 是作用在Pod 上的一个配置,当kubernetes 创建一个pod 时,它就会给这个Pod 分配一个QoS 等级。
当Pod 过载使用资源时,kubernetes 会根据Pod 对象的服务质量和优先级等完成判定,进而挑选对应的Pod 杀死。kubernetes 根据pod 的Requests 和 Limits 属性,把Pod 对象归类为三类 BestEffort、BurStable、Guaranteed
- Guaranteed: Pod 对象为每个容器(包括initContainer)都设置了CPU资源需求和资源限制,切两者值相同;还同时为每个容器设置了内存需求和限制,并且两者的值相同。这类Pod 对象具有最高级别的服务质量
- Burstable: 至少有一个容器设置 CPU 或内存资源 Requests 属性,但不满足 Guaranteed, 这类Pod具有中级服务质量
- BestEffort: 没有为任何容器设置Requests 和 Limits属性,这类Pod对象服务质量是最低级别
当 kubernetes 集群内存资源紧缺,优先杀死BestEffort类别的容器,因为系统不为该类资源提供任何服务保证,但此类资源最大的好处就是能够尽可能的使用资源。
如果系统中没有BestEffort类别的容器,接下来就轮到BUrstable类别的容器,如果有多个Burstable类别的容器,就看谁的内存资源占用多,就优先干掉谁。比如A容器申请16内存资源,实际使用了95%,而B容器申请了26内存资源,实际使用了80%,但任然会优先干掉A容器,虽然A
容器的用量少,但与自身的Requests值相比,它的占比要大于B容器。
对于Guaranteed类别的容器拥有最高优先级,它们不会被杀死,除非其内存资源需求超限,或者OOM时没有其他更低优先级的Pod对象存在,才会千掉Guaranteed类容器。
Downward API
DownwardAPI可以让容器获取Pod的相关元数据信息,比如Pod名称,Pod的IP,Pod的资源限制等,获取后通过env、volume的方式将相关的环境信息注入到容器中,从而让容器通 过这些信息,来设定容器的运行特性。
- 例如:Nginx进程根据节点的CPU核心数量自动设定要启动的worker 进程数。
- 例如:JVM虛拟根据Pod的内存资源限制,来设定对应容器的堆内存大小。
- 例如:获取Pod名称,以Pod名称注册到某个服务,当Pod结束后,调用prestop清理对应名称的注册信息。
可注入的元数据信息
使用 pod.spec.containers.env. valueFrom. fieldRef 可以注入的字段有:
- metadata.name:Pod对象的名称
- metadata.namespace:Pod对象隶属的名称空间
- metadata.uid: Pod对象的UID
- metadata.labels['']:获取Labe1指定KEY对应的值
- metadata.annotations["']:获取Annotat ions对应KEY的值
- status.podIP:Pod对象的IP地址
- status.hostIP:节点IP
- status.nodeName:节点名称
- spec.serviceAccountName:Pod对象使用的ServiceAccount资源名称
使用 pod.spec.containers.env.valueFrom.resourceFieldRef 可以注入的字段有:
- requests.cpu
- requests.memory
- limits.cpu
- limits.memory
环境变量方式注入元数据
yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-down-api
labels:
app: nginx-app
role: backend
zone: beijing
spec:
containers:
- name: pod-down-api
image: nginx
command: ["/bin/bash" , "-c", "env"]
resources:
requests:
cpu: "200m"
memory: "32Mi"
limits:
cpu: "200m"
memory: "64Mi"
env:
- name: APP1_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: APP1_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: APP1_POD_LABELS
valueFrom:
fieldRef:
fieldPath: metadata.labels['app']
- name: APP1_CPU_REQUESTS
valueFrom:
resourceFieldRef:
resource: requests.cpu
- name: APP1_MEM_LIMITS
valueFrom:
resourceFieldRef:
resource: limits.memory
divisor: 1Mi # 默认显示为字节,通过 divisor 调整显示单位为兆
存储卷方式注入元数据
yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-down-api-volumes
labels:
app: nginx-app
role: backend
zone: beijing
spec:
containers:
- name: pod-down-api
image: nginx
resources:
requests:
cpu: "200m"
memory: "32Mi"
limits:
cpu: "200m"
memory: "64Mi"
volumeMounts: # 将环境变量挂载到/etc/podinfo 目录中,没注入一条元数据都会产生一个文件
- name: podinfo
mountPath: /etc/info
volumes:
- name: podinfo
downwardAPI:
items:
- path: pod_name
fieldRef:
fieldPath: metadata.name
- path: pod_namespace
fieldRef:
fieldPath: metadata.namespace
- path: pod_labels
fieldRef:
fieldPath: metadata.labels
- path: req_cpu
resourceFieldRef:
containerName: pod-down-api
resource: requests.cpu
- path: limit_mem
resourceFieldRef:
containerName: pod-down-api
resource: limits.memory
为注册服务注入Pod 名称
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-mysql-register
spec:
replicas: 10
selector:
matchLabels:
app: tools
template:
metadata:
labels:
app: tools
spec:
containers:
- name: register
image: tools:latest # 找一个能够有mysql client的镜像即可
imagePullPolicy: IfNotPresent
command:
- "/bin/bash"
- "-c"
- |
mysql -h 172.0.1.1 -uroot -p1234 -e "create database ${POD_NAME//-/_}"
sleep 99999999
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
lifecycle:
preStop: # pod 终止前执行
exec:
command:
- "/bin/bash"
- "-c"
- mysql -h 172.0.1.1 -uroot -p1234 -e "drop database ${POD_NAME//-/_}"
为 JVM 注入堆内存限制
yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-tomcat-downward
spec:
containers:
- name: tomcat
image: tomcat:9.0.63
ports:
- containerPort: 8080
env:
- name: JAVA_OPTS # JVM 内存设置环境变量
value: -server -Xms${JVM_XMS} -Xmx${JVM_XMX} -XX:+UseConcMarkSweepGC
- name: JVM_XMS # 读取 resources 配置
valueFrom:
resourceFieldRef:
resource: requests.memory
- name: JVM_XMX
valueFrom:
resourceFieldRef:
resource: limits.memory
resources:
requests:
memory: 100Mi
limits:
memory: 100Mi