几年前,老王在小区门口开了家小面馆:煮面、浇头、收银,一个人全包。后来生意火了,他扩成一家大餐厅,请了切配、掌勺、传菜、收银好几个师傅。麻烦也随之而来——切配把牛肉切好了,掌勺的却还没热锅;传菜员等了半天,不知道哪桌的菜该先上。整个后厨乱成一锅粥。老王终于醒悟:后厨缺的不是更多师傅,而是一份让所有人都照章办事的《总菜单》,外加一个能统筹全局的领班。 Docker 的世界也在经历同样的事。单个容器像一个全能的“小面馆”;但一个完整应用——尤其是一套 AI 应用——通常需要数据库、缓存、模型推理、前端页面等多个容器同时协作。Docker Compose 正是那个领班,它手里的《总菜单》就是 docker-compose.yml:把每个服务用什么镜像、暴露哪些端口、谁先启动、数据存在哪儿全部写清楚。你只需敲一条命令,整个后厨按单开工。本文就带你彻底读懂这份总菜单。

岗位关联

掌握 Docker Compose,你就能像点菜一样一键编排整套 AI 应用。这是 AI 工程师走向工程化、DevOps 工程师落地多容器部署的必备技能。

目录
  1. 可视化演示
  2. 总菜单是什么:Compose 概述
  3. 总菜单的文书格式:配置语法
  4. 传菜窗口与路线:网络编排
  5. 后厨的冷柜:卷与存储
  6. 菜单上的流动贴纸:环境管理
  7. 上菜顺序与火候:部署编排
  8. 打烊后的日常:部署运维
  9. AI 的满汉全席:AI 场景实战
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示Docker Compose多容器编排三大维度:服务拓扑(6容器bridge网络+DNS解析+端口映射)、生命周期(up启动/scale扩展/down停止)、网络与数据卷(bridge通信+命名卷+绑定挂载),三模式递进呈现编排核心机制。

本节配有交互动效(进入视口后自动加载,约 3KB)。

多容器服务拓扑:bridge网络+DNS解析 DC管理节点编排6个服务:WEB/API/DB/RED/WRK/NGX 服务名即主机名,Compose内置DNS自动解析容器IP Service → DNS → Container_IP ports字段映射宿主机端口到容器端口

总菜单是什么:Compose 概述

想象你从一家小面馆做起,生意好到不得不开成餐厅。一个人时,煮面、浇头、收银全包;人一多,反而乱了:切配把牛肉切好了,掌勺却还没热锅;传菜员干等半天,不知道哪桌先上。Docker 世界也一样。一个 docker run nginx 是“一个人的小面馆”;但完整的应用通常要数据库、缓存、后端、前端多个容器一起跑,谁先启动、谁连谁、数据放哪,必须有人统筹。

Docker Compose 就是 Docker 官方推出的“后厨领班”,解决单机上的多容器协作问题。它通过一份 docker-compose.yml 文件,把应用涉及的所有服务声明清楚,然后由 Compose 统一创建、启动、停止、清理。

使用 Compose 只有三步:写配置、拉镜像、启动。安装也简单——Docker Desktop 自带 Compose;Linux 上安装 docker-compose-plugin 插件即可。启动时执行 docker compose up -d,它会按依赖顺序把容器逐一拉起;收工时执行 docker compose down,一键清理容器和网络。

这份“总菜单”把每个岗位写得明明白白:谁掌勺、谁切配、谁传菜。老板只需一声令下,后厨自动按单运转——这就是 Compose 的魅力。

Sall={s1,s2,…,sn}\displaystyle S_{\text{all}} = \{ s_1, s_2, \dots, s_n \}
这个公式表达“一个应用 = 一组服务的集合”,每个服务是一个独立容器。
  1. 应用全家福S_all 表示整个应用系统。
    Sall\displaystyle S_{\text{all}}
  2. 集合容器花括号是集合符号,装下所有服务成员。
    {s1,s2,…,sn}\displaystyle \{ s_1, s_2, \dots, s_n \}
  3. 单个服务s_i 是第 i 个服务,例如数据库或推理接口。
    si\displaystyle s_i

