news 2026/5/8 17:10:36

Docker 学习篇(五)| docker 与 docker compose

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker 学习篇(五)| docker 与 docker compose

Docker 学习篇(五)| docker 与 docker compose

  • 一、docker 与 docker compose 的关系
    • 1.1 一句话概括
    • 1.2 它们读什么文件
    • 1.3 它们都能做「构建」和「启动」
  • 二、构建阶段:源码 → 镜像
    • 2.1 docker build —— 单模块构建
    • 2.2 docker compose build —— 批量构建
    • 2.3 构建阶段对比总结
  • 三、启动阶段:镜像 → 容器
    • 3.1 docker run —— 单容器启动
    • 3.2 docker compose up —— 批量启动
    • 3.3 启动阶段对比总结
  • 四、最佳实践:各阶段用什么工具
    • 个人项目推荐路线
    • 什么时候该用 build:,什么时候坚持 image:
    • 一句话总结
  • 五、完整示例:blog 项目走一遍
    • 第一步:写 Dockerfile
    • 第二步:写 docker-compose.yml(全部用 image:)
    • 第三步:本地构建 + 启动
    • 第四步:部署到服务器
  • 速查总表

一、docker 与 docker compose 的关系

1.1 一句话概括

docker 是单兵作战工具,管单个对象(一个镜像、一个容器)。
docker compose 是批量指挥工具,管整个项目(一组容器 + 网络 + 依赖)。

docker ← 管单个:docker run 一个容器、docker build 一个镜像 docker compose ← 管整个项目:docker compose up 启动一组容器

1.2 它们读什么文件

工具读哪个文件能不能读另一个文件
dockerDockerfile不认识docker-compose.yml。敲docker build,它只看当前目录有没有 Dockerfile,yml 放在旁边它也不理
docker composedocker-compose.yml可以通过build:认识 Dockerfile。yml 里写了build: ./my-app,compose 就会去那个目录找 Dockerfile 并调用docker build

关键区别:

docker build -t blog-server . ← 只读 Dockerfile,不认识 yml docker compose up -d ← 读 docker-compose.yml docker compose build ← 读 yml → 找 build: → 读 Dockerfile docker compose up -d --build ← 读 yml → 找 build: → 读 Dockerfile → 构建 → 启动

docker compose能通过 yml 里的build:路径找到 Dockerfile,但 Dockerfile 反过来完全不知道 yml 的存在——这个认知是单向的

1.3 它们都能做「构建」和「启动」

两个工具的本质能力重叠在两个阶段:

docker docker compose │ │ ┌───────┴───────┐ ┌───────┴───────┐ │ │ │ │ 构建 启动 构建 启动 (docker build) (docker run) (compose build) (compose up)

后续章节就从这两个阶段入手,逐个对比。


二、构建阶段:源码 → 镜像

2.1 docker build —— 单模块构建

构建是什么意思?

把源码 + 运行环境(JDK、依赖库等)打包成一个只读的镜像文件。一次构建,到处运行。

读取的文件:

Dockerfile。这是唯一输入,docker-compose.yml 跟它没有任何关系。

命令:

dockerbuild-t镜像名:标签.# ↑ ↑ ↑# 镜像名:标签 构建上下文

存在的不足:

一个项目如果有多个模块(blog-server、blog-ui),需要敲多次:

dockerbuild-tblog-server:latest ./blog-serverdockerbuild-tblog-ui:latest ./blog-ui

手动逐个构建,每个都要敲一遍。项目模块越多越麻烦,而且没人帮你判断构建顺序。


2.2 docker compose build —— 批量构建

构建是什么意思?

通过 docker-compose.yml 批量调用docker build,一次完成所有镜像的构建。本质上是对docker build的批量包装。

读取的文件:

docker-compose.yml。但 compose 自己不会凭空构建——它必须先在 yml 里看到build:指令,才知道要去哪里找 Dockerfile。

# yml 里写了 build: —— compose 认得它,会去读 Dockerfileservices:blog-server:build:./blog-server# → compose 找这里/Dockerfile → 调用 docker build

如果 yml 里用的是image:,compose 在构建阶段就无事可做:

services:blog-server:image:blog-server:latest# → compose 不构建,直接等启动时用已有镜像

命令:

dockercompose build# 构建 yml 中所有写了 build: 的服务dockercompose build blog-server# 只构建指定服务dockercompose up-d--build# 构建 + 启动(一步到位)

存在的不足:

