Kubernetes 自动扩缩容:HPA/VPA/CA 深度解析

概述 自动扩缩容是 Kubernetes 最吸引人的能力之一——流量来了自动扩容,流量走了自动缩容,既保证服务质量又控制成本。但"自动"不等于"无脑",配置不当的扩缩容可能导致:扩容不及时造成服务降级、缩容太激进中断长连接、抖动扩缩导致资源浪费。 K8s 的自动扩缩容体系包含三个层次: 层次 组件 扩缩维度 触发条件 Pod 水平扩缩 HPA Pod 副本数 CPU/内存/自定义指标 Pod 垂直扩缩 VPA Pod 资源配额 CPU/内存历史用量 节点扩缩 Cluster Autoscaler 节点数 Pending Pod 事件驱动 KEDA Pod 副本数 事件源(Kafka/Redis/…) 本文基于 Kubernetes v1.30。参考 Kubernetes 自动扩缩文档 HPA:水平 Pod 自动扩缩容 工作原理 HPA(Horizontal Pod Autoscaler)是一个控制循环,默认每 15 秒执行一次: 1. 从指标 API 获取 Pod 的当前指标值(CPU/内存/自定义) 2. 计算期望副本数 = ceil(当前副本数 * (当前指标值 / 目标指标值)) 3. 与当前副本数比较,决定扩容或缩容 4. 调用 Deployment/ReplicaSet 的 Scale API 修改副本数 核心公式:...

August 19, 2024 · 8 分钟 · 1684 字 · 徐保金

Kubernetes Operator 开发指南

概述 Kubernetes Operator 是将人类运维知识编码为软件的范式。它通过 CRD(Custom Resource Definition)扩展 K8s API,通过 Controller 实现自动化运维逻辑。数据库集群管理、消息队列运维、证书轮转……这些原本需要 SRE 手动操作的工作,Operator 可以自动完成。 Operator 的核心思想是声明式 + 控制循环:用户声明期望状态(如"3 个 Redis 副本"),Controller 持续调整实际状态以趋近期望状态。理解这一模式,不仅能开发 Operator,更能深入理解 K8s 本身的设计哲学。 本文基于 Kubernetes v1.30、operator-sdk v1.37、kubebuilder v4.0。参考 Operator 模式文档 Operator 核心概念 CRD 与 Controller 的关系 用户创建 CR (Custom Resource) ──→ API Server 存储 ──→ Controller Watch ↓ Reconcile 循环 ↓ 比较期望状态 vs 实际状态 ↓ 创建/更新/删除资源 ↓ 更新 CR Status 声明式 vs 命令式 模式 示例 特点 命令式 “创建 3 个 Pod” 执行一次就结束,不关心后续状态 声明式 “保持 3 个 Pod 运行” 持续监控,自动修复偏差 Operator 是声明式的——用户声明 spec....

July 23, 2024 · 14 分钟 · 2770 字 · 徐保金

容器运行时:containerd 与 CRI 深入解析

概述 Kubernetes v1.24 正式移除了 dockershim,这意味着 Docker Engine 不再作为 K8s 的容器运行时。取而代之的是符合 CRI(Container Runtime Interface)规范的运行时,其中 containerd 是事实上的标准选择。 很多运维人员对 containerd 的认知停留在"Docker 的替代品",但实际上 containerd 的架构、镜像管理、命令行工具都与 Docker 有显著差异。本文深入理解 CRI 规范、containerd 架构、日常运维和从 Docker 迁移的实践。 本文基于 containerd v2.0 和 Kubernetes v1.30。参考 containerd 官方文档 CRI 规范 什么是 CRI CRI(Container Runtime Interface)是 K8s 定义的容器运行时接口规范。K8s 不再直接调用容器运行时,而是通过 gRPC 调用符合 CRI 规范的运行时: kubelet → CRI gRPC → 容器运行时(containerd/CRI-O)→ 容器 CRI 接口定义 CRI 定义了两个核心服务: 服务 功能 关键方法 RuntimeService 容器和 Pod 生命周期 RunPodSandbox, CreateContainer, StartContainer, StopContainer ImageService 镜像管理 ListImages, PullImage, RemoveImage, ImageStatus // CRI 接口简化定义 service RuntimeService { rpc RunPodSandbox(RunPodSandboxRequest) returns (RunPodSandboxResponse); rpc StopPodSandbox(StopPodSandboxRequest) returns (StopPodSandboxResponse); rpc RemovePodSandbox(RemovePodSandboxRequest) returns (RemovePodSandboxResponse); rpc CreateContainer(CreateContainerRequest) returns (CreateContainerResponse); rpc StartContainer(StartContainerRequest) returns (StartContainerResponse); rpc StopContainer(StopContainerRequest) returns (StopContainerResponse); rpc RemoveContainer(RemoveContainerRequest) returns (RemoveContainerResponse); rpc ListContainers(ListContainersRequest) returns (ListContainersResponse); rpc ContainerStats(ContainerStatsRequest) returns (ContainerStatsResponse); rpc ListPodSandbox(ListPodSandboxRequest) returns (ListPodSandboxResponse); } service ImageService { rpc ListImages(ListImagesRequest) returns (ListImagesResponse); rpc PullImage(PullImageRequest) returns (PullImageResponse); rpc RemoveImage(RemoveImageRequest) returns (RemoveImageResponse); rpc ImageStatus(ImageStatusRequest) returns (ImageStatusResponse); } 为什么移除 dockershim Docker Engine 不原生支持 CRI,K8s 通过 dockershim 适配层调用 Docker。这带来几个问题:...

