Kubernetes 高级调度01
目录
一、 初始化容器 InitContainer
1. InitContainer 的基本概念
2. 延迟指定时间后启动
3. 使用初始化容器修改内核参数
4. 等待依赖的服务启动后再启动应用
5. pause 容器
二、 临时容器 Ephemeral Containers
1. 临时容器的概念
2. 临时容器的使用示例
三、 自动扩缩容 HPA
1. 什么是 HPA
2. HPA 实践步骤(以 Nginx 为例)
一、 初始化容器 InitContainer
首先来看初始化容器,顾名思义,初始化容器是用来进行初始化操作的。很多情况下,程序的启动需要依赖各类配置、资源。但是又不能继承在原有的启动命令或者镜像当中,因为程序的镜像可能并没有加载配置命令,此时 InitContainer 就起了很大的作用。
1. InitContainer 的基本概念
InitContainer 是 Kubernetes 的初始化容器(也可称之为 Init 容器),它是一种特殊的容器,在 Pod 内的应用容器启动之前运行,可以包括一些应用镜像中不存在的使用工具和安装脚本,用以在程序启动时进行初始化,比如创建文件、修改内核参数、等待依赖程序启动等。
每个 Pod 中可以包含多个容器,同时 Pod 也可以有一个或多个先于应用程序启动的 Init 容器:
- 在 Pod 定义中,
initContainers
与containers
同级,按顺序逐个执行;- 当所有的 Init 容器运行完成时,Kubernetes 才会启动 Pod 内的普通容器。
Init 容器与普通容器的核心差异:
- 总是运行到完成:Init 容器必须执行完毕,才会启动后续容器。
- 串行执行:上一个 Init 容器运行完成后,才会启动下一个。
- 重启策略关联:若 Init 容器失败,Kubernetes 会不断重启 Pod(除非 Pod 的
restartPolicy
为Never
)。
为 Pod 设置 Init 容器时,需在 spec
中添加 initContainers
字段(与 containers
同级),配置方式与普通容器类似,但 Init 容器不支持 lifecycle
、livenessProbe
、readinessProbe
、startupProbe
(因需在 Pod 就绪前运行完成)。
2. 延迟指定时间后启动
需求:让应用容器启动前,Init 容器休眠 15 秒。
YAML 定义(init01.yml
):
apiVersion: v1 kind: Pod metadata:creationTimestamp: nulllabels:run: initc01name: initc01 spec:terminationGracePeriodSeconds: 0containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: n1resources: {}initContainers:- name: initc01image: nginx:1.7.9imagePullPolicy: IfNotPresentcommand: ["sh", "-c", "sleep 15"] # 休眠15秒dnsPolicy: ClusterFirstrestartPolicy: Never status: {}
部署与观察:
# 创建 Pod kubectl create -f init01.yml # 持续查看 Pod 状态(Init 阶段会持续 15 秒) kubectl get pod # 初始状态:STATUS 为 Init:0/1 # 15秒后,STATUS 变为 PodInitializing → Running
3. 使用初始化容器修改内核参数
需求:在 Init 容器中修改物理机内核参数(vm.swappiness=0
,减少 swap 使用)。
关键说明:
容器默认无法修改内核参数,需通过 securityContext.privileged: true
赋予特权。
YAML 定义(init02.yml
):
apiVersion: v1 kind: Pod metadata:creationTimestamp: nulllabels:run: initc02name: initc02 spec:terminationGracePeriodSeconds: 0containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: n1resources: {}initContainers:- name: initc02image: alpine # 选择轻量镜像imagePullPolicy: IfNotPresentcommand: ["sh", "-c", "/sbin/sysctl -w vm.swappiness=0"] # 修改内核参数securityContext:privileged: true # 赋予特权dnsPolicy: ClusterFirstrestartPolicy: Never status: {}
验证:
# 部署 kubectl apply -f init02.yml # 查看 Pod 状态 kubectl get pod # 验证内核参数是否修改成功 kubectl exec -it initc02 -- cat /proc/sys/vm/swappiness # 输出应为 0
4. 等待依赖的服务启动后再启动应用
需求:Web 服务(Nginx)依赖 Redis 和 MySQL 服务,需等两者就绪后再启动。
(1) 创建带 Init 容器的 Pod(myapp.yml
):
Init 容器通过 nslookup
检查依赖服务的 DNS 解析(即服务是否就绪),未就绪则循环等待。
apiVersion: v1 kind: Pod metadata:name: nginxlabels:app: nginx spec:containers:- name: nginximage: nginx:1.7.9ports:- containerPort: 80initContainers:- name: init-redisimage: busybox:1.28command: ['sh', '-c', 'until nslookup redis-server; do echo waiting for redis; sleep 2; done;']- name: init-mysqlimage: busybox:1.28command: ['sh', '-c', 'until nslookup mysql-server; do echo waiting for mysql; sleep 2; done;']
部署后观察初始状态:
kubectl create -f myapp.yml kubectl get pod # 状态为 Init:0/2(两个 Init 容器均未完成)
(2) 创建第一个依赖服务
apiVersion: apps/v1 kind: Deployment metadata:labels:app: redisname: redis spec:replicas: 1selector:matchLabels:app: redistemplate:metadata:labels:app: redisspec:containers:- image: redis:5.0imagePullPolicy: IfNotPresentname: redis --- apiVersion: v1 kind: Service metadata:labels:app: redisname: redis-service spec:ports:- port: 6379protocol: TCPtargetPort: 6379selector:app: redistype: NodePort
部署与验证:
kubectl create -f redis-deployment.yml kubectl get svc # 查看 redis-service 的 NodePort kubectl get pod # Redis Pod 启动后,Init 容器状态变为 Init:1/2
(3) 创建第二个依赖服务
apiVersion: apps/v1 kind: Deployment metadata:labels:app: mysqlname: mysql spec:replicas: 1selector:matchLabels:app: mysqltemplate:metadata:labels:app: mysqlspec:containers:- env:- name: MYSQL_ROOT_PASSWORDvalue: 'moonfdd'image: 'mysql:8.0'imagePullPolicy: IfNotPresentname: mysql --- apiVersion: v1 kind: Service metadata:labels:app: mysqlname: mysql-service spec:ports:- port: 3306protocol: TCPtargetPort: 3306selector:app: mysqltype: NodePort
部署后最终状态:
kubectl create -f mysql-deployment.yml kubectl get pod # Nginx Pod 状态变为 Running(两个 Init 容器均完成,依赖服务就绪)
(4) 完成 MySQL 服务定义
name: mysqlvolumeMounts:- mountPath: /var/lib/mysqlname: volvvolumes:- hostPath:path: /root/k8s/moonfdd/mysql/var/lib/mysql # 主机路径,需提前创建type: DirectoryOrCreatename: volv --- apiVersion: v1 kind: Service metadata:labels:app: mysqlname: mysql-service spec:ports:- port: 3306protocol: TCPtargetPort: 3306selector:app: mysqltype: NodePort
部署与验证:
kubectl create -f mysql-deployment.yml # 输出:deployment.apps/mysql created、service/mysql-service created kubectl get svc # 查看 mysql-service 的 NodePort(如 3306:31452/TCP) kubectl get pod # 等待 MySQL Pod 启动后,Nginx Pod 的 Init 容器完成,状态变为 Running
5. pause 容器
在 Kubernetes 中,pause 容器是每个 Pod 的 “基础容器”,并非暂停执行,而是负责:
- 共享网络命名空间:Pod 内所有容器共享同一个 IP、端口空间,可通过
localhost
通信。- 维持网络接口:为 Pod 配置网络出口,使容器能访问外部网络。
- 保证稳定性:即使业务容器停止,pause 容器运行时,Pod 网络命名空间仍保留。
- 生命周期绑定:pause 容器是 Pod 第一个启动的容器,生命周期与 Pod 绑定(镜像极小,约 700KB,运行
/pause
无限循环)。
Pause 容器的实现逻辑
Pod 内多个容器共享网络的核心是 Infra 容器(即 pause 容器):
- Infra 容器先启动,创建 Pod 的 Network Namespace。
- 业务容器通过
Join Namespace
加入 Infra 的网络命名空间。- 所有容器看到的网络设备、IP、MAC 完全一致,共享 Pod 级网络资源。
验证 pause 容器存在:
# 查看 Nginx Pod 所在节点 kubectl get pod -o wide # 在节点上查看容器(过滤 Nginx Pod 相关容器) docker ps | grep <pod-name> # 输出中会包含: # registry.aliyuncs.com/google_containers/pause:3.6 # pause 容器 # nginx 容器...
二、 临时容器 Ephemeral Containers
生产环境中,业务镜像通常不预装调试工具(如 curl
、wget
、net-tools
),导致排查问题时无法直接执行命令。Kubernetes 1.16+ 引入 临时容器,支持动态注入调试工具,无需修改业务镜像。
1. 临时容器的概念
- 用途:临时附加到 Pod,用于在线调试(如诊断网络、查看进程),不参与业务运行。
- 特性:
- 无自动重启,状态不影响业务容器。
- 不支持
ports
、livenessProbe
、readinessProbe
、resources
等字段(仅调试用)。- 通过特殊 API 创建(非
pod.spec
),无法用kubectl edit
修改,Pod 重启后自动销毁。- 场景:业务容器无 Shell、调试工具缺失时,快速注入
busybox
等镜像进行诊断。
2. 临时容器的使用示例
(1) 创建待调试的 Tomcat Pod
apiVersion: v1 kind: Pod metadata:name: tomcat-testnamespace: defaultlabels:app: tomcat spec:containers:- name: tomcat-javaports:- containerPort: 8080image: kubeguide/tomcat-app:v1imagePullPolicy: IfNotPresent
(2) 部署并查看 Pod
kubectl apply -f pod-tomcat.yml kubectl get pod # 状态:Running(1/1)
(3) 注入临时容器
kubectl debug -it tomcat-test \--image=busybox:1.28 \--target=tomcat-java
tomcat-test
:目标 Pod 名称。--target=tomcat-java
:指定注入到哪个业务容器的命名空间(共享网络、PID 等)。--image=busybox:1.28
:临时容器使用的镜像(含常用调试工具)。
(4) 验证临时容器
# 检查 Tomcat 端口 netstat -tunlp | grep 8080 # 测试网络连通性 wget http://localhost:8080
三、 自动扩缩容 HPA
1. 什么是 HPA
- 作用:根据资源利用率或自定义指标,动态扩缩 Pod 数量(仅支持可扩缩的资源,如 Deployment,不支持 DaemonSet)。
- 原理:HPA 控制器定期(默认 15 秒)查询 Metrics Server,对比实际指标与目标值,调整副本数。
2. HPA 实践步骤(以 Nginx 为例)
(1) 部署带资源请求的 Nginx Deployment
apiVersion: apps/v1 kind: Deployment metadata:name: nginx-serverlabels:name: nginx-server spec:replicas: 2 # 初始副本数selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginxresources:requests: # 必须配置 requests,否则 Metrics Server 无法采集cpu: 10m # 10 毫核(0.01 CPU)image: nginx:1.7.9ports:- name: nginxcontainerPort: 80
(2) 部署 Deployment
kubectl apply -f nginx-deployment.yml kubectl get deployment # 确认初始副本数为 2
(3) 安装 Metrics Server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
验证 Metrics Server 运行
kubectl get pods -n kube-system -l k8s-app=metrics-server
(4) 创建 HPA 规则
kubectl autoscale deployment nginx-server \--cpu-percent=50 \ # 目标 CPU 利用率 50%--min=2 \ # 最小副本数--max=10 # 最大副本数
(5) 模拟负载,触发扩缩容
# 进入 Nginx Pod,或在节点上运行: stress --cpu 2 --timeout 600 # 模拟 2 个 CPU 核心满载,持续 10 分钟 # 观察 HPA 状态: kubectl get hpa # CPU 利用率超过 50% 后,副本数会逐步增加到 max(10)。 # 停止压测后,副本数会回落到 min(2)。