news 2026/9/19 4:12:47

Docker与Docker Compose实战教程:从零搭建容器化应用栈

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker与Docker Compose实战教程:从零搭建容器化应用栈

算起来,我接触 Docker 也有小十年了。从最早在本地虚拟机里折腾镜像,到后来在服务器上跑各种服务,再到用 Docker Compose 一把梭编排整个项目栈,这套工具链几乎贯穿了我整个后端开发生涯。说句实话,Docker 这玩意儿,你光看文档会觉得“哦,不过如此”,但真到了自己部署环境的时候,才知道那些坑有多深。

这篇教程我想了很久要怎么开头。网上关于 Docker 和 Docker Compose 的教程一抓一大把,但多数是照着官方文档翻译一遍,或者是只讲命令不讲为什么。真正能让人从零开始、一步步亲手搭起来、跑起来、再排查问题的文章,其实不多。所以我决定把我自己的实操过程完整地记录下来,包括我踩过的坑、改过的配置、验证过的命令,全部摊开给你看。

先说清楚这篇教程适合谁。如果你是刚接触 Docker 的开发者,想在自己的电脑或者服务器上把环境跑起来;如果你是个运维新手,想用 Compose 把多个服务编排好;或者你只是想在自己的机器上快速部署一个数据库、一个博客、甚至一个 AI 应用,这篇内容都能帮你省下不少时间。我会从零开始,讲清楚安装、概念、实战、排错,保证你照着做就能跑通。

1. 先把思路理清楚:Docker 和 Docker Compose 到底解决了什么问题

1.1 为什么非要用 Docker?

我见过太多新人第一次接触 Docker 时的困惑:我已经装了虚拟机,为什么还要用 Docker?这个问题问得特别好,因为它直接关系到我们为什么要学这套工具。

虚拟机模拟的是整台硬件,然后在这台“虚拟电脑”上装操作系统、装依赖、跑应用,每个虚拟机里都有一套完整的系统,资源开销大、启动慢、占磁盘空间。而 Docker 不一样,它直接共享宿主机的操作系统内核,只把应用和它需要的依赖打包到一个隔离环境里运行。打个比方,虚拟机是“在同一个小区里给每户人家盖独栋别墅”,Docker 则是“在一栋大楼里给每户人家隔出独立房间”——别墅的私密性和隔离性固然更好,但房间才是更轻量、更灵活的方案。

Docker 带来的第一个直接好处,就是环境一致性。以前我们最怕听到的话就是“在我机器上明明是好的”,这句话坑了多少开发和测试。用了 Docker 之后,你本地跑的是这个镜像,服务器上跑的也是同一个镜像,开发环境、测试环境、生产环境完全一致,所有依赖、配置都固化在镜像里,再也不会出现环境差异导致的问题。

第二个好处是快速交付和部署。以前部署一个应用,要写一堆安装脚本,手动配置各种依赖,过程极其痛苦。现在只需要一个 Dockerfile 定义好镜像,一条命令就能把镜像构建出来,推送到仓库,然后在任何一台装有 Docker 的机器上拉取运行,整个流程自动化程度极高。

第三个好处是资源利用率的大幅提升。同一台服务器上,你可以用 Docker 轻松跑十几个互不干扰的应用,而如果用虚拟机,可能跑两三个就资源告急了。这也是为什么现在无论大厂还是小团队,都在大规模用容器化方案。

1.2 Docker Compose 的定位:从“跑单个容器”到“编排整个项目”

Docker 本身解决的是单个容器的生命周期管理,但实际项目里,一个应用往往由多个服务组成:前端 Nginx、后端 Java 服务、MySQL 数据库、Redis 缓存,可能还有消息队列。如果每个服务都用docker run手动启动,你要写一大堆命令、还要自己处理网络和依赖关系,这显然不现实。

Docker Compose 干的事情,就是用一份 YAML 配置文件,定义好整个应用栈的所有服务、网络、卷,然后一条命令全部启动、全部停止。它特别适合开发环境、测试环境以及中小规模的生产环境。