总菜单的文书格式:配置语法

总菜单不能随手涂鸦:菜名写哪、配料写哪、口味备注写哪,都有固定格式。如果不按格式写,传菜员看不懂,整个后厨停摆。docker-compose.yml 的“文书格式”就是 YAML。YAML 靠缩进表达层级,冒号表示键值对。最常见的翻车现场,就是有人用了 Tab 缩进,Compose 直接拒绝启动。

一个最小配置包含三个层级:顶层声明项目元信息,services 列出所有服务,每个服务名下面是它的具体配置。核心字段有四个:image 指定用哪个镜像;ports 配置端口映射;depends_on 声明先启动谁;volumes 挂载数据卷。

例如一个经典三件套:web 依赖 api,api 依赖 db,在文件里就是三个服务名,各自配上镜像和依赖关系。这段配置看似简单,却是整个后厨的“岗位说明书”——每个容器是什么角色、什么时候入场,全都定死了。

菜单文书格式对了,每个岗位才知道自己做什么;YAML 缩进对了,Compose 才知道每个服务如何定义。

si=⟨imagei, portsi, volumesi, envi⟩\displaystyle s_i = \langle image_i,\ ports_i,\ volumes_i,\ env_i \rangle
每个服务可以看作一个四元组:镜像、端口、卷、环境变量。
  1. 服务的四要素s_i 代表一个服务,尖括号里是它的完整档案。
    si=⟨… ⟩\displaystyle s_i = \langle \dots \rangle
  2. 镜像字段image_i 决定容器从哪个镜像创建,相当于“用哪本菜谱”。
    imagei\displaystyle image_i
  3. 端口映射ports_i 定义容器对外暴露的入口。
    portsi\displaystyle ports_i
  4. 存储与配置volumes_i 处理持久化,env_i 注入运行时配置。
    volumesi, envi\displaystyle volumes_i,\ env_i

传菜窗口与路线:网络编排

后厨传菜靠固定窗口和路线:热菜走热菜窗口,凉菜走凉菜电梯。没人会在走廊里大喊“红烧肉你算哪根葱”——大家认窗口、认编号。容器世界也一样,可靠沟通要靠网络规则。

每个容器启动后 IP 都会变。如果程序里写死某个容器的 IP,一重启就断连。Compose 的解决方案是:为每个项目默认创建独立网络,并内置 DNS 服务发现。同一个网络内的容器,直接用“服务名”当主机名访问,IP 变化不影响通信。

在 docker-compose.yml 里可以自定义网络,比如让数据库待在“内网”,只允许 API 服务访问它;前端则通过端口映射把入口暴露给宿主机。容器间通信时,URL 写成 http://api:8000,而不是 http://172.18.0.2:8000。对外提供服务则需要 ports 映射,例如 "8080:80" 表示宿主机 8080 端口转发到容器内 80 端口——这是外部世界进入后厨的唯一“窗口”。

传菜员认窗口编号,容器认服务名。菜单上写清楚走哪个窗口、哪个电梯,请求就能准时送达。

DNS: namei ⟼ IPi\displaystyle \text{DNS}: \ name_i \ \longmapsto \ IP_i
服务名通过内置 DNS 解析为容器 IP,这是服务发现的核心机制。
  1. 服务名name_i 是 compose 里定义的服务名。
    namei\displaystyle name_i
  2. 解析动作longmapsto 表示“映射到”某个具体地址。
    ⟼\displaystyle \longmapsto
  3. 目标 IPIP_i 是容器当前的内网地址,由 Docker 自动分配。
    IPi\displaystyle IP_i

后厨的冷柜:卷与存储

总菜单上会注明“高汤存放在 3 号冷柜,多个灶台共用”。容器是一次性餐盒——用完就扔;但高汤、秘制酱料这些“老本”,必须留在冷柜里,下次还能用。数据卷(volume)就是这个冷柜。

