Kubernetes 高级调度01

目录

[一、 初始化容器 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 定义中,initContainerscontainers 同级,按顺序逐个执行
  • 当所有的 Init 容器运行完成时,Kubernetes 才会启动 Pod 内的普通容器。

Init 容器与普通容器的核心差异:

  • 总是运行到完成:Init 容器必须执行完毕,才会启动后续容器。
  • 串行执行:上一个 Init 容器运行完成后,才会启动下一个。
  • 重启策略关联 :若 Init 容器失败,Kubernetes 会不断重启 Pod(除非 Pod 的 restartPolicyNever)。

为 Pod 设置 Init 容器时,需在 spec 中添加 initContainers 字段(与 containers 同级),配置方式与普通容器类似,但 Init 容器不支持 lifecyclelivenessProbereadinessProbestartupProbe(因需在 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 容器):

  1. Infra 容器先启动,创建 Pod 的 Network Namespace。
  2. 业务容器通过 Join Namespace 加入 Infra 的网络命名空间。
  3. 所有容器看到的网络设备、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

生产环境中,业务镜像通常不预装调试工具(如 curlwgetnet-tools),导致排查问题时无法直接执行命令。Kubernetes 1.16+ 引入 临时容器,支持动态注入调试工具,无需修改业务镜像。

1. 临时容器的概念

  • 用途 :临时附加到 Pod,用于在线调试(如诊断网络、查看进程),不参与业务运行
  • 特性
    • 无自动重启,状态不影响业务容器。
    • 不支持 portslivenessProbereadinessProberesources 等字段(仅调试用)。
    • 通过特殊 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)。  
相关推荐
Fᴏʀ ʏ꯭ᴏ꯭ᴜ꯭.8 分钟前
LVS集群技术
云原生·lvs
528301 小时前
Kubernetes 高级调度 01
云原生·容器·kubernetes
xujiangyan_1 小时前
Kubernetes的微服务
微服务·容器·kubernetes
ocean'4 小时前
网络安全初级第一次作业
云原生·eureka
AKAMAI4 小时前
为何说分布式 AI 推理已成为下一代计算方式
人工智能·云原生·云计算
艾伦_耶格宇6 小时前
【DOCKER】-4 dockerfile镜像管理
运维·docker·容器
you秀6 小时前
K8S中的dns要如何指定??给pod中增加hosts映射,来规避dns冲突问题
java·容器·kubernetes
咚咚?11 小时前
基于gitlab 构建CICD发布到K8S 平台
容器·kubernetes·gitlab