拓冰建站拓冰建站
首页 / 资讯中心 / 正文

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 ar /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] }保存后重启 Dockersudo 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 headtitleDocker Compose Demo/title/head bodyh1Hello, Docker Compose!/h1/body /html再创建一个 Nginx 的配置文件nginx/default.confserver { 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.html和default.conf直接挂载进容器这样做的好处是修改文件后刷新页面就生效不用重新构建镜像二是让 MySQ L 和 Redis 的数据持久化到 Docker 卷里容器重建数据还在。environment里配置 MySQL 的初始密码和数据库信息。MYSQL_ROOT_PASSWORD是 root 用户的密码MYSQL_DATABASE会自动创建一个数据库MYSQL_USER和MYSQL_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- --timeout2 http://demo-db:3306没有返回东西或者连接被拒绝在预期内因为 MySQL 协议不是 HTTP但能看到“Connection refused”也说明主机名解析成功了网络是通的。4.5 容器日志与资源查看在 Compose 项目里查看所有服务的日志非常方便docker compose logs -f-f表示持续跟随输出。想单独看某个服务的日志docker compose logs web查看容器资源占用docker statsdocker 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.ymlharbor.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输出一堆服务包括nginx、harbor-core、harbor-db、harbor-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_PASSWORDadmin volumes: - grafana-data:/var/lib/grafana networks: - monitor-netPrometheus 的配置文件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_URLhttp://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 或手动 kill139是段错误。第三步实在看不出问题可以去掉-d直接前台运行docker compose up这样所有服务的日志会实时刷在终端里问题一眼就能看到哪一行报错。6.4 数据库数据丢失这个问题的原因只有一个没有给数据库容器配置数据卷。很多人第一次部署 MySQL直接docker run -d mysql:8.0看到运行起来了就觉得大功告成结果容器一删数据全没了追悔莫及。在 Compose 里每个需要持久化数据的服务都要明确挂载数据卷。MySQL 挂到/var/lib/mysqlRedis 挂到/dataPostgreSQL 挂到/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: - TZAsia/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_PASSWORDcomplex_password REDIS_PASSWORDanother_password然后在 Compose 文件里这样引用environment: MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}这样既能避免明文密码出现在 Git 历史里又方便不同环境切换配置算是一个低成本但收益很高的习惯。我自己现在的工作流程里Docker 和 Docker Compose 几乎是无处不在的存在。无论是本地快速起一个测试环境、在服务器上部署正式服务还是给客户交付一套可以一键部署的应用Compose 都是我最先拿出来的工具。它把部署这件事的门槛拉得非常低让开发者可以把精力放在应用本身而不是折腾环境。最后再给你一个小技巧刚开始学 Compose 的时候不用急着把所有服务都编排进去。先从单个服务跑通再加第二个、第三个。每加一个服务就验证一次它们之间的通信是否正常这样出了问题能快速定位不至于一下子面对一堆报错无从下手。这套工具链用熟了之后你就发现部署一个新项目根本不是事儿——写一份 Compose 文件跑两条命令整个环境就安安静静地躺在那里了。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门