🏝 Docker 就是"房地产开发":从施工图纸到小区物业的容器化指南

写在前面:前几节课搭了 React 前端、NestJS 后端、Nginx 代理,一个全栈项目零件齐了。但怎么把它们打包部署?答案是 Docker 。今天的课堂从一个 console.log('hello Docker!') 开始,讲到 Dockerfile 标准配方、镜像的 build/push/pull 生命周期,再到 docker-compose 编排多容器------最后用 Milvus 向量数据库 做了实战:一个 docker-compose 文件拉起三个容器,各司其职。有趣的是,readme 用蜜雪冰城的 SOP 来类比 Dockerfile,但今天我要换个更宏大的视角------房地产开发。图纸、楼盘、小区物业,一个不少。以下所有代码和概念均来自课堂真实文件。


一、Dockerfile:施工图纸

图纸就是图纸

readme 原话:

"蜜雪冰城标准操作手册 SOP,写清'先加奶茶、再加奶、放三勺糖、摇匀',任何人照着做,出来味道都一样,就成了连锁店。"
"DOCKERFILE 是一个文本配方文件,里面写着一步步'做菜'的指令,Docker 照着做它就能自动做出一个一模一样的 Docker 镜像,运行。"

这个比喻精准到可怕。但我想换一个更"工程"的视角------Dockerfile 就是施工图纸

施工图纸上写的是什么?

sql 复制代码
1. 打地基(FROM node:18-alpine)
2. 砌墙(WORKDIR /app)
3. 装管线(COPY package*.json ./)
4. 进设备(RUN npm install)
5. 搬家具(COPY . .)
6. 通水通电(EXPOSE 3000)
7. 交付入住(CMD ["node", "index.js"])

任何施工队拿到这份图纸,建出来的楼一模一样------北京建的和上海建的一样,今天建的和明年建的也一样。这就是 Dockerfile 的核心价值:可重复的构建,消除环境差异。

Hello Docker:最简施工图

课堂的 index.js 只有一行:

javascript 复制代码
console.log(`hello Docker! 我跑在容器里了`)

这行代码本身没什么好说的------但它在容器里运行,意味着背后有一份 Dockerfile 把 Node.js 运行环境、这行代码、启动命令打包成了一个镜像。你不需要在本机装 Node.js,不需要配环境变量,docker run 一下,它就跑起来了。

这就是容器化的威力------环境跟着代码走,不是代码去适应环境。


二、镜像生命周期:施工、挂牌、交房

readme 记录了镜像的完整生命流程:

"构建镜像:docker build -t my-hello . → docker login → docker push → docker pull。Dockerfile 是发布项目的标准项目之一。"

翻译成房地产语言:

Docker 命令 房地产类比 干了什么
docker build -t my-hello . 施工建楼 按图纸(Dockerfile)建楼(镜像)
docker login 开发商认证 登录镜像仓库
docker push 挂牌上市 把镜像推到 Docker Hub / 私有仓库
docker pull 买房 从仓库拉取镜像到本地
docker run 入住 从镜像启动一个容器

施工:docker build

bash 复制代码
docker build -t my-hello .
  • -t my-hello:给楼起个名字
  • .:施工图纸在哪?当前目录的 Dockerfile

施工队(Docker 引擎)读图纸,一步步执行------装系统、装依赖、拷代码、设端口、定启动命令。建完之后,你得到一个镜像------一栋建好的、随时可以交付的大楼。

挂牌:docker push

bash 复制代码
docker login    # 开发商认证
docker push my-hello  # 挂牌到 Docker Hub

镜像建好了,只存在你本机------别人用不了。docker push 把镜像推到镜像仓库(Docker Hub 或私有仓库),相当于开发商把楼盘信息挂到房产交易平台上,全世界都能看到、都能下载。

readme 特别强调了一句:

"Dockerfile 是发布项目的标准项目之一。"