June 14, 2024 · 8 分钟 · 1675 字 · 徐保金

Kubernetes Pod故障排查速查

排查路径 kubectl get pods → 看状态 kubectl describe pod → 看 Events kubectl logs → 看日志 常见 Pod 状态 状态 含义 常见原因 Pending 未调度 资源不足、调度约束 CrashLoopBackOff 崩溃重启 应用异常、配置错误 ImagePullBackOff 镜像拉取失败 镜像不存在、认证失败 OOMKilled 内存溢出 内存限制过低 CrashLoopBackOff 排查 最常见故障,排查步骤: # 查看上次崩溃日志 kubectl logs <pod> --previous # 查看退出码 kubectl get pod <pod> -o jsonpath='{.status.containerStatuses[0].lastState.terminated.exitCode}' 退出码含义: 137:OOMKilled → 增加 resources.limits.memory 1:应用错误 → 查应用日志 126/127:命令不存在或权限问题 ImagePullBackOff 排查 kubectl describe pod <pod> | grep -A5 Events 常见原因:镜像名拼写错误、仓库需认证、网络不通。...

May 8, 2024 · 1 分钟 · 185 字 · 徐保金

Kubernetes RBAC 与安全上下文

概述 Kubernetes 默认配置的安全性可以用一个词概括:开放。默认 ServiceAccount 拥有集群内几乎所有 API 的访问权限(取决于版本和 PSP 配置),Pod 以 root 用户运行,容器可以挂载宿主机文件系统,网络全通。这种"默认开放"的设计降低了上手门槛,但在生产环境中是巨大的安全隐患。 从 RBAC 权限模型、ServiceAccount 管理、Pod 安全标准、SecurityContext、网络策略到审计日志,详细梳理 K8s 安全加固的实践方法。 本文基于 Kubernetes v1.30。参考 Kubernetes 安全文档 RBAC 权限模型 RBAC 四个核心对象 对象 作用域 功能 Role 命名空间 定义命名空间内的权限 ClusterRole 集群 定义集群范围或命名空间内的权限 RoleBinding 命名空间 将 Role/ClusterRole 绑定到用户/组/SA ClusterRoleBinding 集群 将 ClusterRole 绑定到用户/组/SA 核心关系: 用户/组/ServiceAccount ──Binding──→ Role/ClusterRole ──包含──→ 权限规则 Role 与 ClusterRole # Role:命名空间级别的权限,只影响指定 namespace apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: production name: pod-reader rules: - apiGroups: [""] resources: ["pods", "pods/log"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["configmaps"] verbs: ["get"] resourceNames: ["app-config"] # 限制只能访问特定 ConfigMap # ClusterRole:集群级别的权限 apiVersion: rbac....

May 2, 2024 · 8 分钟 · 1616 字 · 徐保金

Kubernetes 调度器原理与调优