我在实战中使用 Compose 最大的体感是“项目可复制性”。以前加入一个新项目,光是把环境配好就得花一两天,各种依赖版本冲突、端口被占、配置文件缺失,烦得要命。现在项目仓库里放一份docker-compose.yml,新人进来执行两条命令,整个开发环境就起来了,爽快得不行。

Compose 还有几个特别实用的特点。它能自动创建 Docker 网络,让各服务之间通过服务名直接通信,不需要自己去查 IP 地址;它能通过depends_on控制服务的启动顺序;它能通过 volume 把数据持久化到宿主机,容器删了数据还在。这些特性组合起来,真的能让部署效率提升一个量级。

1.3 我需要准备什么环境?

动手之前,先确认一下你的基础环境。这篇教程以 Linux 为主,因为服务器上大部分都是 Linux 系统,我自己也主要在 Ubuntu 上操作。但 Windows 和 macOS 我也会讲,毕竟现在很多开发者本地用的是这两种系统。

硬件方面没有特别高的要求,只要能跑得动 Docker Desktop 或者 Linux 发行版就行。要注意的是,Docker 在 Windows 上依赖 Hyper-V 或 WSL 2,在 macOS 上依赖 Hypervisor.framework,你的 CPU 必须支持虚拟化并且已经在 BIOS 中开启。这个细节稍后我会专门讲,因为太多人卡在这一步了。

如果你是 Linux 用户,建议用 Ubuntu 20.04 或 22.04 LTS 版本,这是目前最主流的服务器系统,教程里的命令也以这个环境为例。

2. 手把手安装:从零搭好 Docker 环境

2.1 Ubuntu 系统安装 Docker Engine

在 Linux 上安装 Docker,我强烈建议用官方源或者你所在地区的镜像源来安装,不要用系统自带的旧版本。以 Ubuntu 为例,安装 Docker Engine 的标准流程如下。

先更新系统包索引并安装必要依赖:

sudo apt update sudo apt install -y 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 sudo chmod a+r /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 Engine 和相关组件:

sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

这里我要特别提醒一句:上面这条命令已经包含了docker-compose-plugin,也就是 Docker Compose 的官方插件版。以前我们还需要单独去 GitHub 下载docker-compose二进制文件,现在直接通过这个插件就能使用docker compose命令,方便太多了,版本也跟着 Docker Engine 一起维护。

安装完成后,启动 Docker 服务并设置开机自启:

sudo systemctl enable docker sudo systemctl start docker

验证安装是否成功,跑一下版本命令:

sudo docker version

如果能看到 Client 和 Server 两段信息,说明核心组件已经正常工作了。

2.2 解决普通用户权限问题

这里有个非常常见的坑:安装好 Docker 后,你发现每次执行docker命令都要加sudo,不仅麻烦,而且在某些自动化脚本里会造成权限报错。原因是 Docker 的守护进程默认以 root 身份运行,它的 socket 文件只允许 root 用户访问。

解决办法是把当前用户加入docker用户组:

sudo usermod -aG docker $USER

然后退出当前会话,重新登录(或者执行newgrp docker),这样之后再运行docker命令就不需要加sudo了。

不过我得说句实话,加入 docker 组的用户其实拥有了等同于 root 的权限,因为通过 Docker 可以挂载宿主机目录、执行特权操作。所以这个操作只建议在个人开发机或者可信的团队环境中使用。如果是生产服务器,还是要严格控制谁能加入 docker 组,甚至可以通过配置远程 API 加 TLS 认证来做更细粒度的权限管理。

2.3 Windows 和 macOS 安装 Docker Desktop

如果你是在 Windows 或 macOS 上开发,最省事的方案是安装 Docker Desktop。它会帮你把 Docker Engine、Compose、Kubernetes 等一系列工具打包在一个图形化应用里。

Windows 用户注意,Docker Desktop 现在默认基于 WSL 2 运行,所以你需要在安装前启用 WSL 2 功能。以管理员身份打开 PowerShell,执行:

wsl --install

这条命令会安装 WSL 2 和默认的 Linux 发行版。装完重启电脑,再去 Docker 官网下载 Docker Desktop Installer,双击安装即可。安装过程中保持默认选项就行,它会自动配置好与 WSL 2 的集成。

macOS 用户更简单,直接下载 Docker.dmg 拖入 Applications 文件夹,打开后在状态栏能看到 Docker 的小鲸鱼图标就说明运行了。

装好后在终端里验证:

docker --version docker compose version

能正常输出版本号就对了。

2.4 更换镜像加速源:解决拉取镜像慢的问题

这里我要分享一个非常实际的体验。国内网络拉取 Docker Hub 官方镜像,速度时快时慢,慢的时候几百 MB 的镜像能让人等到怀疑人生。解决办法是配置镜像加速器。

我这边用的是阿里云的容器镜像服务加速器。你需要先注册一个阿里云账号,然后在控制台找到“容器镜像服务”,里面会给你一个专属的加速地址,格式类似https://xxxx.mirror.aliyuncs.com

然后配置 Docker 的 daemon 配置文件/etc/docker/daemon.json

{ "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"] }

保存后重启 Docker:

sudo systemctl daemon-reload sudo systemctl restart docker

配置好镜像加速之后,再去拉取镜像,速度会有质的提升。这一点在后面的实战中你能直接感受到。

3. 核心概念扫盲:镜像、容器、数据卷、网络

很多教程上来就让你跑docker run hello-world,跑完一脸懵。我觉得在动手之前,花点时间把四个核心概念搞清楚,后面的学习会顺畅非常多。

3.1 镜像(Image)与容器(Container)

镜像可以理解成一个只读的模板,里面包含了你应用运行所需的一切:代码、运行时、系统库、依赖、配置文件。就像做蛋糕用的模具,不管你倒多少次面糊,模具本身不变。

容器则是镜像的一个运行实例。同一个镜像可以同时运行多个容器,每个容器相互隔离,互不影响。就好比同一个模具做出来的蛋糕可以有不同的口味。

镜像和容器是分层构建的,Docker 使用联合文件系统(UnionFS),每一层都是只读的,只有容器运行时在最上层加一个可写层。这也是为什么多个容器共享同一个镜像时,磁盘占用很小——它们共享底层的只读层,只有各自的可写层是独立的。

构建镜像最常见的方式是写 Dockerfile。我给你看一个最简单的例子:

FROM nginx:alpine COPY index.html /usr/share/nginx/html/index.html EXPOSE 80

构建命令:

docker build -t my-nginx:v1 .

这条命令会用当前目录下的 Dockerfile 构建一个名为my-nginx:v1的镜像。-t是给镜像打 tag,便于后续管理。

3.2 数据卷(Volume):容器删除数据不丢失

容器是无状态的,这意味着如果容器被删了,容器内部的文件系统也会一起消失。但数据库的数据、用户上传的文件,这些必须持久化保存,怎么办?答案就是数据卷(Volume)。

Docker 的数据卷有几种形式。一种是名为 Volume 的 Docker 管理卷,通过docker volume create创建,数据存放在 Docker 数据目录下,隔离性好但不好直接访问;另一种是绑定挂载(Bind Mount),直接把宿主机的某个目录挂载到容器里,比如:

docker run -d -v /home/user/data:/var/lib/mysql mysql:8.0

这条命令把宿主机的/home/user/data目录挂载为 MySQL 容器的数据目录。宿主机的这个目录你可以随便用编辑器查看和备份文件,非常直观。在 Compose 里,我们也是用的是这种方式来持久化数据。

3.3 网络(Network):容器之间怎么通信

Docker 默认的网络模式有几种,但最常用的是用户自定义的 bridge 网络。在这个网络里,所有容器通过名字互相访问,不需要知道对方的 IP 地址。

手动创建一个网络:

docker network create my-network

然后启动两个容器并加入同一个网络:

docker run -d --name app --network my-network my-app:latest docker run -d --name db --network my-network mysql:8.0

这时候在app容器内部,直接访问db:3306就能连上 MySQL。Docker 内置的 DNS 服务会把服务名解析成对应的容器 IP。

Compose 里不需要你手动创建网络,它默认会为每个项目创建一个独立的网络,服务名直接用docker-compose.yml里定义的服务名即可。这个设计极大地简化了服务间通信的复杂度。

4. 实战开始:用 Docker Compose 编排 Nginx + MySQL 8 + Redis

有了前面的基础,现在进入重头戏。我们要用 Docker Compose 部署一个完整的应用栈:Nginx 作为 Web 服务器,MySQL 8 作为关系型数据库,Redis 作为缓存。这三件套是 Web 应用最常见的组合,学会了它,你就能举一反三部署其他服务。

4.1 设计项目结构

首先创建项目目录:

mkdir -p ~/docker-demo/nginx cd ~/docker-demo

nginx目录下创建一个简单的静态页面:

<!-- nginx/index.html --> <!DOCTYPE html> <html> <head><title>Docker Compose Demo</title></head> <body><h1>Hello, Docker Compose!</h1></body> </html>

再创建一个 Nginx 的配置文件nginx/default.conf

server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html; location / { try_files $uri $uri/ =404; } }

4.2 编写 docker-compose.yml

这是整个项目的核心文件,我先把完整内容放出来,然后逐段解释:

version: "3.8" services: web: image: nginx:alpine container_name: demo-web ports: - "8080:80" volumes: - ./nginx/index.html:/usr/share/nginx/html/index.html - ./nginx/default.conf:/etc/nginx/conf.d/default.conf networks: - demo-net depends_on: - db - redis db: image: mysql:8.0 container_name: demo-db environment: MYSQL_ROOT_PASSWORD: root_password MYSQL_DATABASE: demo_db MYSQL_USER: demo_user MYSQL_PASSWORD: demo_password ports: - "3306:3306" volumes: - db-data:/var/lib/mysql networks: - demo-net redis: image: redis:7-alpine container_name: demo-redis ports: - "6379:6379" volumes: - redis-data:/data networks: - demo-net volumes: db-data: redis-data: networks: demo-net:

先看version: "3.8"。这一行指定 Compose 文件格式的版本,对应 Docker Compose 的兼容版本。现在新版 Docker Compose 已经不太强制要求了,但写上可以保证兼容性和语义清晰。

services下面定义了三个服务。web用的是nginx:alpine镜像,alpine是精简版 Linux,体积小、启动快,适合做静态服务。我把本机的 8080 端口映射到容器的 80 端口,这样访问http://localhost:8080就能看到页面。

volumes在这里做了两件事:一是把本地的index.htmldefault.conf直接挂载进容器,这样做的好处是修改文件后刷新页面就生效,不用重新构建镜像;二是让 MySQ L 和 Redis 的数据持久化到 Docker 卷里,容器重建数据还在。

environment里配置 MySQL 的初始密码和数据库信息。MYSQL_ROOT_PASSWORD是 root 用户的密码,MYSQL_DATABASE会自动创建一个数据库,MYSQL_USERMYSQL_PASSWORD创建一个普通用户并授权访问这个数据库。

depends_on用来控制服务启动顺序。我们的 Nginx 虽然不直接连接 MySQL 和 Redis,但让基础服务先启动是良好的习惯,能避免应用在启动阶段连接数据库失败。

networks定义了一个自定义网络demo-net,三个服务都加入这个网络,容器之间可以通过服务名访问。

4.3 启动整个应用栈

~/docker-demo目录下执行:

docker compose up -d

-d表示以守护模式运行,日志不会刷屏。第一次运行会拉取镜像,配置好镜像加速的话应该很快。

查看运行状态:

docker compose ps

这个命令会列出所有服务、对应的容器 ID、状态、端口映射信息。三条服务状态都显示Up(或running)就说明启动成功了。