以后项目的交付物不止有源代码、文档,还有 Dockerfile------有了图纸,任何人都能复刻你的环境。

买房:docker pull

bash 复制代码
docker pull my-hello

加盟商(其他开发者或服务器)不需要自己施工,直接从仓库拉取镜像------拎包入住。镜像里包含了运行所需的一切:操作系统、运行时、依赖、代码。不需要装 Node.js,不需要 npm install,不需要配环境变量------一个镜像,到处运行。


三、Docker Compose:小区物业

单个容器好管------一栋楼嘛。但现实项目往往需要多个容器协同。比如课堂提到的全栈项目:

"todos 全栈项目:前端 react + ts + zustand,后端 nest.js Todo Module,nginx 80→3000 跨域。"

至少三个服务:前端、后端、Nginx。手动 docker run 三个容器?可以,但太累。而且启动顺序、网络连接、数据卷挂载全得手动管。

Docker Compose 就是小区物业------一个文件管好所有楼。

readme 对 docker-compose 的定位:

"安装 Milvus:由多个 image 组成的。docker-compose 文件,编排多个 image 工作流。"

一个 YAML 文件,定义所有服务、网络、数据卷。docker-compose up 一条命令,整个小区全部上线。


四、实战:Milvus 向量数据库------一个三栋楼的微型小区

课堂的 milvus-standalone-docker-compose.yml 是一个真实的 docker-compose 文件,拉起 Milvus 向量数据库。Milvus 不是单容器应用------它由三个服务组成。

小区全景图

yaml 复制代码
version: '3.5'

services:
  etcd:        # 楼栋 A:物业档案室
  minio:       # 楼栋 B:地下仓库
  standalone:  # 楼栋 C:主楼

三栋楼,各司其职。让我们逐栋看。

楼栋 A:etcd------物业档案室

yaml 复制代码
etcd:
  container_name: milvus-etcd
  image: quay.io/coreos/etcd:v3.5.25
  environment:
    - ETCD_AUTO_COMPACTION_MODE=revision
    - ETCD_AUTO_COMPACTION_RETENTION=1000
    - ETCD_QUOTA_BACKEND_BYTES=4294967296
    - ETCD_SNAPSHOT_COUNT=50000
  volumes:
    - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd
  command: etcd -advertise-client-urls=http://etcd:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
  healthcheck:
    test: ["CMD", "etcdctl", "endpoint", "health"]
    interval: 30s
    timeout: 20s
    retries: 3

etcd 是一个分布式键值存储------Milvus 用它存元数据。就像小区的物业档案室,记录着"几号楼住了谁、车位分配情况、业主信息"。

关键配置解析:

配置 含义 房地产类比
image: quay.io/coreos/etcd:v3.5.25 用哪个图纸建 开发商选的施工图纸版本
environment 楼内配置 每层楼的功能设置
ETCD_QUOTA_BACKEND_BYTES: 4294967296 4GB 存储配额 档案室最多放多少档案
volumes 数据持久化 档案柜------楼拆了档案还在
command 启动命令 物业上班要做什么
healthcheck 健康检查 每月消防检查
interval: 30s 每 30 秒查一次 检查频率

volumes 这行特别值得注意:

yaml 复制代码
volumes:
  - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd

${DOCKER_VOLUME_DIRECTORY:-.} 是 shell 语法------如果设了环境变量 DOCKER_VOLUME_DIRECTORY 就用它,没设就用 .(当前目录)。数据存在宿主机的磁盘上,容器删了数据还在------楼拆了,档案柜搬到新楼继续用。

楼栋 B:minio------地下仓库

yaml 复制代码
minio:
  container_name: milvus-minio
  image: minio/minio:RELEASE.2024-05-28T17-19-04Z
  environment:
    MINIO_ACCESS_KEY: minioadmin
    MINIO_SECRET_KEY: minioadmin
  ports:
    - "9001:9001"
    - "9000:9000"
  volumes:
    - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data
  command: minio server /minio_data --console-address ":9001"
  healthcheck:
    test: ["CMD", "mc", "ready", "local"]
    interval: 30s
    timeout: 20s
    retries: 3

