
很多朋友问我Docker到底是个什么东西为什么身边搞开发、搞运维、甚至搞测试的同事都在用。每次我都想用一句话讲清楚但发现真的很难——不是概念复杂而是它解决的问题太贴近日常了三言两语说不透。今天这篇我就从实际使用角度出发把Docker从概念到落地的完整链路捋一遍。不管你是刚接触命令行的新手还是已经被各种报错折磨过的“准用户”这篇文章都能给你一条清晰、可执行的路径。我最早接触Docker是因为要在本地搭一套和线上一致的开发环境。那时候最痛苦的事就是代码在本地跑得好好的一发到服务器就各种幺蛾子——JDK版本不对、Redis没装、MySQL编码不对、Linux路径和Windows不一样。每次排查环境问题的时间比写代码还长。后来用了Docker这些折腾基本绝迹了。它本质上就是把你应用运行所需要的一切——代码、运行时、系统库、配置文件——打包成一个标准化的“盒子”这个盒子在谁的机器上都能跑出一模一样的效果。这篇实战笔记会覆盖几个核心部分Docker到底是什么、和虚拟机的本质区别、Windows和Linux下的安装全流程、高频命令速查、MySQL和Redis的真实部署案例、docker compose编排以及我踩过无数次坑之后总结出来的问题排查清单。内容偏实用每个步骤都能直接抄作业。1. 内容整体设计与思路拆解1.1 Docker到底是什么一个装好一切的“标准货柜”先别急着敲命令我们先把概念理清楚。Docker是一个开源的容器化平台它让你可以把应用及其依赖打包成一个轻量、可移植的容器。这个容器可以直接运行在任何安装了Docker的机器上不用管底层操作系统是什么。打个比方以前分发应用就像把一台没组装的电脑寄给别人——CPU、内存、硬盘、显示器分开打包对方收到还得自己组装、装系统、装驱动中间任何一个环节版本不匹配就开不了机。有了Docker之后你直接把整台“装好系统、装好软件、配置完毕”的电脑装进一个标准货柜里寄过去对方只需要有电装了Docker就能开机使用。这个“标准货柜”在Docker里叫镜像Image。镜像跑起来之后就是一个容器Container。镜像和容器的关系可以理解成程序与进程、类与实例的关系——镜像是静态的、只读的模板容器是镜像运行时的动态实例可以启动、停止、删除。1.2 镜像、容器、仓库三个你必须先记住的名词在Docker的世界里有三个最核心的概念几乎所有操作都围绕它们展开镜像Image一个只读的模板定义了容器内要有什么软件、什么配置、什么环境变量。镜像是分层构建的可以理解为每一层都是一个增量补丁。容器Container镜像的运行实例。一个镜像可以启动多个容器它们相互隔离互不影响。仓库Registry集中存放镜像的地方。最常用的是Docker Hub——官方的“镜像应用商店”。你从仓库拉取pull镜像到本地也可以把自己做的镜像推送push上去分享给别人。这三者之间的关系是从仓库拉取镜像 → 基于镜像创建并运行容器 → 容器运行你的应用。理解了这个闭环后面所有命令都不会让你感到困惑。1.3 为什么不用虚拟机容器赢在“轻”和“快”很多人会问虚拟机也能隔离环境、也能打包分发为什么要用Docker这个问题我当年也纠结过直到我实际对比了一次。虚拟机VM是对硬件层做虚拟化每个虚拟机里都要装一个完整的操作系统Guest OS动辄几个GB起步启动要等几分钟占用的CPU、内存都是实打实被扣走的。容器则是对操作系统层做虚拟化所有容器共享宿主机同一个内核容器里只打包应用及其依赖的系统库没有独立操作系统。所以容器的镜像小到几百MB甚至几十MB启动是以毫秒到秒级计算的。对比维度虚拟机Docker容器隔离级别硬件级虚拟化操作系统进程级隔离镜像大小GB级起步MB级为主启动速度分钟级毫秒~秒级资源占用每个VM独占资源多个容器共享内核密度一台机器跑几个VM就吃力一台机器轻松跑几十个容器对开发者和运维来说这种差异意味着本地开发环境秒级拉起、测试环境几秒钟批量创建、生产环境资源利用率大幅提升。这也是为什么容器技术被认为是云原生时代的基石。1.4 镜像加速拉不下来镜像一切白搭镜像下载慢、超时是新手遇到最多的问题没有之一。Docker Hub的服务器在境外直接从官方源拉镜像经常几KB/s甚至直接超时。解决方案就是配置镜像加速器。国内多家云服务商都提供免费的Docker镜像加速服务比如阿里云、腾讯云、华为云都提供了各自的加速地址部分还有网易、中科大等公共加速地址。它们的原理都一样把这些加速器配置为Docker的registry mirror拉镜像时Docker会先从加速器拉取加速器再回源Docker Hub并缓存。配置方式很简单在Docker的配置文件daemon.json里加上registry-mirrors配置即可。Windows和Mac端在Docker Desktop的设置界面里也可以直接配置我们在下一章的安装环节具体讲。2. 环境准备与安装全流程2.1 Windows安装Docker Desktop与WSL2的配合Windows上安装Docker目前官方推荐的路径是Docker Desktop。它底层依赖一个后端环境现在主流是WSL2Windows Subsystem for Linux 2。安装前有几项前置检查一定要做不然启动时会报“virtualization support not detected”之类的错误。先确认你的CPU虚拟化已经在BIOS里打开。开机进BIOS一般是按Del或F2找Intel Virtualization TechnologyIntel VT-x或AMD SVM Mode设为Enabled。这一步不做装完Docker Desktop会直接启动失败报错提示找不到虚拟化支持。第二步是启用Windows功能。控制面板 → 程序 → 启用或关闭Windows功能勾选“适用于Linux的Windows子系统”和“虚拟机平台”。完成后重启电脑然后在PowerShell管理员里执行wsl --set-default-version 2这样WSL的默认版本就是2了。Docker Desktop默认优先使用WSL2后端相比老一代的Hyper-V方案启动更快、资源占用更低。接下来去Docker官网下载Docker Desktop for Windows注意ARM和x86版本别下错一路Next安装即可。安装完成后启动系统托盘会出现Docker图标打开终端执行docker version能看到Client和Server两段信息说明安装成功。如果只有Client没有Server多半是引擎没启动起来检查一下Docker Desktop日志和WSL状态。2.2 Linux安装Ubuntu和CentOS的两种姿势Linux下安装Docker最怕用旧教程。很多网上搜到的教程还在用docker.io这种老包或者手动添加已经废弃的仓库源。这里分享两条被验证过无数次的可靠路径。Ubuntu/Debian系推荐使用官方脚本一键安装curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh这个脚本会自动配置官方或镜像源安装Docker Engine、containerd和CLI工具安装完再执行sudo systemctl enable --now docker sudo systemctl status dockerCentOS/RHEL系则建议手动配置仓库后安装因为官方脚本在部分企业内网环境可能连接不上。先用yum-utils设置仓库sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo然后安装sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo systemctl enable --now docker有个CentOS 7的老用户需要注意CentOS 7自带的3.10内核比较老部分Docker新特性用不了。如果要用较新的Docker版本建议先把内核升级到5.x否则可能出现iptables相关的网络异常。2.3 安装后的初始化用户组、镜像加速、开机自启装完Docker不是终点还有三步初始化操作非常重要很多教程会略过。第一步把当前用户加入docker组免去每次敲命令都要sudo的烦恼sudo usermod -aG docker $USER newgrp docker这里有个坑要注意修改完用户组后必须重新登录终端或执行newgrp docker才生效。如果忘记这一步会一直报“permission denied while trying to connect to the Docker daemon socket”。第二步配置镜像加速。Linux下修改/etc/docker/daemon.json{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com, https://docker.nju.edu.cn ] }改完重启Dockersudo systemctl restart docker。Windows用户则在Docker Desktop的设置 → Docker Engine里把同一个JSON内容贴进去点击Apply Restart。第三步确认开机自启。Ubuntu/Debian系用systemctl管理的话enable --now已经同时设置了开机自启。如果用的是Docker Desktop它的设置里默认有启动时自动启动的选项记得勾上。3. Docker常用命令与核心配置解析3.1 镜像管理命令拉取、查看、删除镜像操作是整个Docker使用频率最高的动作命令本身不难搞清楚几个核心的就够用。# 拉取一个镜像默认从Docker Hub拉取latest标签 docker pull mysql:8.0 # 查看本地所有镜像 docker images # 查看镜像详细信息 docker inspect mysql:8.0 # 删除镜像 docker rmi mysql:8.0 # 清理所有悬空镜像没有标签的中间层镜像 docker image prune这里有一个细节容易踩坑docker pull不指定标签时默认拉取latest。生产环境强烈建议指定明确的版本号。我之前就遇到过某天重新部署时把latest里的MySQL 8.0.36拉下来但线上跑的还是8.0.28一个配置参数行为变了排查了很久。镜像标签锁定版本是最基础的环境可复现性保障。3.2 容器生命周期命令run、start、stop、rm容器的命令是另一个高频面试题也是实际使用中最常敲的。最核心的还是docker run它的参数非常多但有几组是必须掌握的docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD123456 \ -v /data/mysql:/var/lib/mysql \ --restartalways \ mysql:8.0我来逐个拆解这几个参数的含义-d后台运行容器detach模式不会霸占当前终端--name给容器起一个名字方便后续管理-p 3306:3306端口映射。宿主机3306端口映射到容器内3306端口。这样外部访问宿主机IP3306就能进入MySQL-e设置环境变量。这里设置了MySQL的root密码-v /data/mysql:/var/lib/mysql数据卷挂载。把宿主机目录挂到容器内目录容器删除后数据还在宿主机上--restartalways容器意外退出或Docker重启后自动拉起容器其他常用的容器操作命令# 查看运行中的容器 docker ps # 查看所有容器包括已停止的 docker ps -a # 启动一个已存在的容器 docker start mysql8 # 停止一个容器 docker stop mysql8 # 删除容器需先停止 docker rm mysql8 # 强制删除运行中的容器 docker rm -f mysql8 # 进入容器内部 docker exec -it mysql8 bashdocker exec -it是调试时最常用的命令。进入容器后你能像在一台独立Linux机器里一样操作查看日志、改配置、跑命令。-it是-i交互式和-t分配终端的组合少一个都会导致无法正常交互。3.3 日志、资源查看与清理运维离不开的几组命令实际使用中容器运行出问题第一件事就是看日志。# 查看容器日志最新100行 docker logs --tail 100 mysql8 # 实时跟踪日志输出 docker logs -f mysql8 # 带时间戳查看日志 docker logs -t mysql8docker logs -f是排障利器。之前我在容器里部署Java应用启动后一直没反应执行docker logs -f才发现是内存参数设置导致的OOM日志里清清楚楚。没有这个命令问题定位难度会大很多。资源占用情况也是日常要关注的# 查看所有容器的CPU、内存、网络占用 docker stats # 查看容器的进程信息 docker top mysql8 # 查看容器的资源使用明细 docker inspect mysql8 | grep -i memory最后是清理# 清理所有已停止的容器 docker container prune # 清理所有未被使用的网络 docker network prune # 一键清理容器 网络 悬空镜像 构建缓存 docker system prune -adocker system prune -a这个命令杀伤力很大会删除所有没有被容器使用的镜像磁盘空间告急时用一次能腾出大量空间。但有经验的人都明白一个道理执行之前先确认有没有私有的、无法重新拉取的本地镜像否则就是灾难。3.4 数据卷与网络让容器数据持久化、容器间互通的两大支柱容器是“用完即走”的如果没有数据卷容器一删除里面写入的数据全部丢失。**数据卷Volume**就是Docker提供的持久化方案。挂载数据卷前面已经演示过这里补充三种方式匿名卷-v /var/lib/mysql不指定宿主机路径Docker自动分配一块目录存储后续管理比较麻烦不推荐。命名卷-v mysql-data:/var/lib/mysqlDocker管理该卷的宿主机路径复用性好。宿主机路径挂载-v /data/mysql:/var/lib/mysql最直观适合有固定宿主机目录要求的场景。网络方面Docker容器默认通过NAT网络与外界通信。多个容器之间要互相访问最简单的方式是创建自定义网络docker network create my-net docker run -d --network my-net --name mysql8 mysql:8.0 docker run -d --network my-net --name app myapp同一个自定义网络里的容器可以通过容器名直接互相访问。比如应用容器里配置数据库地址直接写mysql8:3306就行不需要去查IP。这个特性在docker compose编排中会被大量使用。4. 实战用Docker部署MySQL 8.0从零到可连接4.1 需求分析与端口、目录、密码的规划很多人第一次用Docker部署MySQL就是因为本机或者公司的测试环境MySQL版本太乱想用Docker快速拉起一个干净的实例。这个需求非常典型也最适合作为第一个练手项目。动手之前先想清楚三件事端口宿主机3306是否被占用如果本机已经有MySQL在跑映射宿主机端口要换成3307之类的未占用端口。数据目录决定把数据落在宿主机的哪个目录这个目录后续要定期备份。密码root密码不要用太简单的即使只是测试环境。我这边的规划是宿主机端口3306数据目录/data/mysqlroot密码Root2024版本锁定mysql:8.0。4.2 完整启动命令与参数逐项说明第一步创建宿主机数据目录并赋予适当权限sudo mkdir -p /data/mysql第二步执行run命令启动容器docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDRoot2024 \ -v /data/mysql:/var/lib/mysql \ -e TZAsia/Shanghai \ --restartalways \ mysql:8.0这里比前面的示例多了个TZAsia/Shanghai环境变量把容器时区设置为东八区。MySQL的时间函数与系统时区有强关联不设置时区的话默认UTC时间会和北京时间相差8小时排查数据问题时会非常头疼。第三步验证容器是否正常运行docker ps docker logs --tail 20 mysql8看到日志中ready for connections字样说明MySQL已经正常启动。4.3 数据持久化验证与远程连接配置验证数据持久化是否生效最简单的方式是进入容器创建一个测试数据库然后删除容器再重新启动一个新容器挂载同一个数据卷看看数据是否还在。# 进入容器创建测试库 docker exec -it mysql8 mysql -uroot -pRoot2024 -e CREATE DATABASE test_persist; # 删除容器容器内的数据默认随之消失 docker rm -f mysql8 # 用相同参数重新创建容器 docker run -d --name mysql8 -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDRoot2024 \ -v /data/mysql:/var/lib/mysql \ -e TZAsia/Shanghai \ --restartalways \ mysql:8.0 # 检查数据是否还在 docker exec -it mysql8 mysql -uroot -pRoot2024 -e SHOW DATABASES;test_persist库仍然存在说明数据卷挂载生效。这一步虽然简单但我强烈建议每个新手都亲手验证一遍。只有自己确认过“容器删了数据还在”才能真正理解数据卷的价值。远程连接时注意MySQL 8.0默认的认证插件是caching_sha2_password老版本客户端可能连不上。如果遇到Authentication plugin caching_sha2_password cannot be loaded的报错进入容器执行以下SQLALTER USER root% IDENTIFIED WITH mysql_native_password BY Root2024; FLUSH PRIVILEGES;把root的认证方式改成mysql_native_password。生产环境建议单独创建专用账号并限制权限不要图省事直接改root。4.4 开机自启与容器异常恢复--restartalways这个参数在前面出现过这里重点说一下它的几种取值和适用场景restart策略行为适用场景no容器退出不自动重启临时测试容器on-failure[:max-retries]非正常退出才重启脚本任务always始终重启Docker启动时也会自动拉起数据库、中间件等常驻服务unless-stopped手动停止后不再重启其余情况自动重启调试过程中的服务生产环境部署MySQL、Redis这类常驻服务--restartalways是标配。Docker服务重启后这些容器也会自动恢复省去手动拉起的麻烦。5. 实战进阶Redis主从复制与Docker Compose编排5.1 单机MySQL已经会了Redis为什么还要主从部署MySQL解决的是“数据库版本统一、环境干净”的问题。但很多业务系统还需要Redis做缓存而且为了高可用还要配主从复制。用Docker部署Redis主从的好处是通过容器快速创建多个Redis实例它们之间网络互通、配置隔离模拟生产环境的主从拓扑非常方便。主从复制的核心逻辑是主库Master负责写操作从库Slave/Replica负责读操作主库把写操作的命令同步给从库。好处是三重的读写分离提升吞吐量、数据热备份降低丢失风险、从库可以承担故障切换的职责。5.2 docker compose文件编写两个Redis实例一个compose搞定docker compose的作用是用YAML文件定义多个容器一条命令自动创建和启动。它避免了手动敲大量docker run命令的繁琐也让服务编排的配置有迹可循。我新建一个目录redis-cluster在里面创建docker-compose.ymlversion: 3.8 services: redis-master: image: redis:7.0 container_name: redis-master ports: - 6379:6379 command: redis-server --appendonly yes volumes: - redis-master-data:/data networks: - redis-net redis-replica: image: redis:7.0 container_name: redis-replica ports: - 6380:6379 command: redis-server --replicaof redis-master 6379 --appendonly yes depends_on: - redis-master volumes: - redis-replica-data:/data networks: - redis-net volumes: redis-master-data: redis-replica-data: networks: redis-net: driver: bridge注意几个关键点command字段覆盖默认启动命令--replicaof redis-master 6379告诉从库去复制主库。这里写的是容器名redis-master因为compose会自动把服务名解析为容器网络内的DNS名这比写IP可靠得多。depends_on保证主库先启动从库后启动。但它只控制启动顺序不等待主库完全就绪。如果主库初始化较慢从库可能会因连接失败而重试——不过Redis的复制机制本身支持断线重连短暂失败不影响最终一致。volumes和networks在文件底部定义compose会创建对应的命名卷和自定义网络。启动命令就一行docker compose up -d查看状态和验证主从docker compose ps # 进入从库查看复制状态 docker exec -it redis-replica redis-cli info replication输出中role:slave和master_link_status:up表示从库已连接主库、复制链路正常。在主库写数据从库能查到整个主从就通透了。5.3 实际部署一个前后端中间件的完整组合docker compose更大的威力在于编排整个应用栈。我之前给一个小型项目做了这样的编排前端Nginx 后端Java应用 MySQL Redis外面套一层compose一键部署整个项目。这个compose的骨架大概是version: 3.8 services: frontend: image: nginx:1.24 ports: - 80:80 volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./dist:/usr/share/nginx/html:ro depends_on: - backend backend: build: ./backend environment: SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/mydb?useUnicodetrue SPRING_REDIS_HOST: redis depends_on: - db - redis db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: mydb volumes: - db-data:/var/lib/mysql redis: image: redis:7.0 command: redis-server --appendonly yes volumes: - redis-data:/data这里backend服务用的是build指令意味着它会读取./backend目录下的Dockerfile构建本地镜像而不是从仓库拉取。前后端服务之间通过服务名互相访问环境变量里配置的数据库地址直接写db:3306、Redis地址写redis:6379一切都在compose创建的网络里自动解析。这种编排方式的体验用一句话概括从“搭环境半天”变成“一条命令跑通全栈”。团队新同事入职clone代码后直接docker compose up -d十分钟内本地环境就和线上一致了。6. 常见问题与排查技巧实录6.1 Docker Desktop启动失败virtualization support not detected这个报错信息很多人会在Windows上遇到。我排查过几次出现这个提示通常有四个原因BIOS虚拟化没开重启进BIOS确认VT-x/AMD-V已开启。Windows功能没开全控制面板里确保“虚拟机平台”“适用于Linux的Windows子系统”都勾选了。Hyper-V冲突如果机器上装了旧版VirtualBox或VMware并且开启了硬件加速可能与Docker Desktop的虚拟化冲突。要么关掉第三方虚拟机的嵌套虚拟化要么卸载二选一。WSL版本不对检查wsl -l -v确保发行版确实跑在WSL2上。如果是V1执行wsl --set-version 发行版名 2升级。还有一个常被忽视的点安装Docker Desktop后没有重启电脑。Windows的很多内核级功能如Hyper-V、WSL2需要重启才生效这个步骤不能跳过。6.2 docker: permission denied / Got permission denied权限问题在Linux上装了Docker执行docker ps时报permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock原因当前用户不在docker组里没有权限访问Docker守护进程。解决办法前面提过加到docker组并重新登录sudo usermod -aG docker $USER newgrp docker如果还是报错检查一下docker socket的权限ls -l /var/run/docker.sock正常情况是rw-rw----属主是root:docker。如果属主不对可以临时改一下但这属于非标准操作最好还是找到为什么socket权限被改过的原因。6.3 docker: failed to connect to the docker api at npipe:////./pipe/dockerdesktoplinuxen这是Windows上的典型报错说明Docker Desktop没有正常启动。处理顺序查看系统托盘Docker图标是否亮着没有的话手动启动Docker Desktop。启动后等待30秒左右确认引擎状态从Starting变成Running。还不行就重启Docker Desktop托盘右键 → Restart。实在不行重启电脑Windows上很多诡异问题重启就好了。如果重启后依然报这个错误多为WSL2内核损坏或未正确启动。执行wsl --shutdown关闭所有WSL进程再启动Docker Desktop基本能解决。6.4 容器一直重启CrashLoopBackOff现象用docker ps看到容器状态是Restarting或Restarting (1) 2 seconds ago说明容器启动后立刻崩溃退出Docker在反复重启它。排查思路非常固定看日志。执行docker logs --tail 50 容器名日志里通常有启动失败的根因。我遇到最多的情况是MySQL启动失败通常是数据目录权限不对或者my.cnf配置了宿主机路径但目录不存在。配置文件格式错误compose文件或应用配置文件里YAML/JSON语法有问题服务启动即报错退出。依赖服务还没就绪比如后端启动时连不上数据库连接超时后进程退出。虽然depends_on规定了顺序但数据库未必已准备好接受连接这时就要给应用加等待重试机制或者在compose中用健康检查。容器崩溃排查的黄金法则是先看日志别猜。绝大多数问题在日志里都能找到线索。6.5 镜像下载慢或超时加速器配置实操配置了镜像加速器拉取速度依然慢的大概率是加速器本身不稳定。我推荐的做法是在daemon.json里同时配置多个镜像源并定期检查可用性{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com, https://docker.nju.edu.cn ] }如果所有镜像源都失效或者内网环境无法访问外网另一个思路是找一台能正常访问Docker Hub的机器提前把镜像保存为tar包再导入目标机器# 在能访问Docker Hub的机器上 docker pull mysql:8.0 docker save -o mysql8.tar mysql:8.0 # 拷贝到目标机器后导入 docker load -i mysql8.tar这是离线环境部署的标准操作虽然笨一点但非常可靠。6.6 容器内访问宿主机服务的特殊处理容器默认是隔离的容器里访问宿主机上的MySQL、Redis、API这类服务时不能直接写localhost或127.0.0.1因为容器内的localhost指容器自身。Linux上可以用172.17.0.1这是Docker默认网桥的宿主机网关地址。Windows/macOS的Docker Desktop则可以直接使用host.docker.internal这个特殊域名。很多新手第一次遇到“容器里连不上宿主机服务”的问题就是困在这里。环境宿主机访问地址Linux默认bridge网络172.17.0.1Windows/macOS Docker Desktophost.docker.internal使用host网络模式localhost容器与宿主机共享网络栈7. 最终实操心得与建议最后分享一些我个人在实际使用中的体会。第一Docker的学习曲线其实没有想象中陡峭真正让小白的崩溃的往往不是概念而是一堆底层环境问题——Windows的虚拟化、Linux的权限、加速器失效。把这些拦路虎提前排干净后续的使用一定顺畅很多。第二一定要亲手敲一遍。看十篇教程不如自己从头到尾执行一条docker run命令。从拉镜像、起容器、映射端口、挂载数据卷到排查一次容器崩溃这些动作一旦形成肌肉记忆Docker在你眼里就从“黑科技”变成了“顺手工具”。第三镜像tag锁版本、数据卷必须挂载、配置统一走compose。这三条习惯能帮你避开绝大多数生产事故。我见过太多线上事故的根源就是环境不一致。Docker给了我们一把应对这个问题的利器但利剑要用得稳前提是把地基夯实。这个内容后续还可以扩展的方向很多比如如何编写自己的Dockerfile、怎么做多阶段构建减小镜像体积、如何用docker compose做服务健康检查与自动恢复、怎么配合CI/CD实现提交代码自动部署。每一步都是独立的进阶主题等你有了一定基础之后可以逐个击破。先说这么多。希望这篇实战笔记能帮你把Docker这块硬骨头啃下来真正做到从概念到实践一键跑通。