从 0 学习 Docker——一个 Java 后端实习生的 7 大核心精讲(含项目实战)
从 0 学习 Docker——一个 Java 后端实习生的 7 大核心精讲(含项目实战)
副标题:从"装环境 2 小时"到"docker run 一行",Java 后端入门 Docker 必看
一、开场引入:为什么"Docker"对后端实习生这么重要?
实习第 1 周,我接手一个老服务,要在本地跑起来联调。
我按 README 装 JDK、装 Maven、装 Redis、装 MySQL、配置环境变量……装了一下午,结果跑起来还是报错:java.lang.NoClassDefFoundError。
mentor 路过看了一眼:“用 Docker。”
我一脸懵:“Docker?什么鬼?”
mentor 抛下一句话:
“Docker 是’环境打包机’——你写一次 Dockerfile,别人在任何机器上一行命令就能跑起来。装环境不再是难题。”
5 分钟后,mentor 给我一个 docker-compose.yml,30 秒拉起全套环境——MySQL、Redis、应用服务一条龙。
我当时就震惊了:“原来这就是 Docker”。
回去翻了《Docker 实战》《Kubernetes 权威指南》……
这次我学到一个重要的事:Docker 不可怕,先学 7 个核心就够——镜像、容器、Dockerfile、Compose、数据卷、网络、仓库。
今天这篇博客,我就把这 7 个核心 + 项目实战 Dockerfile 模板掰开揉碎讲透,让更多像我一样的后端新人少走弯路。
💡 金句:Docker 不可怕,先学 7 个核心就够。把这 7 个吃透,90% 的后端场景你都能搞定。
二、概念扫盲:什么是 Docker
2.1 一句话定义
Docker = 把应用 + 依赖 + 环境打包成一个"标准集装箱",在任何机器上一键运行。
2.2 Docker vs 虚拟机
| 维度 | 虚拟机 | Docker |
|---|---|---|
| 启动速度 | 分钟级 | 秒级 |
| 体积 | GB 级 | MB 级 |
| 性能 | 50% 损耗 | 几乎无损耗 |
| 隔离性 | 强(独立 OS) | 中(共享内核) |
| 启动密度 | 几十个 | 几百上千个 |
2.3 Docker 架构
2.4 7 大核心地图
今天这篇博客,围绕这 7 大核心展开:
- 基础 2 件套:镜像 + 容器(Docker 的"灵魂")
- 制作 2 件套:Dockerfile + Compose(怎么"做")
- 进阶 3 件套:数据卷 + 网络 + 仓库(生产环境必备)
💡 金句:Docker 不可怕,先学 7 个核心就够。
三、精讲 1:镜像(image)
3.1 一句话定义
镜像 = 一个"只读模板",用来创建容器。
可以理解成"装应用的 ISO 镜像"——是个模板,本身不运行。
3.2 类比
| 类比 | 解释 |
|---|---|
| Java 类 | 镜像 = class,容器 = instance |
| PPT 模板 | 镜像 = 模板,容器 = 你做的 PPT |
| 设计图 | 镜像 = 设计图,容器 = 实例化的房子 |
3.3 镜像的分层结构
好处:相同层只下载一次,5 个服务共享 base 镜像,省流量省时间。
3.4 实战命令
# 拉取镜像
docker pull openjdk:8
# 查看本地镜像
docker images
# 删除镜像
docker rmi openjdk:8
# 给镜像打标签
docker tag myapp:latest registry.example.com/xxx/myapp:v1.0
# 推送到仓库
docker push registry.example.com/xxx/myapp:v1.0
3.5 关键点
- ✅ 镜像是只读的,容器是可写的
- ✅ 镜像分层存储,复用 base 层
- ❌ 不要把"日志/数据"放进镜像(应该挂数据卷)
- ✅ 项目里的
openjdk8私有 base 镜像就是"基础架构组维护的"分层
💡 金句:镜像 = 类,容器 = 实例。 镜像只读,容器可写。
四、精讲 2:容器(container)
4.1 一句话定义
容器 = 镜像的运行实例。
镜像是个"模板",容器是跑起来的进程。
4.2 容器的生命周期
4.3 实战命令
# 启动容器(最常用)
docker run -d -p 8080:8080 --name my-app myapp:v1.0
# 启动参数解读:
# -d 后台运行
# -p 8080:8080 宿主机 8080 映射容器 8080
# --name 容器名
# 查看运行中的容器
docker ps
# 查看所有容器(含停止的)
docker ps -a
# 进入容器(排错神器)
docker exec -it my-app bash
# 看日志
docker logs -f my-app
# 停止 / 启动 / 删除
docker stop my-app
docker start my-app
docker rm my-app
4.4 容器 vs 进程
很多人以为容器是"轻量虚拟机",其实容器本质是一个受限的 Linux 进程:
| 维度 | 进程 | 容器 |
|---|---|---|
| 隔离 | ❌ 无 | ✅ namespace |
| 资源限制 | ❌ 无 | ✅ cgroup |
| 文件系统 | 共享 | 独立(rootfs) |
💡 金句:容器不是"轻量虚拟机",是"受限的 Linux 进程"。这个认知能帮你理解所有 Docker 现象。
五、精讲 3:Dockerfile ⭐ 项目实战重头
5.1 一句话定义
Dockerfile = “镜像的源代码”,用 DSL 描述怎么构建镜像。
5.2 9 大核心指令
| 指令 | 作用 |
|---|---|
FROM | 基础镜像 |
MAINTAINER | 维护者 |
WORKDIR | 工作目录 |
COPY | 复制本地文件 |
ADD | 复制(可解压 tar) |
RUN | 构建时执行命令 |
ENV | 设置环境变量 |
EXPOSE | 声明端口 |
CMD | 启动命令 |
ENTRYPOINT | 入口点 |
5.3 ⭐ 项目实战模板(脱敏版)
这是我实习的项目里 5 个业务服务的统一 Dockerfile 模板:
# ========== 业务服务 Dockerfile 模板 ==========
# 1. 基础镜像:内网私有仓库统一封装好的 openjdk8
FROM registry.example.com/xxx/openjdk8:latest
# 2. 维护者
MAINTAINER xiaoba777
# 3. 工作目录
WORKDIR /apps
# 4. 时区(重要!国内项目必须)
ENV TZ Asia/Shanghai
# 5. 把 Maven 打好的 fat jar 拷进来
ADD ./target/xxx-service.jar app.jar
# 6. 同步时区到容器内
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ
# 7. 启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]
5 个业务服务就用上面这个模板,只换第 5 行的 jar 名——这就是"一份模板到处套"。
5.4 重型工具服务的"两阶段 Dockerfile"(项目实战 2)
项目里有一个"文件在线预览"工具,因为要装 LibreOffice + 中文字体,依赖很重。模板如下:
# ========== 阶段 1:基础环境镜像(重型依赖,几乎不变) ==========
FROM registry.example.com/xxx/openjdk8:latest
# 安装字体、图形库(重型系统依赖)
RUN apt-get update && apt-get install -y --no-install-recommends \
tzdata locales xfonts-utils fontconfig \
fonts-wqy-microhei fonts-wqy-zenhei \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# 装 LibreOffice(办公软件,体积大但不变)
COPY LibreOffice_deb.tar.gz /tmp/
RUN cd /tmp && tar -zxf LibreOffice_deb.tar.gz && dpkg -i *.deb && rm -rf /tmp/*
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
WORKDIR /opt
# ========== 阶段 2:业务 jar 镜像(频繁发版) ==========
FROM registry.example.com/xxx/xxx-tool-base:1.0 # 上面那个 base
# 只装业务代码
ADD ./target/xxx-tool.tar.gz /opt/
WORKDIR /opt/xxx-tool
好处:基础环境镜像几天才改一次,业务镜像每天发版——发版时只重做业务层,缓存复用,发版从分钟级降到秒级。
5.5 关键点
- ✅
FROM用具体 tag,不要用latest(生产事故重灾区) - ✅
COPY比ADD安全(ADD会自动解压 tar,容易出岔子) - ✅
ENTRYPOINT用 exec 形式(["java", "-jar"]),不用 shell 形式 - ✅ 时区必须设:
ENV TZ+RUN ln -snf - ✅ 每行一个
RUN,用&&串起来(减少镜像层数) - ❌ 不要在 Dockerfile 里塞敏感信息(密码、token)
💡 金句:Dockerfile 是"镜像的代码",要像写代码一样维护它。一份好的 Dockerfile 模板,可以套到 N 个服务上。
六、精讲 4:docker-compose
6.1 一句话定义
docker-compose = “多容器编排器”,用 YAML 文件一次性启动多个容器。
6.2 为什么需要 compose?
启动一个服务用 docker run 就行。但启动 5 个服务 + 数据库 + 缓存,要写 N 个 docker run?
6.3 实战模板:本地起一个 Spring Boot 项目
# docker-compose.yml
version: '3.8'
services:
# 1. Spring Boot 应用
app:
image: myapp:latest
build: . # 用当前目录的 Dockerfile 构建
ports:
- "8080:8080"
depends_on:
- mysql
- redis
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/test
- SPRING_REDIS_HOST=redis
# 2. MySQL
mysql:
image: mysql:8.0
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: test
volumes:
- mysql-data:/var/lib/mysql
# 3. Redis
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
mysql-data: # 声明数据卷
6.4 实战命令
# 启动所有服务
docker-compose up -d
# 查看服务状态
docker-compose ps
# 看某个服务日志
docker-compose logs -f app
# 停止 + 删除
docker-compose down
# 停止但保留数据卷
docker-compose down --rmi all
6.5 关键点
- ✅
depends_on只控制启动顺序,不等待服务就绪(MySQL 启动慢但容器已 “running”) - ✅ 端口冲突会导致启动失败
- ❌ 项目里没有用 docker-compose(因为有外部 K8s 平台),但本地起环境非常方便
- ✅ compose 是入门友好的工具
💡 金句:compose 是"单机版 K8s",本地起环境用它最爽。项目不用不代表你不用——自己 side project 必备。
七、精讲 5:数据卷(volume)
7.1 一句话定义
数据卷 = “容器外挂硬盘”,把容器内的数据持久化到宿主机。
7.2 为什么需要数据卷?
容器默认数据存在容器内——容器删了,数据没了!
7.3 两种挂载方式
| 方式 | 命令示例 | 适用场景 |
|---|---|---|
| 匿名卷 | docker run -v /data myapp | 临时测试 |
| 具名卷 | docker run -v mysql-data:/data mysql | 生产推荐 |
| bind mount | docker run -v /host/path:/data myapp | 本地开发(实时同步代码) |
7.4 实战命令
# 创建具名数据卷
docker volume create mysql-data
# 查看所有数据卷
docker volume ls
# 查看某个数据卷详情
docker volume inspect mysql-data
# 启动容器时挂载
docker run -d -v mysql-data:/var/lib/mysql mysql:8.0
# 删除数据卷(**危险!会丢数据**)
docker volume rm mysql-data
7.5 关键点
- ✅ 数据库必须挂数据卷(MySQL/Redis/MongoDB)
- ✅ 日志挂卷(避免容器满磁盘)
- ❌ 不要把代码挂卷当 bind mount 用在生产(生产代码应该固化在镜像里)
- ✅ compose 里用
volumes:声明
💡 金句:容器是"无状态"的,数据卷是"有状态"的归宿。数据库 / 日志 / 配置 必须挂卷。
八、精讲 6:网络(network)
8.1 一句话定义
Docker 网络 = 让容器之间、容器与宿主机之间能"打电话"。
8.2 3 种内置网络
8.3 bridge 网络(最常用)
# 创建自定义网络(推荐,容器间可以用服务名互通)
docker network create my-net
# 启动容器加入网络
docker run -d --network my-net --name app1 myapp:v1.0
docker run -d --network my-net --name app2 myapp:v2.0
# 此时 app1 可以直接 ping app2(DNS 解析服务名)
docker exec -it app1 ping app2
8.4 在 compose 里用网络
version: '3.8'
services:
app:
networks:
- my-net
mysql:
networks:
- my-net
networks:
my-net:
driver: bridge
好处:app 容器可以通过服务名 mysql 直接访问 MySQL,不用记 IP。
8.5 关键点
- ✅ 默认 bridge 容器间只能用 IP 互通,自定义 bridge 可以用服务名
- ✅ 项目里用 Spring Cloud 服务发现(由
bootstrap.yml解析服务名),类似 Docker 网络 - ❌ 生产环境通常用 K8s 网络(更强大)
- ✅ 本地开发用自定义 bridge 网络最方便
💡 金句:网络是 Docker 最容易踩坑的部分。记住一句话:自定义 bridge + 服务名互通。
九、精讲 7:仓库(registry)
9.1 一句话定义
仓库 = 存放镜像的"中央服务器"。
9.2 2 种主流仓库
| 仓库 | 特点 | 适用场景 |
|---|---|---|
| Docker Hub | 官方公共仓库 | 学习 / 开源 |
| Harbor | 企业私有仓库 | 生产(公司内网) |
9.3 项目里的仓库使用
我实习的项目用的是公司内网私有仓库(Harbor 类),所有镜像推到这里:
# 1. 登录仓库
docker login registry.example.com
# 2. 给镜像打 tag(必须带仓库地址)
docker tag myapp:v1.0 registry.example.com/xxx/myapp:v1.0
# 3. 推送
docker push registry.example.com/xxx/myapp:v1.0
# 4. 拉取
docker pull registry.example.com/xxx/myapp:v1.0
9.4 镜像命名规范
registry.example.com/xxx/myapp:v1.0=仓库地址 / 命名空间 / 服务名 : 版本
9.5 关键点
- ✅ 镜像 tag 必须带仓库地址才能 push
- ✅ 生产环境用私有仓库(不暴露代码到公网)
- ✅ 项目里
registry.example.com/xxx/openjdk8就是"基础架构组维护的 base 镜像" - ❌ 不要把密码/密钥打进镜像
💡 金句:仓库是"镜像的 GitHub"。生产用 Harbor,学习用 Docker Hub。
十、7 大核心的关系图
金句:Dockerfile 是图纸,Image 是产品,Container 是房子,Volume 是地皮,Network 是道路,Compose 是城市规划,Registry 是物流中心——7 大件组成了 Docker 的完整生态。
十一、5 个常见踩坑(过来人的血泪教训)
| # | 踩坑 | 现象 | 解法 |
|---|---|---|---|
| 1 | FROM ...:latest | 生产镜像版本漂移 | 用具体 tag(openjdk:8.0.252) |
| 2 | 时区没设 | 容器时间差 8 小时 | ENV TZ + RUN ln -snf |
| 3 | 数据没挂卷 | 容器删了数据丢 | 数据库/日志必须挂卷 |
| 4 | Dockerfile 加了密码 | 镜像泄露,密码泄露 | 用环境变量 / secrets |
| 5 | 容器里 apt-get update 缓存没清 | 镜像臃肿 1GB+ | && rm -rf /var/lib/apt/lists/* |
每个坑我都真实踩过。把这些记下来,能让你少调 3 天 bug。
十二、6 步学习路线
如果你想系统学 Docker,按这个顺序来:
- 第 1 步:装 Docker Desktop,跑
hello-world - 第 2 步:拉镜像 + 启容器 + exec / logs 排错
- 第 3 步:学 9 大指令,写自己的 Dockerfile
- 第 4 步:docker-compose 起 MySQL + Redis + Spring Boot 一条龙
- 第 5 步:数据卷 + 网络
- 第 6 步:私有 Harbor + CI/CD 自动化构建
💡 过来人的金句:Docker 不难,关键是"动手"。光看文档 10 遍,不如
docker run一行。
十三、结尾
写到这里,Docker 的 7 大核心就讲完了。
Docker 不可怕,它是后端开发绕不开的工具。面试官问"如何保证环境一致性"、“如何做 CI/CD”、"如何做微服务部署"等问题,本质都是 Docker 知识的延伸。
把今天这篇博客收藏起来,第一次装环境、第一次写 Dockerfile、第一次排错——都能翻出来看看。
剩下的 30%?K8s / Dockerfile 高级优化 / 多阶段构建 / BuildKit / 镜像安全,等你工作 3 年再学不迟。先把基础打牢,7 大核心吃透,再去啃容器编排。
推荐阅读
如果你想深入学 Docker,这几本 / 这些资料值得读:
- 📚 《Docker 实战》(Jeff Nickoloff)—— Docker 入门经典
- 📚 《Kubernetes 权威指南》(龚正 / 吴龙辉 等)—— K8s 进阶必看
- 📖 Docker 官方文档(docs.docker.com)—— 永远的第一手资料
- 📖 Docker Compose 官方文档—— Compose 配置全解
- 🔗 Play with Docker(labs.play-with-docker.com)—— 在线免费玩 Docker
- 🔗 Docker Hub(hub.docker.com)—— 镜像仓库
- 🔗 Harbor 官方文档(goharbor.io)—— 企业私有仓库
写在最后
如果这篇博客对你有帮助,请:
- ⭐ 点赞——你的点赞是我继续写下去的动力
- 📌 收藏——下次装环境 / 写 Dockerfile 翻出来看看
- ➕ 关注我——后续会更新 K8s / Dockerfile 优化 / CI/CD 系列
- 💬 评论区留言——告诉我你想看什么主题,我安排!
我是 程序员小八777,一名 Java 后端实习生,把实习中学到的"踩坑经验"写成博客,分享给更多和我一样在成长路上的同学们。
我们下期见!🚀
更多推荐




所有评论(0)