概述 Kubernetes 调度器是控制平面中最核心的组件之一——它决定每个 Pod 运行在哪个节点上。调度质量直接影响集群的资源利用率、应用性能和可靠性。理解调度器的工作原理,是做好 K8s 生产运维的基本功。 从调度流程、过滤打分机制、亲和性、污点容忍、优先级抢占到自定义调度器,详细梳理调度器的原理与调优实践。 本文基于 Kubernetes v1.30。参考 Kubernetes 调度器文档 调度流程 整体流程 Pod 创建 → API Server → etcd → 调度器 Watch → 调度决策 → 绑定到节点 → kubelet 创建容器 调度器的核心工作分为两个阶段: 1. 过滤(Filter):排除不满足条件的节点 → 候选节点集 2. 打分(Score):对候选节点打分 → 选择最高分节点 详细调度流程 ┌──────────────┐ │ Pod 入队 │ └──────┬───────┘ ▼ ┌──────────────┐ │ 调度周期开始 │ └──────┬───────┘ ▼ ┌────────────────────────┐ │ 扩展点:PreFilter │ ← 预过滤(检查 Pod 是否可调度) └────────────┬────────────┘ ▼ ┌────────────────────────┐ │ 扩展点:Filter │ ← 过滤不满足条件的节点 │ (排除不可行节点) │ └────────────┬────────────┘ ▼ ┌────────────────────────┐ │ 扩展点:PostFilter │ ← 过滤后无节点?(触发抢占) └────────────┬────────────┘ ▼ ┌────────────────────────┐ │ 扩展点:Score │ ← 对候选节点打分 │ (选择最优节点) │ └────────────┬────────────┘ ▼ ┌────────────────────────┐ │ 扩展点:Reserve │ ← 预留资源 └────────────┬────────────┘ ▼ ┌────────────────────────┐ │ 扩展点:Permit │ ← 允许/延迟/拒绝 └────────────┬────────────┘ ▼ ┌────────────────────────┐ │ 扩展点:PreBind │ ← 绑定前处理 └────────────┬────────────┘ ▼ ┌────────────────────────┐ │ 扩展点:Bind │ ← 绑定到节点 └────────────┬────────────┘ ▼ ┌────────────────────────┐ │ 扩展点:PostBind │ ← 绑定后处理 └────────────────────────┘ 调度队列 调度器内部维护三个队列:...

April 29, 2024 · 8 分钟 · 1655 字 · 徐保金

K8s 网络模型:CNI 与 Service 网络

