我第一次被Docker“教育”,是在一次周末加班部署的时候。项目要上线,环境是CentOS 7,JDK、MySQL、Redis、Nginx一样一样手动装,装到一半发现版本不对,卸载重来,前后折腾了大半天。后来同事跟我说:“你试试把整个环境打个包,跑在容器里。”我心想这不就是个轻量虚拟机吗?结果真正用起来才发现,根本不是一回事。
这篇文章基本算是我多年Docker使用经验沉淀下来的一套笔记。网上流传的那份“狂神说Docker”笔记我一直留着,刚入门时就是跟着它跑通了第一个容器,非常感激;后来在生产环境踩了不少坑,我又在原笔记基础上补了大量实操细节和故障排查经验。今天全部分享出来,适合刚接触容器的新手,也适合已经用了一段时间、但没系统梳理过命令和原理的人。内容比较长,建议先收藏,遇到问题再回来翻。
先把我最核心的体会放在前面:Docker不难,难的是理解它的设计思想。一旦想明白“镜像只读、容器可写、数据靠卷、通信靠网络”这四句话,后面所有命令和配置都是顺水推舟。
1. 装好Docker这一关:Windows和Linux双平台避坑实录
装Docker看起来是最简单的一步,但“virtualization support not detected”和“Docker Desktop failed to start”这两个错误,常年霸占Docker相关搜索榜前列。问题不是Docker本身难装,而是前置条件太容易被忽略。
1.1 Windows装Docker Desktop前先确认虚拟化开关
Docker Desktop在Windows上有两种后端,老版本用Hyper-V,新版本默认走WSL2。不管哪一种,前提都是CPU虚拟化必须开启。很多人启动Docker Desktop后看到虚拟化报错,第一反应是重装,其实问题基本出在BIOS或Windows功能上。
排查步骤按这个顺序来:
- 打开任务管理器 → 性能 → CPU,看右下角“虚拟化”是否显示“已启用”。
- 如果显示“已禁用”,重启进BIOS,找到Intel Virtualization Technology或SVM Mode(AMD平台),设为Enabled。
- 确认BIOS没问题后,检查Windows功能里是否开启了“适用于Linux的Windows子系统”和“虚拟机平台”。路径是控制面板 → 程序 → 启用或关闭Windows功能。
- 如果用的是老版本Docker Desktop,还需要勾选“Hyper-V”,同时注意别和其他虚拟机软件抢资源。
有个很容易被忽略的细节:某些主板的BIOS虚拟化选项藏得很深,比如部分品牌台式机在Advanced → CPU Setup里,有的需要开机按F2而不是Del。实在找不到就直接用主板型号搜索“怎么开启VT”,别硬猜。
1.2 WSL2模式修复的最后一招
如果你确定BIOS和Windows功能都开了,Docker Desktop仍然报虚拟化问题,有一种常见情况是WSL2本身没装好。打开PowerShell(管理员),执行:
wsl --install wsl --set-default-version 2然后重启电脑,再打开Docker Desktop。另外,老版本Windows 10跑WSL2会有一堆莫名其妙的问题,建议直接把系统升到较新版本,省心很多。
1.3 Ubuntu与CentOS的安装命令差别
Linux下安装Docker相对简单,但要注意“系统自带源里的版本”和“Docker官方源里的版本”是两个概念。
Ubuntu上很多教程直接让执行apt install docker.io,这个包确实能用,但版本往往落后。我更推荐用官方源安装:
sudo apt update sudo apt install 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 a+r /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 docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginCentOS 7虽然官方已经不再维护,但存量机器还很多,升级到新版Docker用这套:
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服务默认不会开机自启。所以每次配置完/etc/docker/daemon.json这类文件,记得用下面两条命令收尾:
sudo systemctl enable docker sudo systemctl start docker1.4 权限报错的根源是用户组
很多Linux新手装完Docker,执行docker ps直接收到permission denied,原因很简单:docker命令需要root权限,而当前用户不在docker组里。解决办法不是每次都加sudo,而是把用户加进docker组:
sudo groupadd docker sudo usermod -aG docker $USER newgrp docker这里必须提醒一句:能加入docker组的用户,基本等同于拥有root权限,因为Docker可以把宿主机任意目录挂载进容器。多人共用的生产服务器上,不要随便给普通用户加这个组。
2. 镜像和容器:这两个概念搞明白,Docker就入门了一半
2.1 菜谱和菜的关系
很多人一开始把Docker想象成虚拟机,这个类比害人不浅。虚拟机里装的是完整操作系统,每个虚拟机都是一台独立电脑;而Docker容器共享宿主机内核,它本质上只是一个隔离的进程运行环境。
我更愿意用菜谱和菜来打比方:
- 镜像就是菜谱加半成品食材包,它是只读的,里面定义了环境的一切:装了什么系统、什么依赖、什么程序、启动命令是什么。
- 容器就是照着菜谱做出来的一道菜,你可以往里面加料、改配置,但菜谱本身不会变。
- 仓库就是大菜市场,里面有别人做好的各种菜谱,比如MySQL菜谱、Redis菜谱、Nginx菜谱。
用命令来解释更直观:
docker pull mysql:8.0 # 去仓库下载MySQL 8.0镜像 docker run -d --name mydb mysql:8.0 # 基于镜像创建并启动容器 docker ps # 查看运行中的容器 docker ps -a # 查看所有容器,包括已停止的 docker stop mydb # 停止容器 docker rm mydb # 删除容器 docker images # 查看本地所有镜像 docker rmi mysql:8.0 # 删除镜像注意docker rm删除的是容器,docker rmi删除的是镜像,很多新手在这俩上面栽跟头。
2.2 镜像是分层的
镜像的另一个重要特性是分层(Layer)。你pull一个镜像的时候,输出里会显示很多层,每一层对应一个小改动。比如一个基于CentOS的镜像,底层是系统基础层,往上可能是JDK安装层,再往上才是你的应用jar包层。
分层最大的价值在于复用和节省空间。本地已经有一个CentOS基础层,再拉其他基于CentOS的镜像,基础层就不用重复下载。这也是Docker镜像比虚拟机文件小得多、启动速度快得多的根本原因。
2.3 镜像标签里的学问
镜像名后面的冒号是标签(tag),mysql:8.0和mysql:latest是两回事。生产环境强烈建议固定tag,不要用latest。latest会随着官方更新变化,今天拉的和明天拉的可能是不同版本,等出了问题你根本不知道线上跑的到底是哪个版本。我见过不止一次因为latest导致MySQL大版本意外升级、配置文件不兼容的线上事故。
3. 拉镜像慢的解决方案:加速器配置与自建仓库
3.1 为什么直连Docker Hub经常超时
Docker Hub的镜像服务器在海外,国内网络环境下拉取大镜像经常出现进度条长时间不动、或者卡在等待状态。这个问题属于基础设施层面的问题,自己换DNS、重启网卡都解决不了。主流思路是给Docker配置镜像加速器,或者自建私有仓库。
3.2 daemon.json配置加速器
Docker守护进程会读取/etc/docker/daemon.json加载加速器配置,Windows则在Docker Desktop的Settings → Docker Engine里改同样格式的JSON:
{ "registry-mirrors": [ "https://docker.1ms.run", "https://docker.xuanyuan.me" ] }保存后Linux执行systemctl restart docker,Windows重启Docker Desktop即可生效。
这里说明一下:加速器只对从Docker Hub拉取的公共镜像生效,对私有仓库和其他第三方仓库不生效。而且很多公共加速地址会变动,建议多配几个,失效了及时更换。
3.3 企业内网自建Registry
如果团队内部经常要分发同一个镜像,与其每个人各自去外网拉,不如搭一个内部镜像仓库。用极简的Docker Registry做演示:
docker run -d -p 5000:5000 --restart=always --name registry registry:2推送和拉取方式:
docker tag mysql:8.0 192.168.1.100:5000/mysql:8.0 docker push 192.168.1.100:5000/mysql:8.0 docker pull 192.168.1.100:5000/mysql:8.0默认情况下Registry走HTTP协议,而Docker守护进程只信任HTTPS的仓库,所以要在daemon.json里声明内网HTTP仓库:
{ "insecure-registries": ["192.168.1.100:5000"] }自建仓库的价值不只是拉取快。生产环境里镜像内容可审计、版本可控,出问题可以快速回滚到上一个版本,这些在运维中比“拉得快”重要得多。
4. 数据持久化:容器删了不代表数据还在
4.1 容器是“用完即走”的
容器被删除后,容器内的所有数据也会随之消失,因为容器写入层本来就是临时的。这是设计思想,不是Bug——容器被定位成“无状态”的进程运行环境。但数据库、配置文件、日志这些必须有状态,所以Docker提供了卷(Volume)和绑定挂载(Bind Mount)两种持久化方式。
4.2 -v挂载和命名卷的区别
先看最简单的绑定挂载,把宿主机的一个目录映射进容器:
docker run -d --name mysql8 \ -p 3306:3306 \ -v /data/mysql:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=123456 \ mysql:8.0这里/data/mysql是宿主机目录,/var/lib/mysql是容器里MySQL的数据目录。容器删了,宿主机目录里的数据还在,下次重新run一个容器,把同一个目录挂载进去,数据就回来了。
命名卷(Named Volume)则是把目录托管给Docker管理,做有状态服务时更推荐:
docker volume create mysql_data docker run -d --name mysql8 \ -v mysql_data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=123456 \ mysql:8.0两者区别在于:绑定挂载的路径由你在宿主机指定,方便直接查看和备份;命名卷的路径由Docker管理,跨主机迁移时更规范。我生产环境的习惯是:数据库用命名卷,日志和应用配置用绑定挂载。
4.3 MySQL 8.0部署实例与字符集坑
热词里大家都在搜“docker安装mysql8.0并使用”,说明新手踩坑多。先给一套完整的运行命令:
docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD='Root@123' \ -e TZ=Asia/Shanghai \ -v mysql_data:/var/lib/mysql \ -v /etc/localtime:/etc/localtime:ro \ mysql:8.0进容器测试连接:
docker exec -it mysql8 mysql -uroot -pMySQL 8.0默认的认证插件是caching_sha2_password,老版本的Navicat连接会报认证失败。如果确实需要兼容老客户端,可以改认证方式:
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'Root@123'; FLUSH PRIVILEGES;还有字符集问题。Docker官方MySQL镜像默认字符集可能是utf8mb4,但排序规则不一定符合预期,中文业务系统建议启动后执行SET NAMES utf8mb4,或在my.cnf里显式配置。
4.4 数据库备份与恢复
容器里的MySQL备份不用进容器,直接在宿主机用docker exec配合mysqldump:
docker exec mysql8 sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --databases yourdb' > backup.sql恢复:
cat backup.sql | docker exec -i mysql8 mysql -uroot -p这里有个关键细节:备份要用sh -c 'exec ...'的形式,而不是直接docker exec mysqldump,这样能让mysqldump成为容器内的1号进程,避免shell残留导致备份不完整或命令挂起。我早期就因为这个吃过亏,备份出来的SQL缺了最后一段,恢复系统时才追悔莫及。
5. 容器网络:端口映射与跨容器通信
5.1 -p映射端口的本质
容器内部有独立的网络命名空间,宿主机要访问容器内的端口,必须通过端口映射。docker run -p 3306:3306意思是把宿主机的3306端口映射到容器的3306端口,左侧是宿主机端口,右侧是容器端口。
新手经常问:为什么改了容器里的端口,外面连不上?因为映射关系在创建容器时就固定了,要改端口映射只能删了容器重新run。Docker不是路由器,端口映射是一条不可热更新的规则。
5.2 自定义bridge网络才是容器互通的正解
默认情况下,容器通过名为bridge的默认网络互联,可以用IP互访,但IP会随容器重建而变化,不稳定。更推荐创建自定义bridge网络,让容器之间用容器名互相访问:
docker network create mynet docker run -d --name redis1 --network mynet redis:7 docker run -d --name redis2 --network mynet redis:7在redis1容器里可以直接用redis2作为主机名连接。Docker内置的DNS会自动完成容器名到IP的解析,这是服务发现最简单的实现形态。
5.3 实战:Redis主从集群
热词里有“docker安装redis主从”,我分享一下标准做法。先建网络,再分别启动主从节点:
docker network create redis-net docker run -d --name redis-master \ --network redis-net \ -p 6379:6379 \ redis:7 redis-server --appendonly yes docker run -d --name redis-slave1 \ --network redis-net \ redis:7 redis-server --replicaof redis-master 6379进入从节点检查状态:
docker exec -it redis-slave1 redis-cli info replication看到role:slave且master_link_status:up,说明主从正常。整个过程最关键的是--replicaof redis-master 6379里用了容器名而不是IP,如果写死IP,以后主节点重建、IP一变,从节点就会失联。这就是自定义网络相比IP直连的最大优势。
5.4 外部访问失败先查防火墙
端口映射配好了但外部访问不上,很多情况是宿主机防火墙拦截。CentOS 7常见的放行方式:
firewall-cmd --permanent --add-port=3306/tcp firewall-cmd --reload如果是云服务器,还要去安全组放行端口。最典型的现象是“本机连得上、外部连不上”,第一反应应该是查安全组,而不是去容器里翻日志。
6. Docker Compose:多容器编排的正确打开方式
6.1 一条docker run解决不了的问题
一个典型Web项目,可能需要MySQL、Redis、Nginx、应用服务四个容器。如果都靠手敲docker run,命令又长又不直观,每次重建环境都要重新敲一遍。Compose的作用就是让容器编排变成“写配置文件 + 执行up”。
6.2 一个可直接套用的docker-compose.yml
以部署MySQL 8.0加Redis 7.0为例:
version: '3.8' services: mysql8: image: mysql:8.0 container_name: mysql8 restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: 'Root@123' TZ: 'Asia/Shanghai' ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql - ./conf/mysql:/etc/mysql/conf.d networks: - app-net redis: image: redis:7 container_name: redis7 restart: unless-stopped command: redis-server --appendonly yes --requirepass Redis@123 ports: - "6379:6379" volumes: - redis_data:/data networks: - app-net volumes: mysql_data: redis_data: networks: app-net: driver: bridge启动命令:
docker compose up -d docker compose ps docker compose logs -f mysql8新版Docker已内置compose子命令docker compose,老环境才需要单独安装docker-compose。如果提示找不到命令,用pip install docker-compose或安装docker-compose-plugin包。
6.3 restart策略要理解到位
restart: always不是“重启容器”的意思,而是“无论容器以什么方式退出,Docker守护进程都会把它拉起来”,除非明确docker stop。对于有状态服务,我建议用restart: unless-stopped。两者唯一差别在于:手动docker stop之后,unless-stopped不会自动拉起,而always会在Docker服务重启后又把它拉起来。这个区别在“故意停掉一个服务维护”的场景里非常重要。
6.4 敏感信息交给.env管理
compose文件里写明文密码,提交到Git仓库等于把数据库密码公之于众。生产环境至少用.env文件管理:
# .env MYSQL_ROOT_PASSWORD=ChangeMe123 REDIS_PASSWORD=ChangeMe456compose文件里用${MYSQL_ROOT_PASSWORD}引用,然后在.gitignore里忽略.env。进一步可以上Docker Secrets或专门的密钥管理服务,但对中小团队来说,先做到.env不入库已经是很大进步。
多说一句:很多从GitHub拉下来的开源项目,比如Dify这种,代码里通常有一个.env.example模板文件,部署前第一步就是复制成.env再执行docker compose up -d。很多人部署失败,不是命令写错,而是漏了cp .env.example .env这一步。
7. 自己写Dockerfile,把项目变成镜像
7.1 核心指令速览
Dockerfile是构建镜像的配方文件。最常用的指令有这几个:
- FROM:基础镜像,一切从这里开始
- WORKDIR:设置工作目录
- COPY:把文件复制进镜像
- RUN:构建时执行的命令
- EXPOSE:声明容器监听端口
- ENV:设置环境变量
- CMD/ENTRYPOINT:容器启动后的默认命令
以 Spring Boot 项目为例:
FROM eclipse-temurin:17-jdk WORKDIR /app COPY target/app.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]构建:
docker build -t myapp:v1 .7.2 多阶段构建瘦身
Java项目构建需要JDK和Maven,运行只需要JRE。如果只用一个基础镜像,构建产物里会混入大量编译器内容,镜像体积轻松上500MB。多阶段构建可以解决这个问题:
# 第一阶段:构建 FROM maven:3.9-eclipse-temurin-17 AS builder WORKDIR /build COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn package -DskipTests # 第二阶段:运行 FROM eclipse-temurin:17-jre WORKDIR /app COPY --from=builder /build/target/app.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]构建完用docker images查看,运行镜像会小很多。瘦身不是洁癖,体积小的镜像拉取快、启动快、攻击面小,生产环境收益非常明显。
7.3 IDEA一键打包Docker镜像
热词里有“idea 打包docker镜像”,说明很多Java开发想省掉命令行构建的麻烦。IDEA的做法是:
- 在File → Settings → Build, Execution, Deployment → Docker里连接本机或远程Docker。
- 在运行配置里新建Dockerfile运行配置,指定Dockerfile路径和镜像名。
- 点击运行,IDEA自动完成build。
有一点注意:如果是远程Docker,IDEA构建时需要把上下文目录上传到远程服务器,项目大了会慢。这种情况更推荐在CI流水线里构建,本地只负责开发和推代码。
7.4 微服务部署的常见误区
“docker部署微服务项目”这个关键词很火。微服务容器化不是简单地把每个服务打成镜像就完事,还有服务发现、配置中心、网关、日志收集一堆问题要处理。如果只有四五个服务,用Compose加自定义网络就够;如果有几十个服务,就要考虑Kubernetes这类编排平台。但上手K8s之前,先把Docker本身的网络、卷、健康检查吃透,不然直接跳进K8s只会更晕。
8. Docker Desktop故障排查手册
8.1 “Failed to connect to the docker api at npipe”型错误
Windows上Docker Desktop突然连不上,报错信息出现npipe:////./pipe/dockerDesktopLinuxEngine,多半是Docker引擎挂了,不是Docker Desktop整体坏了。常见修复顺序:
- 右键Docker Desktop托盘图标,选择Restart。
- 不行就退出Docker Desktop,打开PowerShell执行
wsl --shutdown,再重新启动。 - 再不行,在Settings → Troubleshoot里点Clean / Purge data,这会重置Docker的WSL发行版数据,一般能救回来,但也会清掉Docker Desktop默认卷里的数据。
如果你之前把数据都挂载到宿主机目录或命名卷里,第三步就没那么可怕。这也是我一直强调数据必须持久化的原因之一。
8.2 “unexpected EOF”类拉取中断
docker pull到一半报unexpected eof,基本是两种原因:网络不稳定导致传输中断,或者镜像加速器超时。处理手段是换一个更稳定的加速器,重新pull。大镜像本身就是分层下载的,中断后重新执行会续传已下载的层,不用太担心。
8.3 Docker磁盘占用爆炸
Docker用久了,Windows的C盘会被镜像和构建缓存占满。先看占用:
docker system df清理:
docker system prune -a这个命令会删掉所有未使用的镜像和构建缓存,执行前注意看输出确认没删错。我平时用更温和的组合:docker image prune -a清理无用镜像,docker builder prune清理构建缓存,按需执行,避免把还在用的镜像误删。
8.4 WSL2网络卡顿导致容器内DNS异常
另一种低频但很折磨人的情况是,容器里能ping通IP但解析不了域名,同时宿主机网络一切正常。这时候先怀疑WSL2的虚拟网络适配器卡死了。PowerShell执行wsl --shutdown,等几秒再启动Docker Desktop,绝大多数能恢复。如果频繁出现,可以在用户目录下的.wslconfig里给WSL2限制内存,避免Docker和Windows抢资源。
9. 特定场景与冷门问题:从KODBOX到国产环境
9.1 网盘类轻应用:KODBOX与DVWA的“一条命令”价值
docker部署kodbox是很常见的家庭或小团队需求。KODBOX是网盘应用,容器化部署在群晖或任意Linux服务器上都很方便,数据目录挂载出来就能用:
docker run -d \ --name kodbox \ -p 8080:80 \ -v /data/kodbox:/var/www/html \ kodbox/kodbox注意数据卷要挂到宿主机足够大的磁盘上,网盘的容量是命根子。另外如果接了反向代理,记得把WebSocket相关配置带上,否则在线预览大文件会断连。
类似地,安全学习常用的DVWA靶场也能一条命令拉起:
docker run -d -p 8080:80 vulnerables/web-dvwa这类实验环境用完即删,容器化“用完即走”的价值体现得淋漓尽致。
9.2 GitLab这种“重量级”选手:资源规划比命令更重要
GitLab的容器化部署也是一个高频搜索词。gitlab-ce镜像有好几个GB,内存建议至少4G,2G也能跑但明显卡顿。典型命令:
docker run -d \ --name gitlab \ -p 8022:22 -p 8080:80 \ --restart unless-stopped \ -v gitlab_config:/etc/gitlab \ -v gitlab_logs:/var/log/gitlab \ -v gitlab_data:/var/opt/gitlab \ gitlab/gitlab-ce:latest部署后要修改/etc/gitlab/gitlab.rb里的external_url,改成实际访问的域名或IP,否则clone地址会不对。首次启动初始化很慢,docker logs -f gitlab里看到“gitlab Reconfigured!”才算完成,别以为卡住了。
9.3 人大金仓数据库与龙芯架构:兼容性要先确认
人大金仓数据库在政企场景用得不少,官方提供了Docker镜像,部署方式和其他关系型数据库类似,但特别要注意授权文件的位置,通常需要通过挂载方式提供给容器。容器化本身不复杂,复杂的是授权协议和厂商的部署要求。很多情况下不是技术不允许,而是许可证不覆盖容器场景,所以项目初期就要确认“是否允许容器化部署”这个前提。
热词里还有“龙芯 docker”。龙芯是LoongArch架构,和常见的x86_64、ARM64都不一样,很多镜像没有提供LoongArch版本,pull时会报not found manifest。解决办法通常是:
- 到镜像仓库搜是否有loongarch64标签的镜像。
- 官方没有就基于支持LoongArch的基础镜像自己构建。
- 很多开源社区已经有人在做龙芯适配,直接搜“镜像名 + loongarch”关键词。
跨架构问题的根本就是镜像和宿主机CPU架构必须匹配,理解了这一点,排查思路就清晰了。
9.4 定时任务类面板的依赖管理:用Dockerfile固化依赖
热词“docker青龙 依赖管理”反映了很多人在Docker里跑定时任务面板的困扰。这类面板本质是脚本执行器,容器里需要各种运行时依赖。常见的错误做法是图方便直接在容器里装:
docker exec -it qinglong bash -c "npm install -g xxx"这样调试确实快,但容器一重建,依赖全没了。正确的做法是用Dockerfile构建自定义镜像,把依赖固化进去:
FROM whyour/qinglong:latest RUN npm install -g xxx && pip install xxx构建成自己的镜像后再跑容器,无论容器怎么重建,依赖都在。我的观点一直很明确:凡是需要容器环境提供的东西,全部用Dockerfile固化,这才叫可复现的部署。
最后分享几点我自己沉淀下来的经验
第一,数据卷的命名规范要提前定好。我见过很多团队的volume名字乱七八糟,MySQL的数据叫data,Redis的也叫data,时间一长根本分不清哪个卷对应哪个服务。建议统一用项目名_服务名_data的格式。
第二,每一条docker run命令最好留档。如果你习惯用命令启动容器,就把命令保存成shell脚本,或者写成compose文件,别只躺在终端历史里。不然半年以后想查某台机器的MySQL当初是用什么参数启动的,根本无从下手。
第三,容器起不来、日志为空、排查无从下手时,按这个顺序走:先docker logs看输出,再docker inspect看状态,最后检查挂载目录的权限。绝大多数启动失败都出在这三件事上,别一上来就删容器重建,那样永远学不到根因。
这次先分享到这儿。Docker的内容远不止这些,镜像安全扫描、CI/CD集成、Kubernetes编排都还有大量可挖的东西。后面我会把微服务编排和灰度发布的实战经验陆续整理出来,感兴趣的话可以留意后续更新。遇到具体问题,也欢迎在评论区把你的docker run命令或完整报错贴出来,我们一起看看问题到底出在哪。