MinIO 是一个 S3 兼容的对象存储------Milvus 用它存向量数据和索引文件。就像小区的地下仓库,存大件物品。

它开放了两个端口:

yaml 复制代码
ports:
  - "9001:9001"   # 管理控制台
  - "9000:9000"   # API 接口

左边的 9001 是宿主机端口,右边的 9001 是容器内端口。宿主机:容器------你可以从浏览器访问 localhost:9001 打开 MinIO 的管理控制台。

账号密码都是 minioadmin------课堂环境用的默认值,生产环境绝对不能这样。

楼栋 C:milvus-standalone------主楼

yaml 复制代码
standalone:
  container_name: milvus-standalone
  image: milvusdb/milvus:v3.0.0
  command: ["milvus", "run", "standalone"]
  security_opt:
    - seccomp:unconfined
  environment:
    MINIO_REGION: us-east-1
    ETCD_ENDPOINTS: etcd:2379
    MINIO_ADDRESS: minio:9000
  volumes:
    - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus
  healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
    interval: 30s
    start_period: 90s
    timeout: 20s
    retries: 3
  ports:
    - "19530:19530"
    - "9091:9091"
  depends_on:
    - "etcd"
    - "minio"

主楼是整个小区的核心------Milvus 向量数据库本体。

它怎么找到另外两栋楼的?靠环境变量:

yaml 复制代码
environment:
  ETCD_ENDPOINTS: etcd:2379     # 档案室在哪
  MINIO_ADDRESS: minio:9000     # 仓库在哪

etcd:2379minio:9000 用的是服务名(容器名)作为主机名------Docker Compose 自动创建了一个网络,三栋楼在同一个小区(网络)里,可以用楼栋名互相串门。

三栋楼的协作关系

最后两行是关键:

yaml 复制代码
depends_on:
  - "etcd"
  - "minio"

depends_on 定义了启动顺序------主楼必须在档案室和仓库之后启动。你不能物业档案室还没建好就让人住进来。

但注意:depends_on 只保证启动顺序 ,不保证服务就绪 。etcd 容器启动了,但 etcd 服务可能还在初始化中。这就是 healthcheck 存在的意义------主楼的 start_period: 90s 给了 90 秒的宽限期,让它等另外两栋楼的服务真正就绪。

整个协作流程:

markdown 复制代码
docker-compose up
    ↓
etcd 容器启动        ← 档案室先建
minio 容器启动       ← 仓库同时建
    ↓ healthcheck 通过
milvus 容器启动      ← 主楼开工,连上 etcd 和 minio
    ↓ start_period: 90s 等待
milvus 服务就绪      ← 19530 端口对外服务

小区网络

文件最后一行:

yaml 复制代码
networks:
  default:
    name: milvus

三栋楼在同一个叫 milvus 的网络里。这个网络是 Docker Compose 自动创建的------容器之间用服务名通信(etcd:2379minio:9000),不需要知道对方的 IP。物业内部通讯,靠楼栋名就行。


五、从单楼到小区:Docker 的两层抽象

今天的文件恰好展示了 Docker 的两层抽象:

第一层:Dockerfile → 单个镜像

readme 说的:

"DOCKERFILE 是一个文本配方文件,里面写着一步步'做菜'的指令。"

一个 Dockerfile 产出一个镜像------一栋楼。适合简单应用,比如课堂的 index.js,一个 Node.js 镜像就够了。

第二层:Docker Compose → 多容器编排

readme 说的:

"docker-compose 文件,编排多个 image 工作流。"

一个 docker-compose.yml 编排多个镜像------一个小区。适合复杂应用,比如 Milvus(三个服务协同)或全栈项目(前端 + 后端 + Nginx)。

层级 文件 产出 适用场景
第一层 Dockerfile 单个镜像 单服务应用
第二层 docker-compose.yml 多容器协作 多服务系统

