ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

K8s入门到实战:从Pod、Service到集群迁移与压测全解析

K8s入门到实战:从Pod、Service到集群迁移与压测全解析 前阵子帮人排一个 K8s 集群的问题业务方一脸无奈地说我这服务在 Docker 里跑得好好的搬到 K8s 就各种诡异不是 CrashLoopBackOff 就是 Service 不通。这几乎是每个刚接触 K8s 的人都会遇到的坎。K8s 也就是 Kubernetes容器编排领域的事实标准现在已经成了后端和运维绕不开的东西。这篇文章我不会照本宣科而是按我自己从搭集群、写部署文件、做迁移、扛压测一路走过来的经验把 K8s 的基础知识和实战链路串一遍。内容是给三类人准备的:准备系统学习 K8s 的运维和开发、正在准备 K8s 相关面试的求职者、以及要把老服务迁上 K8s 的团队。看完你至少能明白 K8s 解决了什么问题知道从哪下手搭一套能用的环境并且能独立把一个有状态的服务部署、更新、监控跑通。1. 为什么说K8s不是Docker多机版先搞清楚它到底解决了什么1.1 容器数量上了规模问题就变了性质很多人学 K8s 之前已经用 Docker Compose 把业务跑得很顺几个后端、一个 Redis、一个 MySQLdocker-compose up 一下全拉起来日志、网络、存储都给你管好。但当你手底下的服务数量翻到十几二十个、部署到好几台机器上的时候问题就变了性质。举个最简单的例子。一台机器挂了Docker Compose 不会帮你去另一台机器上把服务拉起来服务从 3 个副本扩到 10 个副本得有人一台一台去执行 docker run流量进来的时候也没人知道应该往哪台机器的哪个端口转发。这些问题单个看都不复杂但组合在一起就是编排问题而这恰恰是 K8s 的核心范畴。我给非技术人员打过一个比方一台服务器上的容器管理像管一个小厨房你颠勺煎炒烹炸全在自己掌握里K8s 则是一个连锁餐饮中央调度系统它不关心某一口锅具体怎么炒它关心的是全部门店今天能不能都按标准出菜、哪家厨子请假了菜由谁顶上、食材库存不够了怎么调配。这就是为什么说 K8s 不是Docker 多机版它解决的问题层级和 Docker 根本不一样。注意这句话不意味着 Docker 和 K8s 是替代关系。Docker或者说 containerd是底层容器运行时K8s 是上层的编排调度平台两者是配合工作的关系。1.2 必须理解的四个核心抽象Pod、Controller、Service、IngressK8s 的概念体系庞大但最核心的其实是四个抽象Pod 是最小调度单位Controller 维持期望状态Service 提供稳定访问入口Ingress 统一七层路由。把这条主链路理清楚后面学什么都顺。Pod 是 K8s 里最小的调度和运行单元是一组必须跑在同一台机器上、共享网络和存储的容器的集合。为什么要引入 Pod 而不是直接用容器因为有些服务不是单个进程能搞定的比如业务容器配一个日志采集 Sidecar 容器它们必须同生共死、共享网络栈Pod 就是这个组合的最小单元。实际开发中大多数情况一个 Pod 里只有一个主容器但理解为什么存在 Pod能帮你读懂 kubelet、CNI 这些组件的很多设计逻辑。Controller 是 K8s 的监工。Deployment 管无状态应用StatefulSet 管有状态应用DaemonSet 保证每个节点跑一个副本Job 和 CronJob 管一次性任务。你告诉它我要 3 个副本它就持续保证集群里正好有 3 个对应的 Pod有 Pod 挂了会在其他节点重新拉起来。这种期望状态的持续对比机制就是 K8s 自愈能力的基础。Service 解决的是Pod 会变的问题。Pod 随时可能被销毁重建IP 一直在变。Service 给一组 Pod 提供一个稳定的虚拟 IP 和 DNS 名字你通过 Service 访问服务K8s 把流量转发到后面实际的 Pod 上同时自带负载均衡。Ingress 则是从外部进入集群的那道门它可以理解成一个七层网关根据域名和 URL 路径做路由转发同时承担 TLS 终止等职责。这四个概念之间存在一条完整的链路Deployment 管好 Pod 的个数和健康Service 给 Pod 一个稳定的名字Ingress 把域名流量引到 ServiceService 再把流量分发到后端 Pod。理解了这条链路K8s 的主干也就通了。1.3 声明式APIK8s和传统运维脚本的本质区别用 Docker 的习惯本质是命令式操作docker run、docker stop、docker rm你每一步都明确告诉它去做什么。而 K8s 是声明式的你写一份 YAML描述我期望的状态比如nginx 应用需要 3 个副本然后 kubectl apply 丢给它K8s 内部的控制循环就开始工作持续对比期望状态和实际状态中间有偏差就自动去调和。这个差异非常关键。命令式脚本最大的问题在于一旦中间某一步失败后续步骤不会执行你得自己处理各种异常分支而声明式的方式控制循环在后台不断纠正不需要你关心每一步怎么执行系统自己保证最终状态符合你的描述。所以 K8s 天然具备自愈能力副本少了补副本节点挂了迁移 Pod探针发现进程异常就重启。我做了很多年运维最初很不适应这种转变总觉得不写脚本心里没底。但真正用久了你会发现声明式地维护一组 YAML 文件比一堆顺序执行的 Shell 脚本可靠太多。YAML 文件可以纳入 Git 做版本管理每次变更都有记录review 起来清清楚楚。这也是 K8s 被行业看好的核心原因它把系统应该长什么样和怎么一步步变成那样这两件事彻底解耦了。2. 从零搭建K8s集群本地学习和生产环境的两个岔路口2.1 本地环境选型minikube、kind 还是 k3s我见过不少人学 K8s 的第一步就是找三台服务器吭哧吭哧按教程搭一套生产级集群。对想快速入门的人来说这个动作太重了而且很容易卡在各种网络问题上。本地开发环境其实有更适合的选项。minikube是最接近完整 K8s 的本地方案它启动一个虚拟机或容器在里面跑一个单节点集群支持大多数 K8s 核心功能比如 NodePort、PVC、Dashboard。适合想完整体验 K8s 功能的初学者。缺点是启动稍慢需要下载的东西比较多。kindKubernetes in Docker用 Docker 容器模拟 K8s 节点非常轻量秒级启动特别适合在 CI/CD 流水线里做集成测试。它默认使用 containerd 作为运行时也比较贴近生产。缺点是在容器里跑容器网络和存储的限制多一些。k3s是 Rancher 出的轻量发行版安装包只有几十兆内存占用极低。它精简掉了一些默认插件但核心功能完整保留既能在树莓派上跑也能在小规模生产环境用。我现在身边不少朋友在单机或边缘场景直接上 k3s。方案启动速度资源占用完整度适用场景minikube中中高本地完整学习、功能验证kind快低中CI/CD、快速试验k3s很快很低中高轻量环境、边缘节点、小规模生产个人建议如果你从零开始学 K8s优先用 minikube 或 k3s因为能体验到完整的 K8s 功能链路如果只是写代码后想在流水线里快速起一个集群做验证kind 更合适。2.2 生产集群搭建前的四个关键决策本地环境玩转了真正要在生产搭集群时有四个决策直接影响后续体验值得在动手前就想清楚。第一是容器运行时选什么。早些年大家习惯在 K8s 里用 Docker Engine 作为运行时但 containerd 成熟之后我更推荐直接使用 containerd。原因很简单Docker Engine 多了一层 dockerd 守护进程和 shim 逻辑性能和运维成本都更高而 containerd 更轻、更稳定也是 K8s 官方主推的方向。新搭建的集群直接选 containerd没必要再用 Docker 做运行时。第二是 CNI 网络插件。这是集群里最容易出问题又最让人头疼的部分。Flannel 配置简单、适合入门但网络策略和性能偏弱Calico 支持 BGP 路由和 NetworkPolicy是目前应用最广的选择Cilium 基于 eBPF性能和功能都很突出适合对网络要求高的场景。没有特殊需求时Calico 是比较稳妥的默认项。第三是控制平面节点能不能高可用。生产环境控制平面至少要 3 台做冗余etcd 是有状态服务必须放在奇数个节点上保证选举能正常进行前面再用负载均衡器把 apiserver 流量分发到三个控制节点。单控制节点的集群在生产里我是不推荐的一旦重启或宕机整个集群的管控面就断了。第四是安装工具怎么选。kubeadm 是社区标准工具灵活性强但各种细节都要自己把控kubespray 用 Ansible 做自动化部署省心但对网络和操作系统有一定要求如果需求偏简单直接用云厂商的托管服务比如阿里云 ACK、AWS EKS把控制面和 etcd 都托管了业务团队只需要关心工作节点这是成本效率最高也最省事的生产方案。2.3 安装部署时我踩过的几个坑搭建过程中有几个经典坑我几乎每次帮别人排查都会碰到先列出来给大家避一避。swap 必须关掉。内存不够时系统会走 swap而这会严重影响 Pod 的 QoS 保障和 kubelet 的资源计算kubeadm init 默认会在有 swap 的节点上报错。别偷懒只敲一句 swapoff -a要同时把 /etc/fstab 里的 swap 行注释掉不然机器重启后 swap 又回来了。内核参数不改必出网络问题。kubeadm 官方文档要求设置 net.bridge.bridge-nf-call-iptables1否则 CNI 插件处理桥接流量时会出问题。典型表现是 Pod 之间网络不通kubectl logs 里能看到一堆 conntrack 相关报错。检查 sysctl 配置这一步千万别跳过去。镜像拉取一直被卡住。这通常是网络访问问题。最省心的方式是在 kubeadm init 时通过 --image-repository 指定可用的镜像仓库地址并在 containerd 的配置文件里配好 registry 的镜像加速。这个动作如果放到集群搭好之后再补就晚了很多 Pod 会一直停在 ImagePullBackOff。还有一个容易被忽略的点kubeadm init 报错时不要急着重复执行先看 /var/log/messages 或者 journalctl -u kubelet 的日志。很多问题其实一眼就能看出来但新手常常不查日志就重新 init结果卡在同一个地方。学会看 kubelet 日志排障效率会高很多。3. 手搓第一个应用上集群从YAML到Helm的完整链路3.1 看得懂的YAML一个Deployment是怎么描述出集群中的服务的K8s 里一切皆资源而资源用 YAML 描述。很多新手一看到 YAML 就头大其实它的结构非常固定apiVersion 指定资源的 API 版本kind 指定资源类型metadata 写名称和标签spec 写资源期望的状态。就这四个字段万变不离其宗。我拿一个真实的 Deployment 拆解一下apiVersion: apps/v1 kind: Deployment metadata: name: user-service # Deployment 的名字 labels: app: user-service spec: replicas: 3 # 期望的 Pod 副本数 selector: matchLabels: app: user-service template: metadata: labels: app: user-service spec: containers: - name: user-service image: registry.example.com/user-service:1.2.0 ports: - containerPort: 8080 resources: requests: cpu: 250m memory: 256Mi limits: cpu: 500m memory: 512Mi readinessProbe: # 就绪探针什么时候可以开始接流量 httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 20 periodSeconds: 10注意 selector 和 template.labels 这两个字段它们必须匹配。Pod 的数量由 replicas 控制Controller 通过 label selector 知道哪些 Pod 归我管。这种设计的好处是你可以用 kubectl label 给 Pod 动态打标签Controller 能感知到变化从而支持一些灵活的操作。resources 里的 requests 和 limits 也值得好好理解。requests 是至少给这么多调度器依据 requests 决定把 Pod 放在哪个节点上limits 是最多能用这么多超过之后容器会被限制甚至杀掉。requests 写少了高并发时容器容易被 OOMKilled写多了资源利用率低。这个经验值只能靠压测慢慢摸没有一步到位的银弹。3.2 让服务能被访问Service和Ingress怎么配合Deployment 创建出来的 Pod 有 IP但这些 IP 是临时的Pod 重建就变。为了让服务有一个稳定入口需要创建 Service。最常用的 Service 类型是 ClusterIP它提供集群内部的虚拟 IP通过 label selector 把流量转发到匹配的 Pod 上apiVersion: v1 kind: Service metadata: name: user-service spec: type: ClusterIP selector: app: user-service ports: - port: 80 # Service 的端口 targetPort: 8080 # 转发到容器里的端口当服务多了以后直接在 Service 上暴露端口会很乱所以通常会在 Service 前面再挂一层 Ingress。Ingress 是七层网关按照域名和路径做路由。比如apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example-ingress spec: rules: - host: api.example.com http: paths: - path: /user pathType: Prefix backend: service: name: user-service port: number: 80整条链路就是外部流量 → Ingress根据域名/路径路由 → Service负载均衡 → 某个 Pod。集群内部服务之间的调用则直接通过 Service 的 DNS 名字访问比如 http://user-service:80K8s 的 CoreDNS 会负责解析。3.3 配置管理ConfigMap、Secret、PVC分别解决什么问题把配置硬编码进镜像是最容易踩的坑环境切换要重新构建镜像密码泄漏也是常有的事。K8s 提供三件套来解决这个问题。ConfigMap 管非敏感配置数据。可以把 application.yml、环境变量、配置文件的内容都放进去然后挂载到容器里apiVersion: v1 kind: ConfigMap metadata: name: user-service-config data: application.yml: | server: port: 8080 spring: datasource: url: jdbc:mysql://mysql-service:3306/user_dbSecret 管敏感信息比如数据库密码、token、TLS 证书。Secret 的值要求是 base64 编码创建之后通过 volume 挂载或环境变量注入进容器。需要提醒的是Secret 只是做了 base64 编码并不是真正的加密生产环境一定要开 etcd 加密存储并且配合 RBAC 严格控制访问权限。PVC 解决的是数据持久化问题。Pod 是一次性的容器里的数据随着 Pod 删除就没了。PVC 向集群申请一块持久化存储Pod 声明挂载它。存储后端可以是 NFS、Ceph也可以是云厂商的云盘。使用 StorageClass 动态供给时你只需要声明我要 10Gi 存储存储系统会自动创建对应的 PV这个体验在云环境上尤其顺畅。3.4 Helm把反复手写的YAML变成一条命令一个稍微复杂的服务动辄要写 Deployment、Service、Ingress、ConfigMap、Secret 五六个 YAML 文件。如果项目里有十几个服务手写 YAML 的日子基本没法过这就是 Helm 存在的意义。Helm 是 K8s 的包管理工具。核心概念是 Chart一个 Chart 是一个包含模板和默认配置的目录。你可以把 Deployment、Service、Ingress 这些 YAML 都写成模板把镜像版本、副本数、资源配额这些可变量用变量代替部署的时候通过 values.yaml 或命令行参数传入不同的值。实际用下来Helm 最大的价值是版本化和可回滚。每一次 helm upgrade 都会生成一个 release 版本记录如果新版本出了问题一条 helm rollback 就能回到上一个稳定版本。这比手动 kubectl apply 一堆 YAML、然后不知道谁改了什么体验好太多了。很多团队刚开始觉得 Helm 学习成本高不愿意用我一般建议先在开发环境试一个简单的 Chart跑通之后基本就回不去了。生产环境没有 Helm发布和回滚都太痛苦。4. 微服务在K8s里的正确打开方式流量治理、滚动更新与优雅下线4.1 从Service到Service Mesh微服务多了之后流量怎么治Service 解决了服务发现和基础负载均衡但对微服务场景来说还不够。你想做灰度发布让 10% 的流量打到新版本你想给服务之间的调用加熔断、限流、重试你想统计服务间的调用链路。这些能力 Service 都不提供传统做法是在每个服务里用 SDK 实现这就是 Service Mesh服务网格要解决的问题。Service Mesh 的核心思路把服务之间的通信能力从业务代码里剥离出来下沉到一层独立的代理Sidecar里。Sidecar 容器跟业务容器共享一个 Pod接管所有进出流量实现服务发现、负载均衡、流量控制、可观测性业务代码零侵入。目前常见的开源方案是 Istio 和 Linkerd。Istio 功能全面但资源占用大Linkerd 轻量很多。如果你用的是 Dubbo 这类 RPC 框架也可以关注 Dubbo Mesh 方向通过 K8s 原生 Service 结合 Mesh 能力改造让 Dubbo 服务在云原生环境下继续发挥治理能力同时享受 K8s 弹性和自愈红利。什么时候需要引入 Service Mesh我的建议是别一开始就上等真正遇到流量治理痛点再引入。比如某个服务的版本灰度反复出问题、调用链排查极其痛苦、或者需要统一的熔断降级策略时再上。提前引入了多出来的运维复杂度会让你苦不堪言。4.2 滚动更新怎么做到不中断服务K8s 默认的更新策略是滚动更新先起一个新的 Pod等它就绪后再把一个旧 Pod 下线逐步替换直到所有旧版本都被新版本替代。但很多人第一次做滚动更新时会发现更新过程中仍有部分请求失败。原因通常是两个没配 readinessProbe或者探针配置得太粗。readinessProbe 是我是否准备好接流量的信号一旦探针连续失败K8s 会把该 Pod 从 Service 后端摘除。如果没有配探针新 Pod 一启动就被加进 Service此时容器内的应用可能还没完成初始化一接流量就报错。另一个容易忽略的是滚动更新的参数spec: strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # 更新过程中最多可以比期望副本数多几个 maxUnavailable: 0 # 更新过程中最多允许几个副本不可用生产环境我一般建议把 maxUnavailable 设成 0maxSurge 设成 1先扩容一个新的确认它健康再缩容一个旧的。这样在任何时刻都有足够的服务实例在跑不容易出现流量打到正在停机的 Pod 上。4.3 优雅停机为什么你的服务一升级就出现5xx滚动更新过程中旧的 Pod 会收到 SIGTERM 信号然后进入 terminating 状态。但这里有个微妙的细节kubelet 在给容器发 SIGTERM 之前已经把 Pod 从 Service 的 Endpoints 里摘掉了但摘掉到 kube-proxy 同步生效有一个传播延迟。如果容器收到 SIGTERM 立刻退出在这段时间内到达的请求就会 5xx。解决思路很明确容器收到 SIGTERM 之后不要立刻退出而是等一小段时间让还在途的请求处理完再退出。具体做法有两种在 Deployment 里配置terminationGracePeriodSeconds给 Pod 更长的优雅退出时间在容器里加一个 preStop 钩子收到终止通知时先 sleep 几秒给流量足够的时间从 Endpoints 中摘除。我用的最多的是组合方案preStop 里 sleep 5-10 秒同时把业务框架的优雅停机功能打开Spring Boot 对应 server.shutdowngraceful每次发布业务侧基本观察不到错误。补充一个实战细节如果你的服务有 WebSocket 长连接只处理完 HTTP 请求还不够需要单独处理连接迁移和断开通知否则客户端会表现出一段时间的断线。这一块最好在代码层面对 SIGTERM 做监听并主动通知。4.4 Prometheus Grafana把集群状态变成可观测的指标集群搭起来、服务跑起来之后最怕的就是黑盒不知道服务状态不知道资源水位出问题了只能靠用户投诉。我的习惯是集群搭完当天就把监控配上。推荐组合是 Prometheus Grafana。Prometheus 负责采集和存储指标Grafana 负责可视化展示和告警。在 K8s 上最简单的方式是用 kube-prometheus-stack 这个 Helm Chart 一键安装它会自动部署 Prometheus、Alertmanager、Grafana以及各类 exporter 和预置告警规则。真正值得花时间的不是安装而是想清楚要盯哪些指标。我日常主要关注四类集群层面节点 CPU/内存水位、磁盘使用率、Pod 数量、集群事件工作负载层面Deployment 副本数是否等于期望值、Pod 重启次数、容器 OOMKilled 数量网络流量层面Service 的 QPS、P99 延迟、5xx 数量存储层面PVC 使用率。告警规则不要贪多。我的经验是刚开始只需要配最核心的几条比如 Pod 频繁重启、节点 NotReady、PVC 使用率超过 85%其他的等实际踩过坑再慢慢补。规则太多狼来了的故事每天在群里上演到最后真正重要的告警也被忽略了。5. 一次真实的迁移实战单节点K8s上的若依微服务搬上云5.1 迁移前的清单镜像、数据、编排三条线今年上半年我协助团队做过一次迁移把一套运行在单节点 K8s 上的若依微服务整套环境迁移到阿里云 ECS 上的新集群要求准不停服、不丢数据。若依是一个典型的 Java 微服务管理系统包含网关、多个业务服务以及配套的 MySQL 和 Redis。整个迁移过程挺有代表性复盘一下。动手之前先分三条线理清楚镜像、数据、编排。镜像无论原集群里是自建仓库还是本地镜像都要把业务镜像重新打上目标仓库的标签并推送过去。注意镜像的 tag 有没有规范别迁移完发现不知道哪个镜像对应哪个版本。数据最核心的是 MySQL 的数据一致性迁移。若依这类系统业务数据全在 MySQL 里Redis 里的缓存可以容忍少量丢失重新缓存就行但 MySQL 不能丢一行。编排把原集群所有 Deployment、Service、ConfigMap、Secret、PVC 的 YAML 导出来清理掉环境相关的硬编码再适配到新集群。直接 kubectl get xxx -o yaml 导出是可以参考的但通常需要重构。编排这块给一个实用建议如果原集群已经用了 Helm迁移会轻松非常多只要把 values.yaml 重写一遍helm install 一套就是新环境。如果原来全是裸 YAML这次迁移正好是整理成 Helm Chart 的好机会不然下次迁移还要再痛苦一次。5.2 数据一致性怎么做到不停服、不丢数据准不停服、不丢数据这八个字难度主要在最后一步切换。准不停服不是真的完全没有瞬时抖动而是要把窗口尽量压缩。当时我的思路是典型的在线迁移 增量追平 快速切换。具体步骤是这样先在目标环境把 MySQL 实例准备好通过 mysqldump 导出一份全量数据恢复到新库开启 MySQL 的 binlog 增量同步。最简单的方式是用 DTS 这类数据传输工具云厂商基本都有或者用 Canal 把源库的 binlog 同步到目标库全量加增量并行跑持续观察源库和目标库的延迟当延迟压到几秒以内时就进入切换窗口在业务低峰期停掉源库的写入或者直接把流量切到新环境等待增量追平然后启动新环境对外服务保留源环境只读运行 24 到 48 小时确认没有数据差异后再彻底下线。这套方案的关键点在于增量追平。如果你的业务是持续写入的靠手工在最后时刻导出导入是无法保证一致性的必须要有一个 binlog 级别的增量同步机制。单节点的 K8s 环境里跑着 MySQL迁移到云上建议直接用云数据库 RDS高可用和备份都替你管了省心很多。Redis 那边简单一些可以先在新环境搭一个主从再由应用层触发缓存预热。即使有少量缓存丢失也只是首次访问变慢一点不会丢业务数据。容我多说一句迁移期间一定要留一条快速回退的路。本地环境保留运行到新环境稳定或者至少保留所有配置和备份出问题能一键回切。不要抱着一定要成功的心态迁移出问题不可怕可怕的是没有退路。5.3 搬完不是结束jmeter高并发压测验证迁移完成后压测人员用配套的 jmeter 脚本对整个环境做了高并发测试验证云上环境的承载能力。这一步非常关键因为服务能跑和服务扛得住是两个概念。压测的流程大致是这样先用 jmeter 跑小规模请求确认脚本和测试数据没有问题逐步增加并发数比如从 100 并发到 500 并发再到 1000 并发每个阶段持续 5-10 分钟观察系统表现记录三类核心指标TPS每秒事务数、响应时间的 P99、错误率压测过程中同时观察 K8s 侧的状态Pod CPU/内存水位、HPA 是否触发扩容、数据库连接池是否打满。压测中最常见的结果是副本数不够CPU 先到瓶颈Pod 被限流P99 延迟直线上升。这时候需要做的很简单把 Deployment 的副本数调大或者配置 HPA 让它根据 CPU 使用率自动扩缩容apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: user-service-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: user-service minReplicas: 3 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70压测最好在业务低峰期做并且做好限流预案。有一次我们在压测时没控制好并发量直接把数据库连接池打满导致线上其他服务也跟着变慢。后来在压测脚本里加了全局启动延迟同时在网关层做了限流配置确保压测流量不会影响真实用户。压测数据出来之后不要只盯着 TPS。TPS 高但 P99 超过 2 秒对用户来说依然很卡。一次成功的压测应该给你一个这套系统在什么流量下开始劣化的明确答案并在此基础上反推出合理的容量规划和扩容策略。6. 把K8s学得扎实一点常用命令、面试考点和避坑心得6.1 我日常最常用的kubectl命令清单有人觉得 kubectl 命令太多记不住其实日常高频的就那么几条。我按使用场景整理了一下自己使用频率最高的命令场景命令说明查看资源kubectl get pods -A查看所有命名空间的 Pod 状态查看详情kubectl describe pod查看 Pod 事件、状态变化排障第一步看日志kubectl logs -f -c实时看容器日志多容器时指定容器名进入容器kubectl exec -it -- /bin/sh进容器排查问题转发端口kubectl port-forward svc/user-service 8080:80本地直接访问集群内服务调试利器查看资源占用kubectl top nodes / kubectl top pods查看节点和 Pod 的 CPU/内存实际使用查看集群事件kubectl get events --sort-by.lastTimestamp集群出问题时先看事件应用变更kubectl apply -f deployment.yaml声明式应用 YAML查看滚动状态kubectl rollout status deployment/user-service查看发布进度回滚版本kubectl rollout undo deployment/user-service回滚到上一个版本排障的通用流程我一般是kubectl get pods 看状态kubectl describe pod 看事件kubectl logs 看应用日志必要时 kubectl exec 进容器进一步排查。这一条链路走下来80% 的问题都能定位。6.2 面试里绕不开的几个K8s必问题K8s 相关的岗位面试问题其实相对固定。我梳理几个最高频的同时也是很多人平时没真正搞懂的点。问Docker 和 K8s 有什么区别这是基础但最常翻车的题。简洁版回答Docker 是容器化技术负责将应用和应用依赖打包成镜像、在单机上运行容器做的是容器运行时和单机编排层面的工作K8s 是容器编排平台解决多台机器上容器的调度、扩展、自愈、服务发现等问题。Docker Compose 可以编排单机上的多个容器但 K8s 是跨节点的、声明式的、带自愈能力的一整套系统。别把两者对立起来它们是不同层级的配合关系。问谈谈 Pod 的生命周期Pod 有 Pending、Running、Succeeded、Failed、Unknown 等阶段还有 CrashLoopBackOff 这种异常状态。真正的考点在于探针livenessProbe 失败会重启容器readinessProbe 失败会从 Service 摘除流量startupProbe 用于慢启动应用。这几种探针的搭配使用体现的是你对生产可用性的理解。问Deployment 和 StatefulSet 有什么区别Deployment 适合无状态应用Pod 是等价的名字随机可以随意替换StatefulSet 适合有状态应用每个 Pod 有稳定的网络标识序号和独立的 PVC启动和终止有严格顺序。典型例子是数据库、ZooKeeper、Kafka 这类集群。追问往往是有状态应用到底适不适合放 K8s答案看场景数据库这类对性能和运维精细度要求极高的优先考虑云数据库托管自建场景中 StatefulSet 配合 Operator 也是常见方案。问集群节点资源不足时怎么办考察你对调度机制的理解。常规思路先 kubectl top nodes 看真实使用情况确认是不是某个 Pod 的 requests 设置过高再用 describe 看哪些 Pod 处于 Pending找出无法调度的原因然后针对性地加节点、清理无用 Pod、调整资源配额。同时要理解 requests 和 limits 的差异调度只看 requests不会看实际用量。6.3 学了这么多实操时最值得记住的经验这篇内容讲了不少基础知识和实战经验如果只能总结一条实操时最值得记住的经验我会说先让系统跑起来再一点点理解它是怎么工作的。K8s 的知识体系非常庞大如果非要把所有原理都搞清楚再动手很可能学到一半就放弃了。我建议走最小闭环路线用 minikube 或 k3s 搭一个本地环境把一个最简单的 Nginx 服务部署上去访问它然后再去理解 Deployment、Service、Ingress 各自做了什么。一个闭环跑通之后后面所有概念都有了落地的锚点。另外还有一个非常实用的做法多读别人的 YAML但不盲从。社区里现成的 Chart 是最好的学习材料比如 bitnami 的 Helm Chart、nginx-ingress 的部署清单读它们的结构、变量、探针配置比自己啃文档效率高得多。但要注意版本差异网上很多教程用的镜像、API 版本可能已经过时遇到报错是再正常不过的结合报错去查官方文档往往能避掉 80% 的坑。
返回列表