容器文件系统是临时的,容器删除后,里面写入的文件全部蒸发。数据卷是 Docker 管理的独立存储区,生命周期与容器分离。这是“持久化”的本质:锅可以换,但冷柜里的老汤不能丢。

声明一个命名卷,只需在文件顶层 volumes 下写个名字,服务里用 卷名:容器路径 的格式挂载。例如 model_cache:/cache,就把卷挂到了容器的 /cache 目录。还有一种是 bind mount,直接把宿主机目录映射进容器,适合开发时热更新代码。多个容器挂同一个卷时,它们就像共用一个冷柜:模型服务写缓存,另一个服务能立刻读到。注意 docker compose down 默认不删卷,只有显式加 -v 才会连冷柜一起清空。

冷柜里的老汤不会因为锅刷了就消失;卷里的模型权重,也不会因为容器删了就丢失。

ci⇌V⇌cj\displaystyle c_i \rightleftharpoons V \rightleftharpoons c_j
两个容器通过同一个卷双向读写,实现数据共享。
  1. 两个容器c_i 与 c_j 代表参与共享的两个服务。
    ci, cj\displaystyle c_i,\ c_j
  2. 共享卷V 是命名卷,相当于公共冷柜。
    V\displaystyle V
  3. 双向读写rightleftharpoons 表示两个方向都可以读写同一份数据。
    ⇌\displaystyle \rightleftharpoons

菜单上的流动贴纸:环境管理

总菜单上随时可以贴一张流动贴纸:“今日 VIP 席有忌口,改上素汤。”这些话不用重印菜单,贴上去就行。环境变量就是容器上的流动贴纸。

同一个镜像如果写死配置,换环境就得重新构建镜像。环境变量让“镜像不动,配置可变”——开发、测试、生产共用同一个镜像,只换变量。这就是 12-Factor 应用里“配置与代码分离”的思想。

Compose 提供三种写法。environment 直接在 yml 里写键值对,适合少量配置;env_file 引用一个外部 .env 文件,适合放较多或敏感的配置,注意别提交进 Git 仓库;变量替换 ${VAR:-default} 则让 compose 文件从宿主机环境或 .env 中取值,取不到就用默认值。比如 ${GPU_MODE:-cpu},同一份编排文件既能跑 CPU 也能跑 GPU,全看运行时怎么传。

贴纸撕下还能换新的;环境变量改完重启就生效——菜单(镜像)不用重印。

