
我第一次正经用Docker是在一台CentOS 7服务器上部署一个内部管理系统当时按照网上的教程一条命令跑起来MySQL和一个Java应用前后不到十分钟就把环境搞定了。那个瞬间我意识到容器化技术这东西解决的不只是部署速度问题它把整个软件交付的思维方式都换了。后来这些年我给不少团队做过Docker相关的培训和排障Windows上的安装报错、Linux下的权限问题、镜像加速、数据卷丢失、多容器网络不通……各种各样的坑都踩过一遍。这篇内容不是从官方文档复制摘要而是把Docker从入门到真正上手会用到的核心知识以及我在实际部署中遇到的坑和解决办法一次性梳理清楚。适合刚开始接触容器化技术的同学也适合已经在用Docker但遇到问题不知道怎么排查的开发者。1. 先把核心问题说清楚容器化技术到底解决了什么1.1 环境不一致是软件工程里最磨人的问题先想一个很常见的场景你本地开发环境一切正常代码提交之后运维同学在测试服务器上部署结果一启动就报错——本地没有这个错测试环境偏偏出现了。查到最后要么是操作系统版本不一样要么是某个依赖库版本对不上要么是环境变量没配。这个问题的根源就是传统部署方式里“环境”这个变量太不可控了。容器化技术的核心思路是把“应用”连同它依赖的运行环境一起打包成一个标准化的单元。这个单元里不仅包括你的代码还包括操作系统级别的依赖、配置文件、运行时环境、环境变量甚至连系统库的版本都定死了。别人拿到这个单元之后只要宿主机上有一个能运行容器的引擎就能在几乎一致的环境里把应用跑起来。我用一个比较生活化的类比来解释传统部署就像把一堆零件运到目的地再组装零件在运输途中可能磕碰、可能缺件、可能不同批次有不兼容容器化相当于把整个组装好的成品装进标准集装箱无论是高铁、货轮还是卡车只要按集装箱标准来就能直接搬运。这个“环境一致性”的价值在团队协作里体现得最明显。以前新人加入项目光配置开发环境就要一天有了Docker之后把镜像拉下来直接启动五分钟进入开发状态。1.2 镜像、容器、仓库三者之间的关系初学者最容易混淆的三个概念是镜像Image、容器Container和仓库Repository。它们之间的关系可以拿面向对象编程来理解镜像是类容器是实例。镜像是一个只读的模板里面包含了运行某个应用所需的文件系统和配置容器是这个模板运行起来后的一个具体进程在镜像之上多加了一层可写层。同一个镜像可以启动多个容器每个容器各自独立互不干扰。仓库则是存放镜像的地方。最常用的是Docker Hub公共仓库类似代码里的GitHub用来分享和拉取别人打包好的镜像。在企业内部也可以自建私有仓库用来存放自己构建的镜像。日常使用时最常用的流程就是三条命令docker pull从仓库拉镜像docker run根据镜像启动容器docker commit或docker build创建新镜像。# 拉取镜像 docker pull nginx:latest # 根据镜像启动容器-d 表示后台运行-p 映射端口 docker run -d -p 80:80 nginx:latest # 查看当前运行中的容器 docker ps这三个概念是整个容器化技术的地基后面的所有操作包括编写Dockerfile、使用Docker Compose编排多服务、搭建私有仓库都是围绕它们展开的。把这层关系理清了后面的内容才不容易乱。2. Docker安装并不是一路绿灯Windows和Linux的踩坑实录2.1 Windows安装Docker Desktop三座大山必须挨个过我见过太多人在Windows上安装Docker Desktop被卡住报错信息五花八门。最常见的有三类。第一类是报错Docker Desktop failed to start because virtualisation support wasnt detected。这个信息已经说得很直接了——虚拟化没有开启。Docker Desktop在Windows上依赖Hyper-V或WSL2来运行Linux虚拟机而这两者都需要CPU虚拟化功能开启。解决办法分两步先到BIOS里把Intel VT-x或AMD-V打开再到Windows功能里启用“虚拟机平台”和“适用于Linux的Windows子系统WSL”。# 以管理员身份运行PowerShell启用WSL和虚拟机平台 dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart # 安装WSL2内核并设为默认版本 wsl --set-default-version 2第二类是报错Weve detected that you have an incompatible version of Windows。Docker Desktop对Windows版本有硬性要求Windows 10必须更新到特定的版本号以上Windows 11则没有这个问题。遇到这个报错不要想着绕过去Windows更新里把系统补丁打全再重装最新版的Docker Desktop。有些老系统确实不具备条件那就老老实实换一套方案比如装一个Linux虚拟机在虚拟机里使用Docker Engine。第三类情况是安装完Docker Desktop之后界面一直停留在“Starting”状态。这绝大多数情况下都是WSL2的问题要么是老版本WSL2与Docker Desktop不兼容要么是WSL2发行版损坏。先把WSL2重置再重装一次基本能解决。# 查看WSL状态 wsl --status # 注销并重新安装默认WSL发行版 wsl --unregister docker-desktop wsl --shutdown2.2 Linux安装Ubuntu和CentOS 7的差异Linux下安装Docker就分两大流派使用软件源安装和使用官方脚本安装。Ubuntu上最简单的方式是直接使用软件源sudo apt-get update sudo apt-get 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 [archamd64 signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginCentOS 7这种老系统就麻烦一点它的内核版本默认是3.10Docker官方建议升级内核到更高版本才能稳定运行。这也是为什么搜索词里会出现“CentOS 7升级Docker”这个热度。升级流程大概是先安装elrepo-release仓库再更新内核最后重启系统选择新内核启动sudo yum install -y epel-release sudo rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org sudo yum install -y https://www.elrepo.org/elrepo-release-7.0-4.el7.elrepo.noarch.rpm sudo yum --enablerepoelrepo-kernel install -y kernel-lt # 重启后确认新内核 uname -r安装Docker引擎本身反而简单直接使用官方脚本curl -fsSL https://get.docker.com | bash这个脚本会自动检测发行版、配置软件源、安装依赖并启动Docker服务。个人学习和测试场景用它最省事生产环境还是建议按照官方文档逐个步骤执行方便审计和控制。2.3 权限错误和服务启动失败的排查链路Linux上装完Docker之后很多新手第一条命令docker version就会报错permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock这个报错的原因非常固定当前用户不在docker用户组里。Docker守护进程监听在/var/run/docker.sock这个Unix套接字上默认只有root用户和docker组内的用户能访问。解决办法就是把当前用户加入docker组然后重新登录会话sudo usermod -aG docker $USER newgrp docker还有一种情况是docker service启动失败比如执行service docker start之后容器一直无法启动systemctl status docker显示“Active: failed”。排查思路要按顺序来先看最直接的原因执行journalctl -u docker -n 50查看最近日志如果日志里有iptables相关的错误多半是防火墙规则和Docker冲突可以尝试先清空iptables规则如果是storage-driver相关的报错比如overlayfs不支持那就得在/etc/docker/daemon.json里显式指定存储驱动为vfs或devicemapper。Windows上还有一种特别隐蔽的情况就是Docker Desktop 4.26版本在Windows 10的某些更新组合下装了WSL2依然启动失败。我遇到过一例最后是把Docker Desktop的版本从4.26降回4.25解决的。所以别迷信最新版稳定优先生产环境尤其如此。排查这类启动问题记住一个原则错误信息永远比猜测可靠先认真读报错再决定下一步。3. 镜像、容器、数据卷、网络四个必须真正搞懂的概念3.1 镜像分层机制为什么Docker镜像能省这么多空间很多人以为Docker镜像就是一堆文件打成一个包其实不是。镜像采用的是分层存储结构每一层都对应镜像构建过程中的一个步骤。比如一个基于Ubuntu的Python应用镜像可能包含四层操作系统基础层、系统依赖层、Python运行时层、应用代码层。分层的最大好处是共享。如果本机已经有一个Ubuntu基础镜像拉取任何基于这个基础镜像构建的新镜像时只需要拉取差异层不需要整个镜像重新下载。这大大节省了磁盘空间和网络带宽。用docker history可以查看一个镜像的构建历史和每一层的大小docker history nginx:latest每一层都是只读的容器运行时会在这组只读层之上再加一个可写层。应用程序往文件系统里写任何东西都会记录在这个可写层里。所以“容器为什么不能持久保存数据”——因为可写层随容器销毁而销毁。要持久化保存数据就得使用数据卷。3.2 容器是运行态的镜像生命周期管理容器的生命周期比镜像复杂得多。一个容器的典型状态序列是created已创建→ running运行中→ paused已暂停→ exited已退出。日常操作中最常用的命令# 启动容器 docker start container_id # 停止容器 docker stop container_id # 删除容器先停止再删 docker rm container_id # 查看所有容器包括已退出的 docker ps -a这里有个细节需要留意docker stop发送的是SIGTERM信号容器内进程收到后可以优雅退出如果进程没有响应Docker会再发送SIGKILL强制结束。所以在自己的应用里最好注册信号处理函数收到SIGTERM时先做清理工作再退出不然数据文件很容易写坏。3.3 数据卷容器删除之后数据不能丢容器本身是“用完即弃”的但数据库文件、上传的图片、日志文件这些不能随容器一起消失。Docker的数据卷Volume和绑定挂载Bind Mount就是用来解决这个问题的。绑定挂载是把宿主机的某个目录直接挂载到容器内部路径映射很直观docker run -d -v /data/mysql:/var/lib/mysql mysql:8.0这条命令把宿主机的/data/mysql目录挂载到容器的/var/lib/mysqlMySQL写的数据就会落在宿主机磁盘上。删除容器再重建数据依然在。数据卷Volume是Docker自己管理的一块存储区域路径由Docker决定用-v指定名称即可docker run -d -v mysql_data:/var/lib/mysql mysql:8.0两种方式各有取舍。绑定挂载的路径直白、日志和临时文件方便直接查看但受宿主机目录权限影响较大具名数据卷更干净且Docker会处理文件权限问题推荐数据库这类生产数据使用数据卷。另外Windows上的Docker Desktop修改镜像存储路径实际是修改WSL2磁盘镜像vhdx文件的存放位置在Docker Desktop的Settings里调整不要自己去改虚拟磁盘文件非常容易搞坏。3.4 网络模式容器之间如何通信Docker默认容器之间的网络是互相隔离的但也提供了多种网络模式。最常用的是bridge网络默认的网络模式。启动容器时如果不指定就会加入默认的docker0网桥。同一个bridge网络里的容器可以通过容器名互相访问不需要写IP地址。# 创建一个自定义桥接网络 docker network create my-net # 启动容器时指定网络 docker run -d --name mysql8 --network my-net mysql:8.0 docker run -d --name redis1 --network my-net redis:7.0这时在mysql8容器里可以直接使用redis1这个主机名访问RedisIP变了也不影响。这种基于容器名的服务发现机制是Docker Compose和多容器应用的网络基础。端口映射是另一个重点。容器内的端口和宿主机端口不是天然打通的需要显式映射docker run -d -p 3306:3306 --name mysql8 mysql:8.0-p 3306:3306的含义是宿主机的3306端口转发到容器的3306端口。生产环境要注意宿主机端口不要暴露到公网数据库这种敏感服务尤其要谨慎。4. 镜像下载慢的真正原因与镜像源配置4.1 为什么docker pull那么慢新手第一次拉镜像往往会被折磨到崩溃一个几百MB的镜像下载半天还没结束。原因其实很简单Docker Hub的服务器在国外国内直连的速度非常不稳定尤其是拉大镜像时经常断流。这不是你的网络问题也不是Docker坏了就是物理距离和运营商线路的问题。解决办法就是配置镜像加速器。原理是在/etc/docker/daemon.json里指定一个国内可用的镜像源地址Docker拉取镜像时先从该源拉取拉不到再回退到Docker Hub。国内主流云厂商都提供Docker镜像加速服务比如阿里云、腾讯云、中科大等。4.2 配置镜像源的具体步骤{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com, https://docker.mirrors.ustc.edu.cn ] }配置文件改完之后重启Docker服务sudo systemctl daemon-reload sudo systemctl restart docker验证生效方式docker info | grep -A 5 Registry Mirrors配置好镜像源之后我之前拉一个1GB的镜像时间从原来的半小时缩到两三分钟体验提升非常明显。需要注意镜像加速器有时也会失效或者限速建议多配几个地址作为备选。另外如果是在公司内网可能还有自建私有仓库把内网仓库地址和加速器都写在registry-mirrors里按优先级顺序拉取。4.3 从镜像仓库到离线部署除了公共镜像源实际项目中还会有几个特殊的镜像需求。比如Hadoop这类大数据组件市面上有好多社区打包好的镜像可以直接搜索使用再比如人大金仓这类国产数据库官方也提供了Docker镜像拉下来跑一次就能完成测试环境搭建KodBox这类私有网盘工具同样有成熟的镜像一条命令就能部署一套。容器化让这些复杂软件的环境准备时间从小时级压缩到分钟级。如果目标服务器无法访问外网还有一个离线部署方案在一台能联网的机器上把镜像保存为tar文件然后拷贝到目标机器上导入。# 在联网机器上导出镜像 docker save -o mysql8.tar mysql:8.0 # 在离线机器上导入镜像 docker load -i mysql8.tar这个方案在政务、内网、涉密环境里用得非常多熟练掌握很有必要。5. 实战一用Docker安装MySQL 8.0并完成数据持久化5.1 一条命令把MySQL 8.0跑起来安装MySQL 8.0被搜索得这么频繁说明传统安装方式让太多人吃过亏。用Docker确实简单得多但必须注意一个关键问题MySQL容器的数据持久化。如果直接执行docker run mysql:8.0不挂数据卷容器一删数据全没了。我的推荐做法是建一个专门的数据目录然后用挂载卷启动mkdir -p /data/mysql8/conf mkdir -p /data/mysql8/data # 正式启动MySQL实例 docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDRoot123456 \ -e TZAsia/Shanghai \ -v /data/mysql8/data:/var/lib/mysql \ -v /data/mysql8/conf:/etc/mysql/conf.d \ --restartalways \ mysql:8.0几个参数要解释一下。MYSQL_ROOT_PASSWORD是初始化时设置root密码的环境变量只在第一次初始化数据目录时生效TZ设置时区不然MySQL的默认时区会跟系统差出八小时--restartalways让Docker在宿主机重启后自动拉起容器这个参数对生产环境几乎是必备的。启动完成后用docker ps确认容器状态。如果状态是“Up”说明MySQL已经正常运行了。5.2 进入容器执行命令很多人会遇到一个问题宿主机上没有安装mysql客户端怎么连接容器里的MySQL答案是用docker exec -it进入容器内部执行命令。docker exec -it mysql8 bash # 进入容器后连接MySQL mysql -uroot -pdocker exec是Docker里最高频使用的命令之一它允许在运行中的容器内部执行任意命令。-it参数表示交互式终端后面的bash表示进入容器后启动一个bash shell。除了交互方式也可以直接在宿主机上执行单条命令# 在容器内执行SQL docker exec -it mysql8 mysql -uroot -pRoot123456 -e SHOW DATABASES;这里会引出一个安全习惯的问题不要在命令行里直接暴露数据库密码尤其是生产环境。更好的方式是使用环境变量或配置文件命令行的密码会被记录到shell history里。5.3 数据卷持久化与备份恢复挂载了数据卷之后备份就变得非常简单直接把宿主机上的/data/mysql8/data目录打包复制一份即可。恢复就更简单了把备份文件解压回原目录重新启动容器数据就回来了。不过注意MySQL数据文件在运行期间不适合直接拷贝最好用官方工具先做逻辑备份# 在宿主机上执行利用docker exec调用容器内的mysqldump docker exec -it mysql8 mysqldump -uroot -pRoot123456 --all-databases /data/backup/all.sql这种方式生成的SQL文件在任何环境里执行都能恢复数据比直接拷贝数据文件更安全实用。我个人的习惯是逻辑备份每天定时执行一次数据量特别大的核心库再配合快照方案。6. 实战二Redis主从部署与容器网络协作6.1 Redis主从环境搭建Redis用Docker部署的场景也非常多主从模式的搭建方式比手工部署简洁得多。假设我们要搭建一主一从master监听6379端口slave监听6380端口。先启动masterdocker run -d \ --name redis-master \ -p 6379:6379 \ -v /data/redis/master:/data \ redis:7.0 --appendonly yes主从的关键是replicaof配置。Redis容器支持在启动命令后面追加配置参数--replicaof参数用来指定主库地址和端口docker run -d \ --name redis-slave \ -p 6380:6379 \ -v /data/redis/slave:/data \ redis:7.0 --appendonly yes --replicaof redis-master 6379这里有个网络细节从库通过redis-master这个容器名解析主库地址前提是两个容器在同一个bridge网络里。如果你直接用--link redis-master或者没指定自定义网络就会遇到解析失败的坑。用docker run时记得先创建自定义网络再启动两个容器并指定网络docker network create redis-net docker run -d --name redis-master --network redis-net -p 6379:6379 -v /data/redis/master:/data redis:7.0 --appendonly yes docker run -d --name redis-slave --network redis-net -p 6380:6379 -v /data/redis/slave:/data redis:7.0 --appendonly yes --replicaof redis-master 63796.2 验证主从状态主从是否同步成功用Redis自带命令验证即可docker exec -it redis-slave redis-cli INFO replication输出结果里找到role:slave和master_link_status:up就说明从库已经连上主库了。如果状态是down直接原因基本都是网络不通优先检查两个容器是否连接到了同一个网络。Redis主从只是一个起点。实际项目中RabbitMQ、Kafka、Elasticsearch这类中间件部署思路几乎一致先把数据目录挂载出来把端口映射好再处理节点间通信。Docker比起传统部署方式省去了大量下载依赖、修改配置文件、注册系统服务的时间。7. 从单容器到整套服务Dockerfile与Docker Compose编排7.1 编写一个可复用的Dockerfile当手头有自己开发的应用时就需要用Dockerfile来自定义镜像。这里用一个SpringBoot项目举例它使用JDK 1.8这正好对应了不少人搜索“SpringBoot JDK1.8打包到Docker”的场景。# 使用带JDK 1.8的基础镜像 FROM openjdk:8-jre-alpine # 设置工作目录 WORKDIR /app # 把构建好的jar包复制进镜像 COPY app.jar /app/app.jar # 暴露端口 EXPOSE 8080 # 设置启动命令 ENTRYPOINT [java, -jar, app.jar]构建命令docker build -t myapp:v1.0 .Dockerfile看起来简单但有几个细节点值得注意。基础镜像要选带-jre的而不是-jdk的生产环境不需要编译功能镜像能小一半以上COPY和ADD的区别ADD支持自动解压tar包和从URL下载但容易造成镜像内容不可预期推荐优先使用COPYCMD和ENTRYPOINT的区别CMD可以被docker run后面的命令覆盖ENTRYPOINT不会定义启动命令时两者配合使用才灵活。如果应用是PHP思路也一样基础镜像换php:8.2-fpm把代码复制进镜像再配合Nginx容器使用。Dockerfile的语法其实就那么多关键是养成小镜像、分层缓存、安全可控的构建习惯。7.2 Compose编排多条docker run的终极归宿一个稍微完整的项目往往需要同时启动好几个容器Nginx、后端应用、MySQL、Redis、消息队列。每个容器都用docker run一条条敲不仅费劲还容易遗漏参数。Docker Compose就是用来解决这个问题的工具它把多个服务定义在一个YAML文件里一条命令全部启动。version: 3.8 services: mysql8: image: mysql:8.0 container_name: mysql8 ports: - 3306:3306 environment: MYSQL_ROOT_PASSWORD: Root123456 TZ: Asia/Shanghai volumes: - mysql_data:/var/lib/mysql restart: always redis: image: redis:7.0 container_name: redis ports: - 6379:6379 volumes: - redis_data:/data command: redis-server --appendonly yes restart: always app: build: . container_name: myapp ports: - 8080:8080 depends_on: - mysql8 - redis restart: always volumes: mysql_data: redis_data:启动命令docker compose up -ddepends_on表达的是服务间的启动依赖关系但要注意它只控制启动顺序不保证依赖服务已经完全就绪。比如app等服务依赖mysql8如果MySQL初始化很慢app启动时可能还没法连接。比较规范的做法是在应用里加上重试机制或者使用健康检查配合Compose的condition来控制启动。7.3 一键部署微服务项目的路径微服务场景下一个项目可能有十几个服务Docker Compose是很好的起点。很多团队把每个微服务模块都打成独立镜像然后在Compose文件中统一编排。这套模式下新环境从零到全部服务可用基本就是两条命令的事docker compose build docker compose up -d比传统方式动辄写几百行部署脚本、手动装环境、检查依赖要省太多事。我见过一次最夸张的对比一个十二个微服务模块的项目原来部署一次需要两个人忙一下午用Compose之后一台新机器从装Docker到全套服务启动半小时全部搞定。这也是“Docker部署微服务项目”搜索热度高的原因——它真的把部署这个环节的成本打下来了。8. 生产环境绕不开的细节日志、资源限制与故障排查思路8.1 容器日志管理Docker的日志管理是很多人上手后最容易忽略的地方。默认情况下容器的标准输出会被Docker收集可通过docker logs查看docker logs --tail 100 -f myapp--tail 100表示只查看最后100行-f表示持续跟踪输出。但默认的json-file日志驱动有一个隐患日志文件会无限制增长时间长了可能占满磁盘。生产环境强烈建议在/etc/docker/daemon.json里配置日志轮转{ log-driver: json-file, log-opts: { max-size: 10m, max-file: 3 } }这个配置表示每个容器日志文件最大10MB超过后轮转最多保留3个文件。配置完成后重启Docker服务生效。对于日志量特别大的服务还可以改用gelf、fluentd等日志驱动把日志直接发送到集中式日志平台。8.2 资源限制防止容器吃光宿主机内存容器虽然是一个隔离单元但在默认情况下它使用的CPU和内存是不受限制的。如果某个容器里的进程有内存泄漏很可能把宿主机整个拖垮。生产环境启动容器时一定要加上资源限制docker run -d \ --name myapp \ --memory512m \ --cpus1.0 \ -p 8080:8080 \ myapp:v1.0--memory512m限制容器最多使用512MB内存超过就会被内核OOMOut Of Memory杀掉--cpus1.0限制容器最多使用一个完整的CPU核心。这两个参数在实际部署中是安全底线尤其对于自动化拉起的容器没有限制等于埋雷。8.3 常见故障的通用排查思路Docker用久了不可避免会遇到各种启动失败、容器退出、网络不通的问题。排查思路其实有一条主线先看容器层再看镜像层最后看宿主机层。第一步永远是docker ps -a确认容器当前状态。如果容器已经退出用docker logs查看容器内进程的输出如果容器一直处于重启状态说明启动命令或应用进程本身有问题。# 查看容器状态 docker ps -a # 查看容器日志 docker logs --tail 200 container_id # 查看容器详细信息包括挂载、网络、环境变量 docker inspect container_id如果docker inspect里看到挂载目录不存在或者权限错误就用绑定挂载的方式解决如果是docker compose up时端口冲突报错会明确提示“port is already allocated”直接改端口即可。再深层次的问题比如容器启动正常但连接外部失败可以docker exec进入容器内部用ping或curl测试网络连通性。8.4 一些长期使用Docker后形成的小习惯最后分享几个我长期使用Docker后形成的工作习惯算不上什么高深技巧但确实帮我减少了很多重复排障。第一每台机器一装完Docker第一件事就配置镜像源和日志轮转这两个配置能避免后面90%的“慢”和“磁盘满”问题。第二给容器命名永远不用默认的随机名而是按“服务名序号”的规则比如mysql8-primary、redis-cache-01排查时一眼就能认出来。第三启动容器前先想清楚三条数据要不要持久化、端口要不要暴露、资源要不要限制这三个问题都想清楚了再写docker run命令。第四非必要不进入容器内部修改配置容器里的任何修改都会随容器销毁而消失应该把配置通过挂载或环境变量注入。第五docker buildx构建多架构镜像这件事等真的需要部署到ARM服务器时再研究也不迟入门阶段先把单架构构建和Compose编排用好。用Docker这几年我最大的感受是它确实把部署流程极大的简化了但真正让这套技术稳定运行起来的还是对环境细节的敬畏。那些看起来不起眼的权限、网络、数据卷配置才是容器化技术从“能跑”走向“好用”的关键。希望这篇内容能帮你少踩几个坑把更多时间花在业务本身。