Kubernetes 网络模型四大要求 Kubernetes 网络模型的设计基于四个核心要求,理解它们是掌握 K8s 网络的基础。根据 Kubernetes 官方网络模型文档,这四个要求构成了集群网络通信的基石。 1. Pod 间通信(Pod-to-Pod) K8s 要求所有 Pod 之间可以直接通过 IP 通信,无需 NAT(网络地址转换)。这意味着: 每个 Pod 拥有独立的 IP 地址 Pod 之间通信使用真实 Pod IP,不经过 NAT 转换 无论 Pod 调度到哪个 Node,Pod 间网络始终扁平可达 这是 K8s 网络模型最核心的设计决策。传统数据中心网络中,跨主机容器通信通常依赖端口映射或 NAT,而 K8s 选择了扁平网络模型,让每个 Pod 成为网络中平等的一等公民。 2. Node 与 Pod 通信(Node-to-Pod) Node 上的进程(包括 kubelet、kube-proxy)必须能直接与该 Node 上任何 Pod 通信,同样不经过 NAT。这个要求保证了: kubelet 可以执行健康检查(liveness/readiness probe) 节点上的监控 agent 能直接采集 Pod 指标 主机网络进程与 Pod 网络互通 3. Service 网络 Service 提供了一个稳定的虚拟 IP(ClusterIP),将流量负载均衡到后端 Pod。Service 网络是独立于 Pod 网络的虚拟地址段(默认 10....

April 12, 2024 · 4 分钟 · 722 字 · 徐保金

Kubernetes Ingress 控制器选型与配置

概述 Kubernetes Service 提供四层负载均衡,但在生产环境中,绝大多数 Web 应用需要七层路由能力:基于域名的虚拟主机、基于路径的路由、TLS 终止、灰度发布。Ingress 就是 K8s 对七层路由的抽象,而 Ingress Controller 则是这一抽象的具体实现。 选择 Ingress Controller 不是一个小决策——它处于所有外部流量的入口位置,一旦选错或配置不当,影响的是整个集群的服务可用性。本文对比主流 Ingress Controller 的优劣,并给出生产环境配置实践。 本文基于 Kubernetes v1.30。参考 Kubernetes Ingress 文档 Ingress 原理 数据流路径 客户端 → 负载均衡器(云LB/MetalLB) → Ingress Controller Pod → Service → Pod ↑ Ingress 资源 (路由规则) Ingress Controller 本质上是一个运行在集群中的 Pod(通常是 Deployment 或 DaemonSet),它: 监听 K8s API 中的 Ingress 资源变化 将 Ingress 规则翻译成自身配置(如 nginx.conf) 热加载配置,处理外部请求并路由到对应 Service Ingress 资源结构 apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp-ingress namespace: production annotations: nginx....

March 27, 2024 · 7 分钟 · 1490 字 · 徐保金

Docker 镜像优化:从 1GB 到 50MB

镜像过大的危害 很多团队在容器化初期不太关注镜像体积,一个 Spring Boot 应用镜像动辄 800MB-1.2GB,一个 Go 应用也常有 700MB+。镜像过大带来的问题远不止"占点磁盘": 拉取慢,部署延迟高:在 CI/CD 流水线或弹性扩容场景下,节点需要先拉取镜像再启动容器。1GB 的镜像在百兆内网下载需要 80 秒以上,而 50MB 的镜像仅需 4 秒。对于 HPA 自动扩容场景,这意味着故障恢复窗口被拉长。 安全攻击面大:基础镜像里包含了大量你根本用不到的系统工具(curl、wget、gcc、bash 等)。攻击者一旦拿到容器 shell,这些工具就是横向移动的跳板。镜像越小,攻击面越窄。 存储成本累积:一个镜像 1GB,每天构建 5 次、保留 30 天就是 150GB。10 个微服务就是 1.5TB。 Harbor / Registry 的存储成本和备份成本随之飙升。 构建缓存效率低:大镜像的每一层都更大,构建缓存命中后的加载也更慢,拖慢整体 CI 流水线。 本文参考 Docker 官方多阶段构建文档 多阶段构建(Multi-stage Build) 为什么需要多阶段构建 传统 Dockerfile 的关键问题是:构建工具和运行时环境混在同一个镜像里。 以 Go 应用为例,编译需要 go 工具链和 gcc,但运行时只需要一个二进制文件。如果用 golang:1.22 做基础镜像,最终镜像里会带上整个 Go SDK(约 800MB+),而你的应用二进制可能只有 15MB。 多阶段构建允许在一个 Dockerfile 中定义多个 FROM,每个 FROM 开始一个新阶段,最终镜像只保留最后一个阶段的内容。 多阶段构建语法 # ===== 阶段1:构建阶段 ===== FROM golang:1....

March 14, 2024 · 4 分钟 · 766 字 · 徐保金

Docker Compose 生产环境实战指南

概述 很多团队对 Docker Compose 的认知停留在"本地开发环境编排工具"。但事实上,在中小规模生产场景(单节点或少量节点)下,Compose 依然是性价比极高的方案。它语法简洁、学习成本低、不需要一整套 K8s 集群运维能力,就能完成多服务编排、依赖管理、健康检查、资源限制等核心工作。 本文不重复 Compose 基础语法,而是聚焦生产环境中的真实痛点:服务依赖怎么管才不会启动雪崩、健康检查怎么写才靠谱、密钥怎么不硬编码进 compose 文件、日志怎么不把磁盘写满、什么时候该从 Compose 迁移到 K8s。 本文基于 Docker Compose V2(docker compose 子命令),V1(docker-compose 独立二进制)已停止维护。参考 Compose 规范 多服务编排 生产级 Compose 文件结构 一个典型的生产环境应用至少包含:应用服务、数据库、缓存、反向代理。下面是一个完整的 Web 应用编排示例: # docker-compose.yml name: myapp services: # ========== 反向代理 ========== nginx: image: nginx:1.25-alpine container_name: myapp-nginx restart: unless-stopped ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./nginx/conf.d:/etc/nginx/conf.d:ro - cert_data:/etc/letsencrypt:ro - log_data:/var/log/nginx depends_on: web: condition: service_healthy networks: - frontend logging: driver: json-file options: max-size: "10m" max-file: "3" # ========== 应用服务 ========== web: build: context: ....

February 7, 2024 · 8 分钟 · 1653 字 · 徐保金