简介这是一份面向容器编排初学者、后端开发者及运维人员的 Kubernetes 课件围绕集群基础概念、核心组件、监控与日志、应用生命周期管理、调度、存储和集群安全等主题展开可用于课堂讲授、自学梳理或团队内部分享。压缩包内含 1 个 PPTX 文件大小约 1.25MB以幻灯片形式系统组织知识点目录清晰便于按章节浏览、复习和二次编辑内容从集群架构中的接口服务、控制器管理、调度器、键值存储、节点代理和网络代理等组件讲起并解释最小部署单元、控制器、服务、标签和命名空间等核心对象。课件还结合常用命令介绍集群状态查看、资源利用率监控、组件与应用日志管理以及应用的创建、发布、升级、弹性伸缩和回滚流程有助于读者建立较完整的知识框架。已有 2191 人学习适合作为入门阶段的提纲式参考。1. 从一份 Kubernetes 课件说起它补的是概念缺的是落地那一段第一次翻这份 Kubernetes 课件我先跳到目录末尾看到「调度、存储、集群安全」三个词就放心了——它不是那种只讲 Pod 和 Deployment 的入门幻灯片。k8s 这东西概念图谁都能画难的是从kubectl敲下去到容器真的跑起来这一整条链。课件把内容切得很实在基本概念、监控与日志、应用生命周期管理、调度、存储、集群安全基本对应一个运维从「能把服务起起来」到「出事能定位」的六步路。它的问题也明显——课件属性太重命令给到kubectl rollout undo就停了参数为什么这么填、填错报什么错得自己补。下面我按「架构立住 → 跑通一次部署 → Pod 细节 → 监控排错 → 三块自检」的顺序把它拆开刚接手集群的开发能照着敲已经能跑但总在回滚和排错上翻车的运维能对上参数。2. 集群架构与核心对象apiserver 到 kubelet 这条链谁在管什么这一章是整份课件的骨架。很多人学 k8s 卡住不是因为记不住七个组件名字而是不知道一个kubectl apply之后请求在集群里怎么流转、卡在哪一环该去看谁。把这条链捋顺后面所有排错都有落点。2.1 控制面四组件apiserver 是唯一入口etcd 是唯一真相kube-apiserver 是整个集群的统一入口对外用 RESTful API 提供服务所有对象资源的增删改查和 watch 监听都先交给它再由它提交给 etcd 存储。这句话的分量在于「唯一」两个字kubelet 不直接找 schedulercontroller-manager 也不直接改 etcd任何组件想动集群状态都得走 apiserver。所以排查问题的第一现场永远是 apiserver 的日志和它的健康端点。kube-controller-manager 是一堆控制器的集合体。它的工作模式是「期望状态」和「实际状态」的差量收敛你声明 Deployment 要 3 个副本Deployment controller 创建 ReplicaSetReplicaSet controller 再去创建或删除 PodNode controller 盯着节点心跳Endpoints controller 维护 Service 和后端 Pod 的对应关系。一个资源对应一个控制器controller-manager 管的就是这些控制器。kube-scheduler 负责给新创建、还没绑定节点的 Pod 选一个 Node。它的算法分两段先过滤掉不满足条件的节点资源不够、亲和性不匹配、污点不容忍再对剩下的节点打分排序选最高分。这里有个常见误解——调度只是「决定」真正把 Pod 跑起来的是目标节点上的 kubelet。etcd 是分布式键值存储保存的是整个集群的状态数据Pod、Service、Secret、ConfigMap 全在里面。它是唯一可以直接读写 etcd 的组件所依赖的底座。我一般会跟人说集群挂了可以重建etcd 数据没了就是真的没了所以备份是唯一的后悔药。kubeadm 部署的集群常见做法是这样备一份# kubeadm 部署的集群证书路径一般是下面这几个按实际环境改 ETCDCTL_API3 etcdctl snapshot save /backup/etcd-$(date %F-%H%M).db \ --endpointshttps://127.0.0.1:2379 \ --cacert/etc/kubernetes/pki/etcd/ca.crt \ --cert/etc/kubernetes/pki/etcd/server.crt \ --key/etc/kubernetes/pki/etcd/server.key # 校验快照是否完整别等恢复的时候才发现文件是坏的 ETCDCTL_API3 etcdctl snapshot status /backup/etcd-xxxx.db -w table--endpoints指向本机 etcd 的 2379 端口三个证书参数缺一不可少一个就是context deadline exceeded或者证书校验失败。snapshot status那一步别省我见过备份脚本跑了一年实际写出来的是 0 字节文件恢复时才发现那才叫血泪经验。登录到控制面机器上验证这几件事基本能确认控制面是活的# 集群信息和 apiserver 地址 kubectl cluster-info # 控制面组件的 Pod 状态静态 Pod 一般都在 kube-system 下 kubectl get pods -n kube-system -o wide # apiserver 的逐项健康检查比 /healthz 信息量大得多 kubectl get --raw /readyz?verbose/readyz?verbose会逐条列出 etcd、准入控制、控制器等子检查项的通过情况哪一项[-]失败就直接指向对应组件比盲翻日志快很多。2.2 Node 侧三件套kubelet 拉容器、kube-proxy 写规则、引擎干活kubelet 是 Master 放在 Node 上的 Agent它做几件事向 apiserver 注册节点、watch 到绑定到本节点的 Pod、管理本机容器的生命周期创建容器、挂载数据卷、下载 Secret、周期性上报节点和容器状态。注意 kubelet 本身不直接操作容器运行时它通过 CRI 接口喊话底下接的是 containerd 或者 docker。kube-proxy 在 Node 上实现 Pod 网络的代理维护 iptables 或 ipvs 规则完成 Service 的四层负载均衡。它不转发流量本身ipvs 模式下尤其如此它做的是「把规则写对」。所以 Service 访问不通时kubectl get endpoints为空说明是 selector 的问题Endpoints 有值但访问超时才轮到怀疑 kube-proxy 的规则。容器引擎containerd / docker是最终真正跑容器的那一层。课件里写的是 docker 或 rocket现在主流新集群基本是 containerd但排查思路不变容器起不来crictl或docker那一层的日志永远是最后一环。# kubelet 是不是活着重启过几次 systemctl status kubelet # 实时跟 kubelet 日志Pod 调度上来却起不来时最常看的地方 journalctl -u kubelet -f --no-pager # 节点状况重点看 MemoryPressure / DiskPressure / Ready 三个 Condition kubectl describe node node-name | grep -A 8 Conditionsjournalctl -u kubelet里出现failed to pull image就是镜像问题出现failed to create pod sandbox多半是 CNI 网络插件没就绪两类错误的处理路径完全不同别混着查。2.3 五个对象的咬合关系Label 是胶水Endpoints 是证据课件把 Pod、Controllers、Service、Label、Namespace 列成五个并列的概念实际它们是咬合在一起的。Pod 是最小部署单元是一组容器的集合同一个 Pod 内的容器共享网络命名空间Pod 本身是短暂的——这四条决定了后面所有的设计取向。Controllers 决定 Pod 怎么被管。Deployment 管无状态应用支持滚动更新和回滚StatefulSet 管有状态应用给每个副本稳定的网络标识和有序的启停DaemonSet 保证每个节点跑一个副本日志采集和网络插件常用它Job 是一次性任务CronJob 是定时任务。选错控制器是新手最常见的返工点比如拿 Deployment 去跑数据库Pod 一重建存储和网络标识就全乱。Service 解决的是「Pod 会失联」这个问题。它通过 Label Selector 匹配一组 Pod给它们一个固定入口和访问策略。Label 是附加到资源上的键值对用来关联、查询和筛选Namespace 把对象在逻辑上分开但要注意——Namespace 只做对象层面的隔离网络默认并不隔离要真隔离得靠 NetworkPolicy。# 看 Pod 带的标签 kubectl get pods --show-labels # 按标签筛选 kubectl get pods -l appnginx # 最关键的一条Service 到底有没有匹配到 Pod kubectl get endpoints webkubectl get endpoints web输出的ENDPOINTS列如果显示none说明 selector 和 Pod 标签对不上这时候不要去查网络先回去对标签。这个命令我基本上每次排查 Service 都是第一个敲的。下面这张表是我自己整理的对象职责对照贴在显示器边上那种对象解决的问题关键字段出问题先看Pod最小调度与运行单元spec.containers、volumesdescribe pod的 EventsDeployment无状态副本数与滚动更新replicas、selector、strategyrollout status、ReplicaSetStatefulSet有状态、稳定标识、有序启停serviceName、volumeClaimTemplatesPVC 是否 PendingDaemonSet每节点一份tolerations、nodeSelector节点污点是否容忍Service固定入口与四层负载selector、port、targetPortget endpoints3. 用命令行与 YAML 跑通一次部署从 create 到 NodePort 暴露架构讲完就得动手。这一章的目标很具体不打开任何编辑器纯命令行把一个服务从零跑起来、暴露出去再用 YAML 复现一遍最后走完升级、扩缩容、回滚、删除的完整生命周期。这套动作跑顺了课件第三章的内容就算真的落地了。3.1 命令行五分钟起服务并暴露先从最省事的路径开始。用kubectl create deployment直接生成一个 Deployment再expose把端口放出去# 创建 Deployment指定镜像和副本数镜像换成你自己的 kubectl create deployment web --imagedemo/java-app:1.0 --replicas2 # 确认 Deployment 和 Pod 都起来了-o wide 能看到 Pod 落在哪个节点 kubectl get deploy,pods -o wide # 暴露为 NodePort 类型集群外可通过 节点IP:NodePort 访问 kubectl expose deployment web \ --port80 \ --target-port8080 \ --typeNodePort \ --nameweb # 拿分配到的 NodePort kubectl get svc web这里四个参数必须分清--port是 Service 自己监听的端口--target-port是容器实际监听的端口--typeNodePort表示在每个节点上开一个高位端口转发进来--name不给的话默认跟 Deployment 同名但容易和别的资源撞。target-port填错是最常见的翻车点——Pod 明明 RunningService 也能查到访问就是 502 或超时因为流量转到了容器没监听的端口上。kubectl get svc web输出里PORT(S)列会写成80:31234/TCP这种形式冒号后面那个 31234 就是 NodePort默认范围 30000–32767。集群如果开了防火墙或者安全组这个范围得放行否则内网其他机器访问不了本机curl却正常很容易误判成 Service 有问题。3.2 YAML 字段拆解apiVersion、selector 与 template 是强绑定关系命令行适合试手真上生产还得写 YAML。课件里给的 Deployment 模板是全篇最有价值的片段之一我把它补上注释重新贴一遍apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default spec: replicas: 3 # 期望副本数controller 会持续向这个数字收敛 selector: matchLabels: app: nginx # 必须和下面 template 里的 labels 完全对得上 template: # Pod 模板改了它才会触发滚动更新 metadata: labels: app: nginx # 这个标签是 selector 匹配的唯一依据 spec: containers: - name: nginx image: nginx:1.15 ports: - containerPort: 80 # 仅声明用途不做端口限制但 Service 要靠它对齐三个字段值得单独说。apiVersion: apps/v1是当前 Deployment 的稳定版本老课件里常见的extensions/v1beta1在新集群上直接报no matches for kind。selector.matchLabels在apps/v1里是必填项且创建后不可修改它和template.metadata.labels必须严格一致不一致的话 apiserver 会拒绝创建报selector does not match template labels。template是唯一能触发滚动更新的部分——你改replicas只是伸缩改template里的镜像或环境变量才会生成新的 ReplicaSet。不确定字段怎么写的时候别去搜博客直接问集群# 逐层展开字段说明比翻文档准 kubectl explain deployment.spec.strategy kubectl explain deployment.spec.template.spec.containers.resources # 只校验不提交写完 YAML 先干跑一遍 kubectl apply -f deploy.yaml --dry-runserver--dry-runserver会把请求真的发给 apiserver 做准入校验但不落库比--dry-runclient靠谱得多能提前抓到 selector 不匹配、字段拼错这类问题。3.3 升级、扩缩容、回滚、删除一条不能颠倒的操作序列课件第三章给了完整的命令清单我按实际使用顺序重排一遍并且补上每步该盯什么# 1. 升级镜像注意这里写的是容器名 nginx不是 Deployment 名 kubectl set image deployment/web nginxnginx:1.15 # 2. 阻塞式观察滚动更新成功返回 0失败会卡住并给出原因 kubectl rollout status deployment/web --timeout120s # 3. 看历史版本CHANGE-CAUSE 列默认是空的除非加 --record 或写注解 kubectl rollout history deployment/web # 4. 回滚到上一个版本或指定某个 revision kubectl rollout undo deployment/web kubectl rollout undo deployment/web --to-revision2 # 5. 手动伸缩临时验证用 kubectl scale deployment web --replicas10 # 6. 自动伸缩CPU 超过 80% 就在 10 到 15 之间调整 kubectl autoscale deployment web --min10 --max15 --cpu-percent80 # 7. 清理两个资源要分别删 kubectl delete deploy/web kubectl delete svc/web有两个参数需要点出来。滚动更新的节奏由spec.strategy.rollingUpdate下的maxSurge和maxUnavailable控制默认分别是 25%意味着 4 副本的 Deployment 在更新期间最多会有 5 个 Pod 同时存在、最少保证 3 个可用副本数少的时候比如 2 个这个比例算下来会变成「先起新的再删旧的」更新期间资源会短暂超配节点资源紧张时容易触发驱逐。另一个是revisionHistoryLimit默认保留 10 个旧 ReplicaSet。如果你做过十几次发布再想回滚到很早的版本会发现rollout history里那个 revision 已经没了--to-revision直接报unable to find。要长期保留就从一开始把这个值调大或者干脆别依赖 ReplicaSet 历史靠 Git 里的 YAML 版本回退更可控。kubectl autoscale建出来的 HPA 依赖 Metrics API如果集群里没装 metrics-serverHPA 会一直显示unknown/80%且不触发伸缩——这个问题我在第 5 章细说。4. Pod 的共享机制与资源限额infra container 和 requests/limits 到底怎么算课件第四章讲 Pod 对象存在的意义和实现机制这段内容被很多人跳过但它决定了你对「一个 Pod 里的容器到底共享什么、不共享什么」的判断准不准也决定了你写resources时是在拍脑袋还是在算账。4.1 infra containerPod 里为什么只能有一个网络视图Pod 本身是个逻辑概念没有对应的实体进程它落地靠的是 infra container也叫 pause 容器。kubelet 创建 Pod 时先起一个极小的 pause 容器由它持有这个 Pod 的 network namespace然后其他业务容器通过加入这个命名空间的方式「接进来」。结果是同 Pod 内所有容器看到的网络设备、IP 地址、MAC 地址完全一样彼此可以通过127.0.0.1通信。这就是课件里说的「亲密性应用」场景的由来两个应用之间有文件交互、需要通过 localhost 或 socket 通信典型组合是 nginx php-fpm、或者调用极其频繁不想走网络栈都适合放进同一个 Pod。nginx 和 php-fpm 走127.0.0.1:9000是最经典的例子。但共享网络不等于共享文件系统。容器之间的文件系统依然是隔离的要共享存储必须显式挂同一个 Volume。这一点课件写的是「通过共享容器的挂载实现存储共享」表述有点绕实际操作是给两个容器各写一段volumeMounts指向同一个volumes名字apiVersion: v1 kind: Pod metadata: name: share-demo spec: containers: - name: web image: nginx:1.15 volumeMounts: - name: logs mountPath: /var/log/nginx # nginx 往这里写日志 - name: tail image: busybox:1.36 command: [sh, -c, tail -f /logs/access.log] volumeMounts: - name: logs mountPath: /logs # 边车容器从同一个卷读日志 volumes: - name: logs emptyDir: {} # 生命周期跟随 PodPod 删除即清空两个容器的mountPath故意写成不一样这是有意的卷共享的是底层目录挂载点是各自独立的所以 web 写到/var/log/nginx/access.logtail 从/logs/access.log就能读到同一份内容。emptyDir适合这种临时中转如果日志要留到 Pod 删除之后得换hostPath或者 PVC。验证共享网络最直接的办法是进容器看网卡# 看 Pod 里所有容器的名字确认 pause 容器不在这里它是隐式的 kubectl get pod share-demo -o jsonpath{.spec.containers[*].name} # 进第一个容器看 IP再进第二个看两者应该完全一致 kubectl exec -it share-demo -c web -- ip addr kubectl exec -it share-demo -c tail -- ip addr第二个命令在 busybox 里可能没有ip换成hostname -i也行输出的是同一个 Pod IP。4.2 imagePullPolicy 的三个取值默认值不是固定的 IfNotPresent课件列了三个取值但漏了一个关键细节默认值取决于镜像标签。规则是——如果镜像标签是latest或者没写标签默认Always如果写了具体标签比如nginx:1.15默认IfNotPresent。很多人以为默认永远是IfNotPresent结果用了:latest的镜像每次重建 Pod 都去拉一遍在弱网或者仓库限流的环境下就是漫长的ImagePullBackOff。三个取值的语义很清晰IfNotPresent是宿主机上没有才拉Always是每次创建 Pod 都重新拉Never是永不主动拉、只用在本地已经预置镜像的场景比如离线环境或者用 DaemonSet 预热过的节点。私有仓库还要配imagePullSecretsapiVersion: v1 kind: Pod metadata: name: my-pod spec: imagePullSecrets: - name: myregistrykey # 这个 secret 必须和 Pod 在同一个 namespace containers: - name: java image: demo/java-app:1.0 imagePullPolicy: IfNotPresentmyregistrykey是用kubectl create secret docker-registry建出来的类型是kubernetes.io/dockerconfigjson。这里有个高频坑secret 是 namespace 级别的Pod 在default、secret 建在kube-system就会报secret myregistrykey not found。另一个更省事的做法是把 secret 挂到 ServiceAccount 的imagePullSecrets上这样该 namespace 下所有用这个 SA 的 Pod 都不用重复写。4.3 requests/limits 的算账方式与 QoS 分级课件这一段把两个概念写反了——它把limits标成「申请配额」、把requests标成「限制配额」实际正好相反。requests是容器启动时向调度器申请的保底资源调度器拿它来判断节点还剩多少可分配量limits是容器运行时的硬上限超了会动手。这个反转如果照着背后面配 HPA 和排查 OOM 会一路错下去。CPU 和内存超限的后果完全不同。CPU 是可压缩资源超过limits.cpu不会杀容器只会被 cgroup 限流throttle表现是接口变慢、延迟毛刺内存是不可压缩资源超过limits.memory直接 OOMKilledPod 重启describe pod里能看到Last State: Terminated, Reason: OOMKilled。apiVersion: v1 kind: Pod metadata: name: web spec: containers: - name: java image: demo/java-app:1.0 resources: requests: # 调度依据节点剩余资源必须满足它 memory: 64Mi cpu: 250m # 250m 0.25 核1000m 才是 1 核 limits: # 运行时上限内存超了直接 OOMKilled memory: 128Mi cpu: 500m这两个值怎么定我的习惯是先压测再定Java 应用先给requests等于实际稳态用量的 1.2 倍limits.memory给稳态峰值的 1.5 到 2 倍留出 GC 和堆外内存的空间limits.cpu可以给到requests的 2 倍容忍突发。定完跑一轮压测用kubectl top pod看实际消耗再回调。这组配置还决定了 Pod 的 QoS 等级节点资源紧张时按等级驱逐QoS 等级条件驱逐优先级Guaranteed每个容器都设了 requests 和 limits且两者相等CPU 和内存都要最低最后被驱逐Burstable至少一个容器设了 requests 或 limits但不满足 Guaranteed中等BestEffort所有容器都没设 requests 和 limits最高优先被驱逐核心业务配成 Guaranteed 不是洁癖是被驱逐过一次之后的自然反应。反过来临时任务、批处理配 BestEffort 反而合理被驱逐了重跑就行。排查资源问题常敲这几条# 看 Pod 实际的 requests/limits 和当前用量 kubectl describe pod web | grep -A 6 -E Limits|Requests # 需要 metrics-server 支持没有会报 Metrics API not available kubectl top pod web --containers5. 监控日志与排查kubectl top 没数据背后的五个坑课件第二章给了一串命令从kubectl cluster-info到kubectl top pod看着都对但真到集群里敲kubectl top大概率直接报错。这一章把监控链路拆开再把我在实际环境里反复踩到的几个坑按「现象 → 原因 → 解决」列清楚。5.1 Metrics Server 与 cAdvisor 的数据链路kubectl top不是 apiserver 自带的能力它查的是metrics.k8s.io这个聚合 API背后由 Metrics Server 提供数据。链路是这样每个节点上的 kubelet 内置了 cAdvisor负责采集本节点容器的 CPU、内存等指标通过 Summary API 暴露出来Metrics Server 周期性向所有 kubelet 拉取聚合成 Pod 和 Node 两个维度的数据再注册成 apiserver 的一个 APIService。所以这条链上任何一环断了kubectl top都会失败。# 确认聚合 API 注册上了STATUS 要是 True kubectl get apiservice | grep metrics # metrics-server 的 Pod 是否 Running重启次数是否在涨 kubectl get pods -n kube-system -l k8s-appmetrics-server # 日志里最常出现的两类错误x509 证书校验失败、连不上 kubelet 10250 kubectl logs -n kube-system deploy/metrics-server --tail50 # 数据通了之后这两条才有意义 kubectl top node kubectl top pod -A --sort-bycpu | head -20--sort-bycpu配上head是我每周巡检的固定动作能一眼看出谁在偷吃资源。注意kubectl top pod默认只查当前 namespace跨命名空间要加-A这一点和kubectl get pods的行为一致但经常有人忘了加然后以为没数据。5.2 五条踩坑记录从现象倒推原因第一条error: Metrics API not available。现象是kubectl top直接报这句kubectl get apiservice | grep metrics能看到v1beta1.metrics.k8s.io但 STATUS 是 False。原因通常是 metrics-server 没装或者装了但起不来。解决是先看 Pod 状态如果是CrashLoopBackOff八成是证书问题——metrics-server 访问 kubelet 的 10250 端口时自签证书校验不过。常见做法是给 Deployment 加一个启动参数--kubelet-insecure-tls仅限测试环境生产该配 CA然后删掉 Pod 让它重建。第二条Pod 一直ImagePullBackOff。现象是kubectl get pods显示ImagePullBackOff或ErrImagePulldescribe pod的 Events 里能看到Failed to pull image。原因要么是镜像名或标签写错要么是私有仓库没配imagePullSecrets要么是节点根本连不上仓库。解决顺序是先kubectl describe pod看 Events 里的完整报错区分是manifest unknown镜像不存在还是unauthorized认证失败还是i/o timeout网络问题三类错误的处理路径完全不同。第三条Pod 反复重启RESTARTS一直涨。现象是 Pod 状态在Running和CrashLoopBackOff之间跳describe pod里Last State显示Reason: OOMKilled。原因是limits.memory设小了应用启动或处理大请求时被内核干掉。解决是先kubectl top pod看实际峰值把limits.memory调到峰值的 1.5 倍以上同时检查 JVM 的-Xmx有没有超过容器 limit容器里-Xmx不设或者按宿主机内存算是 Java 应用 OOMKilled 的头号原因。第四条Service 访问不通但 Pod 是 Running。现象是curlService 的 ClusterIP 超时但kubectl get pods一切正常。原因大概率是 selector 和 Pod 标签对不上导致 Endpoints 为空。解决是kubectl get endpoints svc-name输出none就回去核对spec.selector和template.metadata.labels如果 Endpoints 有值但访问还是不通再查targetPort是否等于容器的containerPort最后才怀疑 kube-proxy。第五条回滚时找不到目标版本。现象是kubectl rollout undo deployment/web --to-revision2报unable to find revision。原因是revisionHistoryLimit默认只有 10发布次数超过之后旧 ReplicaSet 被 GC 掉了。解决是把revisionHistoryLimit调到 20 或更大同时别把kubectl rollout history当成发布记录——它只在加了--record或者给 Pod 模板写了kubernetes.io/change-cause注解时才有 CHANGE-CAUSE 内容否则只有 revision 号回滚时根本分不清哪版是哪版。5.3 三种日志的取法组件日志、标准输出、落盘日志课件的日志部分分了三层这个分层是对的值得展开。k8s 组件的日志要分两类看用 systemd 托管的kubelet 就是走journalctl -u kubelet以静态 Pod 形式跑的kube-proxy、etcd、apiserver 在 kubeadm 集群里都是走kubectl logs# systemd 托管的组件 journalctl -u kubelet --since 30 min ago --no-pager # 静态 Pod 形式的组件名字后面带随机后缀用 labels 筛更稳 kubectl logs -n kube-system -l k8s-appkube-proxy --tail100 # 系统层面的日志节点内核问题看这里 tail -n 200 /var/log/messages应用日志走容器标准输出是最省事的kubelet 会把 stdout/stderr 落到节点磁盘上并按大小轮转# 当前日志 kubectl logs pod-name # 实时跟等价于 tail -f kubectl logs -f pod-name # 多容器 Pod 必须用 -c 指定容器否则默认第一个 kubectl logs -f pod-name -c container-name # 看上一个容器实例的日志Pod 重启后查崩溃原因必用 kubectl logs pod-name --previous--previous这个参数救过我很多次Pod 因为启动失败反复重启时kubectl logs拿到的可能是刚起来还没输出就挂掉的那个实例加上--previous才能看到真正报错的那一份。如果应用不往标准输出写只往文件写就得挂hostPath把日志落到节点上apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: web image: nginx:1.15 volumeMounts: - name: logs mountPath: /usr/local/nginx/logs volumes: - name: logs hostPath: path: /tmp/logs type: DirectoryOrCreate # 目录不存在时自动创建课件里给的type: Directory要求目录必须提前存在不存在的话 Pod 会一直ContainerCreating并报hostPath type check failed。改成DirectoryOrCreate省事得多代价是它会自动建目录、权限按默认走生产环境还是建议提前规划好目录并显式设type: Directory避免权限问题。6. 把调度、存储、安全串成一条自检链课件没展开的三块怎么验课件目录里列了调度、存储、集群安全正文却没细讲这三块恰恰是集群从「能跑」到「跑得稳」的分水岭。我的习惯是准备一份十分钟能跑完的自检清单接一个新集群或者排查完一次故障都过一遍。调度这块Pod卡在Pending时别急着看节点资源先看 Eventskubectl describe pod pod-name | grep -A 10 Events如果看到0/3 nodes are available: 3 Insufficient cpu是资源不够回去核requests看到node(s) had taint {key: value}是节点有污点没容忍用kubectl describe node node | grep -i taint确认看到node(s) didnt match Pods node affinity是nodeSelector或亲和性写死了不存在的标签。这三种错误的修法完全不同全靠 Events 那一行区分。存储这块PVC 长时间Pending是最常见的表现kubectl get pvc -A kubectl describe pvc pvc-name -n nsEvents里说no persistent volumes available for this claim说明没有匹配的 PV检查容量、accessModes、storageClassName三个属性是否和已有 PV 对得上——这三个必须全部匹配差一个都绑不上。如果用了动态供给就去看 StorageClass 的 provisioner Pod 是不是活着。安全这块最容易被跳过。课件提到集群安全但没展开实际最该先验的是 ServiceAccount 的权限边界# 以某个 ServiceAccount 的身份试探权限不改任何实际状态 kubectl auth can-i get pods \ --assystem:serviceaccount:default:demo-sa -n default # 反过来查这个 SA 到底被授了哪些权限 kubectl auth can-i --list \ --assystem:serviceaccount:default:demo-sa -n default第二条命令输出的是完整的权限清单我一般会顺手扫一眼有没有*.*这种通配授权——有的话基本可以认定是早期图省事留下的该收就收。把三块合成一张自检表贴在工位上比翻文档快自检项触发命令关键判据常见结论调度describe pod看 EventsFailedScheduling的具体原因资源不足 / 污点未容忍 / 亲和性不匹配存储get pvcdescribe pvc是否 Pending容量、accessModes、StorageClass 三者不匹配权限auth can-i --list是否有通配授权ServiceAccount 权限过大需收敛网络get endpoints是否为noneselector 与 Pod 标签不一致这套自检我是从一次事故之后固定下来的。当时一个服务突然全量不可用二十多个人围着查网络插件、查 kube-proxy、查节点状态最后发现是有人改 Deployment 的时候顺手把template.metadata.labels的app值从web改成了web-v2而 Service 的 selector 还写着app: webEndpoints 直接空了。整件事的定位时间不到三十秒——如果第一时间敲了kubectl get endpoints。从那以后我每次改完任何带 selector 的 YAML都以kubectl get endpoints svc-name的输出作为发布完成的最后一道确认不管前面rollout status显示多绿。希望这个习惯也能帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?