1. 猿辅导2024运维面试这趟水到底有多深作为一个有几年经验的运维工程师我今年面了猿辅导的运维岗位。整体走下来最直观的感受是这场面试不考八股文式的死记硬背而是把大量精力放在你是否真的在生产环境里解决过问题上。猿辅导在线教育业务的技术栈规模和复杂度都不低高峰期的流量压力、大规模集群管理、多区域容灾这些场景决定了他们对运维的要求不会停留在会装系统、会配nginx这个层面。整个面试流程一般在四轮左右。第一轮通常是线上技术面重点过你技术栈的广度。Linux常见命令、网络基础、Redis和MySQL这类中间件的基础使用都会快速扫一遍。这一轮节奏比较快基本不会死磕某个点更像是在确认你的基础是否扎实。第二轮是深度技术面也是整场面试里信息量最大的一轮核心围绕容器化和Kubernetes展开。面试官会从你日常怎么用kubectl开始一路问到kubelet怎么和containerd通信再到Pod里进程的完整调用链甚至追问CNI网络插件和cgroup资源隔离的具体实现。这个过程中最让我印象深刻的问题是你说说看kubernetes到底是怎么调用containerd的从原理到实体调用链路完整讲一遍。第三轮是系统设计或实战场景题。我遇到的是一个开放题如何在生产环境从零搭建一个系统并做好后续维护。没有标准答案但非常考验全局思维。第四轮一般是负责人或HR面聊职业规划、稳定性、协作方式同时也会评估你之前的项目经历是不是真的有深入参与。1.1 面试官真正想验证的是什么从我实际沟通下来的感受猿辅导的面试官不太在意你背了多少条命令而是会用连环追问的方式验证深度。比如你说我排查过containerd的问题他会立刻追问containerd的socket文件在哪个路径kubelet怎么找到containerdcontainerd-shim是干什么的journalctl里看到的报错怎么一步步定位到根因这种问法背后其实在验证一件事你到底是用过还是真懂。可以很明确地说如果只是停留在会用kubectl部署应用的层面在这种追问下是撑不住的。所以如果让我给后来人一个建议那就是不要停留在操作层面要把每个组件之间是怎么协作的搞清楚。这也是我写这篇文章的初衷把面试里问到的最核心的几个点用实战视角重新梳理一遍顺便也帮正在准备运维面试的同学捋一捋思路。2. Kubernetes调用containerd从原理到完整调用链这一块基本是2024年运维面试的高频核心也是很多人容易栽的地方。原因很简单很多人平时和k8s打交道但基本只碰kubectl这一层kubelet往下到容器运行时那一段几乎没有认真看过。2.1 为什么面试官盯着这个问题不放问这个问题的目的是想确认你对容器运行时这条链路有没有完整认知。现在生产环境的主流运行时已经是containerd但很多人的认知还停留在containerd就是以前的docker这个模糊状态。实际上containerd和docker有着本质区别docker是一整套容器解决方案包含客户端、守护进程、镜像构建等完整工具链containerd只是其中负责容器生命周期管理的核心引擎定位更纯粹。另一个背景是从k8s 1.24版本开始dockershim被正式移除kubelet不再支持通过docker socket调用docker。这意味着理解kubelet如何调用containerd已经成为理解现代容器编排架构的基础。你如果还停留在docker ps查容器的思路上在新集群里会直接碰壁因为节点上根本没有docker daemon。2.2 三个关键角色kubelet、CRI、containerd要理解这条调用链先得搞清楚三个角色的分工。kubelet是每个节点上的核心代理组件负责Pod的生命周期管理包括创建、停止、重启、健康检查等。它是在节点上最活跃的k8s组件之一。CRI是kubelet和容器运行时之间的标准接口全称Container Runtime Interface底层基于gRPC协议。CRI定义了两类服务RuntimeService负责Pod沙箱和容器生命周期管理ImageService负责镜像拉取、镜像列表查询等。containerd就是容器运行时本身通过内置的CRI插件实现CRI Service接口。kubelet和containerd之间的通信本质上就是kubelet作为gRPC客户端调用containerd CRI插件暴露出的一组gRPC方法。我用一个生活化的类比来解释kubelet是酒店的客房部经理它只管下指令说客人入住了需要一间房。CRI相当于酒店内部的标准作业流程手册规定了接到入住需求后要通知哪几个部门、按什么顺序处理。containerd是真正的执行员工拿到指令后去铺床、放毛巾、检查设施最终让客人顺利入住。这样分层之后酒店换个保洁公司客房经理的指令方式不用变只要新保洁公司也按同一套手册执行就行。2.3 CRI插件的通信入口和关键文件containerd从1.0版本开始就把CRI插件集成进了主程序。默认情况下containerd的CRI服务监听在Unix socket上路径是/run/containerd/containerd.sock。这个socket就是kubelet与containerd通信的唯一入口。有一个细节值得单独说很多人在节点上看进程会发现除了containerd还有一堆containerd-shim进程。shim是containerd启动每个容器时拉起的中间层进程它负责维持容器进程和containerd主进程之间的关联。即使containerd主进程重启了shim也能让容器进程保持存活这就保证了容器本身的稳定性。这个设计思路在实际运维中非常重要因为containerd升级或异常重启时正在运行的业务容器不会直接挂掉。排查容器问题的时候我强烈推荐用crictl这个工具。它直接和CRI socket交互走的是和kubelet同款接口所以你用它看到的视角和kubelet看到的几乎一致。常用的操作包括crictl ps查看容器列表、crictl logs查看容器日志、crictl inspect查看容器详细信息。相比之下docker ps在纯containerd环境里根本无法使用。2.4 Pod从创建到运行的完整调用链拆解把整个调用链完整串起来大概是这样的kubectl创建Pod - kube-apiserver将Pod写入etcd - kubelet通过watch机制感知到Pod创建事件 - kubelet通过CRI gRPC接口调用containerdsocket路径/run/containerd/containerd.sock - containerd的CRI插件解析请求准备沙箱和容器配置 - containerd拉起containerd-shim进程 - shim调用runc从OCI bundle创建容器 - runc通过cgroup限制资源、namespace做隔离 - 最终启动容器主进程这里有几个容易被追问的点我一个个展开说。Pod和容器是两个层面的概念。在CRI的设计里Pod对应的是一个PodSandbox也就是沙箱。k8s里同一个Pod下的多个容器共享同一个沙箱意味着它们共享网络命名空间、IPC命名空间等这也是为什么同一个Pod里的容器可以通过localhost互相访问。runc是OCIOpen Container Initiative标准的参考实现。containerd、docker这些上层运行时最终都要借助runc来真正启动容器进程。runc做的事情是解析OCI spec创建容器的各种namespace通过cgroup配置资源限制然后启动进程。可以说从k8s到底层操作系统真正创建容器进程这个动作是runc完成的。镜像层的逻辑也要提一下。kubelet在创建容器之前会先通过ImageService接口让containerd拉取镜像。containerd拉镜像的流程包括解析镜像仓库地址、认证、分层下载、解压到本地内容存储。如果镜像拉取失败Pod会一直停留在ImagePullBackOff状态可以通过kubectl describe pod看到具体错误原因。2.5 现场实操验证这条链路如果面试官让你现场验证这条链路或者你自己想在测试环境里确认一遍可以按下面这套步骤操作。先看kubelet启动参数里指定的runtime endpointcat /var/lib/kubelet/kubeadm-flags.env # 通常会看到类似这样的配置 # KUBELET_KUBEADM_ARGS--container-runtime-endpointunix:///run/containerd/containerd.sock然后设置crictl的端点并连接export CONTAINER_RUNTIME_ENDPOINTunix:///run/containerd/containerd.sock export IMAGE_SERVICE_ENDPOINTunix:///run/containerd/containerd.sock crictl version crictl ps -a如果containerd没有正常响应常见的排查路径是systemctl status containerd journalctl -u containerd --no-pager -n 100我在实际环境里遇到过kubelet报failed to connect to containerd绝大多数情况是containerd服务挂了或者是socket文件权限不对kubelet没有权限访问。另外有个容易被坑的地方crictl ps看不到容器但kubectl能看到Pod状态正常这种情况通常是因为kubelet和你的crictl连接了不同的endpoint。kubelet可能被配置成走/run/containerd/containerd.sock而你本地crictl默认的endpoint路径是/var/run/docker.sock或者不对的路径两边视角自然不一样。注意containerd默认的CRI socket路径是/run/containerd/containerd.sock但要注意这个路径和某些发行版或手动安装场景下的路径可能存在差异。排查问题前先确认你连接的socket和kubelet实际使用的是同一个否则看到的状态不一致会误导整个排查方向。2.6 containerd和docker在调用链上的核心差异很多老运维是从docker时代一路过来的这里必须提醒一句docker daemon和containerd不是一回事。在传统docker架构里启动容器时docker客户端把请求发给docker daemondaemon再调用containerd来管理容器生命周期containerd再通过containerd-shim拉起runc创建容器进程。也就是说docker daemon是额外的一层containerd才是真正干活的引擎。而在k8s直接使用containerd的场景里kubelet通过CRI接口直达containerd这一整条链路上完全没有docker daemon。所以k8s移除dockershim之后很多人在节点上执行docker ps发现命令不存在或者在宿主机上找不到docker.sock就是因为节点上根本没有装docker daemon只有containerd在运行。这个认知差异在实际运维中极其重要。如果团队里还有人习惯用docker命令去排查k8s节点上的容器大概率会碰壁。正确的方式是安装crictl并设置好和kubelet一致的endpoint所有对容器的操作都通过crictl完成。3. 生产环境从零搭建一套系统开放题里的硬实力考察猿辅导面试里的那道开放题让我印象相当深刻。如何在生产环境从零搭建一个系统并做好后续维护听起来像是一个老大难问题但考察的点其实非常清晰你有没有全局架构思维能不能区分优先级会不会从运维全景去考虑问题。3.1 接到需求后的第一件事不是装系统如果你在面试里一上来就说先装CentOS那基本就输了一半。正确的思路是先做需求分析和架构规划。几个必问自己的问题这套系统承载什么业务预估高峰QPS是多少数据量级多大是单机应用还是微服务架构要不要容器化部署可用性要求是几个9有没有明确的SLA约束团队规模多大后面谁来维护这套系统这些问题直接决定了后续所有选型。举个例子一个给内部同事用的工单系统和一个对外高并发的核心业务系统技术选型和运维策略完全不在一个量级。前者可能一台性能好点的虚机就够了后者需要从负载均衡、应用集群、缓存、数据库主从到对象存储全部规划一遍。面试时我把这个框架答完面试官明显是认可的。因为大多数候选人都急着讲技术细节很少有人先花时间澄清需求和边界。这一点在生产环境里恰恰是运维最有价值的产出之一——先把问题定义清楚再动手做事。3.2 机器规划与系统安装优化基础设施规划阶段建议按角色分机器。常见的划分方式包括负载均衡层、应用层、缓存层、数据库层、存储层。一开始就模块化未来扩缩容才有弹性。预算有限的情况下至少要保证数据库和应用分离缓存单独放不要把所有角色塞进一台机器。系统安装层面有几个容易被忽略但实际非常关键的点分区规划像/data这种数据目录一定要单独分区。日志、容器数据、数据库文件都往里写如果根分区被写满整个系统都可能hang住。我处理过太多因为根分区爆满导致服务全部不可用的故障而这类故障百分之百可以提前避免。数据盘和系统盘分离云主机场景下系统盘和数据盘分开挂载备份和快照策略才方便做。所有重要数据一律放数据盘系统盘随时可以重装。关闭swap对大多数服务来说swap会严重拖慢性能尤其MySQL和Java应用这类场景。建议直接关闭或者只在极端情况下作为最后防线。内核参数调优vm.max_map_count、fs.file-max、net.core.somaxconn这些参数要根据业务类型提前调好不要等服务起来了再去调。这些参数很多软件在官方文档里都明确要求调整但经常被忽略。系统镜像建议固定版本不要追新。能用就行是生产环境的大忌。生产环境最重要的原则之一是可重复性同一套代码、同一个镜像、同一份系统配置在任何时间任何机器上构建出的结果必须一致。这样排障和扩容才有可预期性。3.3 中间件与核心服务部署接着是应用依赖的中间件。以典型Web系统为例基本绕不开nginx、MySQL、Redis这三类。下面是我按生产标准过一遍时的通用做法。nginx作为流量入口配置上要关注worker_processes和CPU核数的关系通常设成等于CPU核心数keepalive_timeout不要设太长避免过多半开连接占用资源gzip可以开启但要注意压缩级别太高反而消耗CPU。upstream的health_check一定要配不然后端某台机器挂了nginx还会继续往它转发流量。我习惯在nginx层就把静态资源缓存、日志格式、限流策略都提前规划好后端应用就能保持相对干净。MySQL这块一上来就上主从复制是标配但完整的运维远不止复制。初始化参数里innodb_buffer_pool_size通常设为物理内存的60%-70%binlog格式建议用row模式保留周期根据数据量和恢复需求定慢查询日志阈值设在1秒左右方便后续优化。备份策略更是重中之重而且备份之后必须做恢复演练。我见过太多生产事故是从来没做过恢复演练导致的等真正要恢复的时候才发现备份早就坏了。Redis在高性能缓存场景是标配。部署时注意绑定内网IP而不是0.0.0.0设置requirepass配置maxmemory和合理的淘汰策略。持久化方面RDB适合做备份和冷启动场景AOF更安全但文件占用更大、写入开销更高实际可以两者结合使用。还要记得给Redis配置合适的maxmemory-policy不然内存满了各种报错会让人焦头烂额。3.4 监控、日志、告警三步走搭建完服务下一步是可观测性。没有监控的系统等于裸奔。我通常分三层来看指标监控、日志收集、告警推送。指标监控方面目前主流是Prometheus加Grafana。node_exporter负责主机指标cadvisor可以采集容器指标kube-state-metrics负责K8s对象的指标。关键监控项至少包括CPU使用率、内存使用率、磁盘使用率、inode使用率、TCP连接数、JVM指标如果在跑Java应用、接口响应时间和错误率。日志层面ELK和Loki都有人用。中小团队我更推荐Loki资源占用低很多和Grafana无缝集成。关键是要把日志按服务分目录、按大小和日期轮转别让日志把磁盘写满。日志轮转虽然听起来基础但生产环境一半以上的磁盘告警都是日志文件没治理好引起的。告警推送方面最简单的方案是Prometheus的Alertmanager配合webhook把告警发到钉钉群或企业微信群。告警规则不要一开始就铺太多否则狼来了效应很快会让告警失效。我个人的整理经验是先定服务不可用、磁盘将满、错误率突增这三类必告警其余的是慢慢根据实际故障案例补充。告警的价值是让人能快速意识到问题而不是让消息列表变成噪音桶。3.5 安全性、权限与备份恢复安全这个话题在面试里经常被一带而过但生产环境里它往往就是事故重灾区。我按实用角度列几个重点SSH只允许密钥登录禁止root直接登录修改默认端口降低被扫描概率。安全组和防火墙规则最小化只开放业务真正需要的端口。所有中间件设置强密码禁止默认配置裸奔。Redis未授权访问的漏洞在真实世界里挖矿脚本扫得比谁都快。定期升级补丁尤其是操作系统安全补丁和暴露在公网的服务。权限管理上每个人分配独立账号避免所有人共用一个root。离职员工账号必须及时回收。备份和恢复这块是很多面试者忽略的必答题。我想强调一个原则备份的价值在于恢复不在于备份本身。每次做完备份方案我都会问自己一个问题——如果今天机器没了我能在几个小时内恢复服务恢复流程有没有验证过如果你从来没做过灾难恢复演练那你的备份方案是不完整的。数据库备份要在从库上做避免影响主库性能备份文件要异地存放防止单机房故障连备份一起没了。3.6 后续维护必须有的长期视角开放题里面试官一定会追问后续维护怎么开展。我通常强调三个方面容量规划要有提前量不能等磁盘满了再扩容。比如磁盘使用率达到70%就要开始准备扩容方案不要等到95%告警了才想起来。变更管理要有流程所有线上变更必须有回滚方案重要的变更尽量安排在低峰期。日常巡检要有清单比如每天检查哪些核心指标、每周做什么样的人工复核、每月做一次完整的日志审查。这些做法听起来像是流程制度但背后全是真实的血泪教训。你能在面试里把这些问题主动讲出来面试官基本就认可你是有实战经验的人了。因为纸上谈兵的人和真正管过生产系统的人讲出来的感觉是完全不一样的。4. 运维工程师需要学什么从入门到进阶的学习路线面试聊到后半段面试官问了一个看似随意但实际很重要的问题你们平时是怎么学习的这个问题实际在考察你是不是有成长性。结合2024年的行业情况我梳理一下运维工程师这条路上的核心学习内容也顺便回答一下网上经常看到的运维工程师需要学什么这个问题。4.1 第一步Linux基础和网络是地基运维的地基是Linux这不是学会几条命令就行而是要真正理解核心机制。建议重点掌握文件系统和inode、进程模型、权限体系、systemd、网络工具集ip、ss、tcpdump。网络方面TCP三次握手四次挥手不仅面试要考排查问题的时候真的会用到。比如一个接口偶发超时如果你不懂TCP状态机就很难定位是连接复用的问题还是服务端处理慢的问题。学习方式上我不推荐只看视频囤课程。强烈建议手头备一台Linux机器虚拟机就行把每次学到的命令自己敲一遍把服务完整装一遍再把它们搞坏一次然后想办法修好。踩坑才是最快的成长路径。我自己的体会是那些让我记忆最深的知识点全部来自生产事故的排查过程而不是任何一本书或课程。4.2 第二步容器化与云原生必须掌握现在运维面试容器和Kubernetes已经是必考项了。至少要掌握Docker的核心概念镜像、容器、网络、数据卷以及Kubernetes的核心对象Pod、Deployment、Service、Ingress、ConfigMap、Secret。进阶的方向还包括Helm、Operator模式、服务网格如Istio等。关于怎么学K8s我的建议是不要只玩minikube最好真正搭一个多节点集群。用kubeadm可以把集群搭起来但要注意手动试一遍证书管理和etcd备份恢复。我在面试里被问过很多次的就是etcd的备份和恢复这是生产环境中极其重要的运维场景。很多同学对kubeadm一键搭建很熟但问到etcd挂了怎么恢复就答不上来这就是缺乏真实运维经验的明显信号。4.3 第三步自动化、CI/CD与基础设施即代码2024年的运维自动化已经是标配了。Shell脚本是基本功但更进一步就需要Python或Go。Python在运维场景里最常见写脚本做自动化、写工具做批量操作都非常顺手。基础设施即代码IaC方面Terraform管理云资源、Ansible做配置管理是很多公司实际在用的组合。CI/CD方面Jenkins、GitLab CI、ArgoCD至少要熟悉一条链路。这里说一句我的个人经验自动化不是目的稳定性才是。写自动化脚本之前先想清楚这个任务是不是真的高频重复。一个一年只跑一次的任务没必要花三天去写脚本自动化反过来每次发版都要重复做的操作再麻烦也值得自动化。4.4 新方向AI应用运维给运维带来的变化2024年行业里出现了一个热词叫具身智能应用运维这个方向很有意思看起来新但本质上还是传统运维能力和新业务场景的结合。比如AI训练任务通常需要GPU资源管理、特定驱动版本的适配、分布式训练容错和调度策略这对资源监控、任务调度、故障恢复都提出了新要求。运维工程师如果能在传统功底之上理解一些AI训练任务的生命周期尤其是GPU的监控和调度会非常有竞争力。这个方向并不要求你立刻学会写模型训练代码但至少要理解深度学习任务部署的基本流程、常见故障模式和资源特征。面试时如果你能聊到这个层面会明显和其他候选人拉开差距。4.5 高频面试考点与常见翻车点速查最后把2024年运维面试里我实际遇到或朋友反馈过的高频考点整理成一张表方便对照查漏考察方向高频问题常见翻车点容器原理容器隔离的本质是什么只答namespace和cgroup但不清楚这两个机制和runc的关系镜像构建Dockerfile最佳实践有哪些不知道多阶段构建不理解镜像层缓存机制K8s网络Service和Pod的通信原理说不清kube-proxy的iptables/IPVS模式差异K8s存储PV、PVC、StorageClass关系只在背概念不理解动态供给的完整流程故障排查Pod一直CrashLoopBackOff怎么办只知道看logs不会看events和describe备份恢复etcd备份怎么做不知道etcdctl snapshot save的关键参数和恢复步骤这张表的每一行都是真实面试里会被深挖的点。建议照着这个清单逐项自测哪一项说不清楚就回去翻资料补课。面试准备不是背题而是把每个点理解到能向别人讲清楚的程度。5. 从这次面试中得出的几点体会写到这里我把这次猿辅导面试相关的内容都梳理了一遍。最后再分享几个从实际经历中总结的体会希望对准备运维面试的同学有帮助。面试前一定要亲手还原一遍kubelet调用containerd的链路。不用追求在面试里炫技但至少要能清晰地讲出kubelet通过CRI gRPC接口连到containerd的socketcontainerd的CRI插件处理请求containerd-shim维持容器进程runc真正创建容器进程这四步走完才算完整。你能讲清楚这条线面试官对你的容器功底就不会有太多质疑。开放题一定要有框架思维。回答从零搭建一套系统这种题目不要急于说细节。先给出分析框架需求分析、架构规划、部署实施、可观测性、安全与备份、持续维护。框架对了细节都是加分项。运维面试最后拼的其实是真实解决问题的经验。多在公司里主动承担线上排查工作把每次事故的来龙去脉记录成文档沉淀成自己的案例库。这些真实经历比任何面试题集都有说服力。我后来复盘整场面试让我聊得最顺畅、面试官反馈最好的部分全部是自己真刀真枪处理过的生产问题而不是背下来的理论。如果你也在准备运维面试希望这篇文章能帮你少走一些弯路。把基础打扎实把调用链搞清楚把生产思维建立起来机会来的时候就接得住。