在浏览器里访问http://localhost:8080,如果能看到“Hello, Docker Compose!”的页面,恭喜你,整个应用栈已经跑通了。

4.4 验证数据持久化和容器间通信

我们来做一个实验,验证数据持久化是否生效。先进入 MySQL 容器创建一个测试表:

docker exec -it demo-db mysql -uroot -p

输入密码root_password进入 MySQL 命令行,然后:

USE demo_db; CREATE TABLE test (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50)); INSERT INTO test (name) VALUES ('docker'); SELECT * FROM test;

能看到插入的数据后,退出容器。接着模拟容器删除和重建的场景:

docker compose down docker compose up -d

再次进入 MySQL 容器查询数据:

docker exec -it demo-db mysql -uroot -p -e "SELECT * FROM demo_db.test;"

你仍然能看到那条记录。这就是数据卷的作用——容器可以随意删,数据牢牢地留在卷里。

再验证一下容器间通信。进入 Nginx 容器,看能不能 ping 通数据库:

docker exec -it demo-web sh ping demo-db

如果网络配置没问题,ping 命令是有响应的。当然nginx:alpine镜像里可能没有ping命令,你可以换成这个方式验证:在 Nginx 容器里用wget访问 MySQL 的端口:

docker exec -it demo-web wget -q -O- --timeout=2 http://demo-db:3306

没有返回东西或者连接被拒绝在预期内(因为 MySQL 协议不是 HTTP),但能看到“Connection refused”也说明主机名解析成功了,网络是通的。

4.5 容器日志与资源查看

在 Compose 项目里,查看所有服务的日志非常方便:

docker compose logs -f

-f表示持续跟随输出。想单独看某个服务的日志:

docker compose logs web

查看容器资源占用:

docker stats

docker stats会实时显示 CPU、内存、网络 I/O 等数据,在排查性能问题的时候特别有用。

5. 进阶应用:这些热门的部署场景都能用 Compose 搞定

学会了基础的三件套,你会慢慢发现 Docker Compose 几乎是万能胶。我挑几个真实的场景展开讲,每一个都是我自己实际部署过的,可以直接照搬。

5.1 用 Docker Compose 搭建私有镜像仓库 Harbor

先说一个我踩过不少坑的场景:搭建私有镜像仓库。

很多公司内部代码和镜像不便直接推到公网 Docker Hub,需要在本地搭一个仓库管理镜像。Harbor 是目前最主流的开源镜像仓库项目,支持权限管理、镜像复制、漏洞扫描等功能,功能非常全面。

Harbor 官方提供了一套基于 Docker Compose 的离线安装包。整个流程大概是这样的:

# 下载 Harbor 离线安装包 wget https://github.com/goharbor/harbor/releases/download/v2.9.0/harbor-offline-installer-v2.9.0.tgz tar xvf harbor-offline-installer-v2.9.0.tgz cd harbor

然后复制配置文件模板并修改:

cp harbor.yml.tmpl harbor.yml

harbor.yml里关键配置如下:

hostname: harbor.example.com http: port: 80 harbor_admin_password: Harbor12345 database: password: root123 data_volume: /data/harbor

配置好之后运行:

sudo ./install.sh

安装脚本会自动下载依赖镜像、编排服务并启动。成功后会看到docker compose ps输出一堆服务,包括nginxharbor-coreharbor-dbharbor-registry等组件,它们通过一个 Compose 项目整体管理。

在这之后,你就可以通过docker login harbor.example.com推送和拉取私有镜像了,相当顺滑。

5.2 用 Docker 部署监控栈:Prometheus + Node Exporter + Grafana

监控是现代应用不可缺少的一环。Docker Compose 部署监控系统非常方便,我用这套组合监控服务器状态和容器资源。

整个监控栈包含三个核心组件:Node Exporter 采集宿主机指标,Prometheus 存储和查询指标数据,Grafana 负责可视化展示。

docker-compose.yml核心内容:

services: prometheus: image: prom/prometheus:latest container_name: prometheus ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prom-data:/prometheus command: - "--config.file=/etc/prometheus/prometheus.yml" networks: - monitor-net node-exporter: image: prom/node-exporter:latest container_name: node-exporter ports: - "9100:9100" networks: - monitor-net grafana: image: grafana/grafana:latest container_name: grafana ports: - "3000:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=admin volumes: - grafana-data:/var/lib/grafana networks: - monitor-net

Prometheus 的配置文件prometheus.yml里定义抓取目标:

global: scrape_interval: 15s scrape_configs: - job_name: "node" static_configs: - targets: ["node-exporter:9100"]

注意这里targets里写的是node-exporter:9100,因为它们在同一个 Compose 网络里,服务名就是主机名。

启动后,访问http://localhost:3000,用 admin/admin 登录 Grafana,添加数据源http://prometheus:9090,再导入 Node Exporter 的官方仪表盘 ID(比如 1860),漂亮的监控面板就出来了。整个过程从零到面板展示,不到十分钟。

5.3 用 Docker 本地跑大模型 AI 应用

大模型的热度大家有目共睹,很多开发者想在自己电脑上跑 AI 应用做实验。Docker 在大模型本地部署这个场景里也非常能打。

以 ollama 为例,这是一个开源的本地大模型运行时,用 Docker Compose 部署极其简单:

services: ollama: image: ollama/ollama:latest container_name: ollama ports: - "11434:11434" volumes: - ollama-data:/root/.ollama networks: - ai-net

启动后,进入容器下载模型:

docker exec -it ollama ollama run llama3.2

然后你就可以通过 API 用了。你甚至可以直接把 ollama 和 Web 前端项目(比如 Open WebUI)一起编排,打造一个完整的本地 AI 对话界面:

services: ollama: image: ollama/ollama:latest ports: - "11434:11434" volumes: - ollama-data:/root/.ollama open-webui: image: ghcr.io/open-webui/open-webui:main ports: - "3000:8080" environment: - OLLAMA_BASE_URL=http://ollama:11434 volumes: - webui-data:/app/backend/data

这也是 Compose 强大编排能力的体现:一个 AI 应用栈,两条命令跑起来。

5.4 用 Docker Compose 白嫖一个个人博客

前面热词里提到 Hexo 部署到 GitHub,其实个人博客部署用 Docker 也很常见。我自己用过 WordPress 搭博客,也见过很多技术博主用 Ghost。

WordPress 的 Compose 配置非常经典:

services: wordpress: image: wordpress:latest ports: - "8080:80" environment: WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress_password WORDPRESS_DB_NAME: wordpress volumes: - wp-data:/var/www/html depends_on: - db db: image: mysql:8.0 environment: MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress_password MYSQL_ROOT_PASSWORD: root_password volumes: - db-data:/var/lib/mysql

跑起来后访问http://localhost:8080,按照 WordPress 的安装向导操作,几分钟就有一个个人博客。更新主题、插件都在后台完成,数据全部持久化在数据卷里,以后要迁移服务器直接备份卷即可。

6. 实战排坑:常见问题与排查技巧实录

技术文章写到这里,最该写的还是排错。我真的见过太多人卡在同一个地方,Docker 部署失败,十有八九就是下面这几个原因。

6.1 Docker Desktop 启动失败:虚拟化没开启

这个问题的典型报错是:

Docker Desktop failed to start because virtualization support was not detected.

解决思路很明确:确认你的 CPU 虚拟化已经打开。

  • Windows:打开任务管理器,性能选项卡里查看“虚拟化”是否显示“已启用”。如果显示“已禁用”,需要重启电脑进入 BIOS/UEFI,找到 Intel VT-x 或 AMD-V 选项并开启。这一步每个主板界面不同,但核心选项就是这两个词,找不到就在 BIOS 设置里搜 “Virtualization” 或 “VT-x”。
  • macOS:大多数 Mac 都自带虚拟化支持,如果你用的是老款 Mac,检查一下系统设置里是否关闭了 Hypervisor 相关设置。

确认虚拟化开启后,还要确保 WSL 2 可用:

wsl --status

如果显示 WSL 2 已安装,再重启 Docker Desktop 一般就能解决。

6.2 拉取镜像超时和连接失败

典型报错:

Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection

这个问题的根因就是网络访问 Docker Hub 不稳定。解决办法就是我前面提到的配置镜像加速器。如果你已经配置了加速器但还是超时,检查一下/etc/docker/daemon.json格式是否正确,JSON 配置里漏一个逗号或者多一个花括号都会导致 Docker 服务起不来。

改完配置记得完整执行这三步:

sudo systemctl daemon-reload sudo systemctl restart docker docker pull nginx:alpine

最后一条命令是验证,能正常拉取就说明配置生效了。

6.3 容器一直重启或启动后马上退出

这个问题的典型场景是:执行docker compose up后,容器几秒钟就 Exited,或者一直在 Restarting 状态。

排查方法分几步。第一步看日志:

docker compose logs <服务名>

日志会直接告诉你失败原因。最常见的几种:

  • 端口被占用,报错信息类似Bind for 0.0.0.0:8080 failed: port is already allocated。用lsof -i:8080或者netstat -tlnp | grep 8080找到占用进程,杀掉或者改映射端口。
  • 配置文件路径错误,容器里找不到挂载的文件。检查docker-compose.yml里的volumes路径相对于docker-compose.yml文件的位置是否正确。
  • 权限问题,比如挂载目录没有读写权限。报错会提到Permission denied。解决办法是让宿主机目录对当前用户可写,或者调整容器用户。

第二步,用docker ps -a查看容器的退出码。退出码是一个重要线索:0是正常退出,1是通用错误,137是被强制杀掉(通常是 OOM 或手动 kill),139是段错误。

第三步,实在看不出问题,可以去掉-d直接前台运行:

docker compose up

这样所有服务的日志会实时刷在终端里,问题一眼就能看到哪一行报错。

6.4 数据库数据丢失

这个问题的原因只有一个:没有给数据库容器配置数据卷。很多人第一次部署 MySQL,直接docker run -d mysql:8.0,看到运行起来了就觉得大功告成,结果容器一删,数据全没了,追悔莫及。

在 Compose 里,每个需要持久化数据的服务都要明确挂载数据卷。MySQL 挂到/var/lib/mysql,Redis 挂到/data,PostgreSQL 挂到/var/lib/postgresql/data。一定要弄清楚不同镜像的数据目录在哪,挂错目录等于没挂。

6.5 Compose 命令找不到

如果你用的是旧版 Docker,可能没有docker compose这个子命令。这时候有几种选择:

  • 升级 Docker Engine 到新版,推荐,因为这是官方推荐的演进方向。
  • 安装旧的独立docker-compose工具:
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose

注意新版 Compose 的命令是带横线的docker compose,独立版则是带两个词之间连字符的docker-compose。两个命令别混用,写脚本的时候尤其要留意。

6.6 容器时间不对

容器默认使用 UTC 时区,与我们的本地时间差了 8 个小时。日志时间看起来会非常别扭。解决办法是在 Compose 文件里设置时区环境变量:

services: any-service: environment: - TZ=Asia/Shanghai

但要注意,有些镜像不读这个环境变量,需要挂载宿主机时区文件:

volumes: - /etc/localtime:/etc/localtime:ro

这个坑在日志分析、定时任务调度的排障中尤其容易踩到,提前配置好能少很多麻烦。

6.7 常见问题速查表

现象最常见原因快速解决方法
docker compose命令不存在Docker 版本过旧升级 Docker 或用独立版 docker-compose
容器启动即退出配置错误或端口冲突看日志和退出码定位
镜像拉取慢/超时网络原因配置镜像加速器
容器间无法通信服务不在同一网络检查 Compose 网络配置
容器数据丢失未挂数据卷配置 volumes 持久化
宿主机目录挂载不生效路径写错或权限不足检查路径和权限
容器日志时区错误默认 UTC设置 TZ 环境变量

