
不管你是刚转行做后端的小白还是已经被环境问题折磨到怀疑人生的老开发Docker 这个东西迟早会出现在你面前。我第一次接触 Docker纯粹是因为一套老项目要在三台机器上重复部署每次都要重新装依赖、配数据库、改配置稍微漏一步线上就给你颜色看。后来花了一个周末把镜像、容器、数据卷这些东西啃下来才发现当初那些部署痛苦大部分都是因为“环境”这个变量在捣乱。这篇教程没有打算把官方文档重新抄一遍而是把我从零学 Docker、以及在实际项目里用 Docker 安装 MySQL 8.0、搭建 Redis 主从、用 IDEA 打包微服务镜像的完整经验整理出来该避的坑直接告诉你该拆的原理也用大白话讲清楚。适合刚准备装 Docker 的新手也适合装完但遇到各种启动故障、权限问题、镜像下载慢的进阶玩家。1. 学习路线设计先把“装好、跑起来”这件事想清楚1.1 Docker 到底解决了什么问题很多人第一次听 Docker 的时候脑子里会冒出一个问题这不就是个虚拟机吗为什么大家都在吹我最开始也是这么想的直到自己用了一次才体会到差别。虚拟机是把你整个操作系统都虚拟化一遍启动一个虚拟机就像开一台新电脑又慢又占资源。而 Docker 不一样它直接用宿主机内核只把你应用的运行环境和必要依赖打包成一个镜像启动容器的速度快到可以用“秒”来衡量。生活化一点理解虚拟机是把整个厨房都搬过来哪怕你只想炒个菜也得连锅带灶带水龙头全带上Docker 是只带一口锅和厨师灶台直接用对方的炒完菜把锅还回去就行。这带来的直接好处就是你本地开发用的 MySQL 8.0到了测试环境、生产环境只要是基于同一个镜像启动的容器行为就完全一致。版本不一致、系统依赖缺失、配置漏改这类问题基本被消灭在镜像层面。1.2 一条适合绝大多数人的学习路径学 Docker 最忌讳上来就啃官方文档那玩意儿信息密度太高容易劝退。我自己总结下来的路径是先搞懂三个核心名词镜像、容器、仓库。装好 Docker 环境跑通 hello-world。用 docker run 跑一个 MySQL把端口映射、数据卷挂载、环境变量这几个概念通过“实战”串起来。再上手 docker-compose把多个服务一起编排起来感受一把“一条命令启动整个项目”的爽感。最后才是 Dockerfile 定制镜像以及用 IDEA 等工具把项目打包成镜像。这条路径的特点是每一步都能看到实际效果不会出现学了半天不知道学了干什么的感觉。而且 MySQL、Redis 这类中间件是开发中最常见的拿它们当学习素材学完马上就能在工作里用上。2. 环境准备Windows 和 Linux 下的安装与启动2.1 Windows 上装 Docker Desktop 的硬性条件在 Windows 上装 Docker最主流的方式是装 Docker Desktop。但先别急着下载有两个前置条件必须满足不然装完也启动不起来。第一个是虚拟化要在 BIOS 里打开。很多人装完 Docker Desktop点启动直接报错Docker Desktop failed to start because virtualisation support wasnt detected。这个报错十有八九就是 BIOS 里的 Intel Virtualization Technology 或者 AMD SVM Mode 没开。开机进 BIOS找到虚拟化相关选项启用保存重启问题就解决了一大半。第二个是 WSL2 支持。Docker Desktop 在 Windows 上默认不是用 Hyper-V 那一套老方案了而是基于 WSL2 的后端。所以安装之前建议先在 PowerShell 里执行 wsl --status 看看有没有装好 WSL。没装的话按官方要求更新到 WSL2 内核再执行 wsl --set-default-version 2 把默认版本设成 2。这两件事都搞定后再去 Docker 官网下载 Docker Desktop 安装包一路 Next 装完打开应用等它把 Docker Engine 启动起来右下角小鲸鱼图标变成稳定状态就说明环境是通的。注意Windows 家庭版也能装 Docker Desktop不一定要专业版。关键在于 WSL2 和 BIOS 虚拟化而不是系统版本本身。2.2 Ubuntu 等 Linux 发行版上的安装姿势Linux 上安装 Docker 就比 Windows 简单直白多了没有桌面端那层壳子直接装 Docker Engine。以 Ubuntu 为例常规做法是把官方 Docker 源加进来然后安装。很多人直接执行 apt install docker.io这样装也不是不行但装的往往是发行版自带的旧版本。老版本在后续使用中可能和新的 Compose 插件、镜像格式有兼容问题所以我个人更建议用官方的 apt 源方式安装sudo apt update sudo apt install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod ar /etc/apt/keyrings/docker.gpg echo \ deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release echo $VERSION_CODENAME) stable | \ sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin注意最后一行现在官方已经把 docker-compose 插件拆出来了装完直接有 docker compose 命令中间没有横杠这个用法比老旧的 docker-compose 二进制更推荐。2.3 装好后先别急着拉镜像把这三件事做了第一件事给当前用户加入 docker 用户组。默认情况下执行 docker 命令需要 root 权限或者 sudo每次都敲 sudo 很容易烦。执行 sudo usermod -aG docker $USER然后退出终端重新登录之后就能直接敲 docker 命令了。第二件事配置镜像加速器。这个直接关系到你拉镜像的速度。国内网络环境拉 Docker Hub 官方镜像经常慢到怀疑人生配置加速器是必须的。做法是编辑 /etc/docker/daemon.json把国内一些可用的公共镜像加速地址填进去然后重启 docker 服务。第三件事设置开机自启。服务器上 Docker 服务一定要设成开机自启不然哪天重启机器后所有容器全挂了你还在那干着急。执行 sudo systemctl enable docker 即可。3. 核心概念与常用命令从“会用”到“用得明白”3.1 镜像、容器、仓库三个概念串起 Docker 全流程这三个概念理解到位了Docker 就算入门了一半。镜像可以理解成一个只读的模板里面装好了运行某个应用需要的操作系统层、运行环境、代码和配置。它本身是不能被修改的你只能在它基础上创建“容器”。容器是镜像运行起来后的实例你可以进入容器、写文件、装软件但容器一旦被删除这些临时改动就全没了。如果你想要把这一层改动保存下来要么重新构建镜像要么用数据卷把数据挂载到宿主机上。仓库则是存放镜像的地方。最出名的是 Docker Hub你能在上面找到 mysql、redis、nginx 官方维护的镜像。除了公共仓库你也可以在公司内网搭一个私有仓库也就是常说的 docker registry专门存放内部项目的镜像。这三个概念串起来就是一条线从仓库拉镜像镜像跑起来生成容器容器产生的数据用数据卷持久化。3.2 高频命令速查与实操示例我不喜欢贴一堆命令让你背但有几个高频操作几乎每天都在用把它们记熟能省大量时间。docker images # 查看本地镜像列表 docker ps -a # 查看所有容器包括已停止的 docker pull mysql:8.0 # 拉取指定版本镜像 docker rmi 镜像ID # 删除镜像 docker rm 容器ID # 删除容器需要先停止容器 docker exec -it 容器ID bash # 进入容器内部相当于远程登录 docker logs -f 容器ID # 查看容器日志-f持续跟踪 docker stop/start/restart 容器ID # 停止/启动/重启容器有一个非常容易犯的错停止容器不等于删除容器。docker stop 只是把容器暂停了容器还占用磁盘空间。时间久了一堆已停止的容器堆积在那里既占空间又干扰视线。清理已停止的容器可以用 docker container prune一行命令全清掉。还有一个常用技巧docker run --rm 参数。调试临时容器的时候加上它容器退出后会自动删除省得手动清理。比如想临时跑个容器测试配置是否正确这个参数非常实用。4. 典型部署实操MySQL 8.0、Redis 主从与 Compose 编排4.1 用 Docker 装一个 MySQL 8.0 并正常使用网上很多教程让你直接跑一行 docker run mysql连参数都不解释。我见过不少人照抄命令跑起来一个 MySQL结果重启容器数据全没了或者在容器里改配置改完就进不去了。所以我这里把每个关键参数都拆开讲清楚。docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD123456 \ -e TZAsia/Shanghai \ -v /data/mysql/conf:/etc/mysql/conf.d \ -v /data/mysql/data:/var/lib/mysql \ --restartalways \ mysql:8.0逐行解释一下-d 表示后台运行不加的话终端会被日志刷屏。--name mysql8 给容器起个名字后面操作都用这个名字。-p 3306:3306 把宿主机的 3306 端口映射到容器的 3306 端口。注意宿主机端口如果被其他程序占了比如你本地已经装了一个 MySQL就要改成别的端口比如 -p 3307:3306。-e 是环境变量MYSQL_ROOT_PASSWORD 设置 root 密码TZ 设置容器时区。不设 TZ 的话容器里默认是 UTC 时间比北京时间慢 8 小时查日志时会觉得很奇怪。-v 是数据卷挂载把宿主机目录映射到容器内部目录。/var/lib/mysql 是 MySQL 存储数据的位置把它挂载到宿主机上之后就算容器删了重建数据也还在。这一点极其重要。--restartalways 让容器在 Docker 服务重启后自动拉起生产环境基本必备。启动后用 docker ps 看到容器状态是 Up再用 Navicat 或者命令行连接测试能连上就说明部署成功。想改 MySQL 配置的话直接修改宿主机 /data/mysql/conf/ 下的自定义 my.cnf然后 docker restart mysql8 重启容器生效。4.2 Docker Compose 编排 Redis 主从单个容器用 docker run 没问题但服务一多再用手敲命令就太原始了。比如要搭一个 Redis 主从集群你是开两个终端各跑一个 docker run还是写一条很长很长的命令行Docker Compose 就是来解决这个问题的用一个 yaml 文件描述所有服务、网络、数据卷一条 docker compose up -d 全部搞定。先看一个 Redis 主从的例子我用最简单的方案一个主节点一个从节点各自挂载不同数据目录和配置文件。version: 3.8 services: redis-master: image: redis:7.0 container_name: redis-master restart: always ports: - 6379:6379 volumes: - ./redis/master/data:/data - ./redis/master/redis.conf:/etc/redis/redis.conf command: [redis-server, /etc/redis/redis.conf] redis-slave: image: redis:7.0 container_name: redis-slave restart: always depends_on: - redis-master ports: - 6380:6379 volumes: - ./redis/slave/data:/data - ./redis/slave/redis.conf:/etc/redis/redis.conf command: [redis-server, /etc/redis/redis.conf, --slaveof, redis-master, 6379]这里有个细节需要注意从节点可以用 command 参数直接追加 --slaveof redis-master 6379其中 redis-master 是 Compose 网络里主节点的服务名Compose 会自动创建内部网络让容器之间通过服务名互相访问你不需要在宿主机上再配 /etc/hosts。两个 redis.conf 文件需要提前准备好主节点配置里开持久化 appendonly yes从节点同样开持久化。准备完成后在 compose 文件所在目录执行docker compose up -d执行完 docker compose ps 查看两个容器状态再从任意一个容器里执行 docker exec -it redis-slave redis-cli info replication看到 role:slave 且 master_link_status:up就说明主从已经同步上来了。4.3 用 Idea 把 Spring Boot 项目打成镜像再扔进 Docker学会了拉现成镜像部署中间件下一步就是把自己的业务代码打包成镜像。传统做法是写一个 Dockerfile然后在服务器上把 jar 包传上去手动构建。但如果项目开发用的是 IDEA那完全可以利用 IDEA 自带的 Docker 插件一条龙完成“构建镜像 推到远程仓库 部署容器”。首先确保 IDEA 里已经配置好了 Docker 连接。File - Settings - Build, Execution, Deployment - Docker选择 TCP socket 或把 Windows 下的 Docker Desktop 的 Docker Daemon 地址配置进去。配置成功后Settings 里会出现一个绿色的鲸鱼连接状态表示 IDEA 能直接和本机 Docker 通信。然后准备 Dockerfile 文件放在项目根目录。一个精简的 Spring Boot 镜像 Dockerfile 大概长这样FROM openjdk:17-jdk-alpine MAINTAINER your_name COPY target/*.jar app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, /app.jar]如果你用了 MySQL那么在启动容器的时候数据库连接地址不能写成 localhost要写成 MySQL 容器的名字或者 Compose 服务名因为每个容器都有自己的网络命名空间容器内访问宿主机不能直接用 localhost需要改成宿主机局域网 IP 或者使用 Docker 默认的 host.docker.internal。Dockerfile 准备好后先执行 mvn package 打出 jar 包然后在 IDEA 的 Docker 面板里点击构建镜像的按钮选择 Dockerfile 路径镜像名建议写仓库地址加项目名的格式比如 myregistry.com/mall/user-service:v1.0。构建成功后右键镜像可以直接运行容器。这里提醒一句本地调试业务项目端口映射和数据卷挂载一定要确认清楚特别是容器内日志目录如果不挂出来一出问题查日志要 docker exec 进容器里翻非常痛苦。建议构建容器时把 /logs 目录挂载到宿主机固定位置。5. 常见故障排查这些坑我基本都踩过5.1 Docker Desktop 启动失败的两种典型场景第一种就是前面提到的 virtualization support 检测不到。解决方法是进 BIOS 开启虚拟化开启后如果问题依旧再检查 Windows 功能里是否启用了“虚拟机平台”和“适用于 Linux 的 Windows 子系统”这两项这两个是 Docker Desktop 在 Windows 上跑 WSL2 的底层依赖。第二种是 Failed to connect to the Docker API at npipe:////./pipe/dockerDesktopLinuxEngine。这个错误我遇到很多次表面上是连接问题本质是 Docker Desktop 的后端 Engine 根本没起来。常见原因是 WSL2 内核版本太旧或者 Docker Desktop 升级后和旧 WSL 内核不匹配。最快的解决办法是去微软官方下载最新的 Linux 内核更新包装完重启电脑再打开 Docker Desktop 基本就通了。5.2 权限错误docker: permission deniedLinux 下没加 docker 用户组执行 docker 命令大概率报这个错。刚才已经说过解法sudo usermod -aG docker $USER加完重新登录。但还有一种更隐蔽的情况加了组还是不生效。这种情况多半是你还在旧终端会话里系统没有重新加载权限要么退出重进要么干脆记住新开的终端才会生效。5.3 镜像下载慢或者直接超时这是国内用户绕不开的痛点。除了配置镜像加速器还有几个土办法尽量把镜像仓库地址写到完整形式比如 docker pull docker.io/library/nginx:latest有些私有仓库和公共仓库地址有冲突写完整能绕开部分解析问题。如果公司内部有镜像仓库就用公司提供的地址内网拉镜像的速度通常比公网快得多。实在着急的时候可以先用一台网络好的机器拉下镜像再 docker save 打成 tar 包传到目标机器 docker load 导入。这种方式适合离线环境。配置加速器的方法再强调一遍编辑 /etc/docker/daemon.json添加 registry-mirrors 配置然后重启 docker。改完可以用 docker info 查看 Registry Mirrors 是否生效。注意加速器只对 Docker Hub 公共镜像有效。如果用的是某个专有镜像仓库比如公司内部的 Harbor那不在加速器管辖范围内不要指望靠加镜像源解决私有仓库下载慢的问题。5.4 容器时区问题与日志占用容器默认时区通常是 UTC这会导致容器内应用日志时间比本地慢 8 小时。处理方式是在 docker run 时加 -e TZAsia/Shanghai或者在 Dockerfile 里写入 ENV TZAsia/Shanghai。如果是 Compose 编排统一在服务配置里加上 environment: - TZAsia/Shanghai。日志占用是另一个容易被忽略的问题。容器如果不断输出日志默认情况下日志文件会无限增长直到把磁盘塞满。建议在启动容器时加上日志大小限制--log-opt max-size50m --log-opt max-file3这个参数表示单个日志文件最大 50MB保留 3 个文件。对付那些喜欢疯狂打印日志的应用特别有效磁盘空间就稳住了。5.5 关于青龙面板、kodbox 这类项目部署的补充热搜词里还出现了青龙、kodbox、DVWA 靶场这类具体项目。它们的 Docker 部署套路其实完全一样去对应文档或仓库找到 compose 文件把 docker-compose.yml 下载下来按需修改端口和数据目录然后 docker compose up -d 拉起来。青龙这类项目尤其要注意数据卷挂载它的全部数据都存在 /ql/data 目录下不挂载出来升级就是数据灾难。kodbox 则是典型的 LNMP 全家桶直接用官方仓库里现成的 compose 编排即可千万别自己手动一个个装。这种“拿现成 compose 改一改”的思路才是 Docker 生态最大的红利社区已经把常见软件的部署方案全部模板化了你要做的就是先看看都有哪些服务再改改配置端口和目录。6. 最后分享一点实际体会用 Docker 这几年我最大的感受是它没有一开始接触时看起来那么玄乎但绝对值得好好学。它真正解决的是软件交付过程中“环境不一致”这个根问题。你本地跑得起来线上跑不起来在大家都用同一份镜像的前提下这种问题基本不存在了。如果你刚开始学不要试着把所有 Docker 命令都背下来。先老老实实把 MySQL、Redis 这类服务用容器跑起来亲手把端口映射、数据卷挂载、环境变量这几个概念过一遍再研究 Dockerfile。等你能把业务项目打包成镜像并且用 Compose 一次性拉起一组服务的时候你就已经超过大多数只会在网上复制粘贴命令的“Docker 使用者”了。另外我自己的一个习惯每部署一个新项目都会在项目目录里放一份 docker-compose.yml并且把 README 写清楚每个服务的作用、端口、数据目录。半年后再看这个项目不需要回忆照着 README 敲两行命令就能把整个环境拉起来。这个习惯帮我省了太多太多时间。