[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-images":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-images":1590,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-images":1610},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":15,"pinned":16,"draft":16,"body":17,"seo":1586,"stem":1587,"id":1588,"extension":1589},"\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-images","镜像与 Dockerfile","镜像（Image）是 Docker 容器的只读模板，Dockerfile 则是构建镜像的蓝图。本文完整覆盖镜像的搜索、拉取、查看、删除、打标签、推送，以及 Dockerfile 常用指令、多阶段构建与体积优化技巧。","技能小册",[12,13,14],"docker","image","dockerfiles","2026-07-23",false,{"type":18,"value":19,"toc":1560},"minimark",[20,24,43,48,58,61,85,103,110,113,158,180,187,190,217,220,228,245,248,262,265,279,286,370,379,386,389,407,445,452,458,472,493,497,507,510,612,615,619,622,626,874,916,920,1055,1059,1062,1115,1120,1169,1173,1182,1196,1201,1207,1211,1217,1220,1286,1290,1322,1329,1368,1372,1402,1406,1438,1442,1480,1492,1495,1556],[21,22,8],"h1",{"id":23},"镜像与-dockerfile",[25,26,27,28,32,33,36,37,42],"p",{},"镜像（Image）是 Docker 容器的",[29,30,31],"strong",{},"只读模板","，熟悉镜像操作是使用 Docker 的起点；而 ",[29,34,35],{},"Dockerfile"," 则是描述「如何构建一个镜像」的文本文件，两者是一体两面。基础概念与安装见 ",[38,39,41],"a",{"href":40},"\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-intro","Docker 基础概念、安装与命令速查","。",[44,45,47],"h2",{"id":46},"一镜像基础操作","一、镜像基础操作",[49,50,52,53,57],"h3",{"id":51},"_1-搜索镜像docker-search","1. 搜索镜像（",[54,55,56],"code",{},"docker search","）",[25,59,60],{},"在 Docker Hub（默认公共仓库）中搜索镜像。",[62,63,68],"pre",{"className":64,"code":65,"language":66,"meta":67,"style":67},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","docker search nginx\n","bash","",[54,69,70],{"__ignoreMap":67},[71,72,75,78,82],"span",{"class":73,"line":74},"line",1,[71,76,12],{"class":77},"sbgvK",[71,79,81],{"class":80},"s_sjI"," search",[71,83,84],{"class":80}," nginx\n",[86,87,88,96],"ul",{},[89,90,91,92,95],"li",{},"输出包括镜像名称、描述、星级（受欢迎程度）、是否官方（",[54,93,94],{},"OFFICIAL","）等。",[89,97,98,99,102],{},"常用选项：",[54,100,101],{},"--limit N"," 限制搜索结果条数。",[49,104,106,107,57],{"id":105},"_2-拉取镜像docker-pull","2. 拉取镜像（",[54,108,109],{},"docker pull",[25,111,112],{},"从仓库下载镜像到本地。",[62,114,116],{"className":64,"code":115,"language":66,"meta":67,"style":67},"docker pull nginx               # 拉取最新版（标签 latest）\ndocker pull nginx:1.25          # 拉取指定版本标签\ndocker pull alpine:3.18         # 拉取 Alpine Linux 3.18 版本\n",[54,117,118,132,145],{"__ignoreMap":67},[71,119,120,122,125,128],{"class":73,"line":74},[71,121,12],{"class":77},[71,123,124],{"class":80}," pull",[71,126,127],{"class":80}," nginx",[71,129,131],{"class":130},"sutJx","               # 拉取最新版（标签 latest）\n",[71,133,135,137,139,142],{"class":73,"line":134},2,[71,136,12],{"class":77},[71,138,124],{"class":80},[71,140,141],{"class":80}," nginx:1.25",[71,143,144],{"class":130},"          # 拉取指定版本标签\n",[71,146,148,150,152,155],{"class":73,"line":147},3,[71,149,12],{"class":77},[71,151,124],{"class":80},[71,153,154],{"class":80}," alpine:3.18",[71,156,157],{"class":130},"         # 拉取 Alpine Linux 3.18 版本\n",[86,159,160,167,173],{},[89,161,162,163,166],{},"如果不指定标签，默认使用 ",[54,164,165],{},":latest","（不推荐在生产环境依赖隐式 latest，版本升级可能悄悄引入不兼容变更）。",[89,168,169,170,42],{},"支持私有仓库：",[54,171,172],{},"docker pull myregistry.com\u002Fmyimage:v1",[89,174,175,176,179],{},"支持多架构镜像（manifest list）：同一个 tag 在不同 CPU 架构（amd64 \u002F arm64）下会自动拉取匹配的那一份，可用 ",[54,177,178],{},"docker buildx imagetools inspect \u003Cimage>"," 查看包含哪些架构。",[49,181,183,184,57],{"id":182},"_3-查看本地镜像docker-images","3. 查看本地镜像（",[54,185,186],{},"docker images",[25,188,189],{},"列出已下载的镜像。",[62,191,193],{"className":64,"code":192,"language":66,"meta":67,"style":67},"docker images\n# 或\ndocker image ls\n",[54,194,195,202,207],{"__ignoreMap":67},[71,196,197,199],{"class":73,"line":74},[71,198,12],{"class":77},[71,200,201],{"class":80}," images\n",[71,203,204],{"class":73,"line":134},[71,205,206],{"class":130},"# 或\n",[71,208,209,211,214],{"class":73,"line":147},[71,210,12],{"class":77},[71,212,213],{"class":80}," image",[71,215,216],{"class":80}," ls\n",[25,218,219],{},"输出示例：",[62,221,226],{"className":222,"code":224,"language":225},[223],"language-text","REPOSITORY   TAG       IMAGE ID       CREATED       SIZE\nnginx        latest    abc123def456   2 days ago    142MB\nalpine       3.18      789ghi012jkl   3 weeks ago   7.05MB\n","text",[54,227,224],{"__ignoreMap":67},[86,229,230,236],{},[89,231,232,235],{},[54,233,234],{},"-a"," 显示所有镜像（包含中间层）。",[89,237,238,241,242,42],{},[54,239,240],{},"-q"," 只显示镜像 ID，常配合脚本批量操作，如 ",[54,243,244],{},"docker rmi $(docker images -q)",[25,246,247],{},"查看某个镜像的分层历史与构建指令：",[62,249,251],{"className":64,"code":250,"language":66,"meta":67,"style":67},"docker history nginx\n",[54,252,253],{"__ignoreMap":67},[71,254,255,257,260],{"class":73,"line":74},[71,256,12],{"class":77},[71,258,259],{"class":80}," history",[71,261,84],{"class":80},[25,263,264],{},"查看镜像详细元数据（环境变量、入口命令、暴露端口等）：",[62,266,268],{"className":64,"code":267,"language":66,"meta":67,"style":67},"docker inspect nginx\n",[54,269,270],{"__ignoreMap":67},[71,271,272,274,277],{"class":73,"line":74},[71,273,12],{"class":77},[71,275,276],{"class":80}," inspect",[71,278,84],{"class":80},[49,280,282,283,57],{"id":281},"_4-删除镜像docker-rmi","4. 删除镜像（",[54,284,285],{},"docker rmi",[62,287,289],{"className":64,"code":288,"language":66,"meta":67,"style":67},"docker rmi nginx:1.25           # 删除指定仓库:标签\ndocker rmi abc123def456          # 通过镜像 ID 删除\ndocker rmi -f \u003Cimage-id>         # 强制删除（即使有容器正在使用，通常不建议）\ndocker image prune               # 删除所有悬空镜像（dangling images，无标签且无容器使用）\ndocker image prune -a            # 删除所有未使用的镜像（更激进）\n",[54,290,291,303,315,342,355],{"__ignoreMap":67},[71,292,293,295,298,300],{"class":73,"line":74},[71,294,12],{"class":77},[71,296,297],{"class":80}," rmi",[71,299,141],{"class":80},[71,301,302],{"class":130},"           # 删除指定仓库:标签\n",[71,304,305,307,309,312],{"class":73,"line":134},[71,306,12],{"class":77},[71,308,297],{"class":80},[71,310,311],{"class":80}," abc123def456",[71,313,314],{"class":130},"          # 通过镜像 ID 删除\n",[71,316,317,319,321,325,329,332,336,339],{"class":73,"line":147},[71,318,12],{"class":77},[71,320,297],{"class":80},[71,322,324],{"class":323},"stzsN"," -f",[71,326,328],{"class":327},"smGrS"," \u003C",[71,330,331],{"class":80},"image-i",[71,333,335],{"class":334},"su5hD","d",[71,337,338],{"class":327},">",[71,340,341],{"class":130},"         # 强制删除（即使有容器正在使用，通常不建议）\n",[71,343,345,347,349,352],{"class":73,"line":344},4,[71,346,12],{"class":77},[71,348,213],{"class":80},[71,350,351],{"class":80}," prune",[71,353,354],{"class":130},"               # 删除所有悬空镜像（dangling images，无标签且无容器使用）\n",[71,356,358,360,362,364,367],{"class":73,"line":357},5,[71,359,12],{"class":77},[71,361,213],{"class":80},[71,363,351],{"class":80},[71,365,366],{"class":323}," -a",[71,368,369],{"class":130},"            # 删除所有未使用的镜像（更激进）\n",[86,371,372],{},[89,373,374,375,378],{},"如果镜像被容器（包括停止的容器）引用，需要先删除相关容器或使用 ",[54,376,377],{},"-f"," 强制删除。",[49,380,382,383,57],{"id":381},"_5-打标签docker-tag","5. 打标签（",[54,384,385],{},"docker tag",[25,387,388],{},"为本地镜像创建一个新的别名（标签），通常用于准备推送到自定义仓库。",[62,390,392],{"className":64,"code":391,"language":66,"meta":67,"style":67},"docker tag nginx:latest myrepo\u002Fnginx:v1\n",[54,393,394],{"__ignoreMap":67},[71,395,396,398,401,404],{"class":73,"line":74},[71,397,12],{"class":77},[71,399,400],{"class":80}," tag",[71,402,403],{"class":80}," nginx:latest",[71,405,406],{"class":80}," myrepo\u002Fnginx:v1\n",[86,408,409,415,438],{},[89,410,411,412,42],{},"格式：",[54,413,414],{},"docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]",[89,416,417,418,421,422,425,426,429,430,433,434,437],{},"示例中，将本地 ",[54,419,420],{},"nginx:latest"," 赋予一个新标签 ",[54,423,424],{},"myrepo\u002Fnginx:v1","（仓库 ",[54,427,428],{},"myrepo","，镜像名 ",[54,431,432],{},"nginx","，标签 ",[54,435,436],{},"v1","）。",[89,439,440,441,444],{},"注意：",[54,442,443],{},"tag"," 并不复制镜像数据，只是新增一个指向同一份镜像层的引用，因此几乎不占用额外磁盘空间。",[49,446,448,449,57],{"id":447},"_6-推送镜像到仓库docker-push","6. 推送镜像到仓库（",[54,450,451],{},"docker push",[25,453,454,455,437],{},"将本地镜像上传到远程仓库（需先登录：",[54,456,457],{},"docker login",[62,459,461],{"className":64,"code":460,"language":66,"meta":67,"style":67},"docker push myrepo\u002Fnginx:v1\n",[54,462,463],{"__ignoreMap":67},[71,464,465,467,470],{"class":73,"line":74},[71,466,12],{"class":77},[71,468,469],{"class":80}," push",[71,471,406],{"class":80},[86,473,474,484,487],{},[89,475,476,477,480,481,437],{},"推送前需确保镜像标签包含仓库地址（如 ",[54,478,479],{},"myrepo\u002F"," 或 ",[54,482,483],{},"registry.example.com\u002Fmyrepo\u002F",[89,485,486],{},"若推送 Docker Hub，仓库名默认为 Docker Hub 用户名或组织名。",[89,488,489,490,42],{},"推送私有仓库需指定完整域名：",[54,491,492],{},"docker push registry.example.com\u002Fmyapp:v1",[49,494,496],{"id":495},"_7-镜像存储位置","7. 镜像存储位置",[25,498,499,500,503,504,506],{},"Docker 镜像默认存储在 ",[54,501,502],{},"\u002Fvar\u002Flib\u002Fdocker","（Linux）。一般不需要手动操作，使用 ",[54,505,12],{}," 命令管理即可。",[49,508,509],{"id":509},"镜像操作总结表",[511,512,513,526],"table",{},[514,515,516],"thead",{},[517,518,519,523],"tr",{},[520,521,522],"th",{},"操作",[520,524,525],{},"命令",[527,528,529,540,550,562,572,582,592,602],"tbody",{},[517,530,531,535],{},[532,533,534],"td",{},"搜索镜像",[532,536,537],{},[54,538,539],{},"docker search \u003Cname>",[517,541,542,545],{},[532,543,544],{},"拉取镜像",[532,546,547],{},[54,548,549],{},"docker pull \u003Cimage>:\u003Ctag>",[517,551,552,555],{},[532,553,554],{},"查看镜像",[532,556,557,480,559],{},[54,558,186],{},[54,560,561],{},"docker image ls",[517,563,564,567],{},[532,565,566],{},"查看构建历史",[532,568,569],{},[54,570,571],{},"docker history \u003Cimage>",[517,573,574,577],{},[532,575,576],{},"删除镜像",[532,578,579],{},[54,580,581],{},"docker rmi \u003Cimage>",[517,583,584,587],{},[532,585,586],{},"清理悬空镜像",[532,588,589],{},[54,590,591],{},"docker image prune",[517,593,594,597],{},[532,595,596],{},"打标签",[532,598,599],{},[54,600,601],{},"docker tag \u003Csource> \u003Ctarget>",[517,603,604,607],{},[532,605,606],{},"推送镜像",[532,608,609],{},[54,610,611],{},"docker push \u003Cimage>",[25,613,614],{},"掌握这些命令，就能基本管理 Docker 镜像的生命周期。",[44,616,618],{"id":617},"二dockerfile-基础","二、Dockerfile 基础",[25,620,621],{},"Dockerfile 是一个文本文件，包含一系列指令，用于自动化构建 Docker 镜像。通过 Dockerfile，你可以定义应用的环境、依赖、启动命令等，确保应用在任何支持 Docker 的平台上一致运行。每条指令通常会在镜像上新增一层，层与层之间可以复用缓存。",[49,623,625],{"id":624},"_1-常用指令","1. 常用指令",[511,627,628,641],{},[514,629,630],{},[517,631,632,635,638],{},[520,633,634],{},"指令",[520,636,637],{},"说明",[520,639,640],{},"示例",[527,642,643,658,673,688,709,724,743,758,776,791,810,825,840,855],{},[517,644,645,650,653],{},[532,646,647],{},[54,648,649],{},"FROM",[532,651,652],{},"指定基础镜像（必须是第一条指令，多阶段构建可出现多次）",[532,654,655],{},[54,656,657],{},"FROM node:18-alpine",[517,659,660,665,668],{},[532,661,662],{},[54,663,664],{},"WORKDIR",[532,666,667],{},"设置工作目录（如果目录不存在则创建）",[532,669,670],{},[54,671,672],{},"WORKDIR \u002Fapp",[517,674,675,680,683],{},[532,676,677],{},[54,678,679],{},"COPY",[532,681,682],{},"将构建上下文中的文件\u002F目录复制到镜像中",[532,684,685],{},[54,686,687],{},"COPY package.json .",[517,689,690,695,704],{},[532,691,692],{},[54,693,694],{},"ADD",[532,696,697,698,700,701,703],{},"类似 ",[54,699,679],{},"，但支持自动解压 tar 包和拉取 URL（一般优先用 ",[54,702,679],{},"，行为更可预测）",[532,705,706],{},[54,707,708],{},"ADD app.tar.gz \u002Fapp",[517,710,711,716,719],{},[532,712,713],{},[54,714,715],{},"RUN",[532,717,718],{},"在构建镜像时执行命令（通常用于安装依赖）",[532,720,721],{},[54,722,723],{},"RUN npm install",[517,725,726,731,738],{},[532,727,728],{},[54,729,730],{},"CMD",[532,732,733,734,737],{},"容器启动时执行的默认命令（可被 ",[54,735,736],{},"docker run"," 后面的参数覆盖）",[532,739,740],{},[54,741,742],{},"CMD [\"node\", \"app.js\"]",[517,744,745,750,753],{},[532,746,747],{},[54,748,749],{},"ENTRYPOINT",[532,751,752],{},"容器启动时的入口命令（更灵活，不易被覆盖）",[532,754,755],{},[54,756,757],{},"ENTRYPOINT [\"npm\", \"start\"]",[517,759,760,765,771],{},[532,761,762],{},[54,763,764],{},"EXPOSE",[532,766,767,768,57],{},"声明容器运行时监听的端口（仅文档作用，不会自动映射，需配合 ",[54,769,770],{},"-p",[532,772,773],{},[54,774,775],{},"EXPOSE 3000",[517,777,778,783,786],{},[532,779,780],{},[54,781,782],{},"ENV",[532,784,785],{},"设置环境变量（在构建阶段和容器运行时均可用）",[532,787,788],{},[54,789,790],{},"ENV NODE_ENV=production",[517,792,793,798,805],{},[532,794,795],{},[54,796,797],{},"ARG",[532,799,800,801,804],{},"定义构建时变量（仅在构建阶段有效，",[54,802,803],{},"docker build --build-arg"," 传入）",[532,806,807],{},[54,808,809],{},"ARG VERSION=1.0",[517,811,812,817,820],{},[532,813,814],{},[54,815,816],{},"VOLUME",[532,818,819],{},"声明匿名数据卷挂载点，防止该目录写入可写层",[532,821,822],{},[54,823,824],{},"VOLUME \u002Fdata",[517,826,827,832,835],{},[532,828,829],{},[54,830,831],{},"USER",[532,833,834],{},"指定后续指令及容器运行时使用的用户，避免以 root 运行",[532,836,837],{},[54,838,839],{},"USER node",[517,841,842,847,850],{},[532,843,844],{},[54,845,846],{},"LABEL",[532,848,849],{},"为镜像添加元数据（作者、版本等键值对）",[532,851,852],{},[54,853,854],{},"LABEL maintainer=\"a@b.com\"",[517,856,857,862,869],{},[532,858,859],{},[54,860,861],{},"HEALTHCHECK",[532,863,864,865,868],{},"定义容器健康检查命令，供 ",[54,866,867],{},"docker ps"," \u002F 编排系统探测",[532,870,871],{},[54,872,873],{},"HEALTHCHECK CMD curl -f http:\u002F\u002Flocalhost\u002F || exit 1",[875,876,877,883],"blockquote",{},[25,878,879,882],{},[29,880,881],{},"CMD 与 ENTRYPOINT 的区别","：",[86,884,885,893],{},[89,886,887,889,890,892],{},[54,888,730],{}," 的默认参数可以被 ",[54,891,736],{}," 后面的命令整体覆盖。",[89,894,895,897,898,900,901,904,905,908,909,912,913,42],{},[54,896,749],{}," 通常用于定义可执行文件，",[54,899,730],{}," 提供默认参数，两者可组合使用，如 ",[54,902,903],{},"ENTRYPOINT [\"node\"]"," + ",[54,906,907],{},"CMD [\"app.js\"]","，",[54,910,911],{},"docker run image other.js"," 会变成 ",[54,914,915],{},"node other.js",[49,917,919],{"id":918},"_2-示例nodejs-应用的-dockerfile","2. 示例：Node.js 应用的 Dockerfile",[62,921,925],{"className":922,"code":923,"language":924,"meta":67,"style":67},"language-dockerfile shiki shiki-themes material-theme-lighter github-light github-dark","# 使用轻量的 Alpine 基础镜像\nFROM node:18-alpine\n\n# 设置工作目录\nWORKDIR \u002Fapp\n\n# 复制 package.json 和 package-lock.json（先复制依赖文件，利用缓存）\nCOPY package*.json .\u002F\n\n# 安装生产依赖（不安装 devDependencies）\nRUN npm ci --only=production\n\n# 复制其余源代码\nCOPY . .\n\n# 声明容器监听的端口（文档作用）\nEXPOSE 3000\n\n# 建议以非 root 用户运行\nUSER node\n\n# 容器启动时运行应用\nCMD [\"node\", \"server.js\"]\n","dockerfile",[54,926,927,932,937,943,948,953,958,964,970,975,981,987,992,998,1004,1009,1015,1021,1026,1032,1038,1043,1049],{"__ignoreMap":67},[71,928,929],{"class":73,"line":74},[71,930,931],{},"# 使用轻量的 Alpine 基础镜像\n",[71,933,934],{"class":73,"line":134},[71,935,936],{},"FROM node:18-alpine\n",[71,938,939],{"class":73,"line":147},[71,940,942],{"emptyLinePlaceholder":941},true,"\n",[71,944,945],{"class":73,"line":344},[71,946,947],{},"# 设置工作目录\n",[71,949,950],{"class":73,"line":357},[71,951,952],{},"WORKDIR \u002Fapp\n",[71,954,956],{"class":73,"line":955},6,[71,957,942],{"emptyLinePlaceholder":941},[71,959,961],{"class":73,"line":960},7,[71,962,963],{},"# 复制 package.json 和 package-lock.json（先复制依赖文件，利用缓存）\n",[71,965,967],{"class":73,"line":966},8,[71,968,969],{},"COPY package*.json .\u002F\n",[71,971,973],{"class":73,"line":972},9,[71,974,942],{"emptyLinePlaceholder":941},[71,976,978],{"class":73,"line":977},10,[71,979,980],{},"# 安装生产依赖（不安装 devDependencies）\n",[71,982,984],{"class":73,"line":983},11,[71,985,986],{},"RUN npm ci --only=production\n",[71,988,990],{"class":73,"line":989},12,[71,991,942],{"emptyLinePlaceholder":941},[71,993,995],{"class":73,"line":994},13,[71,996,997],{},"# 复制其余源代码\n",[71,999,1001],{"class":73,"line":1000},14,[71,1002,1003],{},"COPY . .\n",[71,1005,1007],{"class":73,"line":1006},15,[71,1008,942],{"emptyLinePlaceholder":941},[71,1010,1012],{"class":73,"line":1011},16,[71,1013,1014],{},"# 声明容器监听的端口（文档作用）\n",[71,1016,1018],{"class":73,"line":1017},17,[71,1019,1020],{},"EXPOSE 3000\n",[71,1022,1024],{"class":73,"line":1023},18,[71,1025,942],{"emptyLinePlaceholder":941},[71,1027,1029],{"class":73,"line":1028},19,[71,1030,1031],{},"# 建议以非 root 用户运行\n",[71,1033,1035],{"class":73,"line":1034},20,[71,1036,1037],{},"USER node\n",[71,1039,1041],{"class":73,"line":1040},21,[71,1042,942],{"emptyLinePlaceholder":941},[71,1044,1046],{"class":73,"line":1045},22,[71,1047,1048],{},"# 容器启动时运行应用\n",[71,1050,1052],{"class":73,"line":1051},23,[71,1053,1054],{},"CMD [\"node\", \"server.js\"]\n",[49,1056,1058],{"id":1057},"_3-构建镜像","3. 构建镜像",[25,1060,1061],{},"在 Dockerfile 所在目录执行：",[62,1063,1065],{"className":64,"code":1064,"language":66,"meta":67,"style":67},"# 构建镜像，指定名称和标签（. 表示当前目录作为构建上下文）\ndocker build -t myapp:v1 .\n\n# 使用非默认名称的 Dockerfile（如 Dockerfile.dev）\ndocker build -f Dockerfile.dev -t myapp:dev .\n",[54,1066,1067,1072,1088,1092,1097],{"__ignoreMap":67},[71,1068,1069],{"class":73,"line":74},[71,1070,1071],{"class":130},"# 构建镜像，指定名称和标签（. 表示当前目录作为构建上下文）\n",[71,1073,1074,1076,1079,1082,1085],{"class":73,"line":134},[71,1075,12],{"class":77},[71,1077,1078],{"class":80}," build",[71,1080,1081],{"class":323}," -t",[71,1083,1084],{"class":80}," myapp:v1",[71,1086,1087],{"class":80}," .\n",[71,1089,1090],{"class":73,"line":147},[71,1091,942],{"emptyLinePlaceholder":941},[71,1093,1094],{"class":73,"line":344},[71,1095,1096],{"class":130},"# 使用非默认名称的 Dockerfile（如 Dockerfile.dev）\n",[71,1098,1099,1101,1103,1105,1108,1110,1113],{"class":73,"line":357},[71,1100,12],{"class":77},[71,1102,1078],{"class":80},[71,1104,324],{"class":323},[71,1106,1107],{"class":80}," Dockerfile.dev",[71,1109,1081],{"class":323},[71,1111,1112],{"class":80}," myapp:dev",[71,1114,1087],{"class":80},[25,1116,1117,882],{},[29,1118,1119],{},"常用构建选项",[86,1121,1122,1131,1137,1143,1156],{},[89,1123,1124,1127,1128,437],{},[54,1125,1126],{},"-t, --tag","：设置镜像名称和标签（可省略标签，默认为 ",[54,1129,1130],{},"latest",[89,1132,1133,1136],{},[54,1134,1135],{},"-f, --file","：指定 Dockerfile 路径。",[89,1138,1139,1142],{},[54,1140,1141],{},"--no-cache","：不使用缓存，强制重新构建所有步骤。",[89,1144,1145,1148,1149,1152,1153,1155],{},[54,1146,1147],{},"--build-arg","：传递构建时变量，例如 ",[54,1150,1151],{},"--build-arg VERSION=1.2","（配合 ",[54,1154,797],{}," 使用）。",[89,1157,1158,1161,1162,1152,1165,1168],{},[54,1159,1160],{},"--platform","：指定目标架构，如 ",[54,1163,1164],{},"--platform linux\u002Famd64,linux\u002Farm64",[54,1166,1167],{},"docker buildx"," 构建多架构镜像）。",[49,1170,1172],{"id":1171},"_4-常见优化技巧","4. 常见优化技巧",[1174,1175,1177,1178,1181],"h4",{"id":1176},"_1使用-dockerignore-文件","（1）使用 ",[54,1179,1180],{},".dockerignore"," 文件",[25,1183,697,1184,1187,1188,1191,1192,1195],{},[54,1185,1186],{},".gitignore","，忽略不需要的文件（如 ",[54,1189,1190],{},"node_modules","、",[54,1193,1194],{},".git","、日志文件等），加快构建速度并减小镜像体积、避免敏感文件被带入镜像。",[25,1197,1198,1199,882],{},"示例 ",[54,1200,1180],{},[62,1202,1205],{"className":1203,"code":1204,"language":225},[223],"node_modules\n.git\n*.log\nDockerfile\n.dockerignore\n",[54,1206,1204],{"__ignoreMap":67},[1174,1208,1210],{"id":1209},"_2多阶段构建multi-stage-builds","（2）多阶段构建（Multi-stage Builds）",[25,1212,1213,1214,1216],{},"在一个 Dockerfile 中使用多个 ",[54,1215,649],{}," 语句，将构建环境和运行环境分离，极大减小最终镜像体积——构建工具（编译器、devDependencies）只存在于中间阶段，不会进入最终镜像。",[25,1218,1219],{},"示例（Node.js + 构建前端静态文件）：",[62,1221,1223],{"className":922,"code":1222,"language":924,"meta":67,"style":67},"# 第一阶段：构建\nFROM node:18 AS builder\nWORKDIR \u002Fapp\nCOPY package*.json .\u002F\nRUN npm ci\nCOPY . .\nRUN npm run build\n\n# 第二阶段：运行（只复制构建产物）\nFROM nginx:alpine\nCOPY --from=builder \u002Fapp\u002Fdist \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\nEXPOSE 80\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\n",[54,1224,1225,1230,1235,1239,1243,1248,1252,1257,1261,1266,1271,1276,1281],{"__ignoreMap":67},[71,1226,1227],{"class":73,"line":74},[71,1228,1229],{},"# 第一阶段：构建\n",[71,1231,1232],{"class":73,"line":134},[71,1233,1234],{},"FROM node:18 AS builder\n",[71,1236,1237],{"class":73,"line":147},[71,1238,952],{},[71,1240,1241],{"class":73,"line":344},[71,1242,969],{},[71,1244,1245],{"class":73,"line":357},[71,1246,1247],{},"RUN npm ci\n",[71,1249,1250],{"class":73,"line":955},[71,1251,1003],{},[71,1253,1254],{"class":73,"line":960},[71,1255,1256],{},"RUN npm run build\n",[71,1258,1259],{"class":73,"line":966},[71,1260,942],{"emptyLinePlaceholder":941},[71,1262,1263],{"class":73,"line":972},[71,1264,1265],{},"# 第二阶段：运行（只复制构建产物）\n",[71,1267,1268],{"class":73,"line":977},[71,1269,1270],{},"FROM nginx:alpine\n",[71,1272,1273],{"class":73,"line":983},[71,1274,1275],{},"COPY --from=builder \u002Fapp\u002Fdist \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\n",[71,1277,1278],{"class":73,"line":989},[71,1279,1280],{},"EXPOSE 80\n",[71,1282,1283],{"class":73,"line":994},[71,1284,1285],{},"CMD [\"nginx\", \"-g\", \"daemon off;\"]\n",[1174,1287,1289],{"id":1288},"_3选择轻量基础镜像","（3）选择轻量基础镜像",[86,1291,1292,1305,1312],{},[89,1293,1294,1295,1298,1299,1191,1302,42],{},"官方镜像通常提供 ",[54,1296,1297],{},"-alpine","（基于 Alpine Linux）版本，体积极小，适合生产环境。例如 ",[54,1300,1301],{},"node:18-alpine",[54,1303,1304],{},"python:3.12-alpine",[89,1306,1307,1308,1311],{},"还可以考虑 ",[54,1309,1310],{},"distroless","（Google 提供，不含 shell 和包管理器，攻击面更小）用于最终运行阶段。",[89,1313,1314,1315,1317,1318,1321],{},"避免使用 ",[54,1316,1130],{}," 标签（不够明确，可能随更新变化），生产环境建议锁定具体版本号，甚至锁定 digest（",[54,1319,1320],{},"image@sha256:...","）以保证可复现构建。",[1174,1323,1325,1326,1328],{"id":1324},"_4合并-run-命令减少层数","（4）合并 ",[54,1327,715],{}," 命令，减少层数",[62,1330,1332],{"className":922,"code":1331,"language":924,"meta":67,"style":67},"# 不推荐：多个 RUN 命令产生多个层，且中间产物也会被保留\nRUN apt update\nRUN apt install -y curl\nRUN rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\n\n# 推荐：合并成一条命令（使用 &&），清理动作在同一层内完成才能真正释放空间\nRUN apt update && apt install -y curl && rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\n",[54,1333,1334,1339,1344,1349,1354,1358,1363],{"__ignoreMap":67},[71,1335,1336],{"class":73,"line":74},[71,1337,1338],{},"# 不推荐：多个 RUN 命令产生多个层，且中间产物也会被保留\n",[71,1340,1341],{"class":73,"line":134},[71,1342,1343],{},"RUN apt update\n",[71,1345,1346],{"class":73,"line":147},[71,1347,1348],{},"RUN apt install -y curl\n",[71,1350,1351],{"class":73,"line":344},[71,1352,1353],{},"RUN rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\n",[71,1355,1356],{"class":73,"line":357},[71,1357,942],{"emptyLinePlaceholder":941},[71,1359,1360],{"class":73,"line":955},[71,1361,1362],{},"# 推荐：合并成一条命令（使用 &&），清理动作在同一层内完成才能真正释放空间\n",[71,1364,1365],{"class":73,"line":960},[71,1366,1367],{},"RUN apt update && apt install -y curl && rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\n",[1174,1369,1371],{"id":1370},"_5利用构建缓存","（5）利用构建缓存",[86,1373,1374,1380,1386],{},[89,1375,1376,1377,437],{},"将容易变化的指令放在 Dockerfile 末尾（如 ",[54,1378,1379],{},"COPY . .",[89,1381,1382,1383,1385],{},"先用 ",[54,1384,679],{}," 复制依赖文件并执行安装，再复制源代码，这样只要依赖文件不变，就会使用缓存，跳过耗时的依赖安装步骤。",[89,1387,1388,1389,1392,1393],{},"使用 BuildKit（Docker 新版默认开启）的 ",[54,1390,1391],{},"--mount=type=cache"," 可以在多次构建之间持久化依赖缓存目录，进一步加速：",[62,1394,1396],{"className":922,"code":1395,"language":924,"meta":67,"style":67},"RUN --mount=type=cache,target=\u002Froot\u002F.npm npm ci\n",[54,1397,1398],{"__ignoreMap":67},[71,1399,1400],{"class":73,"line":74},[71,1401,1395],{},[1174,1403,1405],{"id":1404},"_6减小镜像体积的其他手段","（6）减小镜像体积的其他手段",[86,1407,1408,1417,1420],{},[89,1409,1410,1411,1413,1414,1416],{},"用 ",[54,1412,591],{}," 定期清理悬空镜像；用 ",[54,1415,571],{}," 排查哪一层体积异常大。",[89,1418,1419],{},"尽量在一层内下载、解压、删除临时文件，避免临时文件残留在某一层里（即使后续层删除了它，之前层的体积依旧会被保留）。",[89,1421,1422,1423,1191,1426,1429,1430,1433,1434,1437],{},"生产镜像不要安装调试工具（",[54,1424,1425],{},"vim",[54,1427,1428],{},"curl"," 等），必要时用 ",[54,1431,1432],{},"docker exec"," 结合临时的 debug 容器（如 ",[54,1435,1436],{},"docker run --pid=container:\u003Cid> ... nicolaka\u002Fnetshoot","）排障。",[49,1439,1441],{"id":1440},"_5-总结","5. 总结",[86,1443,1444,1447,1465,1474],{},[89,1445,1446],{},"Dockerfile 是构建镜像的蓝图，通过一系列指令定义环境和启动行为。",[89,1448,1449,1450,1191,1452,1191,1454,1191,1456,1191,1458,1191,1460,1191,1462,1464],{},"常用指令包括 ",[54,1451,649],{},[54,1453,664],{},[54,1455,679],{},[54,1457,715],{},[54,1459,730],{},[54,1461,749],{},[54,1463,861],{}," 等。",[89,1466,1467,1468,1470,1471,1473],{},"使用 ",[54,1469,1180],{},"、多阶段构建、轻量基础镜像、合并 ",[54,1472,715],{},"、善用构建缓存等优化手段，可大幅减小镜像体积，提高构建效率。",[89,1475,1476,1477,42],{},"构建命令：",[54,1478,1479],{},"docker build -t 名称:标签 .",[25,1481,1482,1483,1487,1488,42],{},"掌握镜像操作与 Dockerfile 编写，即可将应用容器化，实现环境一致性和快速部署；下一步可学习 ",[38,1484,1486],{"href":1485},"\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-runtime","容器、数据与网络"," 与 ",[38,1489,1491],{"href":1490},"\u002Fknowledge\u002Fbooklet\u002Fuphold\u002Fdocker\u002Fdocker-compose","Docker Compose",[44,1493,1494],{"id":1494},"参考文献",[511,1496,1497,1506],{},[514,1498,1499],{},[517,1500,1501,1504],{},[520,1502,1503],{},"资料",[520,1505,637],{},[527,1507,1508,1521,1533,1545],{},[517,1509,1510,1518],{},[532,1511,1512],{},[38,1513,1517],{"href":1514,"rel":1515},"https:\u002F\u002Fdocs.docker.com\u002F",[1516],"nofollow","Docker 文档",[532,1519,1520],{},"官方",[517,1522,1523,1530],{},[532,1524,1525],{},[38,1526,1529],{"href":1527,"rel":1528},"https:\u002F\u002Fdocs.docker.com\u002Freference\u002Fdockerfile\u002F",[1516],"Dockerfile 参考",[532,1531,1532],{},"指令完整列表",[517,1534,1535,1542],{},[532,1536,1537],{},[38,1538,1541],{"href":1539,"rel":1540},"https:\u002F\u002Fdocs.docker.com\u002Fbuild\u002Fbuilding\u002Fmulti-stage\u002F",[1516],"多阶段构建",[532,1543,1544],{},"官方指南",[517,1546,1547,1553],{},[532,1548,1549],{},[38,1550,1552],{"href":1551},"\u002Fknowledge\u002Fbooklet\u002Fuphold","运维导读",[532,1554,1555],{},"学习路径",[1557,1558,1559],"style",{},"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 .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 .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 .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":67,"searchDepth":134,"depth":134,"links":1561},[1562,1578,1585],{"id":46,"depth":134,"text":47,"children":1563},[1564,1566,1568,1570,1572,1574,1576,1577],{"id":51,"depth":147,"text":1565},"1. 搜索镜像（docker search）",{"id":105,"depth":147,"text":1567},"2. 拉取镜像（docker pull）",{"id":182,"depth":147,"text":1569},"3. 查看本地镜像（docker images）",{"id":281,"depth":147,"text":1571},"4. 删除镜像（docker rmi）",{"id":381,"depth":147,"text":1573},"5. 打标签（docker tag）",{"id":447,"depth":147,"text":1575},"6. 推送镜像到仓库（docker push）",{"id":495,"depth":147,"text":496},{"id":509,"depth":147,"text":509},{"id":617,"depth":134,"text":618,"children":1579},[1580,1581,1582,1583,1584],{"id":624,"depth":147,"text":625},{"id":918,"depth":147,"text":919},{"id":1057,"depth":147,"text":1058},{"id":1171,"depth":147,"text":1172},{"id":1440,"depth":147,"text":1441},{"id":1494,"depth":134,"text":1494},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fuphold\u002FDocker\u002Fdocker-images","knowledge\u002Fknowledge\u002Fbooklet\u002Fuphold\u002FDocker\u002Fdocker-images.md","md",{"items":1591},[1592,1595,1597,1599,1602,1606],{"path":1490,"title":1593,"description":1594,"category":10,"score":955},"Docker Compose 编排","Docker Compose 是定义和运行多容器 Docker 应用的工具，通过一个 compose.yml 文件即可管理 Web、数据库、缓存等多个服务。本文覆盖安装、完整字段说明、多服务示例、常用指令与常见排错。",{"path":40,"title":41,"description":1596,"category":10,"score":955},"Docker 是一个开源的容器化平台，能将应用程序及其所有依赖打包成轻量级、可移植的容器。本文介绍核心概念、底层原理、跨平台安装配置，并附完整的命令速查表，是学习 Docker 的第一篇。",{"path":1485,"title":1486,"description":1598,"category":10,"score":955},"容器是镜像的运行实例，掌握容器的创建、管理、日志查看，配合数据卷持久化与自定义网络通信，是使用 Docker 的日常核心，也是生产部署前必须掌握的三大基础能力。",{"path":1551,"title":1600,"description":1601,"category":10,"score":344},"运维与协作导读","本目录覆盖日常开发运维中的 Git 版本控制、Docker 容器化与 Nginx 服务网关，与 工程化 · Git、部署相关 等章节互补，提供完整的十阶段学习路径。",{"path":1603,"title":1604,"description":1605,"category":10,"score":74},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fbasics","后端入门概览","本目录覆盖 JavaScript\u002FTypeScript 服务端运行时与框架、数据存储，以及 Rust 系统编程入门，提供从零到部署的完整学习路径。前置建议：JavaScript 基础、工程化 · 环境变量。",{"path":1607,"title":1608,"description":1609,"category":10,"score":74},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fbun\u002Fbase","Bun 基础与核心命令","Bun 是用 Zig 编写的 JavaScript 运行时，内置包管理（bun install）、打包（bun build）、测试（bun test）等，并持续兼容 Node.js API。本文介绍核心特点、安装方式，以及日常最常用的命令与包管理功能。见 运行时对比。",{"series":1611,"title":12,"items":1612,"index":74,"prev":1617,"next":1618},"booklet\u002Fuphold\u002Fdocker",[1613,1614,1615,1616],{"path":1490,"title":1593,"date":15,"pinned":16},{"path":7,"title":8,"date":15,"pinned":16},{"path":40,"title":41,"date":15,"pinned":16},{"path":1485,"title":1486,"date":15,"pinned":16},{"path":1490,"title":1593,"date":15,"pinned":16},{"path":40,"title":41,"date":15,"pinned":16}]