[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-compose":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-compose":1749,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-compose":1770},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":14,"pinned":15,"draft":15,"body":16,"seo":1745,"stem":1746,"id":1747,"extension":1748},"\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-compose","Docker Compose 编排","Docker Compose 是定义和运行多容器 Docker 应用的工具，通过一个 compose.yml 文件即可管理 Web、数据库、缓存等多个服务。本文覆盖安装、完整字段说明、多服务示例、常用指令与常见排错。","技能小册",[12,13],"docker","compose","2026-07-23",false,{"type":17,"value":18,"toc":1729},"minimark",[19,23,50,55,154,157,194,215,222,225,396,402,443,459,463,469,670,674,679,741,745,748,1096,1101,1135,1139,1149,1188,1249,1324,1331,1347,1355,1398,1402,1583,1596,1600,1655,1658,1661,1725],[20,21,8],"h1",{"id":22},"docker-compose-编排",[24,25,26,30,31,34,35,39,40,43,44,49],"p",{},[27,28,29],"strong",{},"Docker Compose"," 是一个用于定义和运行",[27,32,33],{},"多容器 Docker 应用","的工具。通过一个 ",[36,37,38],"code",{},"compose.yml","（旧称 ",[36,41,42],{},"docker-compose.yml","）配置文件，你可以同时管理多个容器（例如 Web 服务、数据库、缓存等），并使用一条命令启动\u002F停止整个应用栈。容器与网络基础见 ",[45,46,48],"a",{"href":47},"\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-runtime","容器、数据与网络","。",[51,52,54],"h2",{"id":53},"一安装","一、安装",[56,57,58,72],"ul",{},[59,60,61,64,65,68,69,71],"li",{},[27,62,63],{},"Windows \u002F macOS","：Docker Desktop 默认已包含 ",[36,66,67],{},"docker compose","（Compose V2，作为 ",[36,70,12],{}," CLI 的子命令），无需额外安装。",[59,73,74,77,78],{},[27,75,76],{},"Linux","：\n",[79,80,85],"pre",{"className":81,"code":82,"language":83,"meta":84,"style":84},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","# 通过官方 docker-ce 仓库安装时会自带 compose 插件\nsudo apt update\nsudo apt install docker-compose-plugin -y\n\n# 或安装独立的旧版二进制（V1，命令为 docker-compose，官方已不再更新新特性）\nsudo apt install docker-compose -y\n","bash","",[36,86,87,96,110,127,134,140],{"__ignoreMap":84},[88,89,92],"span",{"class":90,"line":91},"line",1,[88,93,95],{"class":94},"sutJx","# 通过官方 docker-ce 仓库安装时会自带 compose 插件\n",[88,97,99,103,107],{"class":90,"line":98},2,[88,100,102],{"class":101},"sbgvK","sudo",[88,104,106],{"class":105},"s_sjI"," apt",[88,108,109],{"class":105}," update\n",[88,111,113,115,117,120,123],{"class":90,"line":112},3,[88,114,102],{"class":101},[88,116,106],{"class":105},[88,118,119],{"class":105}," install",[88,121,122],{"class":105}," docker-compose-plugin",[88,124,126],{"class":125},"stzsN"," -y\n",[88,128,130],{"class":90,"line":129},4,[88,131,133],{"emptyLinePlaceholder":132},true,"\n",[88,135,137],{"class":90,"line":136},5,[88,138,139],{"class":94},"# 或安装独立的旧版二进制（V1，命令为 docker-compose，官方已不再更新新特性）\n",[88,141,143,145,147,149,152],{"class":90,"line":142},6,[88,144,102],{"class":101},[88,146,106],{"class":105},[88,148,119],{"class":105},[88,150,151],{"class":105}," docker-compose",[88,153,126],{"class":125},[24,155,156],{},"验证安装：",[79,158,160],{"className":81,"code":159,"language":83,"meta":84,"style":84},"docker compose version\n# Compose V2 写法，注意 compose 前没有连字符\n\ndocker-compose --version\n# 旧版 V1 命令，很多教程和脚本里仍能看到\n",[36,161,162,172,177,181,189],{"__ignoreMap":84},[88,163,164,166,169],{"class":90,"line":91},[88,165,12],{"class":101},[88,167,168],{"class":105}," compose",[88,170,171],{"class":105}," version\n",[88,173,174],{"class":90,"line":98},[88,175,176],{"class":94},"# Compose V2 写法，注意 compose 前没有连字符\n",[88,178,179],{"class":90,"line":112},[88,180,133],{"emptyLinePlaceholder":132},[88,182,183,186],{"class":90,"line":129},[88,184,185],{"class":101},"docker-compose",[88,187,188],{"class":125}," --version\n",[88,190,191],{"class":90,"line":136},[88,192,193],{"class":94},"# 旧版 V1 命令，很多教程和脚本里仍能看到\n",[195,196,197],"blockquote",{},[24,198,199,202,203,205,206,208,209,211,212,214],{},[27,200,201],{},"V1 与 V2 的区别","：V2 是用 Go 重写、作为 ",[36,204,12],{}," 子命令集成的新版本，命令是 ",[36,207,67],{},"（空格）；V1 是独立的 Python 程序，命令是 ",[36,210,185],{},"（连字符）。新项目应统一使用 V2，本文命令均以 ",[36,213,67],{}," 为主，多数场景下把空格换成连字符即对应 V1 写法。",[51,216,218,219,221],{"id":217},"二composeyml-基础示例","二、",[36,220,38],{}," 基础示例",[24,223,224],{},"以下是一个包含 Nginx Web 服务和 Redis 缓存服务的 Compose 文件：",[79,226,230],{"className":227,"code":228,"language":229,"meta":84,"style":84},"language-yaml shiki shiki-themes material-theme-lighter github-light github-dark","services: # 定义服务（容器）\n  web: # 服务名称\n    image: nginx # 使用的镜像\n    ports:\n      - \"8080:80\" # 端口映射 宿主机:容器\n    volumes:\n      - .\u002Fhtml:\u002Fusr\u002Fshare\u002Fnginx\u002Fhtml # 挂载本地目录到容器\n    depends_on: # 依赖关系（启动顺序，不是等待就绪）\n      - redis\n\n  redis:\n    image: redis:alpine # 使用轻量版 Redis\n    ports:\n      - \"6379:6379\"\n    environment: # 环境变量\n      - REDIS_PASSWORD=mysecret\n","yaml",[36,231,232,245,255,268,276,294,301,312,323,331,336,344,357,364,377,388],{"__ignoreMap":84},[88,233,234,238,242],{"class":90,"line":91},[88,235,237],{"class":236},"sQzsp","services",[88,239,241],{"class":240},"sP7_E",":",[88,243,244],{"class":94}," # 定义服务（容器）\n",[88,246,247,250,252],{"class":90,"line":98},[88,248,249],{"class":236},"  web",[88,251,241],{"class":240},[88,253,254],{"class":94}," # 服务名称\n",[88,256,257,260,262,265],{"class":90,"line":112},[88,258,259],{"class":236},"    image",[88,261,241],{"class":240},[88,263,264],{"class":105}," nginx",[88,266,267],{"class":94}," # 使用的镜像\n",[88,269,270,273],{"class":90,"line":129},[88,271,272],{"class":236},"    ports",[88,274,275],{"class":240},":\n",[88,277,278,281,285,288,291],{"class":90,"line":136},[88,279,280],{"class":240},"      -",[88,282,284],{"class":283},"sjJ54"," \"",[88,286,287],{"class":105},"8080:80",[88,289,290],{"class":283},"\"",[88,292,293],{"class":94}," # 端口映射 宿主机:容器\n",[88,295,296,299],{"class":90,"line":142},[88,297,298],{"class":236},"    volumes",[88,300,275],{"class":240},[88,302,304,306,309],{"class":90,"line":303},7,[88,305,280],{"class":240},[88,307,308],{"class":105}," .\u002Fhtml:\u002Fusr\u002Fshare\u002Fnginx\u002Fhtml",[88,310,311],{"class":94}," # 挂载本地目录到容器\n",[88,313,315,318,320],{"class":90,"line":314},8,[88,316,317],{"class":236},"    depends_on",[88,319,241],{"class":240},[88,321,322],{"class":94}," # 依赖关系（启动顺序，不是等待就绪）\n",[88,324,326,328],{"class":90,"line":325},9,[88,327,280],{"class":240},[88,329,330],{"class":105}," redis\n",[88,332,334],{"class":90,"line":333},10,[88,335,133],{"emptyLinePlaceholder":132},[88,337,339,342],{"class":90,"line":338},11,[88,340,341],{"class":236},"  redis",[88,343,275],{"class":240},[88,345,347,349,351,354],{"class":90,"line":346},12,[88,348,259],{"class":236},[88,350,241],{"class":240},[88,352,353],{"class":105}," redis:alpine",[88,355,356],{"class":94}," # 使用轻量版 Redis\n",[88,358,360,362],{"class":90,"line":359},13,[88,361,272],{"class":236},[88,363,275],{"class":240},[88,365,367,369,371,374],{"class":90,"line":366},14,[88,368,280],{"class":240},[88,370,284],{"class":283},[88,372,373],{"class":105},"6379:6379",[88,375,376],{"class":283},"\"\n",[88,378,380,383,385],{"class":90,"line":379},15,[88,381,382],{"class":236},"    environment",[88,384,241],{"class":240},[88,386,387],{"class":94}," # 环境变量\n",[88,389,391,393],{"class":90,"line":390},16,[88,392,280],{"class":240},[88,394,395],{"class":105}," REDIS_PASSWORD=mysecret\n",[24,397,398,401],{},[27,399,400],{},"字段说明","：",[56,403,404,409,419,425,431,437],{},[59,405,406,408],{},[36,407,237],{},"：定义每个容器，名称可自定义，同一网络内可直接用服务名互相访问（Compose 会自动创建一个专属网络）。",[59,410,411,414,415,418],{},[36,412,413],{},"image","：指定镜像（也可以使用 ",[36,416,417],{},"build"," 从 Dockerfile 构建）。",[59,420,421,424],{},[36,422,423],{},"ports","：端口映射。",[59,426,427,430],{},[36,428,429],{},"volumes","：数据卷或绑定挂载。",[59,432,433,436],{},[36,434,435],{},"environment","：设置环境变量。",[59,438,439,442],{},[36,440,441],{},"depends_on","：设置服务依赖（仅影响启动顺序，不保证服务已就绪，需配合健康检查）。",[195,444,445],{},[24,446,447,454,455,458],{},[27,448,449,450,453],{},"关于 ",[36,451,452],{},"version"," 字段","：Compose V2 已不再需要在文件顶部声明 ",[36,456,457],{},"version: \"3.8\"","，写了也会被忽略（并给出弃用提示）；新项目建议直接省略。",[51,460,462],{"id":461},"三常用命令","三、常用命令",[24,464,465,466,468],{},"所有命令需在 ",[36,467,38],{}," 所在目录执行。",[470,471,472,485],"table",{},[473,474,475],"thead",{},[476,477,478,482],"tr",{},[479,480,481],"th",{},"命令",[479,483,484],{},"说明",[486,487,488,503,516,526,540,550,564,574,587,600,610,624,634,644,654],"tbody",{},[476,489,490,496],{},[491,492,493],"td",{},[36,494,495],{},"docker compose up -d",[491,497,498,499,502],{},"后台启动所有服务（",[36,500,501],{},"-d"," 守护模式）",[476,504,505,510],{},[491,506,507],{},[36,508,509],{},"docker compose up -d --build",[491,511,512,513,515],{},"启动前先重新构建镜像（",[36,514,417],{}," 字段的服务）",[476,517,518,523],{},[491,519,520],{},[36,521,522],{},"docker compose down",[491,524,525],{},"停止并删除容器、网络（默认保留数据卷）",[476,527,528,533],{},[491,529,530],{},[36,531,532],{},"docker compose down -v",[491,534,535,536,539],{},"同时删除数据卷（",[36,537,538],{},"-v","）",[476,541,542,547],{},[491,543,544],{},[36,545,546],{},"docker compose logs -f",[491,548,549],{},"跟踪所有服务的日志输出",[476,551,552,557],{},[491,553,554],{},[36,555,556],{},"docker compose logs -f web",[491,558,559,560,563],{},"只跟踪指定服务 ",[36,561,562],{},"web"," 的日志",[476,565,566,571],{},[491,567,568],{},[36,569,570],{},"docker compose ps",[491,572,573],{},"查看当前项目的服务状态",[476,575,576,581],{},[491,577,578],{},[36,579,580],{},"docker compose exec web bash",[491,582,583,584,586],{},"进入 ",[36,585,562],{}," 服务的容器中执行命令",[476,588,589,594],{},[491,590,591],{},[36,592,593],{},"docker compose build",[491,595,596,597,599],{},"重新构建服务（用于 ",[36,598,417],{}," 指令的镜像）",[476,601,602,607],{},[491,603,604],{},[36,605,606],{},"docker compose restart",[491,608,609],{},"重启所有服务",[476,611,612,621],{},[491,613,614,617,618],{},[36,615,616],{},"docker compose stop"," \u002F ",[36,619,620],{},"start",[491,622,623],{},"停止 \u002F 启动已存在的服务（不删除容器）",[476,625,626,631],{},[491,627,628],{},[36,629,630],{},"docker compose config",[491,632,633],{},"验证并查看解析后的最终配置（合并多文件、变量替换后）",[476,635,636,641],{},[491,637,638],{},[36,639,640],{},"docker compose pull",[491,642,643],{},"拉取所有服务声明的镜像最新版本",[476,645,646,651],{},[491,647,648],{},[36,649,650],{},"docker compose top",[491,652,653],{},"查看各服务容器内的进程",[476,655,656,664],{},[491,657,658,617,661],{},[36,659,660],{},"docker compose scale web=3",[36,662,663],{},"docker compose up -d --scale web=3",[491,665,666,667,669],{},"将 ",[36,668,562],{}," 服务扩展到 3 个实例（需服务不绑定固定宿主机端口）",[51,671,673],{"id":672},"四常用场景示例","四、常用场景示例",[675,676,678],"h3",{"id":677},"_1-使用-dockerfile-构建自定义镜像","1. 使用 Dockerfile 构建自定义镜像",[79,680,682],{"className":227,"code":681,"language":229,"meta":84,"style":84},"services:\n  app:\n    build: . # 使用当前目录下的 Dockerfile\n    ports:\n      - \"3000:3000\"\n    environment:\n      - NODE_ENV=production\n",[36,683,684,690,697,711,717,728,734],{"__ignoreMap":84},[88,685,686,688],{"class":90,"line":91},[88,687,237],{"class":236},[88,689,275],{"class":240},[88,691,692,695],{"class":90,"line":98},[88,693,694],{"class":236},"  app",[88,696,275],{"class":240},[88,698,699,702,704,708],{"class":90,"line":112},[88,700,701],{"class":236},"    build",[88,703,241],{"class":240},[88,705,707],{"class":706},"srdBf"," .",[88,709,710],{"class":94}," # 使用当前目录下的 Dockerfile\n",[88,712,713,715],{"class":90,"line":129},[88,714,272],{"class":236},[88,716,275],{"class":240},[88,718,719,721,723,726],{"class":90,"line":136},[88,720,280],{"class":240},[88,722,284],{"class":283},[88,724,725],{"class":105},"3000:3000",[88,727,376],{"class":283},[88,729,730,732],{"class":90,"line":142},[88,731,382],{"class":236},[88,733,275],{"class":240},[88,735,736,738],{"class":90,"line":303},[88,737,280],{"class":240},[88,739,740],{"class":105}," NODE_ENV=production\n",[675,742,744],{"id":743},"_2-链接多个服务nodejs-mongodb-redis-多服务示例","2. 链接多个服务（Node.js + MongoDB + Redis 多服务示例）",[24,746,747],{},"一个更接近真实项目的例子：Node 应用依赖 MongoDB 存储数据、Redis 做缓存，并通过环境变量文件和健康检查确保依赖服务就绪后才启动应用。",[79,749,751],{"className":227,"code":750,"language":229,"meta":84,"style":84},"services:\n  web:\n    build: .\n    ports:\n      - \"3000:3000\"\n    env_file:\n      - .env # 从文件读取环境变量，避免敏感信息写入 compose.yml\n    environment:\n      - MONGO_URL=mongodb:\u002F\u002Fmongo:27017\u002Fapp\n      - REDIS_URL=redis:\u002F\u002Fredis:6379\n    depends_on:\n      mongo:\n        condition: service_healthy # 等待 mongo 健康检查通过再启动\n      redis:\n        condition: service_started\n    restart: unless-stopped\n\n  mongo:\n    image: mongo:7\n    volumes:\n      - mongo-data:\u002Fdata\u002Fdb # 命名卷，持久化数据库文件\n    healthcheck:\n      test: [\"CMD\", \"mongosh\", \"--eval\", \"db.adminCommand('ping')\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n    restart: unless-stopped\n\n  redis:\n    image: redis:7-alpine\n    volumes:\n      - redis-data:\u002Fdata\n    restart: unless-stopped\n\nvolumes:\n  mongo-data: # 声明卷，由 Docker 管理\n  redis-data:\n",[36,752,753,759,765,774,780,790,797,807,813,820,827,833,840,853,860,869,879,884,892,902,909,920,928,977,988,999,1010,1019,1024,1031,1041,1048,1056,1065,1070,1077,1088],{"__ignoreMap":84},[88,754,755,757],{"class":90,"line":91},[88,756,237],{"class":236},[88,758,275],{"class":240},[88,760,761,763],{"class":90,"line":98},[88,762,249],{"class":236},[88,764,275],{"class":240},[88,766,767,769,771],{"class":90,"line":112},[88,768,701],{"class":236},[88,770,241],{"class":240},[88,772,773],{"class":706}," .\n",[88,775,776,778],{"class":90,"line":129},[88,777,272],{"class":236},[88,779,275],{"class":240},[88,781,782,784,786,788],{"class":90,"line":136},[88,783,280],{"class":240},[88,785,284],{"class":283},[88,787,725],{"class":105},[88,789,376],{"class":283},[88,791,792,795],{"class":90,"line":142},[88,793,794],{"class":236},"    env_file",[88,796,275],{"class":240},[88,798,799,801,804],{"class":90,"line":303},[88,800,280],{"class":240},[88,802,803],{"class":105}," .env",[88,805,806],{"class":94}," # 从文件读取环境变量，避免敏感信息写入 compose.yml\n",[88,808,809,811],{"class":90,"line":314},[88,810,382],{"class":236},[88,812,275],{"class":240},[88,814,815,817],{"class":90,"line":325},[88,816,280],{"class":240},[88,818,819],{"class":105}," MONGO_URL=mongodb:\u002F\u002Fmongo:27017\u002Fapp\n",[88,821,822,824],{"class":90,"line":333},[88,823,280],{"class":240},[88,825,826],{"class":105}," REDIS_URL=redis:\u002F\u002Fredis:6379\n",[88,828,829,831],{"class":90,"line":338},[88,830,317],{"class":236},[88,832,275],{"class":240},[88,834,835,838],{"class":90,"line":346},[88,836,837],{"class":236},"      mongo",[88,839,275],{"class":240},[88,841,842,845,847,850],{"class":90,"line":359},[88,843,844],{"class":236},"        condition",[88,846,241],{"class":240},[88,848,849],{"class":105}," service_healthy",[88,851,852],{"class":94}," # 等待 mongo 健康检查通过再启动\n",[88,854,855,858],{"class":90,"line":366},[88,856,857],{"class":236},"      redis",[88,859,275],{"class":240},[88,861,862,864,866],{"class":90,"line":379},[88,863,844],{"class":236},[88,865,241],{"class":240},[88,867,868],{"class":105}," service_started\n",[88,870,871,874,876],{"class":90,"line":390},[88,872,873],{"class":236},"    restart",[88,875,241],{"class":240},[88,877,878],{"class":105}," unless-stopped\n",[88,880,882],{"class":90,"line":881},17,[88,883,133],{"emptyLinePlaceholder":132},[88,885,887,890],{"class":90,"line":886},18,[88,888,889],{"class":236},"  mongo",[88,891,275],{"class":240},[88,893,895,897,899],{"class":90,"line":894},19,[88,896,259],{"class":236},[88,898,241],{"class":240},[88,900,901],{"class":105}," mongo:7\n",[88,903,905,907],{"class":90,"line":904},20,[88,906,298],{"class":236},[88,908,275],{"class":240},[88,910,912,914,917],{"class":90,"line":911},21,[88,913,280],{"class":240},[88,915,916],{"class":105}," mongo-data:\u002Fdata\u002Fdb",[88,918,919],{"class":94}," # 命名卷，持久化数据库文件\n",[88,921,923,926],{"class":90,"line":922},22,[88,924,925],{"class":236},"    healthcheck",[88,927,275],{"class":240},[88,929,931,934,936,939,941,944,946,949,951,954,956,958,960,963,965,967,969,972,974],{"class":90,"line":930},23,[88,932,933],{"class":236},"      test",[88,935,241],{"class":240},[88,937,938],{"class":240}," [",[88,940,290],{"class":283},[88,942,943],{"class":105},"CMD",[88,945,290],{"class":283},[88,947,948],{"class":240},",",[88,950,284],{"class":283},[88,952,953],{"class":105},"mongosh",[88,955,290],{"class":283},[88,957,948],{"class":240},[88,959,284],{"class":283},[88,961,962],{"class":105},"--eval",[88,964,290],{"class":283},[88,966,948],{"class":240},[88,968,284],{"class":283},[88,970,971],{"class":105},"db.adminCommand('ping')",[88,973,290],{"class":283},[88,975,976],{"class":240},"]\n",[88,978,980,983,985],{"class":90,"line":979},24,[88,981,982],{"class":236},"      interval",[88,984,241],{"class":240},[88,986,987],{"class":105}," 10s\n",[88,989,991,994,996],{"class":90,"line":990},25,[88,992,993],{"class":236},"      timeout",[88,995,241],{"class":240},[88,997,998],{"class":105}," 5s\n",[88,1000,1002,1005,1007],{"class":90,"line":1001},26,[88,1003,1004],{"class":236},"      retries",[88,1006,241],{"class":240},[88,1008,1009],{"class":706}," 5\n",[88,1011,1013,1015,1017],{"class":90,"line":1012},27,[88,1014,873],{"class":236},[88,1016,241],{"class":240},[88,1018,878],{"class":105},[88,1020,1022],{"class":90,"line":1021},28,[88,1023,133],{"emptyLinePlaceholder":132},[88,1025,1027,1029],{"class":90,"line":1026},29,[88,1028,341],{"class":236},[88,1030,275],{"class":240},[88,1032,1034,1036,1038],{"class":90,"line":1033},30,[88,1035,259],{"class":236},[88,1037,241],{"class":240},[88,1039,1040],{"class":105}," redis:7-alpine\n",[88,1042,1044,1046],{"class":90,"line":1043},31,[88,1045,298],{"class":236},[88,1047,275],{"class":240},[88,1049,1051,1053],{"class":90,"line":1050},32,[88,1052,280],{"class":240},[88,1054,1055],{"class":105}," redis-data:\u002Fdata\n",[88,1057,1059,1061,1063],{"class":90,"line":1058},33,[88,1060,873],{"class":236},[88,1062,241],{"class":240},[88,1064,878],{"class":105},[88,1066,1068],{"class":90,"line":1067},34,[88,1069,133],{"emptyLinePlaceholder":132},[88,1071,1073,1075],{"class":90,"line":1072},35,[88,1074,429],{"class":236},[88,1076,275],{"class":240},[88,1078,1080,1083,1085],{"class":90,"line":1079},36,[88,1081,1082],{"class":236},"  mongo-data",[88,1084,241],{"class":240},[88,1086,1087],{"class":94}," # 声明卷，由 Docker 管理\n",[88,1089,1091,1094],{"class":90,"line":1090},37,[88,1092,1093],{"class":236},"  redis-data",[88,1095,275],{"class":240},[24,1097,1098,401],{},[27,1099,1100],{},"要点",[56,1102,1103,1112,1126],{},[59,1104,1105,1107,1108,1111],{},[36,1106,441],{}," 配合 ",[36,1109,1110],{},"condition: service_healthy"," 才能真正「等待服务就绪」，仅声明依赖名不会等待应用初始化完成。",[59,1113,1114,1117,1118,1121,1122,1125],{},[36,1115,1116],{},"env_file"," 把配置和密钥从版本控制中分离，配合 ",[36,1119,1120],{},".gitignore"," 忽略 ",[36,1123,1124],{},".env"," 文件。",[59,1127,1128,1131,1132,1134],{},[36,1129,1130],{},"restart: unless-stopped"," 让服务在宿主机重启或异常退出后自动恢复，但手动 ",[36,1133,616],{}," 不会被自动拉起。",[675,1136,1138],{"id":1137},"_3-多环境配置开发-生产覆盖","3. 多环境配置（开发 \u002F 生产覆盖）",[24,1140,1141,1142,1144,1145,1148],{},"Compose 支持多文件叠加，常见做法是把公共配置放在 ",[36,1143,38],{},"，环境差异放在 ",[36,1146,1147],{},"compose.override.yml","（默认自动加载）或显式指定的文件中。",[79,1150,1152],{"className":227,"code":1151,"language":229,"meta":84,"style":84},"# compose.yml（生产基线）\nservices:\n  web:\n    build: .\n    restart: always\n",[36,1153,1154,1159,1165,1171,1179],{"__ignoreMap":84},[88,1155,1156],{"class":90,"line":91},[88,1157,1158],{"class":94},"# compose.yml（生产基线）\n",[88,1160,1161,1163],{"class":90,"line":98},[88,1162,237],{"class":236},[88,1164,275],{"class":240},[88,1166,1167,1169],{"class":90,"line":112},[88,1168,249],{"class":236},[88,1170,275],{"class":240},[88,1172,1173,1175,1177],{"class":90,"line":129},[88,1174,701],{"class":236},[88,1176,241],{"class":240},[88,1178,773],{"class":706},[88,1180,1181,1183,1185],{"class":90,"line":136},[88,1182,873],{"class":236},[88,1184,241],{"class":240},[88,1186,1187],{"class":105}," always\n",[79,1189,1191],{"className":227,"code":1190,"language":229,"meta":84,"style":84},"# compose.override.yml（本地开发，默认自动与上面合并）\nservices:\n  web:\n    volumes:\n      - .:\u002Fapp # 挂载源码实现热更新\n    environment:\n      - NODE_ENV=development\n    command: npm run dev\n",[36,1192,1193,1198,1204,1210,1216,1226,1232,1239],{"__ignoreMap":84},[88,1194,1195],{"class":90,"line":91},[88,1196,1197],{"class":94},"# compose.override.yml（本地开发，默认自动与上面合并）\n",[88,1199,1200,1202],{"class":90,"line":98},[88,1201,237],{"class":236},[88,1203,275],{"class":240},[88,1205,1206,1208],{"class":90,"line":112},[88,1207,249],{"class":236},[88,1209,275],{"class":240},[88,1211,1212,1214],{"class":90,"line":129},[88,1213,298],{"class":236},[88,1215,275],{"class":240},[88,1217,1218,1220,1223],{"class":90,"line":136},[88,1219,280],{"class":240},[88,1221,1222],{"class":105}," .:\u002Fapp",[88,1224,1225],{"class":94}," # 挂载源码实现热更新\n",[88,1227,1228,1230],{"class":90,"line":142},[88,1229,382],{"class":236},[88,1231,275],{"class":240},[88,1233,1234,1236],{"class":90,"line":303},[88,1235,280],{"class":240},[88,1237,1238],{"class":105}," NODE_ENV=development\n",[88,1240,1241,1244,1246],{"class":90,"line":314},[88,1242,1243],{"class":236},"    command",[88,1245,241],{"class":240},[88,1247,1248],{"class":105}," npm run dev\n",[79,1250,1252],{"className":81,"code":1251,"language":83,"meta":84,"style":84},"# 默认会自动加载 compose.yml + compose.override.yml\ndocker compose up -d\n\n# 生产环境显式只用基线文件，忽略 override\ndocker compose -f compose.yml up -d\n\n# 显式叠加多个文件（顺序即优先级，后者覆盖前者）\ndocker compose -f compose.yml -f compose.prod.yml up -d\n",[36,1253,1254,1259,1271,1275,1280,1296,1300,1305],{"__ignoreMap":84},[88,1255,1256],{"class":90,"line":91},[88,1257,1258],{"class":94},"# 默认会自动加载 compose.yml + compose.override.yml\n",[88,1260,1261,1263,1265,1268],{"class":90,"line":98},[88,1262,12],{"class":101},[88,1264,168],{"class":105},[88,1266,1267],{"class":105}," up",[88,1269,1270],{"class":125}," -d\n",[88,1272,1273],{"class":90,"line":112},[88,1274,133],{"emptyLinePlaceholder":132},[88,1276,1277],{"class":90,"line":129},[88,1278,1279],{"class":94},"# 生产环境显式只用基线文件，忽略 override\n",[88,1281,1282,1284,1286,1289,1292,1294],{"class":90,"line":136},[88,1283,12],{"class":101},[88,1285,168],{"class":105},[88,1287,1288],{"class":125}," -f",[88,1290,1291],{"class":105}," compose.yml",[88,1293,1267],{"class":105},[88,1295,1270],{"class":125},[88,1297,1298],{"class":90,"line":142},[88,1299,133],{"emptyLinePlaceholder":132},[88,1301,1302],{"class":90,"line":303},[88,1303,1304],{"class":94},"# 显式叠加多个文件（顺序即优先级，后者覆盖前者）\n",[88,1306,1307,1309,1311,1313,1315,1317,1320,1322],{"class":90,"line":314},[88,1308,12],{"class":101},[88,1310,168],{"class":105},[88,1312,1288],{"class":125},[88,1314,1291],{"class":105},[88,1316,1288],{"class":125},[88,1318,1319],{"class":105}," compose.prod.yml",[88,1321,1267],{"class":105},[88,1323,1270],{"class":125},[675,1325,1327,1328,1330],{"id":1326},"_4-使用-env-文件做变量替换","4. 使用 ",[36,1329,1124],{}," 文件做变量替换",[24,1332,1333,1334,1336,1337,1339,1340,1343,1344,1346],{},"Compose 会自动读取同目录下的 ",[36,1335,1124],{}," 文件，用于替换 ",[36,1338,38],{}," 中的 ",[36,1341,1342],{},"${VAR}"," 占位符（区别于 ",[36,1345,1116],{},"，后者是把内容注入到容器环境变量）。",[79,1348,1353],{"className":1349,"code":1351,"language":1352},[1350],"language-text","# .env\nIMAGE_TAG=1.25\nWEB_PORT=8080\n","text",[36,1354,1351],{"__ignoreMap":84},[79,1356,1358],{"className":227,"code":1357,"language":229,"meta":84,"style":84},"services:\n  web:\n    image: nginx:${IMAGE_TAG}\n    ports:\n      - \"${WEB_PORT}:80\"\n",[36,1359,1360,1366,1372,1381,1387],{"__ignoreMap":84},[88,1361,1362,1364],{"class":90,"line":91},[88,1363,237],{"class":236},[88,1365,275],{"class":240},[88,1367,1368,1370],{"class":90,"line":98},[88,1369,249],{"class":236},[88,1371,275],{"class":240},[88,1373,1374,1376,1378],{"class":90,"line":112},[88,1375,259],{"class":236},[88,1377,241],{"class":240},[88,1379,1380],{"class":105}," nginx:${IMAGE_TAG}\n",[88,1382,1383,1385],{"class":90,"line":129},[88,1384,272],{"class":236},[88,1386,275],{"class":240},[88,1388,1389,1391,1393,1396],{"class":90,"line":136},[88,1390,280],{"class":240},[88,1392,284],{"class":283},[88,1394,1395],{"class":105},"${WEB_PORT}:80",[88,1397,376],{"class":283},[51,1399,1401],{"id":1400},"五常见排错","五、常见排错",[470,1403,1404,1414],{},[473,1405,1406],{},[476,1407,1408,1411],{},[479,1409,1410],{},"现象",[479,1412,1413],{},"可能原因与排查方法",[486,1415,1416,1441,1457,1475,1495,1512,1532,1544,1561],{},[476,1417,1418,1424],{},[491,1419,1420,1423],{},[36,1421,1422],{},"docker compose up"," 后容器立即退出",[491,1425,1426,1427,1430,1431,1433,1434,1437,1438,1440],{},"查看 ",[36,1428,1429],{},"docker compose logs \u003Cservice>"," 看应用报错；确认镜像的 ",[36,1432,943],{},"\u002F",[36,1435,1436],{},"ENTRYPOINT"," 不是一次性任务（如未加 ",[36,1439,501],{}," 前台运行的临时命令）",[476,1442,1443,1446],{},[491,1444,1445],{},"服务之间无法互相访问",[491,1447,1448,1449,1452,1453,1456],{},"确认使用",[27,1450,1451],{},"服务名","而非 ",[36,1454,1455],{},"localhost"," 通信（Compose 内部通过服务名 DNS 解析）；确认服务在同一个 Compose 项目\u002F网络中",[476,1458,1459,1465],{},[491,1460,1461,1462],{},"端口冲突：",[36,1463,1464],{},"port is already allocated",[491,1466,1467,1468,617,1471,1474],{},"宿主机端口已被占用，改用其他宿主机端口，或用 ",[36,1469,1470],{},"docker ps",[36,1472,1473],{},"lsof -i:端口号"," 排查占用进程",[476,1476,1477,1483],{},[491,1478,1479,1480,1482],{},"修改了 ",[36,1481,38],{}," 但不生效",[491,1484,1485,1486,1488,1489,1491,1492],{},"需要重新 ",[36,1487,495],{},"（会重建有变化的服务）；镜像本身变化需先 ",[36,1490,593],{}," 或加 ",[36,1493,1494],{},"--build",[476,1496,1497,1500],{},[491,1498,1499],{},"数据卷里是旧数据",[491,1501,1502,1503,1505,1506,1508,1509],{},"卷的生命周期独立于容器，",[36,1504,522],{}," 默认不会删除卷；确认是否需要 ",[36,1507,538],{}," 一并清理，或直接 ",[36,1510,1511],{},"docker volume rm",[476,1513,1514,1519],{},[491,1515,1516,1518],{},[36,1517,441],{}," 似乎没等服务就绪",[491,1520,1521,1522,1524,1525,1528,1529,1531],{},"默认 ",[36,1523,441],{}," 只保证启动顺序，不保证应用初始化完成，需配合 ",[36,1526,1527],{},"healthcheck"," + ",[36,1530,1110],{},"，或在应用层做重试连接逻辑",[476,1533,1534,1537],{},[491,1535,1536],{},"权限错误，容器内无法写挂载目录",[491,1538,1539,1540,1543],{},"检查宿主机目录权限与容器内运行用户的 UID\u002FGID 是否匹配，或以 ",[36,1541,1542],{},"--user $(id -u):$(id -g)"," 运行",[476,1545,1546,1551],{},[491,1547,1548,1550],{},[36,1549,67],{}," 命令找不到",[491,1552,1553,1554,1557,1558,1560],{},"Compose V2 未安装为插件；确认 ",[36,1555,1556],{},"docker compose version"," 是否有输出，或改用 ",[36,1559,185],{},"（V1，需单独安装）",[476,1562,1563,1566],{},[491,1564,1565],{},"构建后容器仍使用旧代码",[491,1567,1568,1570,1571,1574,1575,1578,1579,539],{},[36,1569,593],{}," 时缓存了旧的层；用 ",[36,1572,1573],{},"docker compose build --no-cache"," 或调整 Dockerfile 中 ",[36,1576,1577],{},"COPY"," 顺序（见 ",[45,1580,1582],{"href":1581},"\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-images","镜像与 Dockerfile",[24,1584,1585,1586,1588,1589,1592,1593,1595],{},"排错的通用思路：先用 ",[36,1587,570],{}," 确认哪个服务状态异常，再用 ",[36,1590,1591],{},"docker compose logs -f \u003Cservice>"," 看具体报错，配合 ",[36,1594,630],{}," 检查变量替换和多文件合并后的最终配置是否符合预期。",[51,1597,1599],{"id":1598},"六总结","六、总结",[56,1601,1602,1607,1613,1640,1652],{},[59,1603,1604,1606],{},[27,1605,29],{}," 简化了多容器应用的编排，适合开发、测试和中小规模生产部署。",[59,1608,1609,1610,1612],{},"通过一个 ",[36,1611,38],{}," 文件定义服务、网络、数据卷，使用一条命令即可管理整个应用栈。",[59,1614,1615,1616,1619,1620,1619,1623,1619,1626,1619,1629,1631,1632,1634,1635,1528,1637,1639],{},"常用命令：",[36,1617,1618],{},"up","、",[36,1621,1622],{},"down",[36,1624,1625],{},"logs",[36,1627,1628],{},"exec",[36,1630,417],{}," 等，结合 ",[36,1633,501],{}," 可实现后台运行；",[36,1636,441],{},[36,1638,1527],{}," 才能真正保证依赖服务就绪。",[59,1641,1642,1643,1619,1645,1648,1649,1651],{},"多文件叠加（",[36,1644,1147],{},[36,1646,1647],{},"-f"," 多文件）与 ",[36,1650,1124],{}," 变量替换，可以优雅地管理开发\u002F生产等多环境差异。",[59,1653,1654],{},"Compose 可与单机 Docker 无缝配合，但不适用于跨多主机的集群（需要使用 Docker Swarm 或 Kubernetes）。",[24,1656,1657],{},"掌握 Docker Compose，可以高效地管理复杂应用的多容器依赖，提升开发和部署效率。",[51,1659,1660],{"id":1660},"参考文献",[470,1662,1663,1672],{},[473,1664,1665],{},[476,1666,1667,1670],{},[479,1668,1669],{},"资料",[479,1671,484],{},[486,1673,1674,1687,1699,1714],{},[476,1675,1676,1684],{},[491,1677,1678],{},[45,1679,1683],{"href":1680,"rel":1681},"https:\u002F\u002Fdocs.docker.com\u002Fcompose\u002F",[1682],"nofollow","Docker Compose 文档",[491,1685,1686],{},"官方",[476,1688,1689,1696],{},[491,1690,1691],{},[45,1692,1695],{"href":1693,"rel":1694},"https:\u002F\u002Fdocs.docker.com\u002Freference\u002Fcompose-file\u002F",[1682],"Compose 文件参考",[491,1697,1698],{},"完整字段说明",[476,1700,1701,1708],{},[491,1702,1703],{},[45,1704,1707],{"href":1705,"rel":1706},"https:\u002F\u002Fdocs.docker.com\u002Fcompose\u002Fhow-tos\u002Fstartup-order\u002F",[1682],"Compose 健康检查依赖",[491,1709,1710,1528,1712],{},[36,1711,441],{},[36,1713,1527],{},[476,1715,1716,1722],{},[491,1717,1718],{},[45,1719,1721],{"href":1720},"\u002Fknowledge\u002Fbooklet\u002Fuphold","运维导读",[491,1723,1724],{},"学习路径",[1726,1727,1728],"style",{},"html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":84,"searchDepth":98,"depth":98,"links":1730},[1731,1732,1734,1735,1742,1743,1744],{"id":53,"depth":98,"text":54},{"id":217,"depth":98,"text":1733},"二、compose.yml 基础示例",{"id":461,"depth":98,"text":462},{"id":672,"depth":98,"text":673,"children":1736},[1737,1738,1739,1740],{"id":677,"depth":112,"text":678},{"id":743,"depth":112,"text":744},{"id":1137,"depth":112,"text":1138},{"id":1326,"depth":112,"text":1741},"4. 使用 .env 文件做变量替换",{"id":1400,"depth":98,"text":1401},{"id":1598,"depth":98,"text":1599},{"id":1660,"depth":98,"text":1660},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fuphold\u002FDocker\u002Fdocker-compose","knowledge\u002Fknowledge\u002Fbooklet\u002Fuphold\u002FDocker\u002Fdocker-compose.md","md",{"items":1750},[1751,1753,1757,1759,1762,1766],{"path":1581,"title":1582,"description":1752,"category":10,"score":142},"镜像（Image）是 Docker 容器的只读模板，Dockerfile 则是构建镜像的蓝图。本文完整覆盖镜像的搜索、拉取、查看、删除、打标签、推送，以及 Dockerfile 常用指令、多阶段构建与体积优化技巧。",{"path":1754,"title":1755,"description":1756,"category":10,"score":142},"\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-intro","Docker 基础概念、安装与命令速查","Docker 是一个开源的容器化平台，能将应用程序及其所有依赖打包成轻量级、可移植的容器。本文介绍核心概念、底层原理、跨平台安装配置，并附完整的命令速查表，是学习 Docker 的第一篇。",{"path":47,"title":48,"description":1758,"category":10,"score":142},"容器是镜像的运行实例，掌握容器的创建、管理、日志查看，配合数据卷持久化与自定义网络通信，是使用 Docker 的日常核心，也是生产部署前必须掌握的三大基础能力。",{"path":1720,"title":1760,"description":1761,"category":10,"score":129},"运维与协作导读","本目录覆盖日常开发运维中的 Git 版本控制、Docker 容器化与 Nginx 服务网关，与 工程化 · Git、部署相关 等章节互补，提供完整的十阶段学习路径。",{"path":1763,"title":1764,"description":1765,"category":10,"score":91},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fbasics","后端入门概览","本目录覆盖 JavaScript\u002FTypeScript 服务端运行时与框架、数据存储，以及 Rust 系统编程入门，提供从零到部署的完整学习路径。前置建议：JavaScript 基础、工程化 · 环境变量。",{"path":1767,"title":1768,"description":1769,"category":10,"score":91},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fbun\u002Fbase","Bun 基础与核心命令","Bun 是用 Zig 编写的 JavaScript 运行时，内置包管理（bun install）、打包（bun build）、测试（bun test）等，并持续兼容 Node.js API。本文介绍核心特点、安装方式，以及日常最常用的命令与包管理功能。见 运行时对比。",{"series":1771,"title":12,"items":1772,"index":1777,"prev":1778,"next":1779},"booklet\u002Fuphold\u002Fdocker",[1773,1774,1775,1776],{"path":7,"title":8,"date":14,"pinned":15},{"path":1581,"title":1582,"date":14,"pinned":15},{"path":1754,"title":1755,"date":14,"pinned":15},{"path":47,"title":48,"date":14,"pinned":15},0,null,{"path":1581,"title":1582,"date":14,"pinned":15}]