ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Docker核心操作与实战:从镜像容器到MySQL/Redis部署

2026/10/7 3:12:57 拓冰建站 浏览量
Docker核心操作与实战:从镜像容器到MySQL/Redis部署 1. 先搞懂 Docker 到底解决什么问题聊到 docker 使用我身边不少同事第一反应还是“跟虚拟机差不多”。这个理解其实不准确也很容易导致后面的使用方向跑偏。Docker 本质上是一种操作系统级别的虚拟化技术它跟 VMware 那种跑完整操作系统的虚拟机完全是两回事。最直观的差别就是启动速度。虚拟机启动要几分钟Docker 容器基本是秒级启动。原因是容器直接共享宿主机内核不需要自己带一套操作系统。docker 使用中最核心的价值可以归结为三点环境一致性、资源隔离、快速交付。环境一致性这点我感触最深。以前在项目里配 MySQL、Redis不同机器上装出来的版本、配置文件、依赖库五花八门经常出现“我这边跑得好好的到你那就挂了”。用了 Docker 之后镜像把运行环境完整打包开发、测试、生产用的都是同一个镜像环境差异问题直接被消灭掉。资源隔离就更好理解了。每个容器都像单独的小房间里面跑着进程房间之间互不干扰。资源不够用可以限制跑完可以直接拆掉重来宿主机本身干净得很。我见过太多人在自己电脑上装各种服务装了一堆依赖系统越用越慢最后只能重装。用 Docker 之后再也不存在这种烦恼。再说三个必须记牢的核心概念镜像Image、容器Container、仓库Registry。镜像就是打包好的模板类似安装光盘只读不可改。容器是从镜像运行出来的实例可以启动、停止、删除所有写入操作都发生在容器层。仓库是存放镜像的地方Docker Hub 是最大的公共仓库企业里也会搭私有仓库。拿做菜来类比的话镜像就是菜谱加所有配料的组合容器就是按菜谱做出来的一道菜仓库就是存放各种菜谱的图书馆。你从图书馆借菜谱拉镜像按菜谱做菜创建容器吃完收拾干净删掉容器随时可以重新做一道一模一样的。这套逻辑想通了后面的 docker 使用就是围绕这几个概念的命令操作而已。2. 安装部署Windows 和 Ubuntu 全流程2.1 Windows 上装 Docker Desktop 的大坑Windows 用户基本都会选 Docker Desktop但安装过程中最常见的报错就是 “Virtualization support not detected” 或者 “Docker Desktop failed to start because virtualisation support wasnt detected”。这个报错的原因很直白虚拟化功能没开或者没启用对应的 Windows 组件。排查顺序建议从下面几步走。第一步按 CtrlShiftEsc 打开任务管理器看“性能”标签页里“虚拟化”状态。如果显示“已启用”说明 BIOS 层面没问题显示“已禁用”就需要重启进 BIOS找到 Intel VT-x 或 AMD-V 相关选项开启不同主板菜单名不一样常见的有 Virtualization Technology、SVM Mode、VT-d反正看到含 Virtual 或 SVM 的选项都开起来。第二步确认 Windows 功能。如果跑的是 WSL2 后端要保证“适用于 Linux 的 Windows 子系统”和“虚拟机平台”这两个功能处于开启状态。在控制面板的“启用或关闭 Windows 功能”里勾上重启后生效。我自己实测下来WSL2 后端比传统 Hyper-V 后端更稳启动速度也更快所以强烈建议在 Docker Desktop 设置里选 WSL2而不是 Hyper-V特别是老机器WSL2 对硬件的兼容性要好很多。第三步是检查 Hyper-V 的状态。在管理员 PowerShell 里执行 systeminfo最后几行会显示 Hyper-V 要求是否全部满足。有两条“已检测到虚拟机监控程序”说明当前已经启用。还有一个隐藏很深的坑如果你以前装过其他虚拟机软件比如 VirtualBox 或者 VMWare它们可能锁定了一些虚拟化资源导致 Docker Desktop 的引擎起不来。遇到这种情况要么把虚拟机软件彻底卸载要么在 Docker Desktop 里切换后端模式。2.2 Ubuntu 下装 Docker Engine 的操作Linux 下没有 Desktop 图形界面那套负担一个命令就能搞定。我个人推荐用官方安装脚本省事而且会匹配当前系统版本curl -fsSL https://get.docker.com | sh如果不想用脚本也可以走 apt 源安装sudo apt update sudo apt install docker.io装完之后设置开机自启并手动拉起来sudo systemctl enable --now docker docker version这里有个 docker 使用中非常经典的问题普通用户执行 docker 命令会报 Permission denied while trying to connect to the Docker daemon socket。原因很简单docker 的 socket 文件默认只对 root 和 docker 组成员开放。解决办法是把当前用户加进 docker 组sudo usermod -aG docker $USER注意执行完命令后要重新登录或者重启 shell 才能生效否则还是会报一样的错误。把用户加入 docker 组等于授予了等同于 root 的特权只有你自己用的开发机可以这么干生产服务器建议老老实实配 sudo。2.3 镜像下载慢怎么解决镜像加速是 docker 使用绕不开的话题。国内环境直接从 Docker Hub 拉镜像经常卡到怀疑人生。解决方案是配置镜像加速器。编辑 /etc/docker/daemon.jsonWindows 上通过 Docker Desktop 设置界面填就行{ registry-mirrors: [https://你的加速器地址] }改完后执行 systemctl daemon-reload systemctl restart docker。目前网上公开的加速器有不少已经停止服务建议自己搜一下当前可用的公共镜像站或者用云厂商提供个人专属加速地址。配置完成后docker pull 的速度通常能提升一个数量级。3. 镜像与容器的核心操作3.1 镜像生命周期管理docker pull 拉取镜像后用 docker images 查看本地已有镜像列表。清理时用 docker rmi 镜像ID删除前要确保没有容器在使用它否则会报冲突。当你想给别人分发镜像或者把镜像拷到离线环境需要用到两个命令docker save -o myimage.tar 镜像名:tag docker load -i myimage.tar我经常在办公网络和机房之间的离线环境用这招一条命令导出到目标机器一条命令导入比从公共仓库拉取稳定太多。另外 docker tag 可以给镜像打标签没有 tag 的镜像推不到私有仓库。3.2 容器起停与进入容器内部创建容器最核心的命令是 docker run先看一个标准示例docker run -d --name nginx-test -p 8080:80 nginx参数含义-d 表示后台运行--name 指定容器名-p 8080:80 把宿主机 8080 端口映射到容器 80 端口。容器运行后用 docker ps 看状态docker ps -a 能看到停止状态的容器。停止的容器可以 docker start 重新启动。进入容器内部调试的话用 execdocker exec -it nginx-test bash-it 表示分配一个交互式终端。这个命令几乎每天都要用进入容器后可以查看运行日志、检查配置、手动执行脚本。不过有一点要提醒为了保持镜像精简很多官方镜像里没有 bash比如 alpine 系列只有 sh进入时要写成 docker exec -it 容器名 sh。查看日志同样常用docker logs -f nginx-test服务半天起不来第一步就是看日志不要瞎猜。日志会默认保存所有标准输出和标准错误加 -f 参数可以持续追踪。3.3 数据卷和端口映射容器本身是短暂的删除容器后所有写入的文件跟着消失。为了持久化存储需要用 -v 参数把宿主机的目录挂载到容器里docker run -d --name mysql8 -p 3306:3306 -v /data/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD123456 mysql:8.0-v /data/mysql:/var/lib/mysql 的含义是宿主机 /data/mysql 目录映射到容器内的 /var/lib/mysql 目录。MySQL 的数据文件会写到容器内这个目录实际上落到了宿主机硬盘上。只要宿主机数据目录在哪怕容器删了重建一个数据也不丢。端口映射对应的是 -p 宿主机端口:容器端口。它的作用是让外部能够访问到容器内的服务。如果容器内 nginx 监听 80 端口你希望外面通过 8080 访问就写 -p 8080:80。这个方向别搞反第一个是宿主机端口第二个是容器端口。3.4 容器之间如何互联很多场景下多个容器需要互相通信比如应用容器要连数据库容器。比较老的教程会教你用 --link 参数但这个方式现在已经不推荐了。正确做法是创建自定义网络然后把容器都加入同一个网络docker network create my-net docker run -d --name mysql8 --network my-net -p 3306:3306 mysql:8.0 docker run -d --name myapp --network my-net myapp-image在同一个自定义网络里容器之间可以直接通过容器名访问不需要暴露端口。myapp 容器里连接数据库可以直接写 mysql8:3306Docker 内置 DNS 会自动解析。用自定义网络的好处是不依赖端口顺序容器重建后 IP 变了也不怕只要容器名不变其他容器照常访问。4. 实战一MySQL 8.0 部署与访问4.1 单机部署的命令和参数选择先用最标准的命令起一个 MySQL 8.0 容器docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDYourPassword \ -e TZAsia/Shanghai \ -v /data/mysql:/var/lib/mysql \ -v /data/mysql-config:/etc/mysql/conf.d \ --restartalways \ mysql:8.0几个参数展开说明一下。MYSQL_ROOT_PASSWORD 是初始化 root 密码必填项不写这个变量容器无法初始化。TZ 设置时区不设置的话容器默认 UTC 时间比北京时间慢八小时做日志排查会非常难受。第二个 -v 挂载的是配置目录自定义的 my.cnf 可以放进宿主机 /data/mysql-config 目录容器启动时会自动加载。--restartalways 表示 Docker 守护进程启动时自动拉起容器一旦主机重启MySQL 服务能跟着恢复不用手动干预。如果你是在小内存机器上部署内存不足会导致 MySQL 容器反复重启甚至直接挂掉。建议限制一下资源docker run -d --name mysql8 -p 3306:3306 -e MYSQL_ROOT_PASSWORD123456 --memory1g --memory-swap1g mysql:8.0--memory1g 限制容器最多使用 1G 内存如果机器本身只有 2G 内存这招能防止 MySQL 把主机搞死。实测在 2G 内存的机器上跑 MySQL 8.0不限制内存的话很容易把所有内存吃掉加上限制后稳定很多。4.2 访问容器内 MySQL 与外部访问从容器内部访问用的是 execdocker exec -it mysql8 mysql -uroot -p从宿主机或者其他机器访问直接用映射出来的端口mysql -h127.0.0.1 -P3306 -uroot -p这里有个非常常见的坑用 Navicat、DBeaver 这类客户端连接 MySQL 8.0 容器时可能会报错 Authentication plugin caching_sha2_password cannot be loaded。这是 MySQL 8.0 默认认证插件变更导致的。解决办法有两条路一是把客户端升级到支持 caching_sha2_password 的版本二是进入容器把 root 账号的插件改回 mysql_native_passworddocker exec -it mysql8 mysql -uroot -p ALTER USER root% IDENTIFIED WITH mysql_native_password BY YourPassword; FLUSH PRIVILEGES;执行完后老客户端就能正常连接了。还要注意一个细节初始化时如果没有设置 MYSQL_ROOT_HOST% root 账号默认只能在容器内部登录宿主机连接也会被拒。不过上面那个标准的 docker run 命令里虽然没有显式写 MYSQL_ROOT_HOSTMySQL 官方镜像默认会创建 root% 允许任意主机访问所以外部连接通常没问题。如果遇到 Access denied就进容器手动补一条授权CREATE USER root% IDENTIFIED BY YourPassword; GRANT ALL PRIVILEGES ON *.* TO root%; FLUSH PRIVILEGES;另一个实际会遇到的问题是局域网内其他机器访问不到数据库但本机可以。优先检查宿主机的防火墙和云服务器的安全组端口没放行一切都白搭。Ubuntu 上防火墙默认可能是开着的执行 sudo ufw allow 3306/tcp 放行。5. 实战二Redis 主从架构部署5.1 用 Docker 起一主一从Redis 主从结构是生产环境的基础配置目的很简单主节点负责写从节点同步数据并负责读既能做读写分离又能做数据冗余。以前没容器的时候要准备两台机器配 redis.conf比较繁琐。现在用 Docker 几分钟搞定。先把主节点跑起来docker run -d \ --name redis-master \ -p 6379:6379 \ -v /data/redis-master:/data \ redis:7 redis-server --appendonly yes这里的 --appendonly yes 开启 AOF 持久化数据写进 /data 目录配合宿主机挂载实现持久化。然后创建自定义网络把主从容器都放进去方便互相通信docker network create redis-net docker network connect redis-net redis-master或者更干脆直接在创建主节点的时候加 --network redis-net但网络创建要在容器之前。无所谓容器先起来再加网络也没问题。启动从节点关键点是加 replicaof 参数声明主节点地址docker run -d \ --name redis-slave \ -p 6380:6379 \ --network redis-net \ -v /data/redis-slave:/data \ redis:7 redis-server --appendonly yes --replicaof redis-master 6379注意这里用的不是 --slaveof因为在 Redis 5.0 之后官方就把 slave 术语改成了 replica参数也跟着变了。--replicaof redis-master 6379 表示从节点从 redis-master 这个主机名对应的 6379 端口同步数据。5.2 验证主从状态是否正常容器运行起来之后进到从节点容器里检查复制状态docker exec -it redis-slave redis-cli info replication关键信息看这三处role 为 slave新版本显示 role:slavemaster_link_status 为 upmaster_host 显示 redis-master。master_link_status 如果是 down通常原因是从节点访问不到主节点检查网络配置确认两个容器在同一个自定义网络里。验证主从同步最直观的方法是写一个 key 看能否同步过去docker exec -it redis-master redis-cli set test hello docker exec -it redis-slave redis-cli get test能取到值说明复制链路没问题。还有一个很多人会忽略的点主从节点都要配置持久化。如果主节点没开 AOF重启后内存数据全丢从节点同步到的数据也得重新全量复制极端情况可能出现主从数据不一致。所以我个人建议主从都开 appendonly yes稳妥。6. 进阶玩法青龙面板、DVWA 靶场、Kodbox 网盘6.1 青龙面板和它的依赖管理青龙面板是个定时任务管理工具很多人拿它跑签到脚本、自动任务热度一直很高。部署命令很简单docker run -d \ --name qinglong \ -p 5700:5700 \ -v /data/ql:/ql/data \ whyour/qinglong:latest启动后浏览器访问 http://ip:5700设置账号密码就能用。第一次登录后配置脚本拉取脚本仓库时经常遇到的问题就是脚本拉不干净、依赖报错。最典型的报错是执行脚本时报 Cannot find module xxx说白了就是脚本需要的 Node.js 依赖没装全。青龙面板里内置了“依赖管理”页面进去先选类型 Node.js然后填依赖名点安装。给两个我实测的经验。第一青龙的服务端和脚本运行环境都是 Node.js模块版本冲突经常出现依赖装多了反而出问题装的时候尽量按脚本作者的说明来不要一股脑全装。第二默认仓库源在国外拉库速度很慢甚至超时解决办法是在“配置文件”里配置镜像加速地址或者把脚本仓库换成国内镜像仓库。很多脚本项目作者会在文档里额外给一份国内仓库地址优先用那个。6.2 用 Docker 快速搭 DVWA 靶场DVWA 是学习 Web 安全的入门靶场在 Kali 里搭建一套原本要装 Apache、MySQL、PHP手工配置麻烦得很。用 Docker 一句话搞定docker run -d -p 8080:80 --name dvwa vulnerables/web-dvwa访问 http://ip:8080默认账号 admin密码 password。首次访问页面底下有个 Create/Reset Database 按钮点一下初始化数据库。如果点完进入登录页后发现报数据库连接错误大概率是数据库初始化还没完成等十几秒刷新页面就好。如果还是连不上重启容器docker restart dvwa容器重启后内置数据库服务会重新拉起一般就能恢复。这是个我踩过很多次的坑一键起服务很方便但等待初始化要有耐心。6.3 Kodbox 个人网盘部署Kodbox可道云是目前口碑不错的私有网盘方案部署方式也是 Docker 化docker run -d \ --name kodbox \ -p 8081:80 \ -v /data/kodbox:/var/www/html \ kodbox/kodbox浏览器访问 http://ip:8081按提示设置管理员账号和存储目录。有个坑必须单独说容器里写 www 目录需要写权限宿主机目录权限不够的话安装过程中会提示目录不可写。解决办法是给宿主机目录授权chmod -R 777 /data/kodbox或者加 --privileged 参数启动容器。前者更可控我一般只用 chmod 处理。Kodbox 这种 Web 程序对权限敏感权限设置不合适会导致上传文件失败、无法生成缩略图等一系列诡异问题。7. 常见问题排查与避坑实录7.1 高频报错一页速查表docker 使用过程中最常见的报错就那么几类我把踩过的问题整理成一张表格方便遇到问题直接查报错信息根本原因处理办法Permission denied while trying to connect to the Docker daemon socket当前用户不在 docker 组sudo usermod -aG docker $USER 后重新登录Cannot connect to the Docker daemon at unix:///var/run/docker.sockDocker 服务没启动systemctl start docker 或启动 Docker DesktopVirtualization support not detectedBIOS 未开启虚拟化重启进 BIOS 打开 VT-x/AMD-VDocker Desktop failed to start because virtualisation support wasnt detectedWSL2 或 Hyper-V 未启用启用“虚拟机平台”和 WSL 功能failed to start docker application container engine引擎进程资源不足或 daemon.json 配置错误检查 daemon.json JSON 格式释放内存镜像拉取超时或速度极慢网络原因配置 registry-mirrors 加速器7.2 网络不通的排查思路容器之间互访不了第一反应用 docker inspect 容器名 查看 IP 和网络配置。然后确认两个容器是否在同一个自定义网络里不在就 docker network connect 连进去。宿主机访问不了容器暴露的端口先确认容器真的在监听端口docker ps docker exec -it 容器名 netstat -tulpn | grep 端口如果容器内服务启动正常宿主机还是访问不了下一步就是防火墙。Ubuntu 下 ufw status 看防火墙状态CentOS 下 systemctl status firewalld把对应端口放行。云服务器还要看安全组规则是否放行端口。容器访问不了外网大多是 DNS 问题。容器内 ping 不通外网域名但能 ping 通 IP说明 /etc/resolv.conf 的 DNS 没配好。在 daemon.json 里加全局 DNS 配置{ dns: [223.5.5.5, 114.114.114.114] }重启 Docker 后再试。这个配置能解决大部分容器内 DNS 解析不了的问题。7.3 资源占用过高怎么办小主机跑多个容器比如 N100 这种低功耗平台跑二十个容器是当下的热门玩法但资源规划没做好很容易把整机拖垮。我个人的经验是三件事必须做每个容器都要限制可用内存docker run 加 --memory 参数。不限制的话一旦宿主机的某个进程占用所有内存整机可能直接 OOM。限制容器日志大小docker run 加 --log-opt max-size10m --log-opt max-file3否则日志文件会无限膨胀占满磁盘。尽量用 alpine、slim 之类的精简镜像同样的服务精简镜像体积能小一半以上运行时内存占用也更低。用 docker stats 命令能实时查看每个容器的 CPU 和内存占用排查性能问题时非常好用。如果是容器数量多导致 Docker Desktop 卡顿Windows 用户可以在 Docker Desktop 设置里调整分配给 WSL2 的内存上限。7.4 其他实际踩过的坑CentOS 7 升级 Docker 是很多运维会遇到的场景旧版本 Docker 的 daemon.json 某些配置项在新版本不再支持升级后服务起不来。处理方式是升级前备份 /etc/docker/daemon.json升级后逐项检查配置是否有 deprecated 项用 dockerd --validate 命令校验配置合法性。docker sql2008、人大金仓数据库这类冷门镜像部署思路和其他数据库一样无非是拉镜像、起容器、映射端口、挂数据目录。国产数据库大多提供了官方镜像使用流程高度类似。hadoop 这种重量级组件用 Docker 跑要注意内存规划一个集群十几个容器拉起内存不够会非常难受建议用 docker compose 统一编排并通过 --memory 限制每个服务的内存上限。8. 用 Compose 和私有仓库进阶管理8.1 Docker Compose 统一编排服务一多一条条 docker run 命令敲既容易遗漏参数又没法整体管理。Docker Compose 就是解决多容器编排问题的。用一个 docker-compose.yml 文件描述所有服务一行命令全部启停。举个典型的多服务示例version: 3.9 services: mysql: image: mysql:8.0 container_name: mysql8 environment: MYSQL_ROOT_PASSWORD: 123456 ports: - 3306:3306 volumes: - /data/mysql:/var/lib/mysql restart: always redis: image: redis:7 container_name: redis7 ports: - 6379:6379 restart: always app: build: . container_name: myapp ports: - 8080:8080 depends_on: - mysql - redis restart: always保存后执行 docker compose up -d整套环境都起来了。docker compose ps 查看状态docker compose logs -f 追踪日志docker compose down 一键关闭。有个细节必须提醒depends_on 只控制服务启动的先后顺序MySQL 容器启动了不代表 MySQL 进程已经就绪。应用容器可能在数据库还没初始化完就开始连接导致报错解决方法是应用的启动逻辑里加重试或者用 healthcheck 让 Compose 等到服务健康后再启动依赖服务。8.2 搭建私有镜像仓库企业内部不希望镜像上传到公共仓库就需要私有仓库。Docker 官方 registry 镜像就能轻松搭docker run -d -p 5000:5000 --name registry --restartalways registry:2之后把本地镜像打个标签推上去docker tag mysql:8.0 localhost:5000/mysql:8.0 docker push localhost:5000/mysql:8.0这里有个坑docker 默认只允许 HTTPS 访问镜像仓库。如果你在内网用 HTTP 访问需要在客户端的 daemon.json 里加 insecure-registries{ insecure-registries: [192.168.1.10:5000] }然后重启 Docker。企业内部用这套方案能极大提升镜像管理效率。8.3 IDEA 打包镜像与微服务部署Java 后端用 IDEA 打包 Docker 镜像的工作流也很成熟。先在项目的 pom.xml 里加 dockerfile-maven-plugin或者在 IDEA 的 Docker 插件里配置连接远程 Docker 守护进程的 TCP 地址。写好 DockerfileFROM openjdk:8-jre-alpine COPY target/app.jar /app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, /app.jar]IDEA 的 Docker 面板里右键 Dockerfile 直接 Build Image构建出来的镜像可以直接部署。这种方式对微服务项目特别友好每个微服务模块对应一个镜像版本迭代、回滚都很方便。PHP 项目打包镜像同理基底用 php:7.4-fpm-alpine把项目代码 COPY 进去安装需要的扩展构建后就能跑。思路都是一套把项目文件、运行环境、入口命令固化进镜像。我个人在实际工作中的体会是docker 使用不是背命令而是理解“一切皆镜像、服务皆容器”这个模型。你只要玩懂镜像构建、容器生命周期、网络和数据卷这三块剩下的各种框架、数据库、中间件怎么部署基本都是查对应的官方镜像文档照方抓药。踩过的坑越多后面越顺手。希望这篇整理能帮你在 Docker 这条路上少走点弯路。