
很多朋友第一次接触 Docker都是从“装个环境跑跑看”开始的。我也不例外早年为了一致的环境折腾过虚拟机换过好几台机器后来发现配置同步本身就是个无底洞。Docker 的“一次构建到处运行”思路某种程度上把环境问题从“反复安装”变成了“拉取即用”这个转变对于我们这种整天跟服务、中间件、部署打交道的人来说确实是省心不少。这篇文字主要针对刚入门的读者会由浅入深地讲清楚几个东西Docker 到底是什么、解决了什么问题、最基本的镜像和容器概念、在不同系统上的安装要点、日常最常用的操作、以及部署 MySQL、Redis 这类中间件时常见的坑。内容偏实操跟着走基本能顺下来。如果你之前踩过“docker 启动失败”“权限不足”“拉镜像慢”的坑这里面也会给到排查思路。1. 先把认知对齐Docker 是干什么的1.1 为什么不用虚拟机很多人在接触 Docker 之前先接触或者听说过虚拟机比如 VMware、VirtualBox。虚拟机给人的第一印象就是“重”一个系统镜像好几个 GB启动还要分配内存和 CPU开机要等半天。我以前在 Windows 上开一个 Ubuntu 虚拟机光启动就得两三分钟占用内存常年维持在 4GB 以上。这还算好的要是同时跑几个磁盘空间直接告急。Docker 的思路完全不一样。它不虚拟整个操作系统而是共享宿主机的内核用“隔离”的方式把进程和资源关在各自的沙箱里。这就有点像把一个大房子隔成一间间独立的小公寓水电来自同一栋楼但每个房间的装修和使用互不打扰。启动一个容器通常只需要一两秒内存占用也可以控制在几十 MB 到几百 MB 之间根本不在一个量级上。本质上Docker 解决的是环境一致性和动态迁移的问题。以前在本机跑得好好的代码到服务器上就出现各种异常大概率是依赖版本不一致或系统路径不兼容。有了 Docker你把代码连同依赖一起打包成镜像在任意装有 Docker 的机器上启动同一个镜像运行结果就是一致的好——同镜像同行为这个特性能让人少很多砸键盘的冲动。1.2 镜像、容器、仓库三个核心概念要用 Docker第一步就是弄清楚三个概念。镜像Image一个只读的模板类似软件的安装包。它包含了运行应用所需的代码、运行时、系统库、环境变量和配置文件。你从仓库拉取或者自己构建得到的就是镜像。容器Container镜像运行起来后的实例。一个镜像是静物容器则是活物——有进程在跑有文件读写可能还有网络端口在监听。一台机器上可以同时跑多个容器彼此隔离通过端口或网络互通。仓库Repository集中存放镜像的地方最出名的是 Docker Hub。仓库下载镜像像用 apt 或 pip 安装软件一样有官方维护的版本也有个人上传的第三方版本。你可以把构建好的镜像推到自己的仓库也可以从公共仓库拉取别人做好的现成镜像省去重新造轮子的时间。把这三个概念连起来工作流通常是从仓库拉镜像 → 基于镜像启动容器 → 容器内运行应用 → 对外提供服务。如果你改了镜像里的配置一般不建议直接改容器里的东西而是基于新状态用docker commit生成新镜像或者更优雅的方式是写 Dockerfile 重新构建确保整个流程可复现。1.3 镜像与容器的关系以及层镜像不是一个大文件而是由多个只读层叠加而成的。每一层代表 Dockerfile 中的一条指令层与层之间有缓存和复用的机制。比如你在两个不同的镜像里都用FROM ubuntu:22.04那么这层 Ubuntu 的基础库会被复用而不是重复存储。这也是为什么 Docker 镜像动辄几百 MB但在本地使用同一份基础层时实际磁盘占用会比想象中少。容器运行的时候Docker 会在镜像层之上挂载一个可写层所有运行时的修改装包、写文件、改配置都会发生在这个可写层。容器停止或删除后这个可写层默认还会保留一段时间但如果你用的是-rm参数一次性容器容器一停可写层就随之清空。这个机制有时候会坑人——你以为数据写进“盘”里了其实写进了容器层容器一删数据就没了。后面讲 MySQL 数据持久化的时候会专门说这个话题。提示把镜像理解成“制作披萨的冷冻面团”层就是面粉、酵母、调料这些原料分层堆叠容器就是烤好的披萨经过加热运行后可以直接吃提供服务。面粉本身不会变但每次加热后面团的形态和口感都可能不同——可写层就是容器运行后产生的变化。2. 安装与启动Windows、Linux 下的实操要点2.1 Windows 上安装 Docker DesktopWindows 上现阶段最主流的安装方式就是 Docker Desktop。它自带一个轻量级虚拟机做底层支撑也支持 WSL 2 后端日常开发够用了。安装包可以从 Docker 官网下载需要注意版本和系统版本匹配Windows 10 需要 2004 及以上版本Windows 11 基本都能装系统比较老的建议先确认是否满足 64 位、CPU 支持虚拟化、内存不少于 4GB。安装过程中有几个容易踩的坑WSL 2 未启用。Docker Desktop 新版默认依赖 WSL 2没启用的话会提示“WSL 2 installation is incomplete”。解决方法是先用管理员身份打开 PowerShell执行wsl --install装完重启再执行wsl --set-default-version 2。国内网络环境下WSL 内核下载可能缓慢或超时可以手动下载 WSL2 内核更新包安装。BIOS 里没打开虚拟化。这个是最常见的启动失败原因报错通常会写“virtualization support not detected”或者“Docker Desktop failed to start because virtualisation support wasnt detected”。判断方法打开任务管理器 → 性能 → CPU看右下角“虚拟化”是否显示“已启用”。如果没有需要重启进 BIOS/UEFI 设置找到 Intel VT-x 或 AMD-V 相关的选项并打开。不同主板路径不同华硕一般在 Advanced → CPU Configuration技嘉直接搜“VT-d”或“SVM Mode”部分戴尔/联想机型有专门的“Virtualization Support”标签。Hyper-V 和 VMware 的冲突。如果你同时装过 VMware Workstation/Player偶尔会遇到两者冲突的情况。解决办法取决于使用优先级要么在 Windows 功能中开启 Hyper-V 后继续用 Docker Desktop要么放弃 Hyper-V 后端改用 WSL 2 后端兼容性更好。我个人现在基本都是用 WSL 2 模式VMware 和 Docker 同时跑也算安稳。装好之后在终端敲docker --version能输出版本号就说明 Docker 客户端已经就绪。接下来建议马上执行docker run hello-world如果出现一段英文提示Hello from Docker!说明整个链路已经通了。2.2 Linux 下安装 Docker EngineLinux 上没有 Docker Desktop 也能直接用 Docker安装方式也比较多。最常见的是通过官方脚本或者发行版自带的包管理器。以 Ubuntu 22.04 为例我更推荐先更新索引、安装必要依赖再添加官方 GPG 密钥和软件源。虽然步骤多一点但能保证拿到官方最新版本也方便之后通过 apt 升级。具体命令序列大致是这样sudo apt update sudo apt install ca-certificates curl gnupg lsb-release sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo deb [arch$(dpkg --print-architecture) 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 update sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin如果机器在国内官方源可能拉不动可以把软件源换成阿里云或清华源的 Docker CE 镜像地址。安装完成后不要急着用先启动并设置开机自启sudo systemctl enable docker sudo systemctl start docker sudo systemctl status docker看到 active (running) 就说明 Docker 守护进程已经在跑了。2.3 启动失败与权限问题排查Linux 下跑 Docker刚安装完最容易遇到两类问题权限问题。直接执行docker ps会提示permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock。这是因为默认情况下只有 root 用户和 docker 用户组能访问 Docker socket。一般做法是把当前用户加进 docker 组sudo usermod -aG docker $USER newgrp docker重新开一个终端再执行docker ps就不需要 sudo 了。注意加完组之后如果还是报权限错误先确认当前终端是否真的刷新了用户组信息很多人会在这里犯迷糊。服务启动失败。用sudo systemctl start docker后提示Job for docker.service failed because the control process exited with error code时先别慌看日志才是关键sudo journalctl -xeu docker.service常见原因无非这几类iptables 规则冲突如果你之前手动改过防火墙规则Docker 默认要操作 iptables NAT 表可能会因为权限或规则顺序问题启动失败。可以临时将 Docker 的 iptables 策略改为 false 试试但不推荐长期关闭会影响容器网络出口。存储驱动不匹配overlay2 通常是首选存储驱动某些老内核或特殊文件系统下会回退到 vfs性能下降明显。检查一下docker info里的 Storage Driver 字段即可。selinux 阻止主要在 CentOS/RHEL 系报错里出现SELinux is not supported或者“permission denied”时考虑临时用setenforce 0验证如果有效就把 selinux 对 docker 目录的 context 配好。提示排查启动失败永远记住“先看日志再动配置”。journalctl和docker logs是两把最趁手的镰刀不看原因就瞎改配置只会把简单问题变成薛定谔式问题——玄学般时而好时而坏。3. 日常实操镜像拉取、容器启停、端口与数据卷3.1 镜像加速解决“拉取慢”的问题新手入门踩得最多的坑其实就是“docker pull nginx 半天不动”。Docker Hub 服务器在国外国内直连的速度只能说随缘。解决办法无非三种把默认 registry-mirror 配成国内镜像加速地址。直接从一些云厂商的镜像仓库拉取比如说阿里云个人版镜像加速器或者腾讯、网易的镜像服务。用代理环境拉取不过很多地区开代理也不稳定反而常遇证书问题。配 registry-mirror 的方式主要是修改 Docker 客户端的 daemon 配置在/etc/docker/daemon.json中追加内容{ registry-mirrors: [ https://your-mirror-url ] }然后重启 Dockersudo systemctl restart docker。如果你用的是 Docker Desktop在 Settings → Docker Engine 里直接改 JSON 也等效。不同镜像加速地址的稳定性和时效性各不相同有的过段时间就失效了。我的经验是官方源依然是兜底方案加速器只是辅助不建议把加速地址当作永久依赖。另外很多云厂商的加速器要求你注册登录后才分配专属地址这里就不安利具体平台了网上搜“Docker 镜像加速”最新文章即可。3.2 镜像是基础常用命令与清理先记住一组最基础的镜像命令之后所有操作都围绕它们展开。docker pull 镜像名:标签拉取镜像。不写标签默认 latest。docker images列出本地已有镜像。会显示仓库名、标签、镜像 ID、创建时间和大小。docker rmi 镜像ID或名称删除本地镜像。需要注意镜像被运行中的容器引用时不能直接删除。docker tag 原镜像 新仓库/新标签给镜像打标签常用于自己构建的镜像准备推送仓库前。容器层面也用得频繁docker ps列出正在运行的容器。docker ps -a列出所有容器包括已停止的。docker run [参数] 镜像基于镜像启动一个新容器。docker start/stop/restart 容器ID管理容器生命周期。docker rm 容器ID删除容器。docker exec -it 容器ID bash进入一个正在运行的容器内部打开终端。新手很容易把docker ps误认为“列出所有镜像”因为名字太像了。这里有个小技巧ps这个词沿袭自 Linux 的“查看进程”所以它看的是容器进程层面的实例不是镜像静态文件。强行记忆不如实际操作几次来得快。3.3 端口映射让容器外的访问生效容器默认有个隔离网络宿主机无法直接访问容器内的服务。要让外部访问容器里的 MySQL、Redis、Web 应用就需要做端口映射。最常用的格式是-p 宿主机端口:容器端口。比如拉一个 Nginx 镜像并把它跑起来docker run -d --name my-nginx -p 8080:80 nginx这条命令的意思是后台运行名为 my-nginx 的容器把宿主机的 8080 端口映射到容器内的 80 端口。之后浏览器访问http://localhost:8080就能看到 Nginx 欢迎页。有个很容易混淆的点-p 8080:80里冒号前面的端口是宿主机听着的后面的端口是容器进程真正监听的别搞反。如果你手头已有多个容器同时监听 80 端口宿主机端口必须各不相同否则后启动的容器会因为端口冲突直接报错。反之如果宿主机端口已被别的进程占用比如你自己起了个 8080 的 Spring Boot 应用Docker 也会启动失败。3.4 数据卷别让数据跟着容器“陪葬”之前提到容器删除后可写层默认也没了。如果你把 MySQL 的数据文件直接写在容器内部那每次删容器重建数据就人间蒸发。生产环境这么干基本等于自杀。解决方案是数据卷Volume。Docker 支持两种常见用法命名卷docker run -v mydata:/var/lib/mysql mysql:8.0数据由 Docker 管理存放目录在宿主机某个特殊路径下。绑定挂载docker run -v /宿主机路径:/容器路径直接把宿主机某个目录映射进容器数据文件对你完全可见可备份。我一般偏向绑定挂载因为排查问题方便备份也直观。比如部署一个 MySQL这样写docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDroot123 \ -v /data/mysql8:/var/lib/mysql \ mysql:8.0这样宿主机/data/mysql8下就是 MySQL 的数据文件容器删了重建只要挂载同一个目录数据就还在。注意-v挂载目录时如果宿主机路径不存在Docker 有时会自动创建目录但有些场景下它创建的目录属主是 root导致容器内进程没权限写数据。至少对 MySQL 这类应用建议先手动mkdir -p /data/mysql8 chown -R 998:998 /data/mysql8MySQL 官方镜像的运行用户 UID 是 999不同镜像版本可能不一样免得启动时各种权限报错。4. 典型实战安装 MySQL 8.0 与 Redis 主从4.1 部署 MySQL 8.0并解决常见失败MySQL 是 Docker 新手最常用来练手的中间件之一。搜索热词里反复出现“docker 安装 mysql 失败”和“docker 安装 mysql8.0 并使用”可见坑不少。我把最常见的失败原因归一下类端口冲突宿主机 3306 已经被本机 MySQL 或另一个容器占用启动就会报Bind for 0.0.0.0:3306 failed: port is already in use。要么停掉旧的要么换映射端口比如-p 3307:3306。密码设置问题MySQL 8 默认的密码策略比较严格设置的密码太简单比如 123456即使容器能启动也会在初始化时因为密码校验过弱而报错容器会反复重启。建议直接用MYSQL_ROOT_PASSWORD设一个复杂度要够的密码比如Root_123456!。数据目录权限问题挂载了宿主机目录但没调权限MySQL 初始化时无法写入文件容器日志里会看到一堆chown: changing ownership of /var/lib/mysql: Operation not permitted。除了手动 chown也可以先不挂载数据目录让它初始化成功后再用docker cp把数据复制出来但操作链要复杂不少。容器初始化时间MySQL 首次初始化需要一点时间刚启动就急着练客户端连接大概率会报Cant connect to MySQL server on 127.0.0.1 (111)。判断是否就绪可以看日志里有没有ready for connections或者直接docker logs 容器ID查看。成功启动后要访问容器内的 MySQL 有两种路径宿主机安装mysql客户端直连或者直接进入容器内用自带的客户端docker exec -it mysql8 mysql -uroot -p输入密码后就能进到 MySQL 命令行。另一种方式是在宿主机用mysql -h127.0.0.1 -P3306 -uroot -p访问前提是宿主机已装客户端。Windows 上没装客户端的话进入容器是最省事的方式。4.2 Redis 主从从单实例到主从复制Redis 也是 Docker 里非常好部署的服务之一。单节点只需要一行命令docker run -d --name redis \ -p 6379:6379 \ -v /data/redis:/data \ redis:7.0Redis 镜像是带配置启动的默认没有密码生产环境第一件事就是记得加上--requirepass或配置文件中设置密码。容器内启动命令可以追加参数docker run -d --name redis \ -p 6379:6379 \ -v /data/redis:/data \ redis:7.0 redis-server --appendonly yes --requirepass mypassword如果只是单点使用到这里就结束了。热词里有“docker 安装 redis 主从”说明很多人想搭一个简单的 Redis 主从复制练手或者为后面做哨兵和集群预热。Docker 下做主从麻烦在于容器间网络最简单的方式是让容器跑到同一个自定义网络里。创建一个 Docker 网络docker network create redis-net然后分别启动主节点和从节点都挂到redis-net网络从节点启动时加--replicaof参数并指定主节点的主机名docker run -d --name redis-master \ --network redis-net \ -p 6380:6379 \ redis:7.0 redis-server --appendonly yes --requirepass masterpass docker run -d --name redis-slave \ --network redis-net \ -p 6381:6379 \ redis:7.0 redis-server --replicaof redis-master 6379 --masterauth masterpass --requirepass slavepass进入从节点容器执行info replication看到role:slave且master_link_status:up说明主从已经建立。这里有个隐藏知识--replicaof的副本级别信息是实时同步的你在主节点执行set操作从节点能立刻看到验证方式就是分别在两个节点执行get同一个 key。严格来说纯主从复制是“半高可用”——主挂了从节点只有数据不能自动提升。生产环境要用 Redis Sentinel 做自动故障转移或者直接用 Redis Cluster。主从倒是在读写分离场景挺好用的。4.3 轻量级编排工具Docker Compose当你开始跑 MySQL Redis 后端服务 前端 Nginx 这种组合时用几十条docker run命令管理会非常痛苦。Docker Compose 就是做“多容器编排”的用一个 YAML 文件描述整套服务镜像、端口、数据卷、环境变量、依赖关系然后一条docker compose up -d全部拉起。一个简单的docker-compose.yml示例services: mysql: image: mysql:8.0 container_name: mydb restart: always environment: MYSQL_ROOT_PASSWORD: Root_123456! ports: - 3306:3306 volumes: - /data/mysql:/var/lib/mysql redis: image: redis:7.0 container_name: myredis restart: always command: redis-server --appendonly yes --requirepass redispass ports: - 6379:6379 volumes: - /data/redis:/data app: build: . container_name: myapp restart: always ports: - 8080:8080 depends_on: - mysql - redis看到没有容器之间通过服务名互相访问比如 Java 应用里连接 MySQL 的 host 可以写mysql而不是 IP 地址。Compose 帮我们省掉了自定义网络的繁琐步骤服务名即主机名。Compose 还能串起构建流程build: .表示当前目录的 Dockerfile 会参与构建改完代码后执行docker compose up -d --build就能自动重新构建并更新容器。热词里有“docker compose 安装”“docker compose 安装 gitlab”之类的其实就是借助 Compose 把原本参数巨多的docker run命令沉淀成可版本化的配置文件以后新机器上一条命令拉起整套环境不用再翻历史命令记录了。4.4 另外一个例子用 Docker 部署 Kodbox 这类“多功能网盘”热词里有“docker部署kodbox”Kodbox可道云是一个私有网盘 / 在线文档管理系统很多家庭用户或小微企业喜欢用 Docker 部署它。一般做法是Nginx PHP Kodbox 本体 数据库Compsoe 编排。官方文档里通常都会给一份现成的docker-compose.yml你只要把数据卷挂载路径和端口改一改docker compose up -d就能跑起来。Keodbox 这类应用有个特点文件上传和下载依赖 PHP 容器和存储目录的权限配合。挂载目录的属主不对会导致上传失败、文件不可写之类的“玄学”问题。我之前遇到过Kodbox 界面能正常登录但一传大文件就报“磁盘写入失败”。排查很久才发现是宿主机挂载目录的权限属主是 rootNginx/PHP 进程在容器内以 www-data 用户运行没有写权限。解决办法就是找到镜像内 www-data 的 UID然后对宿主机目录执行chown -R。这个案例的价值在于很多 Docker 部署问题本质上是“权限上下文”和“挂载目录属性”的问题而不是镜像本身的问题。打日志、看报错、查权限这三板斧能解决 90% 以上的容器部署疑难杂症。5. 网络、存储与架构从单容器走向集群5.1 五种网络模式各有什么用途Docker 自带的网络模式主要有五种实践中最常用的是 bridge、host、none、container 和 overlay。你可能觉得网络这块离入门太远但“docker 网络不通”可是搜索热词里的高频条目说明问题并不少见。bridge 模式默认模式容器通过虚拟网桥docker0与外网通信并获得一个内部 IP。多个容器如果在同一个 bridge 网络里可以直接用容器名互相访问。host 模式容器不再做网络隔离直接使用宿主机的网络栈。性能好、无 NAT 转换但端口直接暴露在宿主机上容易冲突。生产环境偶尔直接用调试时也方便。none 模式容器没有网络。适合跑一些也不需要网络的批处理任务或者当纯计算单元使用。container 模式容器与另一个容器共享网络栈。典型场景是 Grafana 和 Prometheus 在同一网络命名空间下用 localhost 相互访问相当于省了一次映射。overlay 模式跨主机通信用的多用于 Docker Swarm 或 Kubernetes 这类集群方案。入门阶段可以先不管。网络不通最常见的原因不在模式上而是容器启动顺序和网络连接问题容器没加入自定义网络或者服务之间用了 IP 而不是服务名。一旦 IP 变了容器重建会分配新 IP服务就断连。所以我的建议是业务容器尽量用自定义网络 容器名访问不要写死 IP。5.2 容器状态机生命周期管理背后的原理容器是个有状态的生命体状态机大致是created → running → paused → stopped → deleted。新手最容易困惑的是“容器已经停了为什么docker ps看不到但docker ps -a还能看到”。这涉及 Docker 的设计哲学容器默认不会自动删除除非你当初给了--rm参数。停止的容器会保留可写层方便你再次启动继续使用。如果你确定这个容器不会再用了再手动docker rm删除。很多人在清理环境时发现磁盘占用爆表多半就是一堆停止容器没删镜像也没清理。清理系统有一个比较安全的命令组合docker container prune docker image prune -a前者清理所有停止运行的容器后者清理未被容器引用的悬空镜像。执行前建议先确认因为删除操作不可逆。5.3 存储驱动的选择与注意点存储驱动决定了镜像层和容器可写层在宿主机上怎么存放。对 Linux 来说overlay2 是默认且最优的选择。Windows 因为文件系统差异Docker Desktop 底层用的是别的机制一般不用管。如果你不确定当前环境用的是什么存储驱动执行docker info就会输出。若看到 vfs大概率是内核或者文件系统原因导致 overlay2 不可用。vfs 模式磁盘占用高、性能差很多应用容器跑起来奇慢无比问题可能就出在这里。生产环境建议优先排查内核版本和文件系统类型ext4/xfs 都可以再考虑重置 Docker 数据目录。注意Docker 数据默认存在/var/lib/docker。如果系统盘空间紧张可以通过配置>sysctl net.ipv4.ip_forward如果输出 0就需要在/etc/sysctl.conf中设置net.ipv4.ip_forward1并执行sysctl -p。这个问题在 KVM 虚拟化的 VPS 上尤其常见因为它默认关闭包转发。8. 几件不起眼的“小事”影响体验但常被忽略最后分享几个入门阶段经常被忽略的小点都不是什么高深技术但真的能影响日常使用体验。第一容器名别乱用特殊字符。容器名最好只用字母、数字、下划线、连字符尽量简短。以前我用点号连接服务名结果某些工具解析容器名时各种怪问题后来全改成短横线才消停。第二要养成打标签tag的习惯。镜像只用 latest 标签时间一长就分不清哪个是生产版本、哪个是测试版本。生产环境建议固定镜像版本比如mysql:8.0.32不要用 latest否则哪天重新拉镜像版本已经变了行为也变了排查问题时想死的心都有。第三谨慎使用docker exec直接修改容器内文件。你可以把容器想象成一次性的运行环境改完的东西不写进镜像重建后就没了。正确的做法是改 Dockerfile、改配置映射、或者把修改通过新构建固化到镜像里。除非你只想“临时看看”否则别在容器里手工改这改那。第四窗口太多时记得清理。docker ps刷出来的容器数量如果超过几十个先别急着逐个删用docker ps --filter statusexited批量清理停止容器。删除前先看一眼哪些是有价值的命名容器别把要留的测试环境一锅端了。9. 一点个人体会用了几年 Docker 之后我对它的定位已经不再是“一个装环境的小工具”而是一种思考方式——把应用和环境打包成可复用的单元让交付、测试、扩容都围绕这个单元展开。入门阶段不需要一头扎进所有高级特性先学会“拉镜像、跑容器、改端口、挂数据卷、看日志”这五个动作很多东西就能顺起来。刚开始踩几次坑其实不是坏事。被权限问题气过、被磁盘占满坑过、被数据丢失吓过后面再遇到类似问题你至少知道先去哪儿翻日志、去哪个方向找原因。技术这东西实践过、跌过跟头才算真正学会。希望这篇指南能帮你把第一个容器跑起来把第一批问题排查顺。后续如果遇到 Compose 编排、镜像构建、CI/CD 集成这些进阶内容咱们可以再展开聊。