7. 一点实操经验和后续扩展建议

写到最后,我再分享一个我觉得特别关键的实操经验:使用 Docker Compose 管理环境,一定要把docker-compose.yml和所有配置文件纳入版本控制

我踩过一次很疼的坑:在一台服务器上部署了很久的一套服务,后来服务器系统坏了要重装,结果发现原来的docker-compose.yml根本没有备份,配置文件散落在各个目录里,恢复过程极其痛苦。从那以后,我养成了一个习惯:每个项目的 Compose 文件、环境变量样例、部署文档都存在 Git 仓库里,新服务器一键 clone,改一下环境变量就能恢复服务。

另外,生产环境部署时,建议在docker-compose.yml之外单独使用一个.env文件来管理敏感配置,比如数据库密码、API Token。Compose 原生支持.env文件,会自动将里面的变量注入到配置中:

DB_PASSWORD=complex_password REDIS_PASSWORD=another_password

然后在 Compose 文件里这样引用:

environment: MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}

这样既能避免明文密码出现在 Git 历史里,又方便不同环境切换配置,算是一个低成本但收益很高的习惯。

我自己现在的工作流程里,Docker 和 Docker Compose 几乎是无处不在的存在。无论是本地快速起一个测试环境、在服务器上部署正式服务,还是给客户交付一套可以一键部署的应用,Compose 都是我最先拿出来的工具。它把部署这件事的门槛拉得非常低,让开发者可以把精力放在应用本身,而不是折腾环境。

最后再给你一个小技巧:刚开始学 Compose 的时候,不用急着把所有服务都编排进去。先从单个服务跑通,再加第二个、第三个。每加一个服务就验证一次它们之间的通信是否正常,这样出了问题能快速定位,不至于一下子面对一堆报错无从下手。这套工具链用熟了之后,你就发现部署一个新项目根本不是事儿——写一份 Compose 文件,跑两条命令,整个环境就安安静静地躺在那里了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 4:12:20

配电网时序潮流计算:含DG与EV的IEEE33节点建模实操

说实话&#xff0c;配电网的潮流计算做过的人不少&#xff0c;但能把分布式电源、电动汽车充电负荷和时序特性全部揉进一个IEEE33节点模型里做透彻的&#xff0c;并不多见。这个项目标题我一看就很有共鸣——它几乎是目前新型配电网规划领域最典型的“标准考题”之一。很多入门…

作者头像 李华
网站建设 2026/9/19 4:11:29

SSE流式输出实战:Spring Boot与React实现AI对话逐字返回

1. 从"转圈等待"到"逐字蹦出"&#xff1a;流式输出到底改变了什么如果你用过 ChatGPT 的网页版&#xff0c;一定对那种"文字一个个蹦出来"的体验印象深刻。你问它一个问题&#xff0c;它不会让你干等十几秒然后一次性甩出一大段答案&#xff0c;…

作者头像 李华
网站建设 2026/9/19 4:09:42

DeepSeek V4 Pro成本优化实战:从硬件租赁到服务流计费

1. 项目概述&#xff1a;这不是一次技术升级&#xff0c;而是一次成本结构的重新定义“DeepSeek V4 Pro 不下线了”——这句话最近在AI工程圈里传得很快&#xff0c;但很多人只听到了“不下线”三个字&#xff0c;就默认是“服务更稳了”“模型更强了”&#xff0c;甚至有人直接…

作者头像 李华
网站建设 2026/9/19 4:09:02

测试工程师成长路线图:从手工测试到自动化与质量保障

1. 先聊点实在的&#xff1a;测试工程师到底在做什么很多刚入行或者准备转行的朋友问我&#xff0c;测试工程师是不是就是每天"点点点"&#xff0c;拿着测试用例表格&#xff0c;按部就班地执行&#xff0c;然后提交一堆bug列表&#xff1f;我做了七八年测试&#xf…

作者头像 李华
网站建设 2026/9/19 4:03:34

AIStarter+Wan2.2 Animate整合包:本地AI视频生成避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华