前言:为什么学 Docker?
在微服务时代,软件不仅仅是代码,还包含运行环境(OS、JDK、Libs、配置)。Docker 将这一切打包成镜像,实现了“一次构建,到处运行”,彻底解决了 “在我的机器上能跑,演示时就崩了” 的环境一致性问题。
Docker镜像交流社区:Docker Hub Container Image Library | App Containerization

第一部分:核心概念 (入门必看)

初学者必须区分 Docker 的三个基本概念,可以类比为“软件安装”的过程:

概念 类比 详细说明
镜像 (Image) 安装包 一个只读的文件包。包含了应用程序代码、运行库、依赖环境和配置文件。镜像是一层层文件叠加而成的(分层存储)。
容器 (Container) 运行中的软件 镜像运行时的实例。它是隔离的、可写的。你可以从一个镜像启动 N 个不同的容器
仓库 (Repository) 应用商店 集中存放镜像的地方。最常用的是官方的 DockerHub

第二部分:环境配置 (关键步骤:镜像加速)

由于网络原因,在国内直接从 DockerHub 拉取镜像速度非常慢或容易超时。在开始学习命令前,必须配置镜像加速器
目前国内镜像有些问题,可以自行去网上搜索可用的镜像

1. 获取加速地址

推荐使用阿里云(稳定免费)或其他国内源:

  • 阿里云(https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors): 登录控制台 -> 容器镜像服务 -> 镜像工具 -> 镜像加速器 -> 复制 `https://xxxx.mirror.aliyuncs.com

2. 配置步骤 (Linux/CentOS)

直接在终端执行以下命令(注意将 URL 替换为你实际的加速地址):

# 1. 创建配置目录
sudo mkdir -p /etc/docker

# 2. 写入配置文件 daemon.json
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": [
    "https://你的专属ID.mirror.aliyuncs.com"
  ]
}
EOF

# 3. 重新加载配置并重启 Docker
sudo systemctl daemon-reload
sudo systemctl restart docker

3. 验证配置

执行 docker info,在输出末尾找到 Registry Mirrors,如果显示了你配置的地址,即表示成功。


第三部分:Docker 常用命令体系

1. 镜像管理命令

  • docker pull <镜像名>:<标签>:拉取镜像(不写标签默认 latest)。
    • 例:docker pull nginx:1.21
  • docker images:查看本地已下载的镜像。
  • docker rmi <镜像名/ID>:删除本地镜像。
  • docker save/load:将镜像导出为压缩包/从压缩包导入(用于无网环境迁移)。

2. 容器操作命令 (核心)

容器的生命周期:创建 -> 运行 -> 暂停/停止 -> 删除

  • docker run:创建并运行容器(参数最复杂,见下文详解)。
  • docker ps:查看运行中的容器。
    • docker ps -a:查看所有容器(包括已停止的)。
  • docker stop <容器名>:停止容器。
  • docker start <容器名>:启动已停止的容器。
  • docker restart <容器名>:重启容器。
  • docker rm <容器名>:删除容器(注意:运行中的容器无法直接删除,需加 -f 强制删除)。
  • docker logs -f <容器名>:持续查看容器运行日志(排错神器)。
  • docker exec -it <容器名> bash:进入容器内部执行命令。
    • 例:进入 MySQL 容器修改配置

3. docker run 参数详解 (重点掌握)

以启动 MySQL 为例,解析每一个参数的含义:

docker run -d \
  --name mysql \
  -p 3306:3306 \
  -e TZ=Asia/Shanghai \
  -e MYSQL_ROOT_PASSWORD=123 \
  -v ./mysql/data:/var/lib/mysql \
  mysql:8.0
  • -d (Detached): 后台运行,不阻塞当前终端窗口。
  • --name: 给容器起个容易记住的名字(否则 Docker 会随机生成名字)。
  • -p 宿主机端口:容器端口 (Port): 端口映射。
    • 原理:外部请求 -> 宿主机 3306 -> 转发给容器 3306。
    • 注意:容器端口通常由应用决定(如 MySQL 固定 3306),宿主机端口可随意指定(只要不冲突)。
  • -e KEY=VALUE (Environment): 设置环境变量。
    • 用途:覆盖容器内的默认配置(如密码、时区)。具体变量名需查阅 DockerHub 镜像说明。
  • -v 宿主机路径:容器路径 (Volume): 挂载数据卷(见第四部分)。

第四部分:数据持久化 (进阶)

容器有一个特性:用完即焚。容器删除后,其内部产生的所有文件都会消失。为了保留数据(如数据库数据、日志、配置文件),必须使用数据卷

1. 数据卷 (Volume) - Docker 托管

Docker 在宿主机文件系统中管理的一块特定区域(通常在 /var/lib/docker/volumes/)。

  • 特点:路径较深,不方便直接修改,适合存储“不常人为修改”的数据(如 MySQL 的 data 目录)。
  • 命令
    • docker volume create <卷名>
    • docker volume inspect <卷名> (查看具体存储位置)
  • 挂载方式-v html:/usr/share/nginx/html (将名为 html 的卷挂载到容器)

2. 目录挂载 (Bind Mount) - 自定义路径

直接将宿主机的指定目录/文件挂载到容器内。

  • 特点:路径直观,方便修改,适合配置文件代码
  • 挂载方式-v ./mysql/conf:/etc/mysql/conf.d (宿主机当前目录挂载)

最佳实践

  • 数据库数据:使用 Docker 托管的数据卷或指定目录均可。
  • 配置文件 (conf):强烈建议使用目录挂载,方便在宿主机直接编辑。
  • 前端静态资源 (html):使用目录挂载,方便随时更新页面。

第五部分:自定义镜像 (Dockerfile)

当我们开发了自己的 Java/Web 应用,如何将其打包成镜像?这就需要 Dockerfile

官方文档:https://docs.docker.com/engine/reference/builder/

1. 镜像的分层原理 (Layer)

镜像不是一个大文件,而是由很多层堆叠起来的。

  • Base Image: 基础操作系统层(如 Ubuntu, Alpine)。
  • Add-on Layers: 每安装一个软件、拷贝一个文件、执行一条命令,就增加一层。
  • 优势:如果多个镜像共用同一个 Base Image,本地只需存储一份基础层,节省空间。

2. Dockerfile 核心指令

Dockerfile 是一个文本文件,包含构建镜像的指令。

指令 作用 示例
FROM 指定基础镜像 FROM openjdk:11.0-jre-buster
ENV 设置环境变量 ENV TZ=Asia/Shanghai
COPY 拷贝宿主机文件到容器 COPY ./hm-service.jar /app.jar
RUN 构建时执行的 Shell 命令 RUN apt-get update && apt-get install -y vim
EXPOSE 声明容器监听端口 EXPOSE 8080 (仅作为文档说明)
ENTRYPOINT 容器启动时执行的命令 ENTRYPOINT ["java", "-jar", "/app.jar"]

3. 实战:打包 Java 项目

  1. 将打包好的 hm-service.jarDockerfile 放在同一目录。

  2. 编写 Dockerfile:

    FROM openjdk:11.0-jre-buster
    ENV TZ=Asia/Shanghai
    COPY hm-service.jar /app.jar
    ENTRYPOINT ["java", "-jar", "/app.jar"]
    
  3. 构建镜像:

    # 注意最后有个点,代表当前目录
    docker build -t hmall:1.0 .
    

第六部分:Docker 网络 (互联互通)

1. 默认桥接网络的问题

默认情况下,容器重启后 IP 地址可能会变化。如果我们在代码中写死 IP(如 JDBC URL 连接数据库),容器重启后服务就会断连。

2. 自定义网络 (User-Defined Bridge)

Docker 允许创建自定义网络,加入同一网络的容器,可以通过“容器名”互相访问(Docker 内置了 DNS 解析)。

  • 创建网络

    docker network create hmall-net
    
  • 容器加入网络

    • 启动 MySQL:docker run ... --network hmall-net --name mysql ...
    • 启动 Java App:docker run ... --network hmall-net ...
  • 效果
    在 Java 项目的配置文件中,数据库地址不再写 IP,而是直接写容器名:
    jdbc:mysql://mysql:3306/hmall


第七部分:Docker Compose (微服务编排)

1. 痛点

部署一个完整的微服务系统(MySQL + Nginx + 5个 Java 服务),需要执行 7 次 docker run,且要手动管理启动顺序(先 DB 后 App),维护极难。

2. 解决方案

Docker Compose 是一个编排工具,通过一个 docker-compose.yml 文件定义一组相关联的容器。

官方文档:Docker Compose | Docker 文档 — Docker Compose | Docker Docs

3. docker-compose.yml 模板详解

version: "3.8"
services:
  # --- MySQL 服务 ---
  mysql:
    image: mysql
    container_name: mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: 123
    volumes:
      - "./mysql/data:/var/lib/mysql"
    networks:
      - hm-net

  # --- Java 后端服务 ---
  hmall:
    build: .                 # 自动寻找当前目录的 Dockerfile 构建镜像
    container_name: hmall
    ports:
      - "8080:8080"
    networks:
      - hm-net
    depends_on:              # 依赖配置:确保 mysql 先启动
      - mysql

  # --- Nginx 前端服务 ---
  nginx:
    image: nginx
    container_name: nginx
    ports:
      - "18080:18080"        # 宿主机 18080 映射到容器
    volumes:
      - "./nginx/html:/usr/share/nginx/html"
      - "./nginx/nginx.conf:/etc/nginx/nginx.conf"
    networks:
      - hm-net
    depends_on:
      - hmall

# --- 网络声明 ---
networks:
  hm-net:
    name: hmall-net

4. 常用 Compose 命令

  • 一键启动docker compose up -d (构建镜像、创建网络、按顺序启动容器)
  • 一键停止docker compose down (停止容器、删除容器、删除网络)
  • 查看日志docker compose logs -f (聚合所有服务的日志)
  • 查看状态docker compose ps

小结

  1. 环境: 第一步务必配置镜像加速,否则下载极其缓慢。
  2. 基础:熟练掌握 docker run-p (端口), -v (挂载), -e (环境), -d (后台) 参数。
  3. 进阶:理解 镜像分层 概念,会写 Dockerfile 打包自己的应用。
  4. 实战:放弃 Shell 脚本,使用 Docker Compose 编排复杂的微服务环境。
  5. 网络:利用 自定义网络 实现容器间通过名字互访,解耦 IP 依赖。

更多推荐