第十篇:Docker & K8s——标准化应用的“集装箱“和“码头调度中心“

别再纠结容器和虚拟机的区别了,你只需要知道"Docker把应用和环境打包成标准集装箱,K8s就是管理这堆集装箱的码头吊机"

写在前面

Docker和Kubernetes(K8s)是"云原生"时代的基石。面试问到这块,本质上是在问两件事:①你的应用怎么打包和交付的?②上了生产环境怎么管理、怎么扩缩容?

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可能是:

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-alpine
COPY / ADD 把文件拷进镜像 COPY target/app.jar /app.jar
RUN 构建时执行的命令 RUN apt-get update && apt-get install -y curl
CMD 容器启动时执行的命令(可被覆盖) CMD ["java", "-jar", "/app.jar"]
ENTRYPOINT 容器启动时执行的命令(不可被覆盖) ENTRYPOINT ["java", "-jar"]
EXPOSE 声明容器监听的端口(文档作用) EXPOSE 8080
ENV 设置环境变量 ENV JAVA_OPTS="-Xmx512m"

CMD vs ENTRYPOINT的区别(面试考点)

  • CMD :可以被docker run后面的命令覆盖。比如docker run my-app bash会覆盖CMD里的java -jar,执行bash。
  • ENTRYPOINT :不会被覆盖,docker run后面跟的参数会作为追加参数传给ENTRYPOINT。
dockerfile 复制代码
# 写法1:固定命令
ENTRYPOINT ["java", "-jar", "/app.jar"]

# 写法2:可变的JVM参数
ENTRYPOINT ["java", "-jar", "/app.jar"]
CMD ["--spring.profiles.active=prod"]  # 默认参数,可以被覆盖

五、Kubernetes(K8s):容器编排平台

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(环境隔离)

把集群按环境隔开:devtestprod。不同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的滚动更新

  1. 先启动一个新Pod(v2),等它就绪后。
  2. 再停掉一个旧Pod(v1)。
  3. 重复以上步骤,直到所有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秒内完成,用户几乎无感。之后我们调整了maxSurgemaxUnavailable参数,把滚动更新的"步长"调小了,减少回滚时的影响面。"

场景4:"容器里怎么看日志?"

加分回答:

"单个Pod用kubectl logs -f pod-name。但集群环境下我们不会这么查,而是用ELK(Elasticsearch + Logstash + Kibana)或Loki ,在每个节点上部署Filebeat(作为DaemonSet,每个节点一个),收集所有Pod的日志统一打到Elasticsearch,在Kibana里按namespacepodtraceId检索。生产环境根本不会去机器上docker logs,那是灾难。"

小结

核心概念 大白话 面试考点
镜像 静态模板(类) Dockerfile、分层存储
容器 运行中的进程(实例) 容器 vs 虚拟机
Namespace 隔离视野(假装自己是独立系统) Linux底层隔离机制
Cgroups 限制资源(CPU/内存配额) 容器不抢宿主资源
Pod 最小调度单元(1个或多个容器) 为什么需要Pod
Deployment 管理Pod期望状态 副本数、滚动更新、回滚
Service 稳定的访问入口 ClusterIP/NodePort
探针 健康检查 liveness vs readiness

记住一句话:Docker把应用和环境打包成标准集装箱,K8s是管理这堆集装箱的码头调度中心。理解了这个,云原生的大门就对你敞开了。

下一篇我们讲网络与操作系统基础------TCP三次握手、HTTP/HTTPS、Linux排查命令......面试里这些"底层常识"到底怎么答才能显得你真的懂?下期见。

相关推荐
增量星球2 小时前
《持续交付2.0系列一》从技术交付到业务引领
java·docker·容器·devops
Zhu7582 小时前
在k8s环境部署Apache kafka4.3.1
容器·kubernetes·apache
探索云原生16 小时前
终于搞懂 Kueue:5 个核心对象一次讲透
linux·docker·ai·云原生·kubernetes
众人皆醒我独醉17 小时前
etcd,其实不是你以为的"数据库"——Kubernetes 大脑的六个反直觉真相
面试·kubernetes
AI服务老曹17 小时前
Docker部署AI视频分析平台参数配置说明与调优指南
人工智能·docker·音视频
eggcode18 小时前
docker拉取、重命名、导出导入、删除镜像的示例
docker
蜀道山老天师19 小时前
从零读懂 K8s:核心概念、集群架构与工作原理
容器·架构·kubernetes
静待雨落21 小时前
Docker 高频命令
docker·容器
Java小白笔记21 小时前
Docker 命令大全:从入门到精通的完整指令集
spring cloud·docker