资讯动态

Docker容器创建:从镜像到docker run与Nginx实战

发布时间:2026/9/18 7:56:35 来源:尧图企业网站定制
1. 先搞懂镜像和容器到底是什么关系1.1 用“安装包”和“运行中的程序”做类比很多人第一次接触 Docker会被“镜像”“容器”“仓库”这几个词绕晕。我用一个特别土的类比镜像Image就是安装包容器Container就是装好并且正在运行的那个程序。安装包躺在硬盘上不会占 CPU、不会占内存只有当你双击运行它才会变成一个活生生的进程。Docker 也是这个逻辑docker pull把镜像拉到本地docker run才会基于这个镜像创建一个容器并让它跑起来。所以“创建容器”这件事本质上就是告诉 Docker用哪个安装包、给这个程序什么名字、开放哪些端口、挂载哪些目录、要不要开机自启。我刚开始学的时候犯过一个错误以为docker run就是“启动一个已经存在的容器”。其实不是docker run等于创建 启动两个动作合在一起。如果你只想启动一个已经创建但处于停止状态的容器用的是docker start。这个区别特别重要因为很多教程只告诉你敲docker run却没告诉你每敲一次就会多出一个新容器。我实测下来新手最容易出现的状况就是同一个 Nginx 镜像敲了五次docker run结果docker ps -a里躺着五个名字乱七八糟的容器自己都分不清哪个是哪个。所以后面我会专门讲--name和--rm这两个参数它们能帮你省掉大量清理工作。再说得直白一点镜像负责“有什么”容器负责“跑起来”。镜像里包含操作系统的基础文件、运行时环境、你的应用程序代码、依赖库甚至启动命令。容器则是在镜像之上加了一层可写层所有运行时的改动都写在这一层里。你删掉容器可写层就没了镜像本身不会被破坏。这个设计带来的好处是你可以用同一个镜像同时跑十个容器彼此隔离、互不影响。比如同一个 MySQL 镜像你可以跑一个开发库、一个测试库端口不同、数据目录不同它们就是两个完全独立的数据库实例。1.2 创建容器前先确认三件事镜像、端口、数据在敲下docker run之前我建议你花三十秒问自己三个问题能避免八成以上的返工。第一镜像有没有不确定就先docker images看一眼没有就docker pull。第二端口要不要暴露容器内部的服务默认只能容器自己访问外部想访问必须用-p做端口映射。第三数据要不要留下来容器删了数据就没数据库、上传文件、日志这些必须用-v挂载到宿主机目录或者数据卷。这三件事确认完你的docker run命令基本就不会出大错。我见过太多人把 MySQL 容器跑起来往里插了几百条测试数据然后手一抖docker rm把容器删了数据全没。不是 Docker 坑人是没做数据持久化。容器的设计理念就是“无状态、可替换”它默认不负责帮你保存数据。你要把容器当成一次性用品数据放在外面容器随时可以删了重建。理解这一点才算真正入门。所以我在教别人创建容器时一定会先让他们把-v参数练熟而不是急着学 Dockerfile。还有一个容易被忽略的点容器名。不指定--name时Docker 会随机生成一个类似hungry_einstein的名字。自己练习无所谓但在团队环境或者有多个容器时随机名会让你排查问题非常痛苦。我的习惯是项目名加服务名比如blog-nginx、blog-mysql、blog-redis。名字一旦定下来后面进容器、看日志、重启服务都方便。而且容器名在同一个宿主机上是唯一的不能重复这也倒逼你养成规范命名的习惯。1.3 小白最容易混淆的几个概念这里集中澄清几个高频困惑。第一容器不是虚拟机。虚拟机要模拟整套硬件启动慢、占资源多容器共享宿主机内核启动通常一两秒占用就是进程级别。所以你在容器里uname -r看到的内核版本往往和宿主机一样这不是 bug。第二容器里的 root 不完全是宿主机的 root。默认情况下容器内 root 和宿主机 root 的权限并不对等但如果你挂载了宿主机目录又没做用户映射仍然要小心权限问题。第三端口映射不是必须的。只在本机容器之间通信的服务可以放到同一个自定义网络里用容器名互相访问不需要暴露到宿主机。再补充一个docker ps和docker ps -a的区别。前者只看正在运行的容器后者把停止的也列出来。新手经常说“我的容器不见了”其实只是停止运行了-a一看就在。容器停止不等于删除停止后占用的磁盘空间还在日志还在重新docker start就能恢复。真正占空间的是那些Exited很久、你再也不用的容器和悬空镜像定期清理是好习惯但别上来就docker system prune -a那条命令会把没在运行的容器和没被使用的镜像全删掉手快容易出事。2. 环境准备Windows、macOS、Linux 下把 Docker 跑起来2.1 Windows 安装 Docker Desktop 的正确姿势Windows 上最省心的方式是Docker Desktop。去官网下载安装包双击、下一步、重启基本就能用。但这里有几个硬性条件必须满足Windows 10/11 的 64 位专业版、企业版或教育版家庭版需要额外折腾BIOS 里要开启虚拟化Intel VT-x 或 AMD-V系统要启用 WSL2 或者 Hyper-V。很多人卡在启动报错virtualization support not detected就是虚拟化没开或者和 Hyper-V 冲突。我的建议是优先用 WSL2 后端性能和兼容性都更好安装时勾选“Use WSL 2 instead of Hyper-V”即可。如果你用的是 Windows 家庭版也不是不能玩可以走 WSL2 里装 Docker 的路线先在“启用或关闭 Windows 功能”里打开“适用于 Linux 的 Windows 子系统”和“虚拟机平台”重启后wsl --install装一个 Ubuntu然后在 Ubuntu 里按 Linux 的方式装 Docker。这样 Docker 跑在 WSL2 里Windows 侧通过端口访问也没问题。离线安装的场景也存在比如内网机器那就需要提前下载好安装包和 WSL2 内核更新包或者直接在有网机器上导出镜像再拷贝过去但这属于进阶操作小白先把在线安装跑通。Docker Desktop 装好之后托盘会出现一个小鲸鱼图标。第一次启动会问你登不登录账号不登录也能用只是不能推送到公共仓库。设置里我一般会改两个地方一是 Resources 里给足内存和磁盘默认 2GB 内存跑一个 MySQL 就有点紧二是把镜像加速地址配上国内拉镜像会快很多。改完点 Apply Restart等鲸鱼图标稳定不再转圈就说明 Docker 引擎起来了。此时打开 PowerShell 或 CMD敲docker version能看到 Client 和 Server 两段信息才算真正成功。2.2 Linux 上一行命令装 Docker以 Ubuntu 为例Linux 服务器上装 Docker 是我的主战场。最稳的方式是用官方脚本但生产环境我更推荐按官方文档加软件源安装便于后续升级。以 Ubuntu 22.04 为例先更新索引、装依赖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 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-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin装完把当前用户加进 docker 组省得每条命令都 sudosudo usermod -aG docker $USER然后重新登录一次生效。接着启动并设置开机自启sudo systemctl enable docker sudo systemctl start docker sudo systemctl status docker如果你用的是 CentOS、Rocky Linux 或者国产的龙芯平台思路一样只是包管理器和软件源地址不同。龙芯这类架构要注意镜像是否有对应的linux/loong64版本没有的话可以通过--platform指定但前提是应用本身支持。装完先跑docker run hello-world能打印一段欢迎信息就说明引擎、网络、仓库访问全通了。这一步千万别跳过它能一次性验证 Docker 的核心链路是否正常。2.3 验证安装是否成功hello-world 到底干了什么docker run hello-world这条命令看起来简单实际上把 Docker 的核心流程全走了一遍。第一步检查本地有没有hello-world镜像没有就去默认仓库拉取。第二步基于镜像创建一个容器。第三步执行镜像里预设的启动命令打印那段文字。第四步容器退出。你看到的输出里会明确写着 “This message shows that your installation appears to be working correctly.” 这时候再敲docker ps -a能看到一个已经退出的hello-world容器状态是Exited (0)0 表示正常退出。这个过程中你能顺带理解几个概念镜像拉取是分层的输出里的Pull complete一行行往下走每一层都可以被其他镜像复用所以第二次拉别的镜像会快很多。容器退出后默认不会自动删除所以-a才能看到它。如果你加上--rm容器退出后会自动清理适合这种一次性验证场景docker run --rm hello-world我个人的习惯是每到一个新环境先docker version确认引擎在再docker run --rm hello-world确认能拉镜像、能跑容器、能正常退出。两条命令下来环境问题基本就能定位如果docker version只有 Client 没有 Server说明 Docker 服务没起来如果 hello-world 卡在拉取说明网络或镜像源有问题如果创建容器时报权限错误八成是当前用户不在 docker 组。这个排查顺序比上来就装 MySQL 高效得多。3. 创建容器的核心命令docker run 逐参数拆解3.1 docker run 的执行流程docker run是创建容器最核心的命令但很多人只是照抄不知道它内部按顺序做了哪些事。我把它拆成六步第一解析你给的镜像名和 tag本地没有就去仓库拉第二检查镜像的启动配置比如默认命令、工作目录、暴露端口第三在镜像之上创建一层可写层这就是容器第四配置网络、挂载卷、环境变量第五启动容器并执行入口命令第六把容器的标准输入输出接到你的终端或者放到后台。理解这个顺序你就能明白为什么有些参数必须写在镜像名前面比如-p、-v、-e因为它们影响的是创建阶段而不是容器内部的命令。还有一个细节镜像名后面的内容会覆盖镜像里的默认命令。比如 Nginx 镜像默认启动 Nginx你写docker run nginx echo hello容器启动后不会跑 Nginx而是执行echo hello然后退出。新手看到容器“秒退”经常就是这个原因——把本来该给容器的参数写到了镜像名后面。正确做法是所有 Docker 参数放在镜像名之前要传给容器内程序的参数放在镜像名之后。记住这条分界线能少踩很多坑。另外docker run每次都会创建一个全新的容器名字不指定就随机。如果你只是想临时跑个命令强烈建议加--rm退出即删不留垃圾。如果是长期服务就要认真起名字、配重启策略、挂数据卷。我通常把容器分成两类一次性任务型和长期服务型。前者用--rm随用随删后者用-d --restart unless-stopped常驻。分类清楚之后命令怎么写、参数怎么配思路会非常清晰。3.2 最常用的 8 个参数下面这张表是我总结的高频参数几乎覆盖了日常 90% 的场景。建议先记住这八个其他用到再查。参数作用典型写法备注-d后台运行docker run -d nginx不加会占住终端--name指定容器名--name my-nginx同一宿主机唯一-p端口映射-p 8080:80宿主机端口:容器端口-v目录/卷挂载-v /data/html:/usr/share/nginx/html数据持久化-e环境变量-e MYSQL_ROOT_PASSWORD123456初始化配置常用--restart重启策略--restart unless-stopped开机自启靠它-it交互式终端-it ubuntu bash调试用--rm退出即删--rm hello-world一次性任务--network指定网络--network my-net容器间互访这里重点说三个新手最容易写错的。第一-p 8080:80的顺序不能反。前面是宿主机端口后面是容器端口。写成-p 80:8080就会变成访问宿主机 80 转发到容器 8080服务没监听 8080 的话就会报 502 或直接不通。第二-v的路径要用绝对路径。-v data:/app这种写法如果data不是已命名的数据卷Docker 会当成匿名卷处理你以为挂载到了当前目录其实没有。要么写/home/user/data:/app要么先docker volume create data再用-v data:/app。第三-e只是设置环境变量不代表镜像一定会用。具体支持哪些变量要看镜像文档比如 MySQL 的MYSQL_ROOT_PASSWORD、MYSQL_DATABASERedis 的REDIS_PASSWORD需要配合启动参数。3.3 交互式容器与后台容器的区别交互式容器用-it最典型的是docker run -it ubuntu bash。它会给你一个 Ubuntu 容器的 shell你可以像在普通 Linux 里一样敲命令、装软件、看文件。这种容器适合学习和调试但退出方式有讲究敲exit会让容器停止按CtrlP再按CtrlQ则是“脱离”容器让它继续在后台跑。很多人不知道后者每次退出都把容器关了下次还得重来。我刚开始学的时候为了保持一个测试容器不退出甚至专门开着终端不关现在想想挺傻的。后台容器用-d适合 Nginx、MySQL、Redis 这类服务。启动后命令立刻返回只打印一串容器 ID。你可以用docker logs -f 容器名看日志用docker exec -it 容器名 bash进去操作。注意docker exec是进入一个正在运行的容器容器停了就用不了这时候要用docker start先启动或者干脆重新docker run。docker attach也能连回容器但它会把你的终端接到主进程的标准输出上多个终端同时 attach 还可能互相干扰所以我更推荐exec。还有一个组合参数-dit表示后台运行但保留交互能力常用于需要保持标准输入打开的容器比如某些需要交互式初始化的服务。日常使用中服务类容器用-d就够了调试类容器用-it需要后台又保留终端的场景再考虑-dit。把这三个模式分清楚你就能根据场景选择最合适的启动方式而不是无脑复制粘贴。3.4 端口映射和目录挂载的细节端口映射的本质是在宿主机上监听一个端口把流量转发到容器的某个端口。所以宿主机端口不能重复两个容器都想映射 8080 就会报Bind for 0.0.0.0:8080 failed: port is already allocated。排查方法很简单netstat -tulnp | grep 8080或者ss -lntp | grep 8080看谁占了。容器端口则可以重复因为每个容器有独立的网络命名空间。如果你不想暴露到公网可以写成-p 127.0.0.1:8080:80这样只有本机能访问安全性更高。目录挂载要区分绑定挂载bind mount和数据卷volume。绑定挂载直接映射宿主机某个目录比如-v /data/mysql:/var/lib/mysql优点是路径直观、方便备份缺点是依赖宿主机目录结构权限问题也更明显。数据卷由 Docker 管理存储在/var/lib/docker/volumes/下跨平台兼容性好适合数据库这类场景。我的经验是配置文件、代码、静态资源用绑定挂载数据库数据用数据卷。这样既方便改配置又不用担心把数据目录搞乱。权限问题是挂载绕不开的坎。容器里的进程可能以非 root 用户运行比如 Nginx 的 worker 用户如果宿主机目录权限是 root 且没有读权限容器就会报Permission denied。解决办法有几个临时用chmod放开权限但不够安全更好的是用--user指定 UID/GID 启动容器让容器内用户和宿主机目录属主对应上。还有一种常见情况是 SELinux 环境需要在挂载路径后加:z或:Z否则容器读不了。这些细节平时不遇到一遇到就卡半天提前知道能省很多时间。4. 实战从零创建并运行一个 Nginx 容器4.1 拉取镜像先确认 Docker 正常工作然后拉取 Nginx 镜像。你可以直接docker run让它自动拉但我更推荐先docker pull因为拉取过程能看清进度出问题也好定位docker pull nginx:1.25 docker images | grep nginx这里的1.25是 tag也就是版本号。不写 tag 默认是latest但生产环境我不建议用latest因为它会随仓库更新而变化今天跑得好好的明天重建可能就换版本了。锁定具体版本号行为可预期。docker images能看到镜像的仓库名、tag、镜像 ID、大小。你会注意到 Nginx 镜像只有一百多 MB因为它基于 Debian slim 或者 Alpine不是完整的 Ubuntu 桌面系统。这正是容器“小而专”的体现。拉取完成后镜像就在本地了。此时它只是静态文件不占运行资源。你可以用docker inspect nginx:1.25看它的详细配置包括暴露的端口、默认命令、环境变量。这个命令输出很长可以只看关键字段docker inspect nginx:1.25 --format {{.Config.ExposedPorts}} {{.Config.Cmd}}看到map[80/tcp]和[nginx -g daemon off;]就说明这个镜像默认监听 80 端口启动命令是前台运行 Nginx。记住这个信息后面写端口映射和排查问题都用得上。先了解镜像再创建容器这个习惯能让你从“照抄命令”变成“理解命令”。4.2 启动容器并访问接下来创建一个名为my-nginx的容器把宿主机 8080 映射到容器 80并把一个本地目录挂载进去作为网站根目录mkdir -p /home/user/nginx/html echo h1Hello Docker Container/h1 /home/user/nginx/html/index.html docker run -d \ --name my-nginx \ -p 8080:80 \ -v /home/user/nginx/html:/usr/share/nginx/html:ro \ --restart unless-stopped \ nginx:1.25逐段解释一下。-d让它后台跑--name my-nginx起个固定名字-p 8080:80是本机 8080 转发到容器 80-v ...:ro把本地 html 目录只读挂载进去加:ro表示容器内不能改这个目录更安全--restart unless-stopped表示除非手动停止否则 Docker 重启后容器自动起来。执行完会输出一长串容器 ID接着用docker ps curl http://127.0.0.1:8080如果返回你写的Hello Docker Container说明创建、启动、网络、挂载全部成功。浏览器访问http://宿主机IP:8080也能看到同样内容。如果访问不通先docker ps看容器是否 Up再docker logs my-nginx看日志最后检查防火墙和安全组。这个排查顺序能覆盖绝大多数“端口映射了但访问不了”的问题。4.3 进入容器看内部结构容器跑起来之后进去看看能加深理解docker exec -it my-nginx bash进去之后可以执行ls /usr/share/nginx/html能看到你挂载的index.html执行cat /etc/nginx/nginx.conf看默认配置执行ps aux看进程你会发现 Nginx 的 master 进程 PID 是 1。这一点很重要容器里的 1 号进程就是容器的生命线它退出容器就退出。所以启动命令必须前台运行不能写成nginx然后以为它会自动后台。Nginx 官方镜像用daemon off;就是为了让 master 进程保持在前台。你还可以在容器里装个curl测一下容器内部访问apt-get update apt-get install -y curl curl localhost。注意容器里装的软件在容器删除后就没了不会影响宿主机也不会影响镜像。这就是容器“可写层”的概念。如果你想把这些改动固化下来需要docker commit生成新镜像但更规范的做法是写 Dockerfile。小白阶段先用 exec 进去熟悉环境别急着 commitcommit 出来的镜像往往臃肿且不可复现。退出容器时如果只是exit容器不会停因为主进程 Nginx 还在跑。这跟交互式 Ubuntu 容器不一样Ubuntu 容器里你exit1 号进程 bash 退出容器就停了。判断容器会不会停就看 1 号进程是否退出。理解这一点你对容器生命周期的认识就上了一个台阶。4.4 停止、启动、删除容器的正确顺序日常运维就这几条命令顺序搞对不会乱docker stop my-nginx # 停止容器还在 docker start my-nginx # 重新启动 docker restart my-nginx # 重启 docker rm my-nginx # 删除必须先停止 docker rm -f my-nginx # 强制删除运行中也删删除容器前一定要确认数据已经挂载出来。像我们上面的 Nginx网页文件在宿主机目录里删了容器文件还在重新跑一个挂载同一目录就能恢复。但如果没有挂载容器里的改动会随删除一起消失。数据库容器更是如此MySQL 的数据目录必须挂载否则删容器等于删库。我踩过一次坑测试环境 MySQL 没挂载删容器重建后数据全空幸好只是测试数据。从那以后我创建任何有状态容器之前第一件事就是确认-v写对了。清理时可以用docker ps -a找出所有已停止的容器确认无用后再删。批量清理已停止容器docker container prune它会提示你确认删除所有 Exited 状态的容器。但生产机器上慎用因为有些容器只是临时停止你还想docker start恢复。我一般先docker ps -a人工过一遍再决定删哪些。镜像清理用docker image prune删悬空镜像docker system df看磁盘占用做到心里有数。容器用久了磁盘被日志和旧镜像吃掉是常事定期检查比出事再救火强。5. 常见问题与排查实录5.1 端口占用、权限不足、容器秒退容器秒退是最常见的问题。先docker ps -a看状态码如果是Exited (0)说明主进程正常执行完就退出了多半是你把命令写错了比如docker run nginx echo hi。如果是Exited (1)或Exited (137)就要看日志docker logs 容器名。137 通常是 OOM 被杀或者被docker stop强制停止。还有一种情况是容器启动命令需要前台运行但镜像默认命令是后台运行导致 1 号进程退出。解决办法是覆盖启动命令让它前台跑。端口占用的报错很直接port is already allocated。用ss -lntp | grep 端口号找到占用进程要么换端口要么停掉占用进程。Windows 上用netstat -ano | findstr 8080再根据 PID 在任务管理器里找。权限不足常见于挂载目录报Permission denied或Read-only file system。先检查宿主机目录权限和属主再看是否需要--userSELinux 环境加:z。如果是 Docker 命令本身报permission denied那是当前用户不在 docker 组重新登录即可。镜像拉取慢或失败优先检查网络和镜像源。Docker Desktop 在设置里配镜像加速Linux 改/etc/docker/daemon.json加registry-mirrors然后systemctl restart docker。如果公司内网完全隔离就需要把镜像docker save成 tar 包拷过去docker load。离线安装 Docker也是类似思路先准备好安装包和依赖再按顺序装。这些场景平时用不到但一旦遇到就是硬需求知道有这些方案心里不慌。5.2 问题速查表现象可能原因排查命令解决方向容器启动后立刻退出主进程执行完/命令写错docker logs 容器名让主进程前台运行端口映射了访问不了服务没监听/防火墙/绑定地址docker ps、curl 127.0.0.1:端口检查服务、防火墙、监听地址报端口已被占用宿主机端口冲突ss -lntp | grep 端口换端口或停占用进程挂载目录为空路径写错/匿名卷docker inspect 容器名用绝对路径或命名卷权限拒绝目录属主/SELinuxls -l、getenforce调整权限或加:z拉镜像超时网络/镜像源docker pull单独执行配加速源或离线导入容器名冲突已有同名容器docker ps -a改名或删旧容器磁盘占满日志/旧镜像堆积docker system df清理无用容器和镜像这张表建议收藏遇到问题按“现象—原因—排查—解决”四步走比盲目搜索快得多。我自己的习惯是任何容器起不来先看docker ps -a的状态码再看docker logs最后 50 行八成问题能定位。剩下两成再查网络、挂载、权限。排查要有顺序不要东改一下西改一下否则问题没解决还引入新问题。5.3 几个容易踩的坑第一latest陷阱。前面说过生产环境别用latest。我见过一次事故同事用mysql:latest跑数据库某天重建容器镜像更新到了新大版本数据目录格式不兼容直接起不来。锁定版本号升级时显式改 tag才是稳妥做法。第二容器内时间不对。默认容器用 UTC 时间日志时间比北京时间少 8 小时。解决办法是启动时挂载时区文件-v /etc/localtime:/etc/localtime:ro或者设置环境变量-e TZAsia/Shanghai。数据库容器尤其要注意否则排查问题时时间线全是错的。第三日志无限增长。容器日志默认用 json-file 驱动不限制大小跑久了能把磁盘写满。可以在docker run时加日志限制--log-opt max-size10m --log-opt max-file3表示单个日志文件最大 10MB最多保留 3 个。全局默认可以在/etc/docker/daemon.json里配置。这个参数我建议所有长期运行的容器都加上能省掉很多磁盘告警。第四docker-compose up和docker run混用。compose 管理的容器会带项目前缀你用docker run起的容器名可能和它冲突。团队协作时统一用 compose 或者统一用 run别混着来。docker-compose up默认前台加-d才后台改了 compose 文件后docker-compose up -d会重建变化的容器数据卷和网络要提前规划好否则容易出现“配置改了但容器没更新”的迷惑现象。6. 更进一步用 compose 管理多个容器6.1 compose 文件写法当你从“一个容器”走向“一组容器”比如 Nginx 后端 MySQL Redis手敲docker run就太累了而且容易漏参数。这时候用docker-compose.yml把配置写下来一条docker compose up -d全起来。上面那个 Nginx 例子改写成 composeservices: nginx: image: nginx:1.25 container_name: my-nginx ports: - 8080:80 volumes: - /home/user/nginx/html:/usr/share/nginx/html:ro restart: unless-stopped对比一下就能发现docker run的每个参数在 compose 里都有对应字段-p对应ports-v对应volumes--restart对应restart。compose 的价值在于可版本控制、可复用、可一键重建。你把文件提交到代码仓库换台机器docker compose up -d就能还原整套环境。团队里新人入职不用再对着文档一条条敲命令直接拉代码起服务效率完全不一样。再举个 MySQL 的例子顺便把数据持久化和初始化配置写进去services: mysql: image: mysql:8.0 container_name: blog-mysql environment: MYSQL_ROOT_PASSWORD: root123456 MYSQL_DATABASE: blog TZ: Asia/Shanghai ports: - 3306:3306 volumes: - mysql-data:/var/lib/mysql - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro restart: unless-stopped volumes: mysql-data:这里用了命名卷mysql-data数据由 Docker 管理删容器不丢数据。init.sql挂到初始化目录容器第一次创建时会自动执行适合建表、插初始数据。注意docker-entrypoint-initdb.d只在数据目录为空时执行已经有数据了就不会再跑这是很多人“初始化脚本没生效”的原因。6.2 什么时候该用 compose我的判断标准很简单超过一个容器、或者需要反复重建就上 compose。单个临时测试容器docker run --rm足够但只要是长期服务、多个组件有依赖关系、配置需要版本管理compose 就是更优解。它还能定义网络让容器之间用服务名互相访问不用记 IP。比如后端连数据库连接地址直接写mysql:3306compose 会自动做服务发现。再往上走就是 Kubernetes 这类容器编排平台。K8s 解决的是多机调度、自动扩缩容、滚动更新、故障自愈。一个 Pod 里可以放多个容器如果其中一个没起来可能影响整个 Pod 的状态这是 K8s 的调度逻辑。但对小白来说先把单机 Docker 和 compose 玩明白再去碰 K8s基础会扎实很多。容器化的核心不是工具多高级而是你能把应用、依赖、配置、数据这四件事拆清楚。拆清楚了用 run 也好compose 也好K8s 也好都是换汤不换药。最后分享一个我自己的练习路线第一周只练docker run创建各种容器Nginx、Redis、MySQL 各跑一遍重点练-p、-v、-e第二周练docker exec进容器、看日志、排查故障第三周把前面的命令改写成 compose练一键起停和数据持久化第四周再尝试自己写 Dockerfile 把一个小应用打成镜像。每一步都动手做不要只看。我见过太多人收藏了一堆教程真到用的时候连docker ps都敲不利索。容器这东西敲十遍比看一百遍管用。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价