Docker由浅入深详解
2026-06-30 14:58:00 0 举报AI智能生成
《Docker由浅入深详解》是一本全面的指南,旨在带领读者从基本概念深入到高级应用,全面掌握Docker容器技术。本书详细介绍了Docker的核心工作原理,包括容器与镜像的基本操作、网络配置以及数据管理等关键概念。此外,书中还讲解了如何利用Dockerfile和Docker Compose来自动化部署和管理容器化应用,进一步提高开发效率和运维便捷性。本书内容丰富、结构清晰,对初学者友好,同时也不乏对进阶用户有用的高级特性,使得它不仅是一本入门教程,也是一部实用的参考书。
docker
由浅入深详解
容器编排
模板推荐
作者其他创作
大纲/内容
阶段 1:零基础入门(基础概念 + 安装 + 核心命令,0 容器基础可用)
模块 1:容器、虚拟机、Docker 通俗区分 + Java 工程师必学理由
1.1 三者核心区别(大白话类比,开发视角)
<b>虚拟机(VMware/VirtualBox)</b>
完整模拟一台物理电脑,包含独立内核、操作系统、驱动、JDK、中间件,资源完全隔离。
举例:一台虚拟机装 CentOS7,单独分配 2 核 4G,只跑一个 SpringBoot 服务,操作系统就要占用 1G 内存,资源浪费极大,启动要几分钟。
核心缺点:启动慢、资源开销高、打包镜像几十 G,交付部署笨重。
<b>容器(Linux 内核技术)</b>
不模拟完整操作系统,<b>共用宿主机 Linux 内核</b>,只隔离应用进程、文件、网络、权限,仅打包程序 + 依赖库。
举例:只打包 SpringBoot Jar + JDK17,不含完整系统内核,占用内存几十 MB,启动秒级,镜像仅几百 MB。
<b>Docker</b>
不是容器技术本身,是<b>容器标准化工具</b>:封装了容器创建、打包、分发、运行全流程,统一一套命令、镜像格式,解决 “本地能跑、线上环境报错”。
直观对比表
1.2 Java 后端必须学 Docker 的 4 个核心原因(面试高频)
<b>统一开发、测试、生产环境</b>
Java 经典痛点:本地 JDK17、测试环境 JDK11、服务器 JDK8,代码本地正常,线上报类版本异常。Docker 镜像固定绑定 JDK 版本、依赖包,一处打包到处运行。
<b>微服务工程必备</b>
现在 Java 微服务(SpringCloud)动辄十几个服务 + MySQL/Redis/Nacos/MQ,不用 Docker 需要逐个安装配置中间件,容器一键拉起整套集群。
<b>企业上线标准流程</b>
中高级后端、架构岗全部要求容器化部署,CI/CD 流水线(Jenkins/GitLab)核心就是构建 Docker 镜像,不熟悉无法参与上线发布。
<b>K8s 前置基础</b>
高级岗必问 K8s,K8s 只是容器编排平台,底层运行单元就是 Docker 容器,不懂 Docker 完全无法看懂 K8s 调度逻辑。
模块 2:Windows / Mac / Linux Docker Desktop 安装 + 镜像加速 + 常见报错
模块 3:五大核心概念(结合 SpringBoot 项目类比,人话讲解)
3.1 镜像 Image(只读模板)
类比:Java 项目安装包 + 固定运行环境(JDK17)
镜像是静态文件,只读,包含运行程序所有依赖(JDK、Jar、配置文件),不能修改。
举例:openjdk:17 镜像 = 预装 JDK17 的环境模板;自定义镜像 = JDK17 + 你的 SpringBoot Jar 包。
3.2 容器 Container(镜像运行实例)
类比:双击 Jar 包启动后的 Java 进程
用镜像运行出来的独立进程,可读可写,一个镜像可以同时启动 N 个容器。
举例:基于 openjdk17 镜像启动两个容器,分别运行订单服务、用户服务,两个进程完全隔离。
3.3 仓库 Repository
类比:Maven 中央仓库、私服 Nexus
存放 Docker 镜像的远程服务器,分为公有仓库(Docker Hub)、企业私有仓库(Harbor)。
开发流程:本地构建镜像 → push 上传仓库 → 测试 / 生产服务器 pull 拉取镜像部署。
3.4 数据卷 Volume
类比:服务器外挂磁盘
容器删除时内部文件会全部丢失,数据卷把日志、数据库文件、配置文件挂载到宿主机持久保存。
Java 场景:SpringBoot 日志文件、MySQL 库表数据、application.yml 配置全部挂载数据卷。
3.5 网络 Network
类比:机房局域网
Docker 内置独立网络体系,实现容器之间互相通信、宿主机和容器端口互通。
场景:SpringBoot 容器需要连接 MySQL 容器,加入同一自定义网络即可通过容器名称访问数据库。
模块 4:高频 Docker 基础命令(每条搭配 Java 业务实操案例)
一、镜像操作命令
二、容器生命周期命令
三、容器交互与日志(后端调试必用)
四、数据挂载与端口映射(生产必备)
五、系统清理命令(长期开发必备)
模块 5:课后实操完整流程(2 个实战任务,可直接复制执行)
任务 1:完整运行 Nginx 容器(前端静态资源配套 Java 后端)
任务 2:运行 JDK17 容器(Java 核心实操)
阶段学习小结
完成以上内容你将具备:
分清容器、虚拟机本质差异,理解 Java 容器化价值;
三系统 Docker 环境独立部署、解决网络拉取慢问题;
吃透镜像 / 容器 / 仓库 / 卷 / 网络五大核心概念;
熟练使用日常开发全部高频 Docker 命令;
独立运行 JDK、Nginx 容器,具备本地容器调试基础。
阶段 2:核心实操(镜像制作 Dockerfile,Java 核心重点,求职必考)
一、Dockerfile 全部核心指令详解(释义 + Java 场景 + 避坑)
1. FROM
<b>作用</b>:指定基础镜像,所有 Dockerfile 第一行必须是 FROM
<b>Java 常用镜像</b>
openjdk:17-jdk-slim:精简 JDK,日常开发
openjdk:17-jre-alpine:仅运行环境,体积极小,生产首选
centos:7:老式传统项目不推荐,体积臃肿
<b>写法</b>
dockerfile
<b>避坑</b>
不要用不带版本的 openjdk:latest,版本不可控,线上环境混乱
打包运行 Jar 只需要 JRE,不要用完整 JDK,减少镜像体积
2. WORKDIR
<b>作用</b>:设置容器内工作目录,后续命令默认在该目录执行,自动创建文件夹
<b>示例</b>
dockerfile
<b>Java 场景</b>:统一把 Jar 包、配置文件放到 /app目录,不用反复写长路径
<b>避坑</b>:不要频繁切换 WORKDIR,增加镜像分层
3. COPY
<b>作用</b>:本地宿主机文件 / 文件夹复制到容器内,<b>只支持本地文件</b>
语法:COPY 宿主机路径 容器内路径
dockerfile
<b>Java 场景</b>:复制编译好的 SpringBoot Jar、yml 配置文件
<b>避坑</b>
复制 jar 放在 RUN 之后会破坏缓存,构建速度变慢
路径不要写绝对宿主机路径,适配 CI 流水线
4. ADD
<b>作用</b>:功能 = COPY 增强版,额外支持 2 个特性
自动解压 tar/gz 压缩包到目标目录
支持远程 URL 自动下载文件
<b>Java 使用场景极少</b>,仅解压依赖压缩包时使用
<b>避坑</b>:单纯复制 Jar 包、配置文件一律用 COPY,不要滥用 ADD
5. RUN
<b>作用</b>:构建镜像阶段执行命令,执行结果写入镜像分层(构建时运行)
两种写法:
dockerfile
<b>Java 场景</b>:安装依赖、清理缓存、赋予文件执行权限
<b>避坑重点(镜像瘦身核心)</b>
不要多条分开 RUN,每条 RUN 都会新增一层镜像,合并用 &&串联
dockerfile
6. ENV
<b>作用</b>:定义环境变量,构建阶段 + 容器运行阶段都生效
dockerfile
<b>Java 场景</b>:指定 Spring 环境、JVM 参数、数据库地址
<b>避坑</b>:敏感密码不要写在 Dockerfile 中,会存入镜像分层明文,生产用外部 env 文件注入
7. EXPOSE
<b>作用</b>:声明容器对外使用的端口,<b>仅文档注释,不会自动暴露端口</b>
dockerfile
<b>Java 场景</b>:标注 SpringBoot 服务端口 8080
<b>避坑</b>:只写 EXPOSE 没用,启动容器必须配合 -p做端口映射才能外部访问
8. VOLUME
<b>作用</b>:声明持久化挂载目录,容器运行时自动生成匿名数据卷
dockerfile
<b>Java 场景</b>:SpringBoot 日志目录持久化
<b>避坑</b>:生产推荐启动容器手动 -v挂载,Dockerfile VOLUME 无法绑定宿主机指定目录,灵活性差
9. USER
<b>作用</b>:切换容器运行用户,默认 root(高危)
dockerfile
<b>Java 生产强制规范</b>:禁止容器使用 root 用户运行服务,防止容器逃逸攻击
<b>避坑</b>:Alpine 系统创建用户命令是 adduser,CentOS 是 useradd,不要混用
10. CMD
<b>作用</b>:容器启动时默认执行命令,<b>可被 docker run 命令覆盖</b>
仅一条生效,多条只执行最后一条
两种格式:
dockerfile
11. ENTRYPOINT
<b>作用</b>:容器启动入口程序,<b>不会被 run 命令覆盖</b>,run 传参追加到后面
常用于封装启动脚本、统一 JVM 参数
二、高频面试对比考点:CMD vs ENTRYPOINT / COPY vs ADD
三、单层镜像致命缺点 + 多阶段构建 Multi-Stage 完整教程
3.1 传统单层镜像问题(不分离编译、运行)
3.2 多阶段构建原理
3.3 SpringBoot 多阶段构建模板
四、镜像分层原理、缓存机制、全套瘦身优化方案
五、生产级 SpringBoot 完整 Dockerfile(可直接复制,逐行注释)
六、镜像构建、打标签、私有仓库推拉完整配套命令
1. docker build 构建镜像
2. docker tag 镜像重打标签
3. 私有仓库登录 + push 推送镜像
4. pull 拉取私有镜像(测试 / 生产服务器)
5. 基于镜像启动 SpringBoot 容器完整示例
七、本章核心学习总结(面试速记)
Dockerfile 指令核心区分:COPY 优先于 ADD;生产必须 USER 切换普通用户;RUN 合并清理缓存瘦身
CMD 可被 run 覆盖,ENTRYPOINT 作为固定入口,二者组合使用是标准写法
多阶段构建是 Java 项目镜像必备方案,解决体积大、源码泄露两大痛点
缓存关键:先 pom 后 src,依赖分层缓存提升构建速度
上线流程:build 打镜像→tag 私有仓库→login 登录→push 上传,服务器 pull 部署
生产硬性规范:Alpine 轻量 JRE、非 root 用户、多阶段构建、.dockerignore 过滤冗余文件
阶段 3:数据持久化与容器网络(生产必备,解决 Java 项目文件 / 日志存储)
一、数据存储模块(Volume 数据卷)
1. 三种挂载方式完整对比(面试必背)
1)匿名卷(Anonymous Volume)
创建方式:docker run -v /容器内路径 不指定宿主机路径
存储位置:Docker 管理目录自动生成随机 ID 文件夹,无法自定义路径
生命周期:容器删除后匿名卷<b>不会自动删除</b>,残留垃圾文件占磁盘
Java 适用场景:临时缓存、无关紧要临时文件,<b>生产不推荐</b>
示例:
bash
运行
2)具名卷(Named Volume)
创建方式:docker run -v 卷名:/容器内路径
存储位置:Docker 统一管理目录,通过卷名快速识别
优点:方便备份、迁移、批量清理,Docker 原生管理,权限稳定
Java 适配:MySQL 数据库持久化、Redis 持久数据(数据库首选)
示例:
bash
运行
3)绑定挂载(Bind Mount)
创建方式:docker run -v 宿主机绝对路径:/容器内路径
特点:直接映射服务器真实文件夹,宿主机可直接编辑文件
优点:灵活,宿主机直接修改配置、查看日志;缺点:受宿主机目录权限影响
Java 核心场景:
外部挂载 application-prod.yml配置文件
持久化 SpringBoot 项目日志文件
前端静态资源本地热更新
示例:
bash
运行
三种挂载选型总结(生产规范)
表格
挂载类型
匿名卷
具名卷
绑定挂载
优点
无需手动命名
统一管理、易备份、权限稳定
宿主机直接读写文件
缺点
无法定位目录、垃圾多
不能直接自定义宿主机目录
目录权限容易报错
Java 微服务使用场景
本地测试临时缓存,线上禁用
MySQL、Redis 数据库持久化
外部配置文件、业务日志、静态资源
2. 数据卷生命周期、备份、迁移、清理全套实操命令
查看所有数据卷
bash
运行
查看卷详细存储路径
bash
运行
删除单个无用卷(仅无容器挂载时可删)
bash
运行
一键清理所有未被容器使用的卷(本地开发必用)
bash
运行
完整备份具名卷数据(MySQL 迁移核心操作)
原理:启动临时容器,将卷数据打包压缩到宿主机
bash
运行
恢复卷数据(换服务器迁移数据库)
bash
运行
3. Java 项目三大真实挂载案例
案例 1:外部挂载 application.yml,不打包进镜像
宿主机目录:/opt/demo/config,放入 application-prod.yml
bash
运行
优势:环境配置和镜像解耦,测试、生产使用不同配置文件。
案例 2:持久化 SpringBoot 日志文件
bash
运行
线上排查日志不用进入容器,服务器直接 tail -f /opt/logs/user-service/info.log。
案例 3:MySQL 数据库使用具名卷持久化(微服务标配)
bash
运行
容器删除重建,数据库表、数据不会丢失。
4. 数据卷面试高频考点
绑定挂载和具名卷的使用场景区分?
答:配置、日志用绑定挂载;数据库存储用具名卷。
Docker 删除容器时数据卷会一起删除吗?
答:不会,匿名卷 / 具名卷独立存在,需手动 prune 清理。
能不能在 Dockerfile 中 VOLUME 挂载宿主机指定目录?
答:不能,VOLUME 只能声明容器内目录,无法指定宿主机路径,生产挂载统一在 run 命令用 - v。
数据库迁移怎么备份 Docker 卷?
答:启动临时 alpine 容器,将卷数据 tar 压缩到宿主机备份目录。
二、容器网络模块(微服务通信核心)
1. Docker 四大原生网络模式通俗讲解
执行查看网络命令:docker network ls
1)bridge(默认桥接网络)
所有容器默认加入 bridge默认网桥
同一 bridge 下容器可互相 IP 访问,<b>不能通过容器名称通信</b>
外部主机通过 -p端口映射访问容器
适用:本地简单测试,<b>多微服务集群不推荐默认 bridge</b>
2)host(共享宿主机网络)
容器不做网络隔离,直接复用宿主机网卡、IP、所有端口
无需端口映射,容器 8080 = 宿主机 8080
优缺点:性能高;多服务端口极易冲突,隔离性差
适用:网关 Nginx、高性能采集服务,微服务业务服务禁用
3)none(无网络)
容器完全禁用网卡,无任何网络访问能力
适用:纯本地计算任务、安全离线脚本,Java 业务几乎不用
4)container(复用其他容器网络)
新容器共享已有容器的网络栈,共用 IP 和端口
场景:配套 sidecar 日志采集容器,和主 SpringBoot 共用网络
bash
运行
2. 自定义 bridge 网络(微服务生产标准方案)
核心优势(面试必背)
同一自定义网络内,<b>可直接用容器名互相访问</b>(不用记 IP,适配微服务配置)
不同自定义网络之间容器天然隔离,多项目环境互不干扰
支持 DNS 自动解析,SpringBoot 配置数据库地址直接写容器名 mysql8
比默认 bridge 更稳定,无通信延迟问题
自定义网络完整实操
bash
运行
3. 端口映射原理 & 多 SpringBoot 端口冲突解决方案
端口映射原理 -p 宿主机端口:容器端口
Docker 宿主机监听指定端口,流量转发至容器内部端口;容器内部端口相互不影响,冲突只出现在<b>宿主机端口</b>。
多服务端口冲突解决方案(三种)
<b>宿主机端口分段映射(最常用)</b>
容器内部统一 8080,宿主机分配不同端口:
用户服务:-p 8081:8080
订单服务:-p 8082:8080
商品服务:-p 8083:8080
<b>修改容器内 SpringBoot 端口</b>
启动时传入环境变量修改服务端口,宿主机统一 8080(不推荐,配置混乱)
bash
运行
<b>使用 host 网络慎用</b>
host 模式无端口隔离,不适合多微服务并行部署。
4. 综合实操任务:MySQL 容器 + SpringBoot 容器通过自定义网络通信
步骤 1:创建自定义网桥
bash
运行
步骤 2:启动 MySQL,挂载数据卷,加入自定义网络
bash
运行
步骤 3:SpringBoot 容器加入同一网络,数据库地址写容器名 mysql-db
application.yml 配置(无需写 IP)
yaml
步骤 4:启动 SpringBoot 微服务容器
bash
运行
步骤 5:验证容器互通
进入 SpringBoot 容器 ping mysql 容器名,可正常解析通信
bash
运行
5. 网络模块面试高频考点
默认 bridge 和自定义 bridge 核心区别?
答:默认 bridge 不支持容器名 DNS 解析,自定义 bridge 可通过容器名称通信,微服务必须自定义网桥。
host 网络优缺点,什么场景使用?
答:性能高,无端口隔离;适合网关、监控采集,业务微服务禁止使用。
多个 SpringBoot 服务容器端口冲突怎么解决?
答:容器内部统一 8080,宿主机分配不同对外端口映射。
微服务中数据库地址为什么能写容器名称?
答:自定义 bridge 内置 Docker DNS 服务,自动将容器名解析为容器内网 IP。
不同自定义网络下两个容器能否互相访问?
答:不能,网络隔离,需加入同一个网桥或使用 host 模式。
本章生产落地总结
阶段 4:多容器编排 Docker Compose(微服务本地调试必备,面试高频)
一、Docker Compose 核心定位与作用
1. 是什么
Docker Compose 是 Docker 官方<b>单机多容器编排工具</b>,通过一份 docker-compose.yml 统一管理一整套微服务集群(SpringBoot、MySQL、Redis、Nginx、MQ 等),不用手动敲一堆 docker run命令。
2. 核心价值(Java 开发痛点解决)
本地开发一键拉起整套微服务环境,不用逐个启动中间件;
配置统一维护,端口、挂载、网络、环境变量全部写在 YAML,可版本管理;
统一启停、查看日志、批量重启、本地简单扩缩容;
适合:开发机、测试单机环境;<b>不适合多服务器分布式集群</b>(多机器用 K8s)。
3. 运行前提
Windows/Mac:Docker Desktop 内置 Compose,直接用 docker compose;
Linux:需单独安装 docker-compose 插件。
二、docker-compose.yml 顶层核心关键字详解
1. version(版本声明)
指定 Compose 文件语法版本,新项目推荐 "3.8",兼容所有常用特性。
yaml
2. services(核心:所有容器服务定义)
所有微服务、中间件都写在 services 下,每一个 key 代表一个容器(spring-app、mysql、redis、nginx)。
基础结构:
yaml
3. volumes(全局数据卷)
统一声明<b>具名卷</b>,供多个 service 复用,对应前文 MySQL 持久化存储场景。
yaml
4. networks(全局自定义网络)
统一创建网桥,所有服务加入同一网络,支持容器名 DNS 互通,微服务标准规范。
yaml
5. ports 端口映射
格式:宿主机端口:容器内端口,多端口用数组。
yaml
6. environment 容器内环境变量
直接写键值对,注入 Spring 配置、JVM 参数、数据库账号密码。
yaml
7. depends_on 服务启动依赖
定义服务启动先后顺序,仅控制<b>启动顺序</b>,<b>不等待服务就绪</b>(重大坑,下文单独讲)。
yaml
三、高频坑点:depends_on + healthcheck 健康检查
1. depends_on 致命缺陷(面试必考)
depends_on: [mysql] 只会保证:<b>mysql 容器先启动</b>,不会等待 MySQL 服务初始化完成。
场景:SpringBoot 启动速度比 MySQL 初始化快,程序启动报数据库连接失败。
2. healthcheck 健康检查解决方案
给中间件配置健康探针,Spring 服务等待依赖服务健康后再启动。
支持三种检测方式:
test:检测命令
interval:检测间隔
timeout:单次超时
retries:失败重试次数
示例 MySQL 健康检查:
yaml
Spring 服务配合 condition: service_healthy等待健康:
yaml
四、三种环境变量注入方式(Java 项目全覆盖)
方式 1:environment 直接写入 yml(适合固定常量,禁止明文密码)
yaml
方式 2:env_file 外部环境变量文件(推荐,区分多环境)
新建 .env / .env-prod,敏感配置抽离,不提交代码仓库。
<b>.env 文件内容</b>
env
compose 引用:
yaml
方式 3:宿主机外部系统变量(开发 / 流水线动态传参)
yml 中使用 ${变量名} 读取宿主机环境变量
yaml
启动时传参:
bash
运行
五、完整实战 yml:SpringBoot + MySQL8 + Redis + Nginx 微服务集群
六、Compose 全套核心命令 & 使用场景
1. 启动集群(最常用)
bash
运行
2. 停止并删除容器、网络(保留数据卷)
bash
运行
3. 查看运行中的服务
bash
运行
4. 实时查看日志(排查 SpringBoot 报错)
bash
运行
5. 重启 / 停止单个服务
bash
运行
6. scale 本地简单扩缩容(开发测试用)
启动 3 个 SpringBoot 实例,Compose 自动分配不同内网端口,宿主机不暴露多端口:
bash
运行
限制:单机有效,无法做负载均衡,生产集群扩缩容用 K8s。
7. 进入容器内部调试
bash
运行
七、生产环境优化配置(面试加分项)
1. CPU、内存资源限制(防止服务抢占宿主机资源)
通过 deploy.resources.limits限制,上面 yml 已演示:
yaml
2. 容器重启策略 restart
四种策略适用场景:
restart: always:MySQL/Redis 中间件,宕机永久自动重启;
restart: on-failure:SpringBoot 业务服务,异常退出才重启,正常 stop 不重启;
restart: no:测试临时容器,不自动重启;
restart: unless-stopped:除非手动关闭,否则开机自启。
3. 日志持久化、日志切割(避免容器日志爆盘)
全局日志配置,限制单文件大小、保留份数,写入宿主机文件:
yaml
4. 安全优化
挂载配置文件只读:./config:/app/config:ro;
Dockerfile 内使用 USER 非 root 用户运行程序;
密码放入.env,不提交 Git 仓库。
八、面试核心考点:Compose vs K8s 定位区分
1. Docker Compose 适用场景
开发本地、单机测试环境,快速拉起整套微服务;
小型单机部署,无多服务器扩容需求;
简单批量容器管理,无自动负载均衡、自愈、滚动更新。
2. K8s 适用场景
分布式多服务器集群;
生产大规模微服务:自动扩缩容、故障自愈、滚动发布、灰度发布;
统一资源调度、服务发现、Ingress 网关、监控告警。
3. 核心区别对比
表格
维度
运行范围
扩缩容
自愈能力
发布策略
服务发现
生产规模
Docker Compose
仅单台服务器
单机 scale,无负载均衡
仅简单 restart 策略
只能重启重建
单机网桥 DNS
开发 / 小型单机测试
Kubernetes(K8s)
多机器集群
集群自动弹性伸缩
节点故障自动迁移容器
滚动更新、灰度、蓝绿发布
集群内完整服务注册发现
企业线上生产集群
面试标准问答
Q:什么场景只用 Compose 不用 K8s?
A:本地开发调试环境、单机小型内部测试服务,机器数量单一、无需集群调度、无大规模发布运维需求,使用 Compose 简单低成本;线上多节点生产微服务必须使用 K8s。
本章学习小结
Compose 核心是单机多容器编排,yml 统一管理网络、存储、服务依赖;
depends_on 只控制启动顺序,必须搭配 healthcheck 解决中间件未就绪问题;
环境变量三种注入:直接 yml、env_file、宿主机系统变量,敏感配置抽离.env;
生产必配:资源限制、日志切割、重启策略、非 root 运行;
定位边界:Compose 管本地单机,K8s 管分布式集群,二者不冲突,Java 工程师开发用 Compose,上线生产用 K8s。
阶段 5:私有镜像仓库 + 生产运维(企业真实部署流程)
一、镜像仓库:Docker Hub 公有仓库 + Harbor 私有仓库极简部署
二、镜像推拉、权限、仓库 HTTP/HTTPS 配置
三、容器日常运维全套命令(线上日常巡检必备)
四、容器启动失败通用故障排查思路(面试高频)
五、企业镜像安全规范(生产强制要求)
六、企业 CI/CD 流水线联动:Maven 打包自动构建 Docker 镜像
本章面试速记核心要点
阶段 6:Docker 底层原理 + 面试突击(应对高级工程师面试提问)
一、Docker 三大底层核心技术(通俗讲解,面试口述友好)
Docker 本质是 Linux 内核提供的三组能力组合,Windows/Mac 是靠 WSL2 / 虚拟机套 Linux 内核实现容器。
1. Namespace 命名空间:实现<b>进程隔离</b>(容器能看见自己,看不见宿主机 / 其他容器)
Linux 提供 6 大 Namespace,Docker 全部启用,每一项对应一层隔离:
<b>PID Namespace</b>:进程 ID 隔离
容器内部进程 PID 从 1 开始,看不到宿主机、其他容器的进程;宿主机能看见所有容器真实 PID。
Java 场景:容器内只展示 SpringBoot、JVM 进程,不会泄露宿主机服务进程。
<b>NET Namespace</b>:网络栈隔离
每个容器独立网卡、IP、端口、路由表;默认互不干扰,端口不会互相抢占。
<b>MNT Namespace</b>:文件挂载隔离
容器拥有独立挂载视图,宿主机目录不默认暴露,只有手动 -v挂载才可见。
<b>UTS Namespace</b>:主机名隔离
容器可以自定义 hostname,和宿主机主机名互不影响。
<b>USER Namespace</b>:用户 / 用户组隔离
容器内 root 用户映射宿主机普通 UID,就算容器被攻破,也拿不到宿主机 root 权限,安全防护。
<b>IPC Namespace</b>:进程通信隔离
容器间管道、消息队列、共享内存默认隔离,只能靠网络通信。
<b>总结</b>:Namespace 解决「隔离」,让容器以为自己是一台独立机器。
2. Cgroups 控制组:实现<b>资源限制</b>(防止单个容器耗尽服务器 CPU / 内存)
Namespace 只管隔离,Cgroups 限制资源配额,Docker run --memory、--cpus底层全靠 Cgroups:
限制 CPU 使用率、核心数
限制最大内存、Swap 大小(Java 服务 OOM 被 kill 底层触发 cgroup 内存限制)
限制磁盘 IO 读写速度
统计容器资源占用(docker stats数据来源)
Java 生产场景:给 SpringBoot 限制 -m 768m,避免 JVM 爆内存拖垮整台服务器。
3. UnionFS 联合文件系统:实现<b>镜像分层、写时复制</b>(镜像体积小、复用层缓存的根源)
分层存储:Dockerfile 每一条指令生成<b>只读层</b>;
多个镜像共享基础层:比如所有 Java 服务都依赖 openjdk:17-jre-alpine,该层只会存一份,大幅节省磁盘;
容器启动时,最顶层新增一层<b>可读写层</b>,所有修改、新增文件都存在这一层,只读镜像层永远不会改动。
二、镜像与容器底层关系 + 写时复制 CoW 机制
1. 镜像 vs 容器底层关系
<b>镜像(Image)</b>:一堆只读 UnionFS 分层的静态文件集合,模板,无法修改;
<b>容器(Container)</b>:镜像 + 一层独立可读写层 + Namespace 隔离 + Cgroups 资源限制的运行实例;
一个镜像可以同时启动成千上万个容器,每个容器拥有独立读写层,互不干扰。
2. 写时复制 Copy-on-Write(CoW)通俗解释
容器启动后,只读镜像层文件<b>不会拷贝</b>到容器读写层,共用;
当程序只读取文件(比如 Spring 读取 jar 包、yml 配置),直接读底层只读层,无性能损耗;
一旦<b>修改 / 删除文件</b>,Docker 会把该文件完整复制到顶层读写层,后续操作只修改副本;底层镜像原文件保持不变。
举例:修改容器内 application.yml,只会复制一份 yml 到读写层,基础 JDK 层完全不动;删除容器,读写层直接销毁,镜像完好无损。
三、高频面试题 + 标准满分回答(Java 后端专用)
1. Docker 容器和虚拟机区别?
<b>标准答案</b>
内核层面:虚拟机拥有独立完整操作系统内核;Docker 共享宿主机 Linux 内核,仅隔离进程。
资源开销:VM 需要分配完整内存、磁盘给操作系统,占用极高;容器只打包程序 + 依赖,内存 MB 级别。
启动速度:虚拟机分钟级启动;容器秒级启动。
镜像大小:虚拟机镜像 GB 级别;Docker 镜像 MB 级别,传输分发快。
隔离强度:虚拟机硬件级强隔离;Docker 是进程级轻隔离,依赖 Linux 内核。
适用场景:VM 适合异构系统、强安全隔离;Docker 适合微服务快速交付、CI/CD 流水线。
2. Dockerfile 多阶段构建好处?
<b>标准答案</b>
减小最终镜像体积:编译阶段 Maven、源码、编译插件全部丢弃,最终只保留 JRE+Jar 包;
源码安全隔离:业务代码不会打包进线上镜像,防止代码泄露;
利用分层缓存:单独缓存 Maven 依赖层,修改业务代码无需重新下载依赖,构建速度更快;
减少漏洞攻击面:剔除编译工具、操作系统多余软件,降低安全风险。
3. 数据卷三种挂载区别,生产怎么选?
<b>标准答案</b>
三种:匿名卷、具名卷、绑定挂载
匿名卷:-v /容器路径,随机 ID 管理,无法指定宿主机目录;仅本地临时测试,线上禁用。
具名卷:-v 卷名:/容器路径,Docker 统一管理目录,权限稳定、易备份迁移;<b>MySQL、Redis 等持久化数据库专用</b>。
绑定挂载:-v 宿主机绝对路径:/容器路径,直接映射服务器目录,可实时编辑文件;<b>外部配置文件、业务日志专用</b>。
生产选型规范:数据库用具名卷;配置、日志使用绑定挂载;杜绝线上使用匿名卷。
4. bridge 和 host 网络差异?
<b>标准答案</b>
bridge(默认网桥):
容器独立虚拟网卡、独立 IP,通过 - p 端口映射对外暴露;容器网络隔离;自定义 bridge 支持容器名 DNS 互相访问,是微服务标准方案。
host(宿主机共享网络):
容器完全复用宿主机网卡、IP、所有端口,无隔离,无需端口映射;性能高,但多服务极易端口冲突。
使用场景:业务 SpringBoot 微服务一律自定义 bridge;高性能网关、采集组件少量使用 host。
5. CMD 和 ENTRYPOINT 区别,如何组合使用?
<b>标准答案</b>
覆盖规则:
CMD:docker run 镜像 命令会完全替换 CMD 指令;
ENTRYPOINT:run 后面传参只会追加到 ENTRYPOINT 后,不会覆盖入口程序。
分工:ENTRYPOINT 固定程序,CMD 传默认参数,生产标准组合写法:
dockerfile
启动时可动态追加 JVM 参数:docker run xxx -Xmx1G,参数自动拼接至 java 命令后。
使用场景:ENTRYPOINT 写固定启动程序 / 启动脚本;CMD 存放默认启动参数,方便动态覆盖。
6. Compose 能不能用于生产集群?和 K8s 如何分工?
<b>标准答案</b>
Compose<b>不能用于多机器生产集群</b>,仅支持单台服务器容器编排;
短板:无集群调度、无自动故障迁移、无滚动灰度发布、无集群级负载均衡、扩缩容仅单机有效。
分工边界:
Docker Compose:开发本地、单机测试环境,一键拉起整套微服务 + 中间件,提升本地调试效率;
K8s:线上分布式生产集群,负责多节点调度、自愈、弹性扩缩容、灰度发布、统一服务治理。
二者不冲突:开发用 Compose,线上部署迁移至 K8s。
四、Java 后端 Docker 模拟完整问答(自测卷,含答案)
Q1:为什么 Java 项目一定要用 Docker 解决环境问题?
A:Java 存在经典环境不一致问题:本地 JDK 版本、测试环境 JDK、生产 JDK 不统一,出现类版本异常;Docker 镜像固化 JDK、依赖、配置,实现一次打包到处运行;同时是 K8s 底层运行单元,企业微服务上线标准。
Q2:Dockerfile 中 COPY 和 ADD 区别,Java 项目该用哪个?
A:ADD 包含 COPY 功能,额外支持自动解压 tar 包、远程 URL 下载文件;单纯复制 Jar、yml 配置一律使用 COPY,避免 ADD 带来不必要的解压逻辑,规范统一。
Q3:depends_on 有什么坑,如何解决 SpringBoot 启动连不上 MySQL?
A:depends_on 仅控制容器启动顺序,不会等待 MySQL 服务初始化完成,Spring 启动更快直接报连接失败;解决方案:给 MySQL/Redis 配置 healthcheck 健康探针,Spring 服务配置 condition: service_healthy等待中间件就绪。
Q4:容器删除后数据会丢失吗?怎么持久化 Spring 日志和 MySQL 数据?
A:容器读写层会随容器删除销毁,镜像只读层不变;容器内数据必须挂载数据卷持久化:MySQL 用具名卷,日志、外部配置使用绑定挂载。
Q5:生产运行 SpringBoot 容器为什么禁止 root 用户?
A:root 权限容器存在逃逸风险,一旦攻击者入侵容器,可直接操作宿主机;规范:Dockerfile 创建普通业务用户,USER 切换非 root 运行 Jar,缩小安全攻击面。
Q6:镜像瘦身有哪些 Java 项目常用方案?
A:1. 使用 openjdk-jre-alpine 轻量基础镜像;2. 多阶段构建剔除源码、Maven;3. 合并 RUN 指令并同步清理缓存;4. .dockerignore 过滤 target、源码、git 文件;5. 分层缓存,先复制 pom 下载依赖,再复制业务代码。
Q7:私有 Harbor 仓库内网 HTTP 部署需要额外配置什么?
A:Docker 默认不信任 HTTP 非加密仓库,需要修改 daemon.json 添加 insecure-registries仓库地址,重启 Docker 服务才能正常推拉镜像。
Q8:容器启动几秒立刻退出,你的标准排查流程是什么?
A:1. docker logs查看启动日志(90% 报错都在这里);2. 检查端口是否被宿主机占用;3. 检查挂载目录权限是否不足;4. 核对 JVM 参数、数据库连接配置;5. 校验 Dockerfile CMD/ENTRYPOINT 启动命令是否写错。
Q9:docker stats 能看到哪些核心指标,Java 服务重点关注什么?
A:CPU 使用率、内存使用量 / 内存限制、网络 IO、磁盘 IO;Java 重点监控内存占用,持续逼近 limit 代表 JVM 内存配置过小,容易触发 OOM 杀死容器。
Q10:CI/CD 流水线中 Maven 和 Docker 怎么联动发布微服务?
A:流水线拉取代码 → Maven clean package 打包 Jar → Dockerfile 多阶段构建镜像 → 自动打版本标签 → 登录 Harbor 推送镜像 → 远程服务器拉取镜像、重启容器完成发布;多阶段构建无需流水线预装 Maven,环境统一。
五、面试背诵精简总结
底层三驾马车:Namespace 隔离、Cgroups 控资源、UnionFS 分层镜像;
镜像只读、容器多一层读写层,修改触发写时复制;
生产三规范:自定义 bridge 网络、数据库用具名卷、业务非 root 运行;
工具分工:本地 Compose,线上 K8s;
核心面试高频对比:容器 vs 虚拟机、CMD/ENTRYPOINT、COPY/ADD、bridge/host、三种数据卷。
Collect
Get Started
Collect
Get Started
Collect
Get Started
Collect
Get Started
评论
0 条评论
下一页