从 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.yml30 秒拉起全套环境——MySQL、Redis、应用服务一条龙。

我当时就震惊了:“原来这就是 Docker”

回去翻了《Docker 实战》《Kubernetes 权威指南》……

这次我学到一个重要的事:Docker 不可怕,先学 7 个核心就够——镜像、容器、Dockerfile、Compose、数据卷、网络、仓库。

今天这篇博客,我就把这 7 个核心 + 项目实战 Dockerfile 模板掰开揉碎讲透,让更多像我一样的后端新人少走弯路。

💡 金句Docker 不可怕,先学 7 个核心就够。把这 7 个吃透,90% 的后端场景你都能搞定


二、概念扫盲:什么是 Docker

2.1 一句话定义

Docker = 把应用 + 依赖 + 环境打包成一个"标准集装箱",在任何机器上一键运行。

2.2 Docker vs 虚拟机

Docker

App A

Docker Engine

App B

Host OS

虚拟机 (VM)

App A

App B

Guest OS

Hypervisor

Host OS

维度虚拟机Docker
启动速度分钟级秒级
体积GB 级MB 级
性能50% 损耗几乎无损耗
隔离性强(独立 OS)中(共享内核)
启动密度几十个几百上千个

2.3 Docker 架构

REST API

管理

运行

拉取/推送

Docker Client
(docker 命令)

Docker Daemon
(dockerd)

镜像 (Images)

容器 (Containers)

Registry
(Docker Hub / Harbor)

2.4 7 大核心地图

今天这篇博客,围绕这 7 大核心展开:

Docker
7 大核心

基础 2

镜像 Image

容器 Container

制作 2

Dockerfile

docker-compose

进阶 3

数据卷 Volume

网络 Network

仓库 Registry

  • 基础 2 件套:镜像 + 容器(Docker 的"灵魂")
  • 制作 2 件套:Dockerfile + Compose(怎么"做")
  • 进阶 3 件套:数据卷 + 网络 + 仓库(生产环境必备)

💡 金句Docker 不可怕,先学 7 个核心就够


三、精讲 1:镜像(image)

3.1 一句话定义

镜像 = 一个"只读模板",用来创建容器。

可以理解成"装应用的 ISO 镜像"——是个模板,本身不运行。

3.2 类比

类比解释
Java 类镜像 = class,容器 = instance
PPT 模板镜像 = 模板,容器 = 你做的 PPT
设计图镜像 = 设计图,容器 = 实例化的房子

3.3 镜像的分层结构

Layer 4: 应用代码 / jar

Layer 3: 依赖 (pip/npm/maven)

Layer 2: 运行时 (JDK / Python)

Layer 1: 基础 OS (ubuntu/alpine)

好处:相同层只下载一次,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 容器的生命周期

docker run

docker pause

docker unpause

docker stop

docker start

docker rm

created
创建

running
运行中

paused
暂停

stopped
停止

deleted
删除

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 大核心指令

Dockerfile
9 大指令

基础

FROM

MAINTAINER

文件

COPY

ADD

配置

WORKDIR

ENV

RUN

启动

CMD

ENTRYPOINT

指令作用
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(生产事故重灾区)
  • COPYADD 安全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

一个个启

一个个启

一个个启

一个个启

一键

手动 docker run

应用

MySQL

Redis

Nginx

docker-compose up

一份 yaml
一条命令全拉起

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 mountdocker 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 种内置网络

Docker 网络 3 种

① bridge
默认
容器间能通

② host
与宿主机共享网络

③ none
无网络

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 版本

registry.example.com/xxx/myapp:v1.0 = 仓库地址 / 命名空间 / 服务名 : 版本

9.5 关键点

  • ✅ 镜像 tag 必须带仓库地址才能 push
  • ✅ 生产环境用私有仓库(不暴露代码到公网)
  • ✅ 项目里 registry.example.com/xxx/openjdk8 就是"基础架构组维护的 base 镜像"
  • ❌ 不要把密码/密钥打进镜像

💡 金句仓库是"镜像的 GitHub"。生产用 Harbor,学习用 Docker Hub。


十、7 大核心的关系图

docker build

docker run

挂载

加入

管理

pull/push

Dockerfile
构建镜像的脚本

Image
只读模板

Container
运行实例

Volume
数据持久化

Network
容器互通

Compose
多容器编排

Registry
镜像仓库

金句Dockerfile 是图纸,Image 是产品,Container 是房子,Volume 是地皮,Network 是道路,Compose 是城市规划,Registry 是物流中心——7 大件组成了 Docker 的完整生态。


十一、5 个常见踩坑(过来人的血泪教训)

#踩坑现象解法
1FROM ...:latest生产镜像版本漂移用具体 tagopenjdk:8.0.252
2时区没设容器时间差 8 小时ENV TZ + RUN ln -snf
3数据没挂卷容器删了数据丢数据库/日志必须挂卷
4Dockerfile 加了密码镜像泄露,密码泄露用环境变量 / secrets
5容器里 apt-get update 缓存没清镜像臃肿 1GB+&& rm -rf /var/lib/apt/lists/*

每个坑我都真实踩过。把这些记下来,能让你少调 3 天 bug


十二、6 步学习路线

如果你想系统学 Docker,按这个顺序来:

第 1 步
装 Docker Desktop
跑 hello-world

第 2 步
拉镜像 +
启容器

第 3 步
学 9 大指令
写 Dockerfile

第 4 步
docker-compose
起多服务

第 5 步
数据卷 +
网络

第 6 步
私有仓库
+ CI/CD

  1. 第 1 步:装 Docker Desktop,跑 hello-world
  2. 第 2 步:拉镜像 + 启容器 + exec / logs 排错
  3. 第 3 步:学 9 大指令,写自己的 Dockerfile
  4. 第 4 步:docker-compose 起 MySQL + Redis + Spring Boot 一条龙
  5. 第 5 步:数据卷 + 网络
  6. 第 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 后端实习生,把实习中学到的"踩坑经验"写成博客,分享给更多和我一样在成长路上的同学们。

我们下期见!🚀

更多推荐