现实项目几乎都是第二层------很少有只用一个容器的生产系统。Docker Compose 是连接"单个容器"到"完整系统"的关键桥梁。


六、回到全栈项目:Todo 的"楼盘化"

readme 最后提到了全栈项目:

"todos 全栈项目:前端 react + ts + zustand,后端 nest.js Todo Module,nginx 80→3000 跨域。"

现在回头看这个项目------如果用 Docker 部署,就是三个容器:

scss 复制代码
docker-compose.yml
├── frontend    (React + TS + Zustand 镜像)
├── backend     (NestJS 镜像)
└── nginx       (Nginx 镜像,80→3000 反向代理)

Nginx 容器开放 80 端口对外,内部通过 Docker 网络把 /api 请求转发到 backend 容器的 3000 端口------跨域问题在容器层面自然解决,不需要 Vite 代理了。前端容器跑静态文件,Nginx 容器统一代理。

每个容器都有自己的 Dockerfile------前端一份、后端一份、Nginx 一份。docker-compose.yml 把它们组装成一个完整系统。一张图纸建一栋楼,一个 compose 文件管一个小区。

这就是 readme 说的"Dockerfile 是发布项目的标准项目之一"的完整含义------不只是给你一个镜像,而是给你一套可复现的部署方案 。别人拿到你的 docker-compose.yml,docker-compose up 一条命令,整个系统就跑起来了。


七、Milvus 配置文件里的"地产开发"学问

回头看整个 milvus-standalone-docker-compose.yml,每个配置项都有对应的"地产"含义:

配置项 房地产含义
version: '3.5' compose 文件版本 小区规划规范版本
container_name milvus-etcd / milvus-minio / milvus-standalone 每栋楼的门牌号
image etcd:v3.5.25 / minio:... / milvus:v3.0.0 施工图纸版本
environment ETCD_、MINIO_ 楼内功能配置
ports "19530:19530"、"9001:9001" 对外开门------左宿主右容器
volumes ./volumes/xxx:/xxx 地下室------楼拆了数据还在
command 启动命令 物业上班第一件事
healthcheck test/interval/timeout/retries 消防检查制度
start_period 90s 装修宽限期
depends_on etcd + minio 前置工程------先建档案室再建主楼
networks milvus 小区内部道路

一个 YAML 文件,56 行,把三个容器的镜像版本、环境变量、端口映射、数据持久化、健康检查、启动顺序、网络拓扑全部定义清楚。这不是运维,是架构设计。


PS:以前觉得 Docker 难,换个角度想------它就是房地产开发。Dockerfile 是图纸,镜像是楼盘,容器是有人住的房子,docker-compose 是小区物业。docker-compose up 一条命令,整个小区拔地而起。你还在手动 docker run 管单栋楼?

相关推荐
kyriewen1 小时前
我手写了个极简版 React Router——才搞懂 v6 为什么砍了这么多 API
前端·javascript·程序员
a1117761 小时前
Shirone 二次元博客主题 开源
前端·开源
IT_陈寒1 小时前
Python的切片赋值把我坑惨了,这不是bug是特性
前端·人工智能·后端
掘金酱1 小时前
【社区公告】致每一位掘友:关于这次调整, 想再说几句
前端·人工智能
CoderLiu1 小时前
程序化工具调用(PTC)与动态工作流引擎:深入大模型工具调用的架构演进与实践
前端·人工智能·后端
码农胖大海2 小时前
我的第一个产品,只有一段提示词
前端·ai编程·产品
邋遢道2 小时前
# 企业级 Agent 从 0 到 1(二):技术选型与最小骨架
前端·chrome
计算机魔术师2 小时前
我看了 OpenAI 首席科学家的最新长文,把原来的认知推翻了一遍
前端
乱码三千3 小时前
使用ComfyUI+MinMax-H3音视频模型生成视频
前端·后端·github