Vfinal={Venvif Venv is setdefaultotherwise\displaystyle V_{final} =\begin{cases}V_{env} & \text{if } V_{env}\ \text{is set} \\default & \text{otherwise}\end{cases}
容器最终拿到的变量值:优先取环境里已定义的,未定义则回退到默认值。
  1. 宿主变量V_env 是当前环境已经设置的变量。
    Venv\displaystyle V_{env}
  2. 默认回退若变量未定义,则使用 default。
    default\displaystyle default
  3. 最终取值V_final 是容器内实际拿到的值。
    Vfinal\displaystyle V_{final}

上菜顺序与火候:部署编排

总菜单上的出菜顺序是“先文火炖高汤,再爆炒,最后摆盘”。顺序一乱,整桌菜全砸。Compose 也要回答:谁先启动?什么时候才算“真正准备好”?

很多初学者以为 depends_on 就是“等上游就绪后再启动”,其实不然。它只保证上游容器先被创建并启动,但容器启动不等于服务可用——数据库镜像起来了,端口可能还在初始化。如果 API 立刻连接,照样失败。这就好比高汤锅刚放上灶台,你就让人开始炒菜,火候根本不对。

靠谱的姿势是配合健康检查:在服务上写 healthcheck,用命令反复探测就绪状态;然后在依赖方写 depends_on: condition: service_healthy,等待上游“体检合格”再启动自己。此外,Compose 还支持简单的扩缩容:docker compose up -d --scale worker=3 可以把 worker 服务扩到 3 个副本,让多个“传菜员”同时上工。

厨师看到高汤沸腾冒泡,才通知配菜师傅下料;容器看到上游 healthy,才真正开工。

start(sj)  ⟺  h(si)=healthy\displaystyle \text{start}(s_j) \iff h(s_i) = \text{healthy}
下游服务启动的前提是:上游健康检查结果为 healthy。
  1. 下游启动start(s_j) 表示服务 j 开始启动。
    start(sj)\displaystyle \text{start}(s_j)
  2. 上游健康h(s_i) 是服务 i 的健康检查结果。
    h(si)\displaystyle h(s_i)
  3. 等价条件iff 表示“当且仅当”,只有条件成立才放行。
      ⟺  \displaystyle \iff

打烊后的日常:部署运维

总菜单挂上墙只是开始。每天还要查菜卖了多少、哪个灶台糊锅了、午市后要不要歇业打扫。运维,就是后厨的日常管理。

Compose 提供一组命令管理容器生命周期。记住一条主线:启动 → 查看 → 查日志 → 进容器 → 清理。docker compose up -d 后台启动整个项目;docker compose ps 查看所有容器状态;docker compose logs -f api 跟踪某个服务的日志;docker compose exec api bash 钻进容器执行命令排查问题。

还有两个“项目治理”神器:docker compose config 会校验 yml 并渲染出最终配置,排查变量替换问题特别有用;docker compose down 停止并清理容器和默认网络,项目整体收摊。这些命令就像后厨总管的每日巡场——睁眼看订单(ps)、听厨师反馈(logs)、必要时亲自进后厨(exec)、打烊清场(down)。

后厨总管每天睁眼先看订单、听反馈、偶尔亲自下厨、打烊清场,一切井井有条——这就是运维的日常。

up → ps → logs → exec → down\displaystyle up \ \rightarrow\ ps \ \rightarrow\ logs \ \rightarrow\ exec \ \rightarrow\ down
一条从启动到清理的运维主线。
  1. 启动up 创建并启动所有服务,-d 表示后台。
    up\displaystyle up
  2. 观察ps 看状态,logs 看输出。
    ps, logs\displaystyle ps,\ logs
  3. 干预与收尾exec 进入容器排障,down 停止并清理。
    exec, down\displaystyle exec,\ down

AI 的满汉全席:AI 场景实战

一套 AI 应用是满汉全席:模型推理是主菜,向量库是配菜,Redis 是传菜电梯,Postgres 是食材仓库,Nginx 是迎宾门童。总菜单把它们一次安排明白,谁都不能缺席。

AI 服务容器化后通常有多个角色:GPU 推理服务、任务队列、元数据库、对象存储、网关。Compose 能在单机或开发机上把整套系统编排起来,是 AI 工程化落地的轻量选择。一个典型配置骨架:api 服务通过 deploy.resources.reservations 申请 GPU;worker 从 Redis 队列拉取推理任务;postgres 保存请求与结果记录;nginx 做统一入口;模型权重用命名卷挂载,避免每次启动重新下载。

这套编排直接服务于 DevOps 流程:CI 里构建镜像、测试编排文件;CD 里用 up -d 发布新版本,用 down 回收旧环境。一条命令拉起全链路,一条命令整体换新——这就是 AI 应用工程化的“后厨总指挥”。

满汉全席要主厨整体调度,AI 应用也需要一份“总菜单”统一编排——这正是 Docker Compose 的用武之地。

App=f(web, api, worker, cache, db)\displaystyle App = f(web,\ api,\ worker,\ cache,\ db)
AI 应用是多个容器角色共同协作组成的整体。
  1. 应用整体App 代表整个 AI 系统。
    App\displaystyle App
  2. 多角色协作括号里是 web、api、worker、cache、db 五个容器角色。
    web, api, worker, cache, db\displaystyle web,\ api,\ worker,\ cache,\ db
  3. 编排函数f 表示 Compose 把它们组织成可运行整体。
    f(… )\displaystyle f(\dots)

AI 应用场景

大模型推理服务私有化部署

阶段:模型部署 / 推理服务化

解决的问题:传统方式要手动启动多个进程并管理依赖,端口冲突、环境不一致问题频发。AI 解决:一份 Compose 把 Nginx 网关、GPU 推理服务、Redis 缓存、Postgres 记录一次性编排起来,一条命令启动全链路。

具体案例:某企业把对话模型部署到内网,前端 + 推理 api + redis + 数据库在同一台 GPU 服务器上运行,运维同学只需 docker compose up -d,升级模型时替换镜像并 up -d 即可。

机器学习实验训练环境标准化

阶段:环境搭建 / 实验管理

解决的问题:复现实验时经常出现“我这儿能跑、你那儿跑不了”。AI 解决:用 Compose 同时启动 Jupyter、TensorBoard、GPU 训练容器,用卷共享代码与输出,新成员一条命令就获得完全一致的实验环境。

具体案例:算法团队在 GPU 服务器上通过 Compose 拉起 Jupyter + TensorBoard + 数据集卷,成员用浏览器写代码、看训练曲线,实验记录全部落在共享卷里。

数据标注流水线平台

阶段:数据工程 / 标注管理

解决的问题:标注平台由前端、API、任务队列、对象存储多个组件构成,手工启动极易踩依赖坑。AI 解决:Compose 编排标注后端 + MinIO + Redis 队列 + MySQL,一次启动整个流水线。

具体案例:一个标注小组用 Compose 跑起标注平台套件,数据通过 API 批量导入,标注结果写回数据库,全链路一个 up 搞定,下班一个 down 干净收摊。

Python 演示

python71 行
# -*- coding: utf-8 -*-"""生成一个 AI 推理服务的 docker-compose.yml 编排文件"""  class ComposeGenerator:    def __init__(self, project):        self.project = project        self.services = {}     def add_service(self, name, image, ports=None, depends_on=None,                    volumes=None, environment=None):        self.services[name] = {            'image': image,            'ports': ports or [],            'depends_on': depends_on or [],            'volumes': volumes or [],            'environment': environment or {},        }     def to_yaml(self):        text = 'version: "3.8"\nservices:\n'        for name, conf in self.services.items():            text += f'  {name}:\n'            text += f'    image: {conf["image"]}\n'            if conf['ports']:                text += '    ports:\n'                for p in conf['ports']:                    text += f'      - "{p}"\n'            if conf['depends_on']:                text += '    depends_on:\n'                for d in conf['depends_on']:                    text += f'      - {d}\n'            if conf['volumes']:                text += '    volumes:\n'                for v in conf['volumes']:                    text += f'      - {v}\n'            if conf['environment']:                text += '    environment:\n'                for k, v in conf['environment'].items():                    text += f'      {k}: {v}\n'            text += '    networks:\n      - ai_net\n'        text += 'volumes:\n  model_cache:\n'        text += 'networks:\n  ai_net:\n'        return text     def start_order(self):        order = []        remaining = set(self.services.keys())        while remaining:            ready = [n for n in remaining                     if all(d in order for d in self.services[n]['depends_on'])]            if not ready:                raise ValueError('存在循环依赖!')            order.extend(ready)            remaining -= set(ready)        return order  if __name__ == '__main__':    gen = ComposeGenerator('ai-inference')    gen.add_service('redis', 'redis:7-alpine')    gen.add_service('api', 'my-ai/api:latest',                    ports=['8000:8000'],                    depends_on=['redis'],                    volumes=['model_cache:/cache'],                    environment={'MODEL_NAME': 'bert-base'})    gen.add_service('web', 'my-ai/web:latest',                    ports=['8080:80'],                    depends_on=['api'])    print(gen.to_yaml())    print('启动顺序: ' + ' -> '.join(gen.start_order()))
目的:像“总菜单打印机”一样,用 Python 生成 AI 推理服务的 docker-compose.yml,并自动算出容器的启动顺序。
  1. class ComposeGenerator:定义“总菜单生成器”类,负责收集服务和渲染配置。
  2. self.services = {}用字典登记所有服务,服务名是索引,配置是内容。
  3. def add_service(self, name, image, ...)往菜单里添加一道“菜”:服务名、镜像、端口、依赖、卷、环境变量。
  4. text += f' {name}:\n'在 YAML 中为当前服务开一个新段落。
  5. if all(d in order for d in self.services[n]['depends_on']):检查某个服务的所有依赖是否都已启动。
  6. order.extend(ready)将本轮“可以启动”的服务加入启动队列。
  7. remaining -= set(ready)从未启动集合中移除本轮已就绪的服务。
  8. print('启动顺序: ' + ' -> '.join(gen.start_order()))打印拓扑排序结果,直观看到“谁先谁后”。

常见误区

误区“我在 api 下写了 `depends_on: [db]`,可 api 还是连不上数据库,是不是我写错了?”

正解depends_on 只保证 db 容器先被创建并启动,不保证 db 内部的服务已经可用。数据库进程可能还在初始化。要真正等就绪,需要给 db 配置 healthcheck,再用 condition: service_healthy 声明等待。就像传菜员不能只看“锅上灶了”就上菜,得等汤真的沸腾。

为何常见:名字太有误导性,“依赖”很容易让人理解成“就绪”,加上早期教程普遍只讲依赖不讲健康检查。

误区“我在 web 容器里用 `localhost:8000` 访问 api,为什么连不上?”

正解localhost 指的是当前容器自己,不是身边那个容器。Compose 网络里正确的写法是用服务名,例如 http://api:8000。就像找后厨的人不能喊办公室自己的电话分机,要打传菜窗口对应的内线。

为何常见:平时在宿主机开发习惯了 localhost,容易忘记每个容器都是一台独立的小主机。

误区“我怕 down 会把数据库清空,所以容器一直挂着不敢停。”

正解down 默认只停止并删除容器与默认网络,命名卷里的数据会完整保留。只有显式加 -v 才会连卷一起删除。放心每天 down 也没问题,冷柜里的老汤不会丢。

为何常见:看到 down 会“删除容器”就想当然以为全部数据都没了,没分辨容器层与卷的生命周期差异。

误区“既然 Compose 能编排多容器,是不是不用学 K8s 了?”

正解Compose 是单机多容器编排,适合开发、测试与轻量生产;Kubernetes 是跨多台机器的集群调度系统,负责自动伸缩、故障转移、服务网格。两者是“便利店”与“连锁集团总部”的关系,定位完全不同。

为何常见:学会 Compose 后觉得“什么都能管”,把单机编排与集群调度混为一谈——这是容器领域最经典的认知跳跃。

面试题

Q1. Docker Compose 默认查找的配置文件名是?

单选题 · easy

  • A.dockerfile.yml
  • B.docker-compose.yml← 正确答案
  • C.container.yaml
  • D.deploy-apply.yml

答案:B。Compose 默认查找 docker-compose.yml(新版也支持 compose.yaml)。这就像后厨只认那份固定的《总菜单》,换文件名它就找不到了。其他选项是干扰项,dockerfile.yml 容易和 Dockerfile 混淆。

Q2. 在同一个 Compose 网络内,web 容器要访问 api 容器的 8000 端口,正确写法是?

单选题 · easy

  • A.宿主 IP 加映射端口
  • B.固定容器 IP 直连
  • C.服务名加容器端口← 正确答案
  • D.随机分配的域名

答案:C。Compose 内置 DNS 服务发现,容器之间通过“服务名 + 容器内端口”通信,如 http://api:8000。容器 IP 重启会变,所以不应写死;宿主 IP 加映射端口虽然也能通,但不是内部网络的推荐方式。

Q3. 关于 depends_on 的说法,正确的是?

单选题 · mid

  • A.等上游健康后再启动
  • B.仅控制启动先后顺序← 正确答案
  • C.自动重启异常上游
  • D.指定容器内存上限

答案:B。depends_on 只保证上游容器先创建并启动,不保证服务就绪。要等上游健康,需要配合 healthcheck 与 condition: service_healthy。就像“锅先上灶”不等于“汤已煮沸”。

Q4. Compose 中推荐用什么方式持久化数据库数据?

单选题 · mid

  • A.放容器 /tmp 临时目录
  • B.写入宿主机任意目录
  • C.使用命名卷 volume← 正确答案
  • D.写进环境变量配置

答案:C。命名卷由 Docker 管理,生命周期独立于容器,是生产环境持久化数据的推荐方式。容器 /tmp 会随容器销毁而消失;写宿主任意目录属于 bind mount,适合开发但不推荐直接用于数据库。

Q5. 在 compose 文件中写“变量没设置时使用默认值”,正确语法是?

单选题 · mid

  • A.$VAR:default
  • B.${VAR:-default}← 正确答案
  • C.$(VAR:default)
  • D.$VAR-default

答案:B。${VAR:-default} 是 Compose 的变量替换语法:变量有值则用该值,无值则回退到 default。例如 ${GPU_MODE:-cpu} 在未设置 GPU_MODE 时自动用 cpu,其他写法都不是 Compose 支持的格式。

Q6. 执行 docker compose down 后,会发生哪些事?

多选题 · mid

  • A.停止并删除容器← 正确答案
  • B.删除默认网络← 正确答案
  • C.总是删除命名卷
  • D.删除 docker 镜像

答案:AB。down 会停止并删除容器、删除默认网络,但命名卷默认保留(加 -v 才会删除),镜像也从不被删除。这就像打烊清场:桌子收好、灯关掉,但冷藏库里的老汤继续留着。

Q7. 关于 Compose 网络的说法,正确的是?

多选题 · mid

  • A.Compose 自动创建项目专用网络← 正确答案
  • B.服务名可在网络内充当域名← 正确答案
  • C.宿主机可直接访问容器端口
  • D.不同 Compose 项目默认网络隔离← 正确答案

答案:ABD。每个 Compose 项目默认创建独立网络,服务名在网内可解析;不同项目网络互相隔离。宿主机不能直接进容器网络,必须通过 ports 映射才能访问,所以 C 错误。

Q8. 要让 api 服务在 db 的数据库真正可连接后再启动,应如何配置?

单选题 · hard

  • A.在 api 里写 depends_on: [db]
  • B.给 db 加 healthcheck,api 写 condition: service_healthy← 正确答案
  • C.在 api 启动命令前 sleep 10 秒
  • D.把 api 和 db 合并到同一个容器

答案:B。depends_on 只保证启动顺序;sleep 是碰运气。正确做法是给 db 配置健康检查,api 通过 depends_on 的 condition: service_healthy 等待。就像传菜员要等厨师喊“出菜”,而不是自己默数 10 秒。

Q9. 配置 ports: "8080:80" 的含义是?

单选题 · mid

  • A.容器 8080 映射到宿主机 80
  • B.宿主机 8080 映射到容器 80← 正确答案
  • C.容器内双向互通流量
  • D.自动随机分配端口

答案:B。ports 的格式是“宿主机端口:容器端口”,"8080:80" 表示访问宿主机 8080 端口会转发到容器的 80 端口。这是外部世界进入后厨的唯一窗口。

Q10. 用 Compose 部署 GPU 模型推理服务,合理的做法包括?

多选题 · hard

  • A.用 deploy 配置申请 GPU 资源← 正确答案
  • B.模型权重放命名卷避免重复下载← 正确答案
  • C.每次改模型都重新构建镜像
  • D.用 healthcheck 探测推理接口是否就绪← 正确答案

答案:ABD。GPU 要用 deploy.resources.reservations 显式申请;模型权重放卷里可跨容器复用、避免每次重启重下;healthcheck 能探测推理接口是否真正就绪。每次改模型都重打镜像既慢又浪费,应该用卷承载模型文件。