目录
[一、 初始化容器 InitContainer](#一、 初始化容器 InitContainer)
[1. InitContainer 的基本概念](#1. InitContainer 的基本概念)
[2. 延迟指定时间后启动](#2. 延迟指定时间后启动)
[3. 使用初始化容器修改内核参数](#3. 使用初始化容器修改内核参数)
[4. 等待依赖的服务启动后再启动应用](#4. 等待依赖的服务启动后再启动应用)
[5. pause 容器](#5. pause 容器)
[二、 临时容器 Ephemeral Containers](#二、 临时容器 Ephemeral Containers)
[1. 临时容器的概念](#1. 临时容器的概念)
[2. 临时容器的使用示例](#2. 临时容器的使用示例)
[三、 自动扩缩容 HPA](#三、 自动扩缩容 HPA)
[1. 什么是 HPA](#1. 什么是 HPA)
[2. HPA 实践步骤(以 Nginx 为例)](#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: null labels: run: initc01 name: initc01 spec: terminationGracePeriodSeconds: 0 containers: - image: nginx:1.7.9 imagePullPolicy: IfNotPresent name: n1 resources: {} initContainers: - name: initc01 image: nginx:1.7.9 imagePullPolicy: IfNotPresent command: ["sh", "-c", "sleep 15"] # 休眠15秒 dnsPolicy: ClusterFirst restartPolicy: 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: null labels: run: initc02 name: initc02 spec: terminationGracePeriodSeconds: 0 containers: - image: nginx:1.7.9 imagePullPolicy: IfNotPresent name: n1 resources: {} initContainers: - name: initc02 image: alpine # 选择轻量镜像 imagePullPolicy: IfNotPresent command: ["sh", "-c", "/sbin/sysctl -w vm.swappiness=0"] # 修改内核参数 securityContext: privileged: true # 赋予特权 dnsPolicy: ClusterFirst restartPolicy: 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: nginx labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80 initContainers: - name: init-redis image: busybox:1.28 command: ['sh', '-c', 'until nslookup redis-server; do echo waiting for redis; sleep 2; done;'] - name: init-mysql image: busybox:1.28 command: ['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: redis name: redis spec: replicas: 1 selector: matchLabels: app: redis template: metadata: labels: app: redis spec: containers: - image: redis:5.0 imagePullPolicy: IfNotPresent name: redis --- apiVersion: v1 kind: Service metadata: labels: app: redis name: redis-service spec: ports: - port: 6379 protocol: TCP targetPort: 6379 selector: app: redis type: 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: mysql name: mysql spec: replicas: 1 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - env: - name: MYSQL_ROOT_PASSWORD value: 'moonfdd' image: 'mysql:8.0' imagePullPolicy: IfNotPresent name: mysql --- apiVersion: v1 kind: Service metadata: labels: app: mysql name: mysql-service spec: ports: - port: 3306 protocol: TCP targetPort: 3306 selector: app: mysql type: NodePort
部署后最终状态:
kubectl create -f mysql-deployment.yml kubectl get pod # Nginx Pod 状态变为 Running(两个 Init 容器均完成,依赖服务就绪)
(4) 完成 MySQL 服务定义
name: mysql volumeMounts: - mountPath: /var/lib/mysql name: volv volumes: - hostPath: path: /root/k8s/moonfdd/mysql/var/lib/mysql # 主机路径,需提前创建 type: DirectoryOrCreate name: volv --- apiVersion: v1 kind: Service metadata: labels: app: mysql name: mysql-service spec: ports: - port: 3306 protocol: TCP targetPort: 3306 selector: app: mysql type: 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-test namespace: default labels: app: tomcat spec: containers: - name: tomcat-java ports: - containerPort: 8080 image: kubeguide/tomcat-app:v1 imagePullPolicy: 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-server labels: name: nginx-server spec: replicas: 2 # 初始副本数 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx resources: requests: # 必须配置 requests,否则 Metrics Server 无法采集 cpu: 10m # 10 毫核(0.01 CPU) image: nginx:1.7.9 ports: - name: nginx containerPort: 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)。