build: 模式下,compose 帮你省了一个命令,但绑死了构建和源码位置。问题出在部署时:

服务器上: ✅ 有 docker-compose.yml ✅ 有 .tar 镜像文件 ❌ 没有源码 ❌ 没有 Dockerfile docker compose up -d ← 报错:找不到 ./blog-server/Dockerfile

服务器没有源码和 Dockerfile,build:指向的路径不存在,compose 直接报错。build: 在服务器上是死路一条。


2.3 构建阶段对比总结

docker builddocker compose build
构建是什么意思源码+环境 → 一个镜像批量调用 docker build
读什么文件Dockerfile先读 yml 找build:,再读 Dockerfile
命令docker build -t 镜像名 .docker compose build
能同时构建多个吗❌ 一次一个✅ 批量
需要源码位置信息需要(.指定上下文)需要(build:指定路径)
服务器上能用吗✅ 不需要,服务器只需docker load❌ 服务器没源码,build:报错

三、启动阶段:镜像 → 容器

3.1 docker run —— 单容器启动

启动是什么意思?

从已有镜像创建一个容器实例并运行起来。镜像停在文件状态,容器是真正干活的进程。

命令:

dockerrun-d\--nameblog-server\-p8081:8080\-vblog-upload:/app/upload\-eDB_HOST=mysql\--networkblog-net\--restartunless-stopped\blog-server:latest

存在的不足:

服务一多,问题就暴露了:

  1. 命令又长又重复— 四个服务要敲四段类似的参数,端口、挂载、环境变量每个都要手写
  2. 没有统一管理入口— 启停得逐个操作:docker start mysqldocker start redisdocker start blog-server……
  3. 网络得手动建— 容器间要互访,必须先docker network create blog-net,每个容器加--network。漏一个就连不上
  4. 没有启动顺序控制— blog-server 依赖 MySQL,但docker run不会等你,MySQL 没就绪它就挂了

3.2 docker compose up —— 批量启动

启动是什么意思?

根据 yml 声明的一次性配置,把一组镜像启动为一组相互连通的容器。相当于把 N 条docker run写成一份配置文件,一条命令执行。

命令:

dockercompose up-d# 启动所有服务dockercompose up-dblog-server# 只启动 blog-server

compose 自动做了三件事:

  1. 自动建网络— 名叫<目录名>_default,所有容器都在这个网络里,服务名就是 DNS 域名
  2. 自动命名容器<目录名>-<服务名>-1,不用手动--name
  3. 自动管理依赖顺序depends_on保证依赖先启动
services:blog-server:depends_on:mysql:condition:service_healthy# 等 MySQL 健康检查通过才启动

存在的不足:

  1. yml 变了才增量更新— 改 yml 后重跑up -d,没变的服务不动。但如果docker run起了一个同名容器,compose 会报错
  2. 纯 docker run 的场景不适用— 只跑一个 hello-world 测试,写 yml 太隆重了
  3. 容易让人忽略底层— 刚上手时用 compose 很爽,但容器网络、数据卷、镜像分层这些概念不通过docker run亲手敲一遍,很难真正理解

3.3 启动阶段对比总结

docker rundocker compose up
启动是什么意思镜像 → 一个容器镜像 → 一组容器
读什么文件无配置文件,全靠命令行参数docker-compose.yml
命令docker run -d --name ... 镜像名docker compose up -d
网络配置手动docker network create+--network自动创建,服务名 = DNS
容器命名手动--name自动:<目录名>-<服务名>-1
依赖顺序不处理depends_on 控制
适合场景单个容器、临时测试两个及以上服务的项目

四、最佳实践:各阶段用什么工具

个人项目推荐路线

构建阶段:docker build(本地打镜像) ↓ 镜像传输:docker save → .tar → 传到服务器 → docker load ↓ 启动阶段:docker compose up(同一份 yml,不改一行)

为什么构建不用 compose build,启动却用 compose up?

阶段推荐工具原因
构建docker build服务器不需要构建,compose build在服务器上无用还报错
启动docker compose up项目管理需要批量能力,手动 docker run 不可维护

什么时候该用 build:,什么时候坚持 image:

image: 模式(推荐) build: 模式 ───────────────── ───────────── 个人项目、生产部署 大团队分文件场景 本地服务器同一份 yml 本地开发省一个命令

image:模式下,compose不参与构建,只负责启动,职责清晰:

dockerbuild-tblog-server.# 构建归 docker 管dockercompose up-d# 启动归 compose 管

一句话总结

