
别再纠结容器和虚拟机的区别了你只需要知道Docker把应用和环境打包成标准集装箱K8s就是管理这堆集装箱的码头吊机写在前面Docker和KubernetesK8s是云原生时代的基石。面试问到这块本质上是在问两件事①你的应用怎么打包和交付的②上了生产环境怎么管理、怎么扩缩容Docker解决了什么问题你以前上线一个Java应用打Jar包 → 扔到Linux服务器上 → 装JDK → 配环境变量 → 装Redis客户端 → 装Nginx……搞了半天换一台服务器又得重来一遍。更别说十台、一百台服务器了。Docker说把应用和它需要的所有环境JDK、依赖库、配置文件一起打包成一个镜像在任何装了Docker的机器上一个docker run命令就能跑起来。Kubernetes解决了什么问题Docker解决了单机部署环境的问题但它管不了100台机器上100个容器怎么调度挂掉了谁重启流量来了谁负责扩容Kubernetes说我来管。它是容器编排平台负责在成百上千台服务器上调度、管理、扩缩容这些容器。一、Docker的核心概念镜像 vs 容器很多人把镜像和容器搞混。一句话区分镜像Image死的是类静态模板。比如你打包好的my-app:v1.0。容器Container活的是实例运行中的进程。docker run my-app:v1.0跑起来就是一个容器。好比镜像就是装好所有家具的样板间图纸容器就是按照图纸建出来的真实房间。你可以用一张图纸建出无数个一模一样的房间。二、Docker和虚拟机的区别面试必问这是面试绝对高频题你要讲清楚本质区别。2.1 虚拟机VM虚拟的是硬件虚拟机软件VMware/VirtualBox模拟出一套完整的硬件CPU、内存、硬盘、网卡然后在上面装一个完整的客户操作系统Guest OS。资源开销大每个虚拟机都有一个完整OS几GB到几十GB启动分钟级。隔离性强完全隔离一个VM崩溃不影响另一个。2.2 容器Docker虚拟的是操作系统内核所有容器共享宿主机的内核Linux内核只是通过Linux的Namespace技术给自己造了个虚假的独立王国自己独立的PID、网络、文件系统、用户空间通过Cgroups技术限制自己能用的CPU和内存。资源开销小容器只是一个进程几MB到几百MB启动秒级。隔离性弱共享内核一个容器把内核搞崩了概率极低所有容器都崩。面试官追问“Linux的Namespace有哪些”不需要全背记住几个关键的PID Namespace容器里看到的进程是自己的看不到宿主机其他进程。Network Namespace容器有自己的IP、端口互不冲突。Mount Namespace容器有自己的文件系统根目录。UTS Namespace容器有自己的主机名。IPC Namespace容器有自己的共享内存、信号量。一句话总结虚拟机模拟硬件装整套OS重容器共享内核隔离视野轻。三、镜像分层轻量的核心秘密面试官常问“Docker镜像为什么比虚拟机镜像轻那么多”因为Docker镜像是分层存储的UnionFS/OverlayFS。3.1 分层是怎么工作的比如你写一个Java应用Dockerfile可能是FROM openjdk:17-jdk-alpine # 第1层JDK COPY target/app.jar /app.jar # 第2层你的Jar包 CMD [java, -jar, /app.jar] # 第3层启动命令metadata层执行docker build时每一行指令生成一个只读层Layer。如果你有100个不同的Java应用它们都基于同一个openjdk:17-jdk-alpine基础镜像这层JDK在硬盘上只存一份100个应用共享这一层。这就好比100个集装箱共用同一款标准底盘只有上层货物Jar包不同。3.2 容器读写层Copy-on-Write容器运行时会在只读镜像层上再加一个读写层容器层。所有写操作比如程序生成的日志、临时文件都写在容器层不修改底层镜像。好处多个容器共享同一个镜像内存和磁盘占用少。容器删除时只删除读写层镜像还在。所以docker pull时只有你没下载过的层才会下载docker push也同理只上传变动的层不是整个镜像重新上传。四、Dockerfile怎么写的面试常问虽然不用背全部命令但常见的你要懂指令作用示例FROM基于哪个基础镜像FROM openjdk:17-jdk-alpineCOPY/ADD把文件拷进镜像COPY target/app.jar /app.jarRUN构建时执行的命令RUN apt-get update apt-get install -y curlCMD容器启动时执行的命令可被覆盖CMD [java, -jar, /app.jar]ENTRYPOINT容器启动时执行的命令不可被覆盖ENTRYPOINT [java, -jar]EXPOSE声明容器监听的端口文档作用EXPOSE 8080ENV设置环境变量ENV JAVA_OPTS-Xmx512mCMD vs ENTRYPOINT的区别面试考点CMD可以被docker run后面的命令覆盖。比如docker run my-app bash会覆盖CMD里的java -jar执行bash。ENTRYPOINT不会被覆盖docker run后面跟的参数会作为追加参数传给ENTRYPOINT。# 写法1固定命令 ENTRYPOINT [java, -jar, /app.jar] # 写法2可变的JVM参数 ENTRYPOINT [java, -jar, /app.jar] CMD [--spring.profiles.activeprod] # 默认参数可以被覆盖五、KubernetesK8s容器编排平台Docker负责打包运行单个容器K8s负责在成千上万台机器上调度这些容器。5.1 核心概念必须搞懂① Pod最小调度单元Pod是K8s里最小的部署单元。一个Pod里可以跑一个或多个容器通常就一个。同一个Pod里的容器共享网络同一个IP、存储卷、PID空间。典型场景主容器你的Java应用 Sidecar日志收集、监控Agent放在同一个Pod里共享网络和存储。面试官追问“为什么不直接调度容器要加个Pod”因为有些应用需要紧耦合地协同工作比如应用日志需要实时被sidecar收集它们必须部署在同一台机器上共享网络和存储。Pod就是K8s提供的这个最小部署单元里面的容器同生共死。② Deployment无状态应用的管理器Deployment管理着一组Pod的期望状态副本数量Replicas我要跑3个Pod → Deployment确保始终有3个在运行。滚动更新新版本发布时逐个替换Pod不停机。回滚新版本出问题了一键回滚到上一个版本。③ Service稳定的访问入口Pod的IP是飘忽不定的挂了重启就变了K8s的Service给一组Pod提供固定的访问入口ClusterIP 端口。ClusterIP默认集群内部访问比如A服务通过order-service这个域名调B服务。NodePort把端口暴露到宿主机上外部可访问。LoadBalancer对接云厂商的负载均衡器阿里云SLB、AWS ELB。④ Namespace环境隔离把集群按环境隔开dev、test、prod。不同Namespace里的资源互相隔离但网络默认互通可以通过NetworkPolicy限制。一个K8s集群可以跑多个环境节省服务器成本。5.2 K8s是怎么工作的节点角色Master节点控制平面管理集群调度Pod监控状态。包含API Server统一入口、Scheduler调度器、Controller Manager控制器、etcd存集群状态。Node节点工作节点实际跑容器的机器上面运行Kubelet接收Master指令、Kube-proxy网络规则。5.3 滚动更新和回滚面试必问场景你的应用要从v1升级到v2。如果是传统方式先停掉v1 → 部署v2 → 启动v2 → 这中间服务是不可用的。K8s的滚动更新先启动一个新Podv2等它就绪后。再停掉一个旧Podv1。重复以上步骤直到所有Pod都替换成v2。整个过程服务始终可用至少有一个Pod在服务。控制策略maxSurge可以多启动多少个新Pod比如25%。maxUnavailable最多有多少个旧Pod可以不可用比如0保证零停机。回滚kubectl rollout undo deployment/my-app一键回到上一个版本。如果是线上故障比如v2有Bug这是最快最安全的止血手段。5.4 探针健康检查K8s怎么知道一个容器是活着还是挂了靠探针Probe。livenessProbe存活探针如果失败了K8s认为容器死了重启容器。readinessProbe就绪探针如果失败了K8s认为容器还没准备好接收流量不会把请求转发给它。配置方式HTTP GET访问/actuator/health返回200就正常。TCP Socket尝试连端口。Exec执行脚本返回0就正常。六、面试官真正想听什么场景1“Docker和虚拟机有什么区别”普通回答“容器轻量虚拟机重量。”加分回答“本质区别是虚拟化层级不同。虚拟机虚拟的是硬件需要完整的Guest OS所以镜像有几个G启动要几分钟。容器虚拟的是操作系统内核它只是Linux宿主机上的一个普通进程通过Namespace实现资源隔离PID、Network、Mount等通过Cgroups限制CPU和内存。所以容器镜像是MB级别启动是毫秒级。在云原生时代容器是更经济的资源利用方式一台物理机可以跑几百个容器虚拟机只能跑几十个。”场景2“你们项目里Docker和K8s怎么用的”加分回答“我们CI/CD流水线里代码合并到主干后自动触发构建用Maven打Jar包然后docker build构建镜像推送到阿里云镜像仓库ACR。然后通过GitOps方式ArgoCD自动更新K8s的Deployment镜像版本触发滚动更新。配合readinessProbe新版本就绪了才会切流量整个上线过程零停机。”场景3“K8s滚动更新回滚过吗”加分回答体现实战经验“有一次我们发版新版本有个内存泄漏上线后Pod内存持续飙升。我们通过监控发现异常后执行kubectl rollout undo秒级回滚到上一个稳定版本整个回滚过程5秒内完成用户几乎无感。之后我们调整了maxSurge和maxUnavailable参数把滚动更新的步长调小了减少回滚时的影响面。”场景4“容器里怎么看日志”加分回答“单个Pod用kubectl logs -f pod-name。但集群环境下我们不会这么查而是用ELKElasticsearch Logstash Kibana或Loki在每个节点上部署Filebeat作为DaemonSet每个节点一个收集所有Pod的日志统一打到Elasticsearch在Kibana里按namespace、pod、traceId检索。生产环境根本不会去机器上docker logs那是灾难。”小结核心概念大白话面试考点镜像静态模板类Dockerfile、分层存储容器运行中的进程实例容器 vs 虚拟机Namespace隔离视野假装自己是独立系统Linux底层隔离机制Cgroups限制资源CPU/内存配额容器不抢宿主资源Pod最小调度单元1个或多个容器为什么需要PodDeployment管理Pod期望状态副本数、滚动更新、回滚Service稳定的访问入口ClusterIP/NodePort探针健康检查liveness vs readiness记住一句话Docker把应用和环境打包成标准集装箱K8s是管理这堆集装箱的码头调度中心。理解了这个云原生的大门就对你敞开了。下一篇我们讲网络与操作系统基础——TCP三次握手、HTTP/HTTPS、Linux排查命令……面试里这些底层常识到底怎么答才能显得你真的懂下期见。