资讯动态

Docker 实战指南:从容器核心概念到生产环境部署

发布时间:2026/9/14 17:54:12 来源:尧图企业网站定制
做后端开发和运维的人早晚都得跟 Docker 打交道。我清楚记得自己第一次接触 Docker 是在一个项目需要快速搭建测试环境的时候当时需要在三台新服务器上部署 MySQL、Redis 和 Nginx按照传统方式一台一台装光环境配置就折腾了小半天。后来改用 Docker整个流程缩短到了十几分钟。从那天起我就开始系统性地使用这个工具到现在已经有六七年时间日常的本地开发、测试、生产部署几乎都离不开它。这篇内容不是官方的概念手册而是从一个实际使用者的角度把 Docker 从基础概念到常见实战场景完整梳理一遍。内容包括镜像、容器、数据卷、网络这些核心概念Windows 和 Linux 下的安装细节用 Docker 部署 MySQL 8.0、Redis 主从的实际操作步骤还有 Compose 编排、微服务打包等进阶用法。最后汇总一些我踩过的坑和排查思路。不管你是完全没接触过容器技术的新人还是已经在用但总遇到问题的开发者这篇都能给你一些可以直接用的东西。1. Docker 到底是什么先想清楚它解决了什么问题1.1 从“环境不一致”这个老问题说起在 Docker 出现之前团队协作最头疼的一件事就是环境不一致。开发者在 Windows 上写代码、测功能一切正常代码推到服务器上跑 Linux结果因为系统版本不一样、依赖库版本不一样、配置路径不一样程序直接起不来。排查这种问题往往比写代码本身还耗时。Docker 的思路是把应用运行所需的完整环境——包括操作系统层、运行库、配置文件、环境变量——全部打包成一个标准化的交付单元也就是镜像。只要宿主机能跑 Docker 引擎不管底层是 CentOS、Ubuntu 还是 Windows拉下来镜像就能以几乎一致的方式运行。这个特性从根上解决了环境漂移的问题也让“在我机器上能跑”这句话失去意义。另外Docker 和传统的虚拟机是两种完全不同的思路。虚拟机需要模拟完整硬件每个虚拟机里都有一个完整的操作系统占用的磁盘空间以 GB 计算启动时间以分钟计算。而 Docker 容器是直接复用宿主机内核通过 namespace 做隔离、cgroup 做资源限制容器本身只是一个进程级的环境。所以容器镜像通常在几十到几百 MB启动时间基本是秒级。这样的设计让它特别适合微服务架构下大量服务并行部署的场景。1.2 镜像、容器、仓库三个概念串起来理解刚接触 Docker 的人最容易绕晕三个词镜像、容器、仓库。我常用的一个类比是镜像就像是一个程序安装包容器就像是用这个安装包装好并正在运行的一个实例。你可以用同一个安装包在一台电脑上装多份装了之后每份的运行状态是独立的互不影响。仓库则是存放这些安装包的地方类似手机应用商店。具体到实际操作中镜像是一个只读的模板通过docker pull从仓库拉取到本地然后通过docker run基于这个镜像创建一个可写的容器层。容器启动后你对文件系统的所有修改都发生在容器层容器删除后这些修改也会一并消失而原始镜像是不会变的。这也是为什么官方建议不要手动修改运行中容器的内容而是要修改 Dockerfile、重新构建镜像。仓库分为公共仓库和私有仓库。公共仓库最常见的就是 Docker Hub里面有大量官方维护的镜像比如mysql、redis、nginx。私有仓库可以用 Docker 官方提供的registry镜像自己搭建也可以用 Harbor 这类企业级方案。私有仓库适合存放公司内部的应用镜像避免直接暴露在公共网络上。1.3 为什么所有团队都在往 Docker 迁移我这些年看到的技术趋势里Docker 的普及速度算是相当快的。原因不只是它解决了环境一致性问题更重要的是它重新定义了软件的交付方式。过去上线一个服务要准备一大段部署文档等运维建立目录、装依赖、配置参数。现在整个团队就维护一个 Dockerfile每一次构建产出一个标准镜像测试环境、预发布环境、生产环境拉取同一个镜像直接运行。部署过程从“手动操作半小时”变成了“一条命令搞定”。其次Docker 对资源的使用效率远高于虚拟机。单个物理机上可以运行的容器数量远超虚拟机数量这让服务器的利用率大幅提升。对于个人开发者来说Docker 还能完美解决多版本软件共存的问题机器上需要同时有 MySQL 5.7 和 8.0正常安装的话版本冲突很麻烦Docker 直接把两个运行环境隔离互不干扰。还有一点容易被忽视Docker 让本地开发环境的结构和生产环境保持一致。开发者在本地用 Docker Compose 拉起一套和线上完全相同的中间件环境开发完以后代码、配置、依赖一起打镜像发到后端出问题的概率自然低很多。2. 环境准备把 Docker 装好是第一步2.1 Windows 下安装 Docker DesktopVirtualization Support 报错怎么办Windows 上安装 Docker 的主流方式是安装 Docker Desktop。下载安装包后双击按提示操作就行但很多人会在启动时遇到一个经典报错Docker Desktop failed to start because virtualisation support wasnt detected这个报错的意思是 Docker Desktop 检测不到虚拟化支持。我先说明原因Docker Desktop 在 Windows 上依赖 Hyper-V 或 WSL 2 来运行 Linux 容器如果 BIOS 没有开启虚拟化或者系统没有启用相关 Windows 功能启动就会失败。检查顺序一般是这样的打开任务管理器切到“性能”选项卡看 CPU 一栏右下角有没有“虚拟化: 已启用”字样。如果没有需要进入 BIOS在 CPU 设置里找到 Intel VT-x 或 AMD SVM 选项把它设为 Enabled保存重启。以管理员身份打开 PowerShell运行命令systeminfo在输出结果里找“Hyper-V 要求”那一行确认是否正确。在“控制面板 - 程序和功能 - 启用或关闭 Windows 功能”里勾选“适用于 Linux 的 Windows 子系统”和“虚拟机平台”然后重启。确保 WSL 已更新到较新的版本可以在命令行里执行wsl --update。还有一个注意事项如果你本机已经装了 VMware Workstation 或 VirtualBox需要留意这类虚拟化软件和 Docker Desktop 同时启用 Hyper-V 时的兼容性问题。高版本的 VMware 已经支持 Hyper-V 共存但性能上会有一些折损。如果机器配置一般也可以放弃 Docker Desktop改用 WSL 2 里直接安装 Docker Engine 的方式这样资源占用更小。2.2 LinuxUbuntu / CentOS下安装 Docker 引擎Linux 服务器上安装的是 Docker 引擎没有图形界面。Ubuntu 和 CentOS 的安装方式有区别分开说。Ubuntu 推荐用官方 apt 仓库安装。先更新索引并安装一些依赖sudo apt-get update sudo apt-get install ca-certificates curl gnupg lsb-release然后添加 Docker 官方 GPG 密钥和仓库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 $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null接着安装 Docker 引擎sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin安装完成后执行sudo systemctl start docker和sudo systemctl enable dockerDocker 服务就常驻了。CentOS 的流程思路相同但命令不同。先安装工具包sudo yum install -y yum-utils配置仓库sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo然后安装sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin启动服务并用docker version确认安装成功。如果系统本身是 CentOS 7而且是从旧版本升级上来的建议先确认内核版本不低于 3.10否则 Docker 的部分功能可能不稳定。2.3 权限问题与镜像加速几个不得不做的配置Linux 安装完成后第一个会遇到的问题是权限。直接运行docker ps会看到Got permission denied while trying to connect to the Docker daemon socket这是当前用户没有 docker 用户组权限。官方推荐的解决方案是把当前用户加入 docker 组sudo usermod -aG docker $USER newgrp docker执行完再运行docker ps就不会有权限问题了。注意把用户加入 docker 组相当于授予了 root 级别的操作能力因为 docker 守护进程本身是 root 权限运行的所以生产环境的服务器上不要随意把普通用户加到 docker 组这会成为安全隐患。接下来建议配置国内镜像加速。不配置的话从 Docker Hub 拉取镜像经常会出现长时间等待或中断因为官方仓库和国内网络链路之间有明显的延迟。配置方法是在/etc/docker/daemon.json中写入{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com ] }写完后需要重启 Dockersudo systemctl daemon-reload sudo systemctl restart dockerWindows 版 Docker Desktop 可以直接在 Settings 里找到 Docker Engine 的 JSON 配置进行修改。配置好镜像加速之后拉镜像的速度会有非常直观的提升。3. 核心实操镜像、容器、数据卷和网络3.1 镜像管理拉取、查看、删除Docker 的使用场景里镜像操作占了很大比例。最常用的几个命令我在下面列一下它们出现的频率非常高。拉取镜像docker pull nginx:latest我建议在拉取镜像时养成指定版本号的好习惯不要全部使用latest。latest标签是动态变化的可能今天拉下来的是版本 A过几个月变成版本 B导致不同时间构建的容器环境存在差异。如果要做稳定复现使用具体版本号才靠谱例如nginx:1.25.3。查看本地镜像docker images删除镜像docker rmi nginx:1.25.3如果镜像正被某个容器使用需要先删除容器或者加-f强制删除。更常见的做法是先清理无用的容器再清理镜像避免误操作。3.2 容器生命周期从创建到销毁容器是镜像的运行实例。创建一个容器并运行的命令格式是docker run -d --name my-nginx -p 8080:80 nginx:1.25.3我逐个解释参数-d表示后台运行--name给容器起名字-p 8080:80把宿主机的 8080 端口映射到容器内的 80 端口最后一个参数是镜像名。如果不加-d容器会以前台模式运行日志直接输出到终端CtrlC 时容器也会停止这种方式适合调试。容器启动后常用的查看命令有两个docker ps docker ps -a前者只显示运行中的容器后者显示所有容器包括已经停止的。很多新手容器启动失败后执行docker ps看不到任何容器以为镜像没运行其实容器已经停止并被保留下来了要用docker ps -a才能看到。停止、启动、重启、删除容器分别对应docker stop my-nginx docker start my-nginx docker restart my-nginx docker rm my-nginx查看容器日志docker logs -f my-nginx-f是实时跟踪类似tail -f。当我排查容器启动异常时第一步永远是看日志这是定位问题最直接的路径。3.3 数据卷让数据不随容器一起消失容器是临时的但数据必须持久化。这可能是 Docker 使用中最重要的一个理念。默认情况下容器内写入的文件只存在于容器的可写层容器一旦删除这些文件就全部丢失。所以要用数据卷Volume来把宿主机的目录挂载到容器内的某个目录。挂载数据卷的典型命令是docker run -d --name mysql-8 -v /opt/mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD123456 mysql:8.0-v /opt/mysql-data:/var/lib/mysql表示把宿主机上的/opt/mysql-data目录挂载到容器内的/var/lib/mysql目录MySQL 写入的数据实际保存在宿主机上。即使容器被删除、重新用相同命令创建一个新容器只要挂载同一个宿主机目录数据依然在。这种挂载方式同时解决了另一个问题需要改动配置文件时直接在宿主机上修改对应的挂载目录里的配置文件容器内立即生效不需要进入容器内部操作。数据卷在容器编排中的作用会更明显。比如后面要讲的 Redis 主从、微服务架构每个有状态服务都必须配置数据卷否则容器重启或迁移的过程会丢失关键数据这在实际生产环境中是不可接受的。3.4 网络模式端口映射到底发生了什么Docker 的网络模型一开始看起来有点抽象但只要理解端口映射的原理大部分问题就能想通。容器内有自己的网络栈和宿主机是隔离的。如果你运行docker run -p 8080:80 nginx含义是宿主机收到发往端口 8080 的请求后会转发到对应容器的 80 端口。所以外部访问的端口是宿主机的 8080而不是容器的 80。当多个容器之间需要互相通信时更推荐的方式是创建一个自定义网络docker network create my-network然后在启动容器时指定网络docker run -d --name nginx-app --network my-network nginx docker run -d --name redis-app --network my-network redis同一个自定义网络下的容器可以直接用容器名作为主机名互相访问。比如 nginx-app 容器里要连接 redis-app直接配置redis-app:6379就可以了不需要通过 IP 地址。这个特性在微服务架构中非常实用因为容器 IP 是动态变化的用容器名访问才稳定。4. 实战场景一用 Docker 快速部署 MySQL 8.04.1 一次完整的 MySQL 部署过程MySQL 8.0 是现在使用非常广泛的数据库版本用它来做演示最能说明 Docker 的便利性。首先拉取镜像docker pull mysql:8.0然后准备好宿主机上的数据目录和配置目录mkdir -p /data/mysql/{data,conf,logs}接着启动容器docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDMyPss123 \ -v /data/mysql/data:/var/lib/mysql \ -v /data/mysql/conf:/etc/mysql/conf.d \ -v /data/mysql/logs:/var/log/mysql \ mysql:8.0这里几个-v挂载分别对应数据文件、配置文件和日志文件。配置文件挂载的意义在于不要在容器运行时进入内部修改配置而是把配置放在宿主机统一管理。代码化配置才能被 Git 跟踪变更和回滚都会方便很多。启动后验证容器是否正常运行docker ps | grep mysql8 docker logs mysql8 | tail -20看到日志里有ready for connections就说明 MySQL 启动成功了。4.2 使用 MySQL 并处理认证加密问题容器启动后可以通过宿主机上的 MySQL 客户端连接也可以进入容器内使用自带的客户端docker exec -it mysql8 mysql -uroot -p输入启动时设置的密码就能进入 MySQL 命令行。这里有一个很典型的坑使用 MySQL 8.0 时用一些旧的客户端工具连接会报Authentication plugin caching_sha2_password cannot be loaded错误。原因是 MySQL 8.0 默认认证插件是caching_sha2_password而老版本的客户端和部分编程语言的驱动不认识它。解决办法有两个。一是在官方文档和各类文章的推动下现在大部分新版本驱动都已支持caching_sha2_password优先升级驱动版本这是最干净的做法。二是在建用户时显式指定认证插件CREATE USER app_user% IDENTIFIED WITH mysql_native_password BY AppPass123; GRANT ALL PRIVILEGES ON *.* TO app_user%; FLUSH PRIVILEGES;用这种方式创建的账号老客户端就能正常连接。不过在 MySQL 9.0 里mysql_native_password已经被移除建议还是尽早切换到官方推荐的认证方式。4.3 数据恢复和备份容器时代不能忽略的能力容器让部署变得简单也让运维人员容易忽略备份。我在实际项目里见过有人把数据库装在容器里三个月没有做过备份然后一次误操作把所有数据删了最终只能从头重建数据。容器的便利性反而让人放松了警惕。用 Docker 做 MySQL 备份其实很简单。备份命令docker exec mysql8 sh -c exec mysqldump --all-databases -uroot -p$MYSQL_ROOT_PASSWORD backup.sql恢复命令docker exec -i mysql8 sh -c exec mysql -uroot -p$MYSQL_ROOT_PASSWORD backup.sql关键点是理解输入输出重定向的方向。备份时是把容器内命令的标准输出重定向到宿主机文件恢复时是把宿主机文件的输入重定向到容器内的 mysql 命令。出错的概率不高但每次都要想清楚方向。5. 实战场景二用 Docker Compose 编排 Redis 主从5.1 为什么要用 Docker Compose随着服务数量增加一条条docker run命令开始变得笨重。一个普通项目可能同时要运行 MySQL、Redis、Nginx 三个容器每次环境重建都要重新输入好几条复杂命令效率低且容易出错。Docker Compose 就是用来解决这个问题的。它允许你把整套服务定义在一个 YAML 文件中通过docker compose up一条命令把全部服务启动。所有容器的镜像、端口、数据卷、网络关系都集中管理服务之间的关系一目了然。以 Redis 主从为例。一个简单的主从结构包含一个主节点、一个从节点。正常用docker run写命令至少需要两条后面还有配置文件、数据卷挂载等工作。用 Compose 后整个拓扑被写进一个文件以后任何环境都能一键拉起。5.2 编写主从架构的 docker-compose.yml创建redis-cluster-compose/docker-compose.yml内容如下version: 3.8 services: redis-master: image: redis:7.2 container_name: redis-master restart: always ports: - 6379:6379 command: redis-server --appendonly yes --requirepass MasterPass123 volumes: - redis-master-data:/data redis-slave: image: redis:7.2 container_name: redis-slave restart: always ports: - 6380:6379 command: redis-server --slaveof redis-master 6379 --masterauth MasterPass123 --appendonly yes volumes: - redis-slave-data:/data depends_on: - redis-master volumes: redis-master-data: redis-slave-data:几点说明主节点通过--requirepass设置了访问密码。从节点连接主节点时需要通过--masterauth提供主节点的密码没有这一步主从复制会反复失败并在日志中报MASTER aborted replication with error: NOAUTH。从节点的--slaveof redis-master 6379指明主节点的地址和端口。这里直接用服务名redis-master而不是 IP 地址是因为 Compose 会自动把所有服务加入同一个默认网络容器之间可以直接用服务名通信。redis-master-data和redis-slave-data是命名卷Compose 会自动创建并管理。相比直接写宿主机路径命名卷的好处是迁移时更清晰、路径可配置性更强。5.3 启动并验证主从复制在docker-compose.yml所在目录执行docker compose up -d查看容器状态docker compose ps确认两个容器都处于Up状态后验证主从同步。在主节点写入数据docker exec -it redis-master redis-cli -a MasterPass123 set greeting hello在从节点读取数据docker exec -it redis-slave redis-cli -a MasterPass123 -p 6379 get greeting如果返回hello说明主从复制已经正常工作了。生产环境部署时我另外建议加上--replica-read-only yes来锁定从节点的只读状态防止业务代码误写入从节点导致数据不一致。再就是 Redis 主从本身不提供自动故障转移如果生产环境要求高可用需要引入 Redis Sentinel 或直接采用集群模式。这些都是和主从一起规划的事情不要等出问题了再补。5.4 生产环境部署的几个细节从开发环境到生产环境Docker 部署的脑回路要切换一下。开发环境追求方便快捷生产环境追求稳定可控。端口暴露范围需要缩小。开发环境为了本地调试方便通常把所有端口都暴露到宿主机但生产环境里 Redis、MySQL 这类内部组件不应该直接对外提供端口因为容器本身的自定义网络已经解决了服务间通信问题。我更倾向于把端口暴露限制在业务网关层内部服务一律走容器网络。另一个问题是容器的重启策略。在 docker-compose.yml 中默认加上restart: always这样宿主机重启后Docker 会自动把容器拉起来。没有这个配置机器一重启所有服务全部挂掉需要人为操作恢复这在生产环境是不可接受的。资源限制也需要给出。可以在 service 配置里加上deploy: resources: limits: cpus: 0.5 memory: 512M这样单个容器最多使用半个 CPU 核心和 512MB 内存防止某个服务的内存泄漏拖垮整个宿主机。虽然 Compose 在单机模式下有限制语法差异但实践上是有效的。6. 进阶方向GitLab、微服务打包与私有仓库6.1 用 Docker 快速部署 GitLab团队规模只要超过三个人自建 Git 仓库的需求就会冒出来。GitLab 是常见的方案而用 Docker 部署 GitLab 是最省事的路径。命令如下sudo docker run -d \ --name gitlab \ --restart always \ -p 8088:80 \ -p 8443:443 \ -p 8022:22 \ -v /srv/gitlab/config:/etc/gitlab \ -v /srv/gitlab/logs:/var/log/gitlab \ -v /srv/gitlab/data:/var/opt/gitlab \ gitlab/gitlab-ce:latest这里把宿主机的 8088 映射到容器的 80这样访问地址就是http://服务器IP:8088。22 端口映射到 8022是为了让 SSH 方式克隆代码时不和宿主机已有的 SSH 服务冲突。GitLab 首次启动时间比较长大概要两三分钟可以通过docker logs -f gitlab观察初始化进度。初始密码在容器内的/etc/gitlab/initial_root_password文件里需要用docker exec gitlab cat /etc/gitlab/initial_root_password查看首次登录后立即修改。这里有个经验GitLab 这种重量级服务挂在宿主机自带存储上没问题但一旦用户量和代码量上来数据目录的磁盘容量要提前规划否则日志和 Git 数据把磁盘塞满整个服务就会进入不可用状态。建议把数据目录挂在有容量告警的独立数据盘上。6.2 Java 微服务用 IDEA 打包 Docker 镜像微服务架构下每个服务最终都要变成一个可交付的镜像。Java 生态中最方便的方式是直接用 IDEA 的 Docker 插件来打包。先确认 IDEA 里的 Docker 插件已经连接到了本机的 Docker 环境。在 Settings - Build, Execution, Deployment - Docker 里配置好连接方式。然后给项目编写DockerfileFROM eclipse-temurin:17-jre WORKDIR /app COPY target/demo-service-0.0.1.jar app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, app.jar]然后新建一个运行配置选择 Docker指定这个 Dockerfile点运行就能生成镜像。把生成的镜像推送到私有仓库后测试或生产服务器拉下来直接运行整个链路就打通了。需要提醒的是Java 服务打包成镜像后JVM 的参数配置方式有所变化。不要在 Dockerfile 里硬编码-Xmx因为容器本身被限制内存后JVM 不一定能感知到限制。官方推荐使用-XX:MaxRAMPercentage75.0这类比例参数让 JVM 根据容器分配的内存自动调整堆大小。PHP 项目打包镜像的思路类似使用官方 PHP 镜像加上自带的 PHP-FPM再配合编写好的启动脚本。核心是一样的把运行环境固化成 Dockerfile而不是在容器里手动装扩展、改配置那样就失去了一键复现的意义。6.3 搭建私有镜像仓库并推送镜像自己去搭建一个私有仓库没有想象中那么复杂。Docker 官方提供 registry 镜像两条命令就能跑起来docker run -d -p 5000:5000 --restartalways --name registry registry:2然后在需要推送镜像的机器上打上仓库地址的标签docker tag demo-service:0.0.1 localhost:5000/demo-service:0.0.1 docker push localhost:5000/demo-service:0.0.1如果是在别的机器上推送把localhost换成实际的服务器地址。默认情况下 Docker 要求仓库走 TLS否则推送会报错。在可信内网环境下可以给 Docker 的 daemon.json 添加如下配置来跳过{ insecure-registries: [192.168.1.10:5000] }私有仓库的进阶方案是 Harbor。它提供 Web 界面、权限控制、镜像扫描和审计功能适合多人团队使用。但单机小团队用官方 registry 就足够了没必要为了用 Harbor 引入一套复杂的部署维护成本。还有一个值得提的经验生产环境使用第三方容器镜像时强烈建议先 pull 到本地用docker history或docker inspect检查镜像的来源和构建过程确认没有问题之后再推送到自己的私有仓库。这种方式可以保证线上部署的镜像完全可控不依赖外部仓库的可用性和安全性。7. 高频问题排查与避坑实录7.1 docker: unexpected eof 到底有多坑这个报错应该是 Docker 使用中最让人摸不着头脑的一个。执行各种 pull、push 操作时突然出现docker: unexpected EOF.第一次遇到这个问题的反应往往是以为 Docker 崩了去查服务状态、重启 Docker结果问题依旧。根据我的实际经验这个错误的大概率原因是拉取大型镜像时网络中断。特别是跨网络传输大镜像时长连接容易被网络设备切断Docker 客户端抛出这个错误。解决思路有两个方向。一是配置前面提到过的镜像加速器减少跨网络传输的距离和中断概率。二是针对大型镜像可以考虑在网络更稳定的时段操作或者通过docker pull --disable-content-trust临时绕开签名校验拉取。如果unexpected EOF发生在启动容器或者docker exec进容器时则可能是 Docker 守护进程本身出了问题这时候重启 Docker 服务能解决大部分问题sudo systemctl restart docker总之先区分这个报错是出现在网络传输阶段还是本地操作阶段再针对性处理不要盲目重装。7.2 数据目录在外挂盘这是很多人没注意的坑Docker 默认把所有容器、镜像、数据卷都放在/var/lib/docker目录下。如果宿主机系统盘只有 40GB而项目数据量增长很快磁盘最后会被撑满。我维护过一台服务器一开始只部署了一个 MySQL 和一个 Redis以为是够用的结果过了几个月系统盘报警查下来发现是 MySQL 的 binlog 和 Docker 日志占据了几十 GB 空间。处理方式是在安装 Docker 之前就把数据目录改到数据盘或者后期用软链接迁移。迁移动作是这样的sudo systemctl stop docker sudo mv /var/lib/docker /data/docker sudo ln -s /data/docker /var/lib/docker sudo systemctl start docker注意迁移前一定要停 Docker 服务否则文件正在使用会复制出错。还有一种方式是在 daemon.json 中指定>docker logs --since 30m container_name第二步确认宿主机端口是否被其他进程占用netstat -tlnp | grep 3306第三步检查数据卷挂载路径的权限。很多容器在启动时以非 root 用户运行如果宿主机上挂载的目录权限不对容器内用户没有写权限服务会反复启动失败。这时用chmod或chown调整目录权限即可。一个真实案例有一次 Nginx 容器重启后始终报 403翻日志发现是挂载的网站目录权限变成了 700而容器内的 nginx 进程是 www-data 用户进不去目录。把目录权限改成 755 后问题立刻消失。这种问题往往和 Docker 本身无关而是宿主机文件系统权限和容器用户模型之间的冲突。7.4 几个高频问题速查问题现象可能原因排查/解决办法拉取镜像一直转圈或超时网络链路问题、镜像源不稳定配置国内镜像加速换网络环境重试容器启动后立即退出前台进程未保持、端口冲突、配置错误看docker logs检查前台运行命令确认端口占用宿主机重启后容器全没了未配置 restart 策略启动时加--restart always或修改 compose 配置容器无法解析域名DNS 配置问题、网络模式异常自定义网络 检查宿主 DNS必要时指定--dnsdocker exec提示 no TTY终端不支持交互去掉-t参数仅用-i或确认进程是否仍在运行磁盘空间不足容器日志未清理、镜像堆积、数据卷膨胀清理无效容器日志用docker system prune定期清理旧镜像大量日志占用磁盘容器内应用日志全部输出到 stdout 且不轮转在 daemon.json 中配置 log-opts 限制日志文件大小和数量这些坑不是一次踩完的但有一半左右我都在生产环境下亲测遇到过。最想强调的一点是容器日志一定要提前限制大小。一个没做任何日志限制的容器运行几个月后日志文件能轻松占掉几十 GB 磁盘空间。daemon.json 里建议加上{ log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 } }加上这个配置后单容器日志文件超过 100MB 时会自动轮转最多保留三个日志文件。这种设置在线上跑了一两年基本没有再被日志撑爆磁盘过。最后分享一个我自己的习惯每一台服务器上的 Docker 配置文件、docker-compose.yml、Dockerfile 都必须纳入 Git 仓库统一管理。服务器的重建要能做到一条命令恢复环境而不是靠人肉记着当时怎么装的。这套方法帮我省下来的时间远比我刚开始学习 Docker 时投入的时间多得多。Docker 本身不难难的是养成一套规范化的使用习惯把容器当作一种标准化的交付流程而不是临时解决环境问题的工具。真正掌握了这些你会发现部署、迁移、扩容这些事情都可以变得非常从容。

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

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

免费获取报价