docker build + docker compose up,各司其职,互不越界。

— 构建阶段用docker build,因为服务器只需要镜像不需要源码。

— 启动阶段用docker compose up,因为项目管理需要批量能力。

build:是 compose 认识 Dockerfile 的桥梁,但只在本地开发时用,部署到服务器上还是image:最稳。


五、完整示例:blog 项目走一遍

第一步:写 Dockerfile

后端blog-server/Dockerfile(多阶段构建):

FROM maven:3.9-eclipse-temurin-21 AS builder COPY . . RUN mvn clean package -DskipTests FROM eclipse-temurin:21-jre-alpine COPY --from=builder target/*.jar app.jar CMD ["java", "-jar", "app.jar"]

前端blog-ui/Dockerfile(多阶段构建):

FROM node:20-alpine AS builder COPY package*.json . RUN npm install COPY . . RUN npm run build FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf

第二步:写 docker-compose.yml(全部用 image:)

services:mysql:image:mysql:8.0container_name:blog-mysqlports:["3307:3306"]volumes:["mysql-data:/var/lib/mysql"]environment:MYSQL_ROOT_PASSWORD:rootMYSQL_DATABASE:bloghealthcheck:test:["CMD","mysqladmin","ping","-h","localhost"]restart:unless-stoppednetworks:[blog-net]redis:image:redis:7-alpinecontainer_name:blog-redisports:["6380:6379"]restart:unless-stoppednetworks:[blog-net]blog-server:image:blog-server:latestcontainer_name:blog-serverports:["8081:8080"]environment:DB_HOST:mysqlDB_PORT:3306REDIS_HOST:redisREDIS_PORT:6379depends_on:mysql:condition:service_healthyrestart:unless-stoppednetworks:[blog-net]blog-ui:image:blog-ui:latestcontainer_name:blog-uiports:["80:80"]depends_on:[blog-server]restart:unless-stoppednetworks:[blog-net]volumes:mysql-data:networks:blog-net:driver:bridge

第三步:本地构建 + 启动

# ==== 构建阶段:用 docker build ====dockerbuild-tblog-server:latest ./blog-serverdockerbuild-tblog-ui:latest ./blog-ui# ==== 启动阶段:用 docker compose up ====dockercompose up-d# 浏览器访问 http://localhost ← 前端 Nginx# Nginx 代理 /api/* → blog-server:8080# blog-server 连 mysql:3306、redis:6379

第四步:部署到服务器

# 本地导出镜像dockersave-oblog-server.tar blog-server:latestdockersave-oblog-ui.tar blog-ui:latest# 传到服务器后dockerload-iblog-server.tardockerload-iblog-ui.tardockercompose up-d# 同一份 yml,不改一行

部署时建议删掉 yml 中 MySQL 和 Redis 的ports映射——生产环境只暴露前端 80/443 就够了。


速查总表

阶段工具读什么文件命令存在不足
构建docker buildDockerfiledocker build -t 名 .一次构建一个,多个模块敲多次
构建docker compose buildyml →build:→ Dockerfiledocker compose build部署到服务器没源码就废
启动docker run无配置文件(全参数)docker run -d --name ...服务一多不可维护
启动docker compose updocker-compose.ymldocker compose up -d单容器场景写 yml 太隆重
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/8 17:09:35

打开tun模式无法上网

打开tun模式无法上网&#xff08;排除dns的问题&#xff09;&#xff0c;但是使用系统代理可以正常上网&#xff0c;可能和电脑之前安装的虚拟机或者其他能创建虚拟网卡的东西有冲突&#xff0c;解决方法&#xff1a;0、winr 键入cmd&#xff0c;按回车 1、netsh winsock reset…

作者头像 李华
网站建设 2026/5/8 17:08:56

从三星S8看智能手机产业:硬件集成、生态博弈与未来形态

1. 项目概述&#xff1a;从S8看智能手机产业的复杂博弈2017年春天&#xff0c;当三星正式向外界揭开Galaxy S8的面纱时&#xff0c;我作为一名长期跟踪半导体与消费电子行业的从业者&#xff0c;感受到的远不止是一款新手机的发布。那更像是一个信号&#xff0c;一个标志着智能…

作者头像 李华
网站建设 2026/5/8 17:08:56

3个技巧让你彻底告别网盘下载烦恼:LinkSwift直链助手深度解析

3个技巧让你彻底告别网盘下载烦恼&#xff1a;LinkSwift直链助手深度解析 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘…

作者头像 李华