ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Docker容器操作实战:从镜像管理到MySQL部署与排错

Docker容器操作实战:从镜像管理到MySQL部署与排错 如果你刚接触 Docker大概率会被一大堆命令搞得头晕。网上教程东一个西一个今天拉个镜像、明天跑个容器真正遇到问题又不知道从哪里排查。这篇博文不聊虚的直接围绕 Docker 最核心的容器操作展开从安装、镜像管理、容器生命周期到实战部署 MySQL再到常见报错排查一条线串下来让你看完就能在自己机器上折腾起来。Docker 能解决什么问题简单说就是“环境一致性”。以前你本地跑得好好的上了服务器就挂多半是环境差异导致。Docker 把应用和它依赖的环境打包成镜像启动成容器后哪里跑都是同一套环境。这个技能无论你是开发、测试还是运维基本都是刚需。文章适合刚入门、用过但不熟、想系统梳理 Docker 基础操作的人也适合从零开始搭环境的新手照着步骤执行即可。1. 先搞懂 Docker 在干嘛镜像、容器、仓库三件套很多人都听说过 Docker 三大概念镜像、容器、仓库。但要说清楚它们之间的关系还是拿现实里的东西打比方最直接。镜像Image就是模板相当于做饭的菜谱加冷冻食材包。你拿到一个镜像里面已经包含了一个操作系统的最小环境、运行代码所需的依赖、配置文件和启动命令内容只读不可修改。容器Container是基于镜像创建出来的运行实例相当于你按照菜谱真正做出来的一道菜。同一份镜像可以多次启动生成多个互不影响的容器每个容器里的数据变更只存在于自身不会污染镜像本身。仓库Repository的作用和代码仓库更像就是专门存镜像的地方。Docker Hub 是官方默认公共仓库我们日常用的docker pull nginx就是从 Docker Hub 拉取 nginx 官方镜像。为什么这个机制很优雅因为打包好的镜像可以到处分发。开发者在本地构建镜像推送到仓库测试或生产只要拉取同一份镜像就能跑起来彻底绕开了“在我机器上明明是好的”这类尴尬现场。有一个点很多人会忽略容器是易失的。容器被删除后内部产生的文件、数据库数据都会跟着消失。所以部署有状态应用比如 MySQL、Redis、GitLab时一定要把数据目录挂载到宿主机也就是后面会讲到的 Volume 挂载。新手最容易踩的坑就是辛辛苦苦启动了一个 MySQL 容器往里面建了库结果容器一删数据全部归零整个人都懵了。理解镜像与容器的关系是掌握容器操作的第一步也是后续所有命令的基础。2. 安装与初始配置选对姿势后面才省心Docker 的安装本身不难但不同操作系统差异挺大而且很多坑是在安装完之后才出现的比如后台服务起不来、镜像拉不动。先说说选型逻辑。2.1 桌面版和命令行版怎么选如果你用的是 Windows 或 macOS日常开发推荐直接装 Docker Desktop。它自带图形界面带 Docker Engine、Kubernetes 集成、卷管理和资源监控对新手非常友好。Windows 下它依赖 WSL2 或 Hyper-V 做虚拟化后端装之前记得先在 BIOS 里确认虚拟化已开启否则启动时会直接报virtualization support not detected或者Docker Desktop failed to start。Linux 环境则建议装命令行版也就是 Docker Engine因为服务器上基本没有图形界面Desktop 反而不合适。Ubuntu / Debian 可以通过官方 apt 源安装CentOS / RHEL 用 yum / dnf。这里不贴具体发行版的逐行安装命令因为官方文档已经很清晰大家搜索“Ubuntu 安装 Docker”时优先看 docs.docker.com 的原文避免被第三方教程里过时的源带偏。2.2 推荐立刻做的三个初始配置装完之后别急着拉镜像先做三个事配置镜像加速、把当前用户加入 docker 用户组、确认 Docker 服务自启动。镜像加速这个事国内用户几乎必做。因为 Docker Hub 的默认访问链路不稳定直接拉镜像经常超时。你需要在 Docker 的 daemon.json 文件里配置 registry-mirrors例如{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com ] }配置完重启 Docker 服务再拉镜像的速度会有明显提升。这个文件在 Linux 下位于/etc/docker/daemon.jsonWindows Desktop 则在 Settings - Docker Engine 里编辑。注意抓取自用别把加速地址当成私有仓库用。用户组权限的事容易被忽略。Linux 下执行 Docker 命令默认需要 root 权限每次加sudo又很麻烦。执行以下命令把当前用户加入 docker 组sudo usermod -aG docker $USER退出当前终端重新登录一次就能免 sudo 执行 docker 命令了。服务自启动则用systemctl enable docker不然机器重启后还得手动拉起来。2.3 快速验证环境是否可用配置完成后执行docker version docker info docker run hello-worldhello-world是一个超小的测试镜像能正常跑出信息就说明整个环境链路是通的。如果docker run hello-world拉取超时那基本就是镜像加速配置没生效先回头检查daemon.json再继续。到这里环境准备完毕。接下来的容器操作都是在这样的基础上进行的。3. 镜像操作的核心命令拉取、查看、删除、导入导出镜像管理是容器操作的前置步骤。没有镜像容器就是无源之水。很多新手一上来就docker run发现本地没有镜像时Docker 会自动帮你从仓库拉取但这样很容易忽略镜像的版本管控和占用空间问题。3.1 拉取镜像时如何选择版本docker pull是最基本也是用得最多的命令。语法是docker pull [选项] 仓库地址/镜像名:标签镜像名后面的 tag 就是版本号。比如mysql:8.0代表 MySQL 8.0 系列的某个具体版本。很多人不写 tag直接docker pull mysql默认拉取的是latest标签。这在实际开发中很容易踩坑latest是滚动更新的今天拉的和三个月后拉的可能不是同一个版本线上环境全凭运气早晚出事。我的习惯是所有生产环境相关镜像必须指定明确版本号例如mysql:8.0.36保证可复现。另外拉镜像之前可以用docker search快速搜索镜像名称或者直接去 Docker Hub 网页端查看 tag 列表避免凭记忆敲错版本名。3.2 离线环境怎么搬镜像有些企业内部环境完全与外网隔离没法在线拉镜像。这时docker save和docker load就是救命稻草。在能联网的机器上拉取镜像然后导出为 tar 包docker save -o mysql8.tar mysql:8.0.36将 tar 包拷贝到离线机器导入docker load -i mysql8.tar导入完成后用docker images验证是否成功。这个方式同样适用于把镜像从测试机搬到生产机比在目标机器上重新构建要快得多也避开了构建时依赖网络的问题。3.3 镜像占空间了怎么办docker images命令列出本地所有镜像会显示 REPOSITORY、TAG、IMAGE ID、SIZE 等字段。你经常会发现同一镜像的不同 tag 占了好几个 G比如ubuntu和ubuntu:22.04如果内容完全一样只是标签不同是可以直接删掉不用的那个的。删除镜像用docker rmi 镜像名:标签 docker rmi 镜像ID注意如果有容器正在使用某个镜像docker rmi会直接拒绝因为镜像被容器引用着。得先删除容器或者不删容器只删镜像时不带-f就不会误删避免强制删除导致内部引用错乱。另外推荐定期执行docker image prune这个命令会把所有悬空镜像没有 tag 且不被容器引用的镜像一次清理干净。启动过很多容器、反复构建过镜像的机器上悬空镜像积累速度惊人有些能占十几个 G 空间。4. 掌握容器生命周期从创建到销毁镜像只是模板真正跑起来的是容器。这一节是容器操作的核心也是面试和工作里考得最多的部分。4.1 docker run 的常用参数启动容器用docker run但裸用docker run nginx其实没啥意义因为前台启动后终端就卡住了。实践中通常要组合几个关键参数docker run -d \ --name web \ -p 8080:80 \ -v /opt/web:/usr/share/nginx/html \ nginx:1.25逐个解释一下-d后台运行容器终端不阻塞。不加的话日志会直接打到当前终端CtrlC 会停掉整个容器。--name给容器一个固定名字后续操作就不用查随机生成的 ID。-p 宿主机端口:容器端口把容器内部的端口映射到宿主机。比如上面命令里宿主机的 8080 端口转发到容器内的 80 端口浏览器访问http://localhost:8080就能看到 Nginx 默认页。-v 宿主机目录:容器目录目录挂载。容器里的/usr/share/nginx/html目录和宿主机的/opt/web目录共享同一份数据你在宿主机改文件容器里立刻同步。这三个参数是最基础的。此外还有几个高频参数参数作用典型场景--restartalways容器异常退出自动拉起数据库、网关等核心服务-e KEYVALUE传入环境变量MySQL 的 root 密码、应用配置项--networkhost容器直接使用宿主机网络对网络性能要求高的场景--link 容器名让容器访问另一个容器老方法新项目建议用 network早期容器互通4.2 容器的一生启停、进入、日志、删除启动完之后日常操作主要围绕下面几个命令docker ps查看正在运行的容器docker ps -a连已经停止的也列出来。docker exec -it 容器名 bash进入容器内部在容器里执行命令。-it表示交互式终端bash是打开的 shell。容器里有的镜像没有 bash就用sh。docker logs -f 容器名实时查看容器日志。排查问题第一件事永远是看日志不要盲猜。docker start 容器名启动一个已停止的容器docker restart则是重启容器常用于加载新配置或恢复卡死进程。docker stop 容器名优雅停止容器docker kill强制杀死。stop 会留出时间让程序处理收尾工作kill 则直接终止。docker rm 容器名删除已停止的容器。注意运行中的容器需要先 stop 再 rm或者直接docker rm -f强制删除。这里有个非常重要的操作顺序进入容器后你改了什么只在当前容器内生效不会写回镜像。如果你希望把改动保存成一个新镜像需要执行docker commit 容器名 新镜像名:标签但说实话docker commit是很多老手不推荐的操作因为它破坏了镜像构建的可重复性也不可审计。我们更推荐用 Dockerfile 来固化变更流程这也是容器操作进阶的关键方向——用“代码化”的方式管理环境而不是靠手工进容器敲命令。4.3 最常用的生命周期连招实操中有一个高频场景拉取一个新版镜像替换运行中的旧容器。流程是docker pull nginx:1.26 docker stop web docker rm web docker run -d --name web -p 8080:80 nginx:1.26为什么不停下来直接更新因为容器本身是不可变实体更新等价于用新镜像重新创建一个新容器这也是“容器操作”思维和传统服务器运维不一样的地方。你不需要在容器里修修补补而是直接换一个“全新机器”。5. 实战一把部署 MySQL 8.0 并完成使用前配置光讲命令没意思用一个最常见的真实场景串起来部署 MySQL 8.0 并用容器跑一个业务库。这个场景基本涵盖了镜像拉取、数据卷、端口映射、环境变量、容器启停等核心点。5.1 拉取镜像并规划数据目录先用严格版本号拉取镜像docker pull mysql:8.0.36接着规划宿主机上的数据目录MySQL 容器默认把数据写在/var/lib/mysql如果不挂载容器删除后数据全丢。我习惯先创建宿主机的目录mkdir -p /data/mysql8/{data,conf,logs}data存放数据文件conf准备放自定义配置logs放错误日志分目录管理后续备份和排查都清晰。5.2 启动容器时关注这几个细节启动命令docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDYourStrongPass \ -v /data/mysql8/data:/var/lib/mysql \ -v /data/mysql8/conf:/etc/mysql/conf.d \ -v /data/mysql8/logs:/var/log/mysql \ --restartalways \ mysql:8.0.36MYSQL_ROOT_PASSWORD是 MySQL 官方镜像识别的环境变量没有它容器会启动失败。挂载目录按上面规划的来日志和数据分开比较合理。加上--restartalways这样机器重启后 MySQL 自动跟着起来省去每次手工启动的麻烦。启动后用docker ps确认状态为 Up。如果发现秒退大概率是配置或权限问题立刻用docker logs mysql8查看错误。常见原因包括目录权限不足、已有旧数据目录和新版本不兼容、3306 端口被占用等。5.3 连接进入实例并完成修改容器启动成功后进入容器操作 MySQLdocker exec -it mysql8 mysql -uroot -p输入我们设置的密码进入 MySQL 交互界面就可以执行建库建表了CREATE DATABASE demo_db DEFAULT CHARACTER SET utf8mb4; CREATE USER app% IDENTIFIED BY AppPass123; GRANT ALL PRIVILEGES ON demo_db.* TO app%; FLUSH PRIVILEGES;之所以推荐单独创建业务账号而不是一直用 root是因为生产环境权限最小化是底线。root 只保留给运维管理用平时业务连接都用独立账号。从宿主机连接验证mysql -h127.0.0.1 -P3306 -uapp -pAppPass123 demo_db能正常连上说明端口映射和应用账号都生效了。5.4 服务重启与数据持久化验证这里做一个关键验证也是我每次部署完必做的测试。执行docker restart mysql8 docker ps容器重启后再进 MySQL 看看刚才建的库还在不在。只要数据目录挂载正确库和表一定还在。如果发现重建的库消失了第一反应不是怪 Docker而是回去检查-v挂载路径是否匹配镜像内数据目录。对 MySQL 官方镜像来说这个路径就是/var/lib/mysql写错路径等于没挂载数据还是写在了容器内部临时空间里。额外提醒一句MySQL 容器是数据库数据是生命线一切高危操作之前请先确认卷挂载没问题副本备份没问题再执行删容器、删数据之类的动作。6. 常用运维操作资源限制、统计与日志管理容器跑起来了不代表万事大吉。作为日常使用还得知道怎么盯资源占用、怎么限制滥用、怎么处理日志膨胀的问题。这些都是线上集群用 Doker 的进阶基本功但即使是本地开发也建议养成习惯。6.1 查看容器资源占用docker stats这个命令会按实时刷新的方式展示每个运行中容器的 CPU、内存、网络 IO 和磁盘 IO 占用情况有点类似 Linux 的top但针对的是容器维度。我个人排查性能问题时第一步就是这个命令看是哪个容器把系统资源吃满了。按CtrlC退出不加参数默认显示所有运行容器。如果要看容器内部跑了哪些进程用docker top 容器名这在排查容器内进程异常退出或者僵尸进程时非常有用。6.2 限制容器资源用量不加限制的容器可能会把宿主机 CPU 或内存吃满多个容器互相拖垮。在docker run时直接设置docker run -d \ --name app \ --cpus1.5 \ --memory1g \ --memory-swap2g \ nginx:1.25--cpus1.5表示容器最多使用 1.5 个 CPU 核心。--memory1g限制内存上限为 1G。--memory-swap2g表示允许额外使用 1G 的 swap 空间。限制资源之后如果容器内存超限内核会直接触发 OOM容器被杀死而不是让宿主机整个卡死。这个机制在并发压力大的业务场景里尤其重要防止单个容器拖垮全部服务。6.3 容器日志占用过大的处理容器日志默认写到宿主机的/var/lib/docker/containers/id/目录下并且会无限累积。有的容器日志一天能写几个 G把磁盘撑爆。有两个思路一个是启动时限制日志文件大小docker run -d \ --log-opt max-size10m \ --log-opt max-file3 \ nginx:1.25这样每个日志文件最大 10M最多保留 3 个超出就轮转删除日志占用稳稳控制在 30M 以内。另一个思路是定期清理已停止容器和悬空资源docker system prune不加-a的时候只清除已停止的容器、无用的网络、构建缓存和悬空镜像。加-a会把所有未被容器引用的镜像也清掉谨慎使用。这个命令我一般每两周在开发机上跑一次能腾出不少空间。6.4 定期巡检的推荐组合如果是自己维护几台机器又不准备上完整的监控系统我建议定期跑几个命令看看全局状态docker ps -a docker stats --no-stream df -h--no-stream让docker stats只输出一次结果然后退出适合放在脚本里批量巡检。df -h看宿主机磁盘水位防止日志或数据卷把盘写满。7. 常见问题与排查技巧实录报错时别慌这部分我挑几个出现频率最高的报错来写全部是我实操中见过的每个都配有排查思路。这张速查表建议收藏真正报错时对照着来。报错场景常见原因解决思路Docker Desktop 启动报错virtualization support not detectedBIOS 虚拟化未开启 / WSL2 未安装进入 BIOS 开启 VT-x 或 AMD-V安装 WSL2 并升级内核报错failed to connect to the docker api at npipe:////./pipe/docker-desktop-linuxDocker Desktop 引擎未启动重启 Docker Desktop或者点击菜单 Restart 重置引擎Linux 下执行 docker 命令提示 permission denied当前用户不在 docker 用户组执行sudo usermod -aG docker $USER并重新登录拉取镜像一直超时或速度极慢未配置镜像加速 / 加速源失效配置daemon.json的registry-mirrors重启 Docker 验证端口映射后宿主机访问不到服务防火墙拦截 / 容器内服务未监听该端口docker logs查看容器日志确认服务状态检查宿主机防火墙放行端口MySQL 容器秒退 / 反复重启数据目录权限问题 / 端口被占用 / 环境变量缺失docker logs mysql8查看具体错误检查挂载目录属主换一个宿主机端口测试容器删不掉提示正在使用中有依赖该容器资源的其他容器或网络按报错提示先删除依赖资源或使用docker rm -f强制删除谨慎操作启动容器后立刻退出exit code 非 0应用启动失败多半是配置或依赖缺失docker logs看应用日志或进入容器手动执行启动命令定位原因7.1 常见报错逐条深挖报错一Docker Desktop 启动直接失败。Windows 上最典型的就是virtualization support not detected。这不是 Docker 本身的问题是 Windows 功能没开全。查三步BIOS 里虚拟化是否开启看任务管理器 - 性能 - CPU虚拟化状态是否为“已启用”Windows 功能里是否开启了“适用于 Linux 的 Windows 子系统”是否安装了 WSL2 内核更新包。三步全过了再启动 Docker Desktop 基本就稳了。报错二failed to connect to the docker api at npipe。这个报错在 Windows 上特别容易出现在 Docker Desktop 后台引擎还没起来时。别急着找网络问题先看系统托盘有没有 Docker 图标没有就手动打开有但一直转圈就右键点 Restart。等托盘图标稳定后再重试 docker 命令。如果反复失败优先检查 Windows 事件查看器里 Docker 服务的日志。报错三docker 命令提示权限错误。这个在 Ubuntu 上非常常见。无论执行什么 docker 命令都提示permission denied while trying to connect to the Docker daemon socket不是网络问题是当前用户没权限访问 docker.sock。快速解决就是把自己加入 docker 组然后重新登录。注意重新登录是必须的不然 shell 环境变量不刷新加了组也白加。报错四拉镜像速度慢到怀疑人生。这是国内用户头号痛点。很多人以为是网络问题其实是 Docker Hub 的服务器海外部署链路延迟很高。配置镜像加速是解决思路但不同时期的加速地址稳定性也不太一样建议多配几个备选。另外提示某些镜像仓库本身也第三方有加速渠道实在不行用代理拉取但个人使用场景下加速方案通常就够用了。7.2 排查问题时的通用方法论不管报什么错我排查问题的顺序永远是固定的第一步看日志。docker logs 容器名是最直接的线索。如果容器起不来这条命令能看到启动时的报错信息。第二步看状态。docker ps -a看容器的退出码Exit 0 是主动退出非 0 代码各有含义比如 137 一般是内存被杀143 是 SIGTERM。第三步看资源。docker stats看是不是内存、CPU 被耗尽。第四步看配置。回查启动命令里的端口、环境变量、挂载路径是否有低级错误。这个方法的核心是不要凭感觉猜每个信息都有它要告诉你的东西顺着报错链往回追基本都能定位问题。8. 我的几点实操心得最后分享一些比较玄学但很实用的个人体会纯经验没有固定格式。第一多用docker ps -a而不是docker ps。只列运行中的容器确实清爽但排查问题时停止状态的容器往往藏着比运行中更多的线索。看退出码看创建时间看哪次启动开始异常一个命令全搞定了。第二命名习惯和目录规划要趁早。容器名统一用“项目-角色”这种格式比如blog-nginx、blog-mysql数据目录统一规划在/data/项目/下。前期稍微花点心思后期维护大不一样不然容器一多列表里全是随机名字根本分不清谁是谁。第三不要迷信latest也不要迷信别人的一键脚本。我以前图省事用一些博客上的快速部署脚本跑服务遇到问题才发现脚本里干了不少我不知道的事项目结构完全失控。自己把基础命令吃透比把希望寄托在别人写的脚本上可靠得多。第四容器化不是魔法它只是一种运行方式。排查问题、设计架构、做数据管理的基本功还是那些Docker 只是让交付和部署变得更清爽。真正提升效率的永远是清晰的逻辑和熟练的基础功。多跑几遍上面的命令多写几个 Dockerfile你会发现别人口中很高深的“容器操作”其实也就是那么回事。
返回列表