ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Docker容器化实战:从安装部署到MySQL/Redis编排

Docker容器化实战:从安装部署到MySQL/Redis编排 开头我一直觉得Docker 容器化入门这件事最难的其实不是命令而是脑子里那层窗户纸没捅破。很多人第一次听说 Docker看到一堆镜像、容器、数据卷的概念就直接劝退了其实它解决的就是一个特别朴素的痛点环境不一致。你在自己电脑上跑得好好的到了同事那儿、到了服务器上各种依赖版本对不上装了半天环境项目还是起不来。Docker 把这套依赖和环境全部打包成一个轻量级的“集装箱”走到哪儿都能原样跑起来这就是它能火遍整个开发圈的根本原因。这篇教程面向的读者是那种刚接触容器化、想在自己的 Windows 或 Linux 机器上把 Docker 跑起来并且用它部署 MySQL、Redis 这类常用中间件的人。我会从最基础的概念讲起到安装踩坑、常用命令、真实部署案例再到问题排查全程用我实际动手验证过的方式来讲。你照着做基本可以绕开我在最初几个项目里踩过的那些坑。1. 先搞懂 Docker 到底在解决什么问题1.1 从“装环境”这件小事说起在 Docker 出现之前部署一个应用的流程大致是这样的先买一台服务器装操作系统然后装各种依赖库再装数据库、缓存、消息队列最后把代码上传、配置环境变量、启动服务。整个过程里面任何一个环节的版本不对或者系统本身的库和你要装的库冲突都能耗掉你大半天时间。我记得第一次部署一个用到特定版本 Node.js 外加 Redis 和 MySQL 的项目时光是在 CentOS 上把版本之间互相依赖的关系理顺就花了整整一个下午。后来换成 Docker 之后同样的部署工作被压缩到了几分钟——因为应用、运行时、依赖、配置全部被打包成一个不可拆分的整体拉到哪台机器上都能运行。这就是容器化的核心收益环境一致性和交付标准化。1.2 镜像、容器、仓库三个核心概念一次讲清这三个词是 Docker 体系里出现频率最高的也是理解后续所有命令的基础。你可以把它们类比成“程序安装包、运行中的程序、应用商店”的关系。镜像Image是一个只读的、静态的模板里面包含了运行某个应用所需的完整文件系统比如操作系统的基础层、代码、依赖、配置。它不会因为你运行一次就改变是真正意义上的“集装箱图纸”。容器Container是镜像运行起来之后的实例它是可读写的可以启动、停止、删除。同一个镜像可以启动出多个容器彼此之间互不影响。你可以把它理解成同一个“图纸”造出来的多个“集装箱”每个箱子里装的内容物相同但它们是独立的。仓库Registry用于存放和分发镜像最常用的就是 Docker Hub以及国内很多云厂商提供的加速器。我们平时说的“拉镜像”就是从这里把别人做好的镜像下载到本地。这三个概念之间有一条清晰的链路仓库提供镜像镜像创建容器容器带来服务。后面所有操作都是在这条链路上做增删改查而已。把这一点想明白了Docker 就算学会了一半。2. 安装与初始化最坑的第一道坎2.1 Windows 上装 Docker Desktop 的全过程与虚拟化检测安装这块Windows 用户往往会在第一步就卡住这也是网上问得最多的一类问题Docker Desktop 启动时报错提示virtualization support not detected或者是Docker Desktop failed to start because virtualisation support wasnt detected。出现这类报错基本可以断定是 BIOS/UEFI 里面的虚拟化开关没开或者 Windows 的虚拟化相关功能没启用。我建议按下面的顺序依次排查检查主板虚拟化开关。重启电脑进入 BIOS/UEFI 设置不同品牌按键不同常见的有 F2、Del、F10找到 Intel Virtualization TechnologyIntel VT-x或 AMD SVM确保状态是 Enabled。修改保存后重启进系统。确认 Windows 功能是否完整。打开“控制面板——程序——启用或关闭 Windows 功能”勾选“Hyper-V”和“适用于 Linux 的 Windows 子系统”。如果你用的是 Windows 10 家庭版可能看不到 Hyper-V 选项这种情况优先考虑直接安装 WSL2 和 Docker Desktop因为它默认走 WSL2 后端不完全依赖 Hyper-V。验证 WSL 环境。以管理员身份打开 PowerShell执行wsl --status看一下默认版本是不是 2。如果显示的是 WSL 1需要执行wsl --set-default-version 2来切换。这一步做好之后再启动 Docker Desktop 通常就不会再报虚拟化相关的错误了。装好之后还有一个常见的坑就是 Docker Desktop 提示类似failed to connect to the docker api at npipe:////./pipe/dockerDesktopLinuxEngine。这通常是因为 Docker 引擎还没完全启动或者启动过程中崩了。不要急着反复点图标先看右下角的 Docker 小鲸鱼图标是不是稳定显示为绿色如果一直转圈就检查一下 WSL 服务状态或者干脆重启一次 Docker Desktop。2.2 Linux 服务器安装 Docker 与国内镜像加速配置Linux 上的安装比 Windows 要省心不少因为 Docker 原生支持 Linux。以 Ubuntu 和 CentOS 这两类最常见服务器系统为例步骤差异不大我直接给出一套通用的安装方式。Ubuntu 系可以使用官方脚本一条命令安装完curl -fsSL https://get.docker.com | bash -s docker --mirror AliyunCentOS 7/8 也可以使用这条脚本或者选择手动配置 yum 源后安装。安装完成之后用docker version检查客户端和服务端版本能看到 Server 部分说明当前用户已有权限服务已正常启动。紧接着要做的一件事就是配置镜像加速器。国内直连 Docker Hub 拉镜像的速度用“惨不忍睹”来形容一点都不过分好几 GB 的镜像可能要拉几个小时。编辑/etc/docker/daemon.json文件没有就新建一个填入国内可用的镜像加速地址{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com, https://docker.nju.edu.cn ] }保存后执行systemctl daemon-reload systemctl restart docker使配置生效。之后再用docker pull拉一个测试镜像比如hello-world你会发现速度提升非常明显。2.3 安装后的权限与自启动配置Linux 下还有一个新手经常遇到但又很影响体验的问题执行docker ps之类的命令时提示permission denied while trying to connect to the Docker daemon socket或者直接报权限错误。这是因为 Docker 的 socket 文件默认只允许 root 用户访问而你当前的普通用户不在 docker 用户组里。解决办法很简单把当前用户加入 docker 组sudo usermod -aG docker $USER newgrp docker退出当前终端重新登录权限问题就消失了。另外为了让 Docker 服务在服务器重启后自动运行我建议顺手执行一下sudo systemctl enable docker sudo systemctl start docker这两步虽然不是必须的但在真实生产服务器环境里很关键防止机器重启后 Docker 服务没有跟着起来导致依赖容器的业务全部不可用。3. 常用命令从拉镜像到跑容器3.1 镜像管理拉取、查看与删除镜像命令是整个 Docker 使用的基础我挑几个最高频的操作说一下。拉取镜像用docker pull后面可以加版本号比如docker pull mysql:8.0。如果不写 tag默认拉取latest标签。查看本地已有的镜像用docker images会列出镜像的仓库名、标签、镜像 ID、创建时间和大小。删除镜像用docker rmi可以接镜像 ID 或镜像名。这里有一个比较隐蔽的坑如果你要删除的镜像已经被容器使用了Docker 会拒绝删除并提示冲突。这时候要么先停掉并删除相关容器要么加一个-f参数强制删除。不过我不建议习惯性用-f因为很可能会误删还在使用的底层镜像导致依赖它的其他镜像全部失效。3.2 容器生命周期启动、停止、进入与删除容器相关命令是使用频率最高的务必要熟练。启动容器最常用的是docker run。比如跑一个 Nginx 测试docker run -d --name web-test -p 8080:80 nginx-d表示后台运行--name给容器命名-p 8080:80把宿主机的 8080 端口映射到容器内的 80 端口。启动完成后在浏览器访问http://localhost:8080就能看到 Nginx 的欢迎页。这一步能成功说明 Docker 的端口映射和数据通路是通的Docker 就真的入门了。容器运行期间想查看日志用docker logs -f web-test-f是持续跟踪输出。想进入容器内部看环境用docker exec -it web-test bash。停止容器用docker stop web-test启动已存在但没有运行的容器用docker start web-test彻底删除容器用docker rm web-test。3.3 数据卷、端口映射与清理技巧容器本身是临时的删除之后其中产生的数据也会一起消失。所以生产环境部署时数据持久化是必须考虑的问题通常用两种方式实现绑定挂载Bind Mount把宿主机某个目录直接映射进容器比如-v /my/data:/var/lib/mysql。命名卷Named Volume由 Docker 管理宿主机上的存储区域比如-v mysql-data:/var/lib/mysql。我个人的习惯是数据库这类需要备份、迁移的数据用绑定挂载更直观一些不希望被宿主机文件系统干扰的中间数据用命名卷更干净。另外一个和磁盘空间相关的建议是容器和镜像随着时间推移会越积越多占满系统盘。建议定期用docker system prune清理悬空镜像和停止的容器加-a参数会连未被任何容器引用的镜像一起清掉。不过执行之前一定要三思docker system prune -a的删除面很大如果本地有一些构建到一半的镜像也可能被清理掉。4. 实战一用 Docker 部署 MySQL 8.04.1 部署前的路径规划与参数设计从这一节开始我们进入真正的实战。部署 MySQL 8.0 是新手接触“持久化”和“端口映射”这两个概念最好的切入点所以我选它作为第一个完整案例。在跑命令之前先在宿主机上规划好目录结构。我就以/opt/mysql8为例创建三个子目录data存放数据库文件conf存放自定义配置logs存放日志。这样做的核心目的是确保 MySQL 容器删除后数据还留在宿主机上不会随容器一起消失。端口方面如果宿主机 3306 已经被占用可以映射到宿主机其他端口比如-p 33066:3306这样对外提供服务的端口就是宿主机上的 33066容器内部依然是 MySQL 默认的 3306。多租户场景下用不同的宿主机端口来区分不同容器的 MySQL 实例是很常见的做法。4.2 启动 MySQL 8.0 容器与关键参数说明准备好目录和确认好端口之后执行下面的命令启动容器docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDyour_password \ -e TZAsia/Shanghai \ -v /opt/mysql8/data:/var/lib/mysql \ -v /opt/mysql8/conf/my.cnf:/etc/mysql/my.cnf:ro \ -v /opt/mysql8/logs:/var/log/mysql \ --restartalways \ mysql:8.0花一点时间解释几个参数的作用。MYSQL_ROOT_PASSWORD是初始化 root 用户时设置的密码第一次启动容器的时候生效所以不要在容器跑起来之后再改这个环境变量改了也不会生效。TZ设置时区为上海避免日志时间差 8 小时。--restartalways的含义是 Docker 服务重启或者容器意外退出时自动拉起容器这对生产环境非常有用。如果你需要让 MySQL 支持远程连接除了密码之外还要确认 MySQL 8.0 默认的认证插件兼容。早期版本走了mysql_native_password认证8.0 默认是caching_sha2_password部分老的数据库客户端可能连不上。需要兼容时可以创建一个使用传统认证方式的专用用户CREATE USER app% IDENTIFIED WITH mysql_native_password BY your_password; GRANT ALL PRIVILEGES ON *.* TO app%; FLUSH PRIVILEGES;这个操作在 “用 Docker 安装 MySQL 8.0 并使用” 的场景里属于最高频的问题之一提前写好能省去不少麻烦。4.3 初始化完成后的验证与常见权限问题容器启动后先用一条命令确认容器状态docker ps | grep mysql8如果 STATUS 列显示 Up 并且没有重启次数持续增长说明启动成功。再检查日志确认没有问题docker logs mysql8 | tail -n 50看到类似ready for connections的日志基本就稳了。接着进入容器用 MySQL 客户端连接验证权限和数据库docker exec -it mysql8 mysql -u root -p输入密码后能进到 MySQL 命令行说明账号和认证配置没有问题。这个环节我踩过的最典型坑是宿主机上接下来有多个项目共用一个 MySQL 容器导致不同项目的库表混乱。后来我在做多容器部署时果断改成“每个项目一个 MySQL 容器 独立数据卷”的方式效果非常好互不干扰备份恢复也简单得多。这个思路也推荐给你。5. 实战二用 Docker Compose 编排 Redis 主从5.1 Compose 文件为什么值得学当你需要同时管理多个容器时如果还是逐个执行docker run不但命令长还容易漏参数。Docker Compose 就是为了解决多容器编排问题而生的它用一份 YAML 格式的文件把多个容器的镜像、端口、数据卷、环境变量、网络关系全部声明清楚。之后只需要一个docker compose up -d就能把整套服务启动起来。很多开源项目比如 Dify在给用户提供部署方式时首选 Docker Compose。你说它的解压文件夹里为什么始终建议你打开命令行去执行cp .env.example .env因为 Compose 文件大量使用了环境变量占位符项目内的.env文件就是这些占位符的取值来源。少了这一步Compose 文件拿到的是空变量服务自然起不来。你理解了这套机制就会明白那些看似繁琐的启动步骤其实都有存在的意义。5.2 Redis 主从复制的 Compose 文件实例Redis 主从复制的典型场景是读写分离和高可用基础。我们这里在单台机器上用两个 Redis 容器来模拟主从结构一个端口 6379一个端口 6380从节点跟随主节点同步数据。先在项目目录里创建docker-compose.ymlversion: 3.8 services: redis-master: image: redis:7.0 container_name: redis-master command: [redis-server, --appendonly, yes] ports: - 6379:6379 volumes: - ./master-data:/data networks: - redis-net redis-slave: image: redis:7.0 container_name: redis-slave command: [redis-server, --slaveof, redis-master, 6379] depends_on: - redis-master ports: - 6380:6379 volumes: - ./slave-data:/data networks: - redis-net networks: redis-net: driver: bridge注意两个关键细节。第一从节点的--slaveof redis-master 6379里面用的是服务名redis-master而不是 IP这是因为 Compose 会为同一个网络下的多个服务自动做 DNS 解析服务名即主机名。第二depends_on表示从节点依赖主节点会在主节点启动后再启动。不过它只保证启动顺序不保证主节点已完全就绪所以生产环境下如果有脚本要依赖主从数据同步完成还需要在外面做轮询或健康检查。启动方式很简单在 docker-compose.yml 所在目录执行docker compose up -d两个容器启动完成后验证主从关系docker exec redis-slave redis-cli INFO replication在输出里看到role:slave以及master_link_status:up就说明主从同步已经建立成功了。5.3 生产环境下 Compose 部署 Redis 的注意事项单机模拟环境可以随便玩但真要放到生产环境有几个问题需要额外注意。持久化方式默认的 Redis 如果不配 AOF重启后内存数据会丢。上面示例里主节点已经加了--appendonly yes从节点最好也加上避免在主节点出问题时切换角色后从节点没有数据历史。密码保护生产环境必须加密码方式是在 command 里追加--requirepass your_password并在主从同步时通过--masterauth your_password声明授权信息否则主从之间无法完成认证。资源限制不加限制的容器会占用宿主机所有可用内存和 CPU。建议在 Compose 文件的服务层级加上deploy.resources.limits限制 memory 和 cpus防止 Redis 内存膨胀把整个服务器拖垮。备份与恢复数据卷虽然能做到容器级别持久化但卷本身不代表高可靠。我的习惯是额外写一个定时脚本用redis-cli BGSAVE触发持久化再定期把dump.rdb或 AOF 文件同步到异地存储。6. 常见问题与排查技巧实录6.1 Docker Desktop 启动失败类问题这类报错的集中爆发点十有八九出在虚拟化或者 WSL 环境上。前面提到的virtualization support not detected我遇到过很多次。有一次实际检查后发现用户 BIOS 里 VT-x 确实是开着的但 Windows 的“内存完整性”设置和 Hyper-V 功能冲突了导致 Docker Desktop 起不来。当时我是通过“设置 - 隐私和安全性 - Windows 安全中心 - 设备安全性 - 内核隔离”把内存完整性临时关闭再启动 Docker Desktop 就好了。这类问题属于环境叠加冲突没法靠单一的办法解决只能逐层排查。另外如果 Docker Desktop 的图标一直显示“Docker Engine is starting”多半是 WSL 子系统卡住了。可以尝试在管理员 PowerShell 里执行wsl --shutdown然后重新启动 Docker Desktop让 WSL 重新初始化。实测下来这个操作能解决七八成的启动卡死问题。6.2 镜像下载慢与连接失败的解决思路镜像下载慢是所有国内用户都绕不开的问题。除了配置前面提到的镜像加速器之外还可以考虑两个备用手段。一是如果某个镜像源临时不可用可以换一个加速地址。不同加速源的稳定性波动很大多用几个备选源可以在某个源挂掉时自动切换到下一个。二是如果 Docker Hub 上的官方镜像拉不动可以考虑从其他镜像仓库拉取之后重新打 tag比如部分云厂商的镜像仓库里会有同步过来的常用镜像用docker tag改一下仓库名和标签就能假装是在本地构建的镜像方便后续部署和推送。6.3 权限错误与服务启动失败权限错误的核心原因我在前面已经提过就是当前用户不在 docker 用户组里。除了usermod -aG docker之外还有一个冷门但有价值的情况如果你在 Linux 上安装了 Docker 后又手动修改过 docker.service 的启动参数导致服务没有完整启动docker ps也会报连接失败。此时用systemctl status docker看服务状态用journalctl -u docker -n 100排查启动日志比盲目重启更有效。服务启动失败还有一个容易被忽略的原因磁盘空间不足。Docker 在镜像下载和构建时会占用大量临时空间如果根分区满了服务会直接崩溃。遇到服务怎么都起不来的时候先执行df -h确认磁盘余量很多时候问题就解决了。6.4 我踩过的高频低级坑分享最后分享几个我在最初使用 Docker 时反复踩过的低级坑提前看到了就能帮你省下不少时间。第一个坑是误以为容器重启后数据还在。在没加数据卷的情况下容器删除后数据就直接没了。这个认知一定要建立起来否则生产环境会发生很惨痛的教训。第二个坑是端口冲突。不同容器如果都想映射同一个宿主机端口后面的容器会启动失败。我习惯在命名容器时就把端口用途写在名字里比如mysql8-3306、redis-6379一目了然。第三个坑是latest标签的坑。拉镜像时不写具体版本默认拉latest而 latest 所指的版本会随时间变化。今天拉了一个 mysql:latest三个月后再在同一台机器上拉一个 mysql:latest版本可能就变了行为不一致会很难排查。需要稳定复现的环境务必指定明确的版本号。第四个坑是不要在容器里直接改配置文件。容器文件系统的改动在容器重建后全部清零。正确做法是像前面 MySQL 实战那样通过宿主机挂载配置文件进去或者把配置写在 Dockerfile 里重新构建镜像这样才有可复现性。Docker 这个工具用一句话概括就是“一次打包到处运行”。你把它装好、跑通第一个容器就完成了最关键的冷启动再往里的编排、网络、存储、安全都属于在这个地基上盖楼的事。希望这篇教程能帮你顺利迈过那第一道坎。如果你在实操过程中遇到报错优先去看docker logs和journalctl的输出那里面往往藏着最接近真相的答案。
返回列表