[{"data":1,"prerenderedAt":3558},["ShallowReactive",2],{"article-devops\u002Fdocker":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"tags":11,"body":14,"_type":3552,"_id":3553,"_source":3554,"_file":3555,"_stem":3556,"_extension":3557},"\u002Farticles\u002Fdevops\u002Fdocker","devops",false,"","Docker 入门：从镜像、容器到项目部署","面向第一次接触 Docker 的学习笔记，梳理镜像、容器、Dockerfile、常用命令、Nginx 反向代理和服务器部署流程。","2026-05-15",[12,13],"软件工程","DevOps",{"type":15,"children":16,"toc":3529},"root",[17,25,32,37,62,73,78,83,92,98,103,108,147,152,157,169,207,212,223,259,272,277,282,303,314,325,330,358,379,385,396,401,511,516,620,625,650,671,736,741,746,860,865,877,917,937,942,1012,1017,1089,1115,1120,1166,1171,1235,1240,1245,1273,1358,1370,1375,1669,1689,1695,1700,1706,1763,1782,1787,1840,1859,1864,1981,1986,2069,2119,2124,2214,2219,2224,2317,2337,2342,2444,2469,2474,2512,2537,2543,2564,2569,2592,2597,2638,2651,2724,2729,2735,2740,2753,2784,2789,2808,2839,2849,2869,2874,2879,2884,2898,2903,3142,3147,3152,3166,3171,3176,3330,3335,3340,3448,3453,3458,3523],{"type":18,"tag":19,"props":20,"children":21},"element","p",{},[22],{"type":23,"value":24},"text","最近想弄个人博客，记录自己学习的过程，这就需要掌握一些部署的技能，如Docker、Nginx，这篇文章就是",{"type":18,"tag":26,"props":27,"children":29},"h2",{"id":28},"为什么需要-docker",[30],{"type":23,"value":31},"为什么需要 Docker",{"type":18,"tag":19,"props":33,"children":34},{},[35],{"type":23,"value":36},"很多人第一次部署项目时，遇到的不是代码问题，而是环境问题：",{"type":18,"tag":38,"props":39,"children":40},"ul",{},[41,47,52,57],{"type":18,"tag":42,"props":43,"children":44},"li",{},[45],{"type":23,"value":46},"本地能跑，服务器跑不起来。",{"type":18,"tag":42,"props":48,"children":49},{},[50],{"type":23,"value":51},"A 项目需要 Node.js 18，B 项目需要 Node.js 20。",{"type":18,"tag":42,"props":53,"children":54},{},[55],{"type":23,"value":56},"换一台机器，又要重新安装运行环境、配置环境变量、调整启动脚本。",{"type":18,"tag":42,"props":58,"children":59},{},[60],{"type":23,"value":61},"项目越多，服务器上的依赖、日志、进程和端口越难管理。",{"type":18,"tag":19,"props":63,"children":64},{},[65,67],{"type":23,"value":66},"Docker 要解决的核心问题是：",{"type":18,"tag":68,"props":69,"children":70},"strong",{},[71],{"type":23,"value":72},"把应用和它依赖的运行环境一起打包，让它在不同机器上用尽量一致的方式运行。",{"type":18,"tag":19,"props":74,"children":75},{},[76],{"type":23,"value":77},"可以把 Docker 理解成一种轻量的应用交付方式。它不会像传统虚拟机那样完整模拟一台操作系统，而是基于宿主机内核，把不同应用隔离在不同容器中。这样既能减少环境差异，又不会像虚拟机那样笨重。",{"type":18,"tag":19,"props":79,"children":80},{},[81],{"type":23,"value":82},"先记住一句话：",{"type":18,"tag":84,"props":85,"children":86},"blockquote",{},[87],{"type":18,"tag":19,"props":88,"children":89},{},[90],{"type":23,"value":91},"Docker 不是为了让代码变得神奇，而是为了让代码运行环境变得可复制、可迁移、可管理。",{"type":18,"tag":26,"props":93,"children":95},{"id":94},"没有-docker-和有-docker-的部署区别",[96],{"type":23,"value":97},"没有 Docker 和有 Docker 的部署区别",{"type":18,"tag":19,"props":99,"children":100},{},[101],{"type":23,"value":102},"假设服务器上要部署一个 Nuxt 应用，并且使用 Nginx 接收外部请求。",{"type":18,"tag":19,"props":104,"children":105},{},[106],{"type":23,"value":107},"没有 Docker 时，常见结构是：",{"type":18,"tag":109,"props":110,"children":113},"pre",{"className":111,"code":112,"language":23,"meta":7,"style":7},"language-text shiki shiki-themes github-dark","Linux 宿主机\n├─ Nginx（直接安装在宿主机）\n└─ Nuxt 应用（直接运行在宿主机）\n",[114],{"type":18,"tag":115,"props":116,"children":117},"code",{"__ignoreMap":7},[118,129,138],{"type":18,"tag":119,"props":120,"children":123},"span",{"class":121,"line":122},"line",1,[124],{"type":18,"tag":119,"props":125,"children":126},{},[127],{"type":23,"value":128},"Linux 宿主机\n",{"type":18,"tag":119,"props":130,"children":132},{"class":121,"line":131},2,[133],{"type":18,"tag":119,"props":134,"children":135},{},[136],{"type":23,"value":137},"├─ Nginx（直接安装在宿主机）\n",{"type":18,"tag":119,"props":139,"children":141},{"class":121,"line":140},3,[142],{"type":18,"tag":119,"props":143,"children":144},{},[145],{"type":23,"value":146},"└─ Nuxt 应用（直接运行在宿主机）\n",{"type":18,"tag":19,"props":148,"children":149},{},[150],{"type":23,"value":151},"这种方式当然能用，但服务器会逐渐变成一个\"手工配置现场\"：Node 版本、项目依赖、进程管理、日志目录、环境变量都散落在宿主机上。后续迁移、排查问题或部署新项目时，很容易出现环境不一致。",{"type":18,"tag":19,"props":153,"children":154},{},[155],{"type":23,"value":156},"使用 Docker 后，可以有两种常见做法。",{"type":18,"tag":19,"props":158,"children":159},{},[160,162,167],{"type":23,"value":161},"第一种是 ",{"type":18,"tag":68,"props":163,"children":164},{},[165],{"type":23,"value":166},"Nginx 不容器化，只把应用容器化",{"type":23,"value":168},"：",{"type":18,"tag":109,"props":170,"children":172},{"className":111,"code":171,"language":23,"meta":7,"style":7},"Linux 宿主机\n├─ Nginx（直接安装在宿主机）\n└─ Docker\n   └─ Nuxt 容器\n",[173],{"type":18,"tag":115,"props":174,"children":175},{"__ignoreMap":7},[176,183,190,198],{"type":18,"tag":119,"props":177,"children":178},{"class":121,"line":122},[179],{"type":18,"tag":119,"props":180,"children":181},{},[182],{"type":23,"value":128},{"type":18,"tag":119,"props":184,"children":185},{"class":121,"line":131},[186],{"type":18,"tag":119,"props":187,"children":188},{},[189],{"type":23,"value":137},{"type":18,"tag":119,"props":191,"children":192},{"class":121,"line":140},[193],{"type":18,"tag":119,"props":194,"children":195},{},[196],{"type":23,"value":197},"└─ Docker\n",{"type":18,"tag":119,"props":199,"children":201},{"class":121,"line":200},4,[202],{"type":18,"tag":119,"props":203,"children":204},{},[205],{"type":23,"value":206},"   └─ Nuxt 容器\n",{"type":18,"tag":19,"props":208,"children":209},{},[210],{"type":23,"value":211},"这种方式适合刚开始使用 Docker 的阶段。Nginx 仍然由服务器直接管理，Docker 只负责应用本身，理解成本比较低。",{"type":18,"tag":19,"props":213,"children":214},{},[215,217,222],{"type":23,"value":216},"第二种是 ",{"type":18,"tag":68,"props":218,"children":219},{},[220],{"type":23,"value":221},"Nginx 和应用都容器化",{"type":23,"value":168},{"type":18,"tag":109,"props":224,"children":226},{"className":111,"code":225,"language":23,"meta":7,"style":7},"Linux 宿主机\n└─ Docker\n   ├─ Nginx 容器\n   └─ Nuxt 容器\n",[227],{"type":18,"tag":115,"props":228,"children":229},{"__ignoreMap":7},[230,237,244,252],{"type":18,"tag":119,"props":231,"children":232},{"class":121,"line":122},[233],{"type":18,"tag":119,"props":234,"children":235},{},[236],{"type":23,"value":128},{"type":18,"tag":119,"props":238,"children":239},{"class":121,"line":131},[240],{"type":18,"tag":119,"props":241,"children":242},{},[243],{"type":23,"value":197},{"type":18,"tag":119,"props":245,"children":246},{"class":121,"line":140},[247],{"type":18,"tag":119,"props":248,"children":249},{},[250],{"type":23,"value":251},"   ├─ Nginx 容器\n",{"type":18,"tag":119,"props":253,"children":254},{"class":121,"line":200},[255],{"type":18,"tag":119,"props":256,"children":257},{},[258],{"type":23,"value":206},{"type":18,"tag":19,"props":260,"children":261},{},[262,264,270],{"type":23,"value":263},"这种方式更统一，所有服务都由 Docker 管理，通常会配合 ",{"type":18,"tag":115,"props":265,"children":267},{"className":266},[],[268],{"type":23,"value":269},"docker compose",{"type":23,"value":271}," 使用。正式项目中，如果后面还要加入数据库、Redis、后端服务、AI 服务等，多容器编排会更方便。",{"type":18,"tag":19,"props":273,"children":274},{},[275],{"type":23,"value":276},"这两种方式没有绝对优劣。刚入门时，可以先让应用容器化；当项目服务变多、部署流程变复杂时，再把 Nginx、数据库、缓存等服务逐步纳入 Compose 管理。",{"type":18,"tag":26,"props":278,"children":280},{"id":279},"镜像和容器",[281],{"type":23,"value":279},{"type":18,"tag":19,"props":283,"children":284},{},[285,287,293,295,301],{"type":23,"value":286},"Docker 里最重要的两个概念是：",{"type":18,"tag":115,"props":288,"children":290},{"className":289},[],[291],{"type":23,"value":292},"镜像",{"type":23,"value":294}," 和 ",{"type":18,"tag":115,"props":296,"children":298},{"className":297},[],[299],{"type":23,"value":300},"容器",{"type":23,"value":302},"。",{"type":18,"tag":19,"props":304,"children":305},{},[306,312],{"type":18,"tag":115,"props":307,"children":309},{"className":308},[],[310],{"type":23,"value":311},"镜像 Image",{"type":23,"value":313}," 是静态的构建产物。它描述了应用运行需要的文件、依赖、环境和默认启动方式。可以把镜像类比成\"软件安装包\"，也可以类比成面向对象里的\"类\"。",{"type":18,"tag":19,"props":315,"children":316},{},[317,323],{"type":18,"tag":115,"props":318,"children":320},{"className":319},[],[321],{"type":23,"value":322},"容器 Container",{"type":23,"value":324}," 是镜像运行后的实例。它是动态的，是一个被隔离起来的运行环境。可以把容器类比成\"安装并启动后的软件\"，也可以类比成面向对象里的\"对象实例\"。",{"type":18,"tag":19,"props":326,"children":327},{},[328],{"type":23,"value":329},"简单说：",{"type":18,"tag":38,"props":331,"children":332},{},[333,338,343,348,353],{"type":18,"tag":42,"props":334,"children":335},{},[336],{"type":23,"value":337},"镜像是构建结果。",{"type":18,"tag":42,"props":339,"children":340},{},[341],{"type":23,"value":342},"容器是镜像运行后的实例。",{"type":18,"tag":42,"props":344,"children":345},{},[346],{"type":23,"value":347},"一个镜像可以启动多个容器。",{"type":18,"tag":42,"props":349,"children":350},{},[351],{"type":23,"value":352},"删除容器不会自动删除镜像。",{"type":18,"tag":42,"props":354,"children":355},{},[356],{"type":23,"value":357},"删除镜像前，一般要先停止并删除依赖它的容器。",{"type":18,"tag":19,"props":359,"children":360},{},[361,363,369,371,377],{"type":23,"value":362},"比如你构建出一个 ",{"type":18,"tag":115,"props":364,"children":366},{"className":365},[],[367],{"type":23,"value":368},"my-blog:v1",{"type":23,"value":370}," 镜像，就可以用它启动一个博客容器。将来升级版本时，可以重新构建 ",{"type":18,"tag":115,"props":372,"children":374},{"className":373},[],[375],{"type":23,"value":376},"my-blog:v2",{"type":23,"value":378},"，再用新镜像启动新容器。",{"type":18,"tag":26,"props":380,"children":382},{"id":381},"dockerfile-是什么",[383],{"type":23,"value":384},"Dockerfile 是什么",{"type":18,"tag":19,"props":386,"children":387},{},[388,394],{"type":18,"tag":115,"props":389,"children":391},{"className":390},[],[392],{"type":23,"value":393},"Dockerfile",{"type":23,"value":395}," 是写给 Docker 的构建说明书。它告诉 Docker 如何一步一步生成镜像：使用哪个基础镜像、进入哪个工作目录、复制哪些文件、安装哪些依赖，以及容器启动时执行什么命令。",{"type":18,"tag":19,"props":397,"children":398},{},[399],{"type":23,"value":400},"下面是一个入门版 Node.js 项目 Dockerfile：",{"type":18,"tag":109,"props":402,"children":406},{"className":403,"code":404,"language":405,"meta":7,"style":7},"language-dockerfile shiki shiki-themes github-dark","FROM node:20-alpine\n\nWORKDIR \u002Fapp\n\nCOPY package*.json .\u002F\nRUN npm ci --omit=dev\n\nCOPY . .\n\nEXPOSE 3000\n\nCMD [\"npm\", \"start\"]\n","dockerfile",[407],{"type":18,"tag":115,"props":408,"children":409},{"__ignoreMap":7},[410,418,427,435,442,451,460,468,477,485,494,502],{"type":18,"tag":119,"props":411,"children":412},{"class":121,"line":122},[413],{"type":18,"tag":119,"props":414,"children":415},{},[416],{"type":23,"value":417},"FROM node:20-alpine\n",{"type":18,"tag":119,"props":419,"children":420},{"class":121,"line":131},[421],{"type":18,"tag":119,"props":422,"children":424},{"emptyLinePlaceholder":423},true,[425],{"type":23,"value":426},"\n",{"type":18,"tag":119,"props":428,"children":429},{"class":121,"line":140},[430],{"type":18,"tag":119,"props":431,"children":432},{},[433],{"type":23,"value":434},"WORKDIR \u002Fapp\n",{"type":18,"tag":119,"props":436,"children":437},{"class":121,"line":200},[438],{"type":18,"tag":119,"props":439,"children":440},{"emptyLinePlaceholder":423},[441],{"type":23,"value":426},{"type":18,"tag":119,"props":443,"children":445},{"class":121,"line":444},5,[446],{"type":18,"tag":119,"props":447,"children":448},{},[449],{"type":23,"value":450},"COPY package*.json .\u002F\n",{"type":18,"tag":119,"props":452,"children":454},{"class":121,"line":453},6,[455],{"type":18,"tag":119,"props":456,"children":457},{},[458],{"type":23,"value":459},"RUN npm ci --omit=dev\n",{"type":18,"tag":119,"props":461,"children":463},{"class":121,"line":462},7,[464],{"type":18,"tag":119,"props":465,"children":466},{"emptyLinePlaceholder":423},[467],{"type":23,"value":426},{"type":18,"tag":119,"props":469,"children":471},{"class":121,"line":470},8,[472],{"type":18,"tag":119,"props":473,"children":474},{},[475],{"type":23,"value":476},"COPY . .\n",{"type":18,"tag":119,"props":478,"children":480},{"class":121,"line":479},9,[481],{"type":18,"tag":119,"props":482,"children":483},{"emptyLinePlaceholder":423},[484],{"type":23,"value":426},{"type":18,"tag":119,"props":486,"children":488},{"class":121,"line":487},10,[489],{"type":18,"tag":119,"props":490,"children":491},{},[492],{"type":23,"value":493},"EXPOSE 3000\n",{"type":18,"tag":119,"props":495,"children":497},{"class":121,"line":496},11,[498],{"type":18,"tag":119,"props":499,"children":500},{"emptyLinePlaceholder":423},[501],{"type":23,"value":426},{"type":18,"tag":119,"props":503,"children":505},{"class":121,"line":504},12,[506],{"type":18,"tag":119,"props":507,"children":508},{},[509],{"type":23,"value":510},"CMD [\"npm\", \"start\"]\n",{"type":18,"tag":19,"props":512,"children":513},{},[514],{"type":23,"value":515},"这里每一行都对应一个构建或运行阶段的动作：",{"type":18,"tag":38,"props":517,"children":518},{},[519,530,541,552,579,590,609],{"type":18,"tag":42,"props":520,"children":521},{},[522,528],{"type":18,"tag":115,"props":523,"children":525},{"className":524},[],[526],{"type":23,"value":527},"FROM node:20-alpine",{"type":23,"value":529},"：选择一个已有的基础镜像，里面已经包含 Node.js 运行环境。",{"type":18,"tag":42,"props":531,"children":532},{},[533,539],{"type":18,"tag":115,"props":534,"children":536},{"className":535},[],[537],{"type":23,"value":538},"WORKDIR \u002Fapp",{"type":23,"value":540},"：指定容器内部的工作目录，后续命令默认都在这里执行。",{"type":18,"tag":42,"props":542,"children":543},{},[544,550],{"type":18,"tag":115,"props":545,"children":547},{"className":546},[],[548],{"type":23,"value":549},"COPY package*.json .\u002F",{"type":23,"value":551},"：先复制依赖描述文件，方便 Docker 利用构建缓存。",{"type":18,"tag":42,"props":553,"children":554},{},[555,561,563,569,571,577],{"type":18,"tag":115,"props":556,"children":558},{"className":557},[],[559],{"type":23,"value":560},"RUN npm ci --omit=dev",{"type":23,"value":562},"：在构建镜像时安装生产依赖。相比 ",{"type":18,"tag":115,"props":564,"children":566},{"className":565},[],[567],{"type":23,"value":568},"npm install",{"type":23,"value":570},"，",{"type":18,"tag":115,"props":572,"children":574},{"className":573},[],[575],{"type":23,"value":576},"npm ci",{"type":23,"value":578}," 更适合根据锁文件做可重复安装。",{"type":18,"tag":42,"props":580,"children":581},{},[582,588],{"type":18,"tag":115,"props":583,"children":585},{"className":584},[],[586],{"type":23,"value":587},"COPY . .",{"type":23,"value":589},"：把项目其他文件复制到镜像中。",{"type":18,"tag":42,"props":591,"children":592},{},[593,599,601,607],{"type":18,"tag":115,"props":594,"children":596},{"className":595},[],[597],{"type":23,"value":598},"EXPOSE 3000",{"type":23,"value":600},"：声明应用在容器内监听 ",{"type":18,"tag":115,"props":602,"children":604},{"className":603},[],[605],{"type":23,"value":606},"3000",{"type":23,"value":608}," 端口。注意它只是元信息，不会自动把端口暴露到宿主机。",{"type":18,"tag":42,"props":610,"children":611},{},[612,618],{"type":18,"tag":115,"props":613,"children":615},{"className":614},[],[616],{"type":23,"value":617},"CMD [\"npm\", \"start\"]",{"type":23,"value":619},"：容器启动后默认执行的命令。",{"type":18,"tag":19,"props":621,"children":622},{},[623],{"type":23,"value":624},"这里有两个时间点很容易混淆：",{"type":18,"tag":38,"props":626,"children":627},{},[628,639],{"type":18,"tag":42,"props":629,"children":630},{},[631,637],{"type":18,"tag":115,"props":632,"children":634},{"className":633},[],[635],{"type":23,"value":636},"RUN",{"type":23,"value":638}," 发生在构建镜像时，比如安装依赖、编译项目。",{"type":18,"tag":42,"props":640,"children":641},{},[642,648],{"type":18,"tag":115,"props":643,"children":645},{"className":644},[],[646],{"type":23,"value":647},"CMD",{"type":23,"value":649}," 发生在容器启动时，比如启动 Web 服务。",{"type":18,"tag":19,"props":651,"children":652},{},[653,655,661,663,669],{"type":23,"value":654},"真实项目中，还应该配合 ",{"type":18,"tag":115,"props":656,"children":658},{"className":657},[],[659],{"type":23,"value":660},".dockerignore",{"type":23,"value":662}," 使用，避免把 ",{"type":18,"tag":115,"props":664,"children":666},{"className":665},[],[667],{"type":23,"value":668},"node_modules",{"type":23,"value":670},"、构建产物、日志、环境变量文件等内容复制进镜像：",{"type":18,"tag":109,"props":672,"children":676},{"className":673,"code":674,"language":675,"meta":7,"style":7},"language-gitignore shiki shiki-themes github-dark","node_modules\ndist\n.nuxt\n.output\n.env\n*.log\ncoverage\n","gitignore",[677],{"type":18,"tag":115,"props":678,"children":679},{"__ignoreMap":7},[680,688,696,704,712,720,728],{"type":18,"tag":119,"props":681,"children":682},{"class":121,"line":122},[683],{"type":18,"tag":119,"props":684,"children":685},{},[686],{"type":23,"value":687},"node_modules\n",{"type":18,"tag":119,"props":689,"children":690},{"class":121,"line":131},[691],{"type":18,"tag":119,"props":692,"children":693},{},[694],{"type":23,"value":695},"dist\n",{"type":18,"tag":119,"props":697,"children":698},{"class":121,"line":140},[699],{"type":18,"tag":119,"props":700,"children":701},{},[702],{"type":23,"value":703},".nuxt\n",{"type":18,"tag":119,"props":705,"children":706},{"class":121,"line":200},[707],{"type":18,"tag":119,"props":708,"children":709},{},[710],{"type":23,"value":711},".output\n",{"type":18,"tag":119,"props":713,"children":714},{"class":121,"line":444},[715],{"type":18,"tag":119,"props":716,"children":717},{},[718],{"type":23,"value":719},".env\n",{"type":18,"tag":119,"props":721,"children":722},{"class":121,"line":453},[723],{"type":18,"tag":119,"props":724,"children":725},{},[726],{"type":23,"value":727},"*.log\n",{"type":18,"tag":119,"props":729,"children":730},{"class":121,"line":462},[731],{"type":18,"tag":119,"props":732,"children":733},{},[734],{"type":23,"value":735},"coverage\n",{"type":18,"tag":19,"props":737,"children":738},{},[739],{"type":23,"value":740},"如果项目需要先构建再运行，例如 Nuxt、Next.js、Vue、React 等前端项目，通常还会使用多阶段构建：第一阶段负责安装依赖和打包，第二阶段只保留运行所需文件。这样可以减少最终镜像体积，也能让镜像更干净。",{"type":18,"tag":19,"props":742,"children":743},{},[744],{"type":23,"value":745},"下面是一个多阶段构建的例子：",{"type":18,"tag":109,"props":747,"children":749},{"className":403,"code":748,"language":405,"meta":7,"style":7},"# 阶段一：构建\nFROM node:20-alpine AS builder\nWORKDIR \u002Fapp\nCOPY package*.json .\u002F\nRUN npm ci\nCOPY . .\nRUN npm run build\n\n# 阶段二：运行\nFROM node:20-alpine\nWORKDIR \u002Fapp\nCOPY --from=builder \u002Fapp\u002F.output .\u002F\nEXPOSE 3000\nCMD [\"node\", \".output\u002Fserver\u002Findex.mjs\"]\n",[750],{"type":18,"tag":115,"props":751,"children":752},{"__ignoreMap":7},[753,761,769,776,783,791,798,806,813,821,828,835,843,851],{"type":18,"tag":119,"props":754,"children":755},{"class":121,"line":122},[756],{"type":18,"tag":119,"props":757,"children":758},{},[759],{"type":23,"value":760},"# 阶段一：构建\n",{"type":18,"tag":119,"props":762,"children":763},{"class":121,"line":131},[764],{"type":18,"tag":119,"props":765,"children":766},{},[767],{"type":23,"value":768},"FROM node:20-alpine AS builder\n",{"type":18,"tag":119,"props":770,"children":771},{"class":121,"line":140},[772],{"type":18,"tag":119,"props":773,"children":774},{},[775],{"type":23,"value":434},{"type":18,"tag":119,"props":777,"children":778},{"class":121,"line":200},[779],{"type":18,"tag":119,"props":780,"children":781},{},[782],{"type":23,"value":450},{"type":18,"tag":119,"props":784,"children":785},{"class":121,"line":444},[786],{"type":18,"tag":119,"props":787,"children":788},{},[789],{"type":23,"value":790},"RUN npm ci\n",{"type":18,"tag":119,"props":792,"children":793},{"class":121,"line":453},[794],{"type":18,"tag":119,"props":795,"children":796},{},[797],{"type":23,"value":476},{"type":18,"tag":119,"props":799,"children":800},{"class":121,"line":462},[801],{"type":18,"tag":119,"props":802,"children":803},{},[804],{"type":23,"value":805},"RUN npm run build\n",{"type":18,"tag":119,"props":807,"children":808},{"class":121,"line":470},[809],{"type":18,"tag":119,"props":810,"children":811},{"emptyLinePlaceholder":423},[812],{"type":23,"value":426},{"type":18,"tag":119,"props":814,"children":815},{"class":121,"line":479},[816],{"type":18,"tag":119,"props":817,"children":818},{},[819],{"type":23,"value":820},"# 阶段二：运行\n",{"type":18,"tag":119,"props":822,"children":823},{"class":121,"line":487},[824],{"type":18,"tag":119,"props":825,"children":826},{},[827],{"type":23,"value":417},{"type":18,"tag":119,"props":829,"children":830},{"class":121,"line":496},[831],{"type":18,"tag":119,"props":832,"children":833},{},[834],{"type":23,"value":434},{"type":18,"tag":119,"props":836,"children":837},{"class":121,"line":504},[838],{"type":18,"tag":119,"props":839,"children":840},{},[841],{"type":23,"value":842},"COPY --from=builder \u002Fapp\u002F.output .\u002F\n",{"type":18,"tag":119,"props":844,"children":846},{"class":121,"line":845},13,[847],{"type":18,"tag":119,"props":848,"children":849},{},[850],{"type":23,"value":493},{"type":18,"tag":119,"props":852,"children":854},{"class":121,"line":853},14,[855],{"type":18,"tag":119,"props":856,"children":857},{},[858],{"type":23,"value":859},"CMD [\"node\", \".output\u002Fserver\u002Findex.mjs\"]\n",{"type":18,"tag":26,"props":861,"children":863},{"id":862},"构建和运行一个镜像",[864],{"type":23,"value":862},{"type":18,"tag":19,"props":866,"children":867},{},[868,870,875],{"type":23,"value":869},"假设当前目录下已经有 ",{"type":18,"tag":115,"props":871,"children":873},{"className":872},[],[874],{"type":23,"value":393},{"type":23,"value":876},"，可以执行：",{"type":18,"tag":109,"props":878,"children":882},{"className":879,"code":880,"language":881,"meta":7,"style":7},"language-bash shiki shiki-themes github-dark","docker build -t test-docker .\n","bash",[883],{"type":18,"tag":115,"props":884,"children":885},{"__ignoreMap":7},[886],{"type":18,"tag":119,"props":887,"children":888},{"class":121,"line":122},[889,895,901,907,912],{"type":18,"tag":119,"props":890,"children":892},{"style":891},"--shiki-default:#B392F0",[893],{"type":23,"value":894},"docker",{"type":18,"tag":119,"props":896,"children":898},{"style":897},"--shiki-default:#9ECBFF",[899],{"type":23,"value":900}," build",{"type":18,"tag":119,"props":902,"children":904},{"style":903},"--shiki-default:#79B8FF",[905],{"type":23,"value":906}," -t",{"type":18,"tag":119,"props":908,"children":909},{"style":897},[910],{"type":23,"value":911}," test-docker",{"type":18,"tag":119,"props":913,"children":914},{"style":897},[915],{"type":23,"value":916}," .\n",{"type":18,"tag":19,"props":918,"children":919},{},[920,922,927,929,935],{"type":23,"value":921},"这条命令表示：使用当前目录的 ",{"type":18,"tag":115,"props":923,"children":925},{"className":924},[],[926],{"type":23,"value":393},{"type":23,"value":928}," 和项目文件构建一个名为 ",{"type":18,"tag":115,"props":930,"children":932},{"className":931},[],[933],{"type":23,"value":934},"test-docker",{"type":23,"value":936}," 的镜像。",{"type":18,"tag":19,"props":938,"children":939},{},[940],{"type":23,"value":941},"构建完成后，可以启动容器：",{"type":18,"tag":109,"props":943,"children":945},{"className":879,"code":944,"language":881,"meta":7,"style":7},"docker run -d \\\n  --name test-docker \\\n  -p 80:3000 \\\n  test-docker\n",[946],{"type":18,"tag":115,"props":947,"children":948},{"__ignoreMap":7},[949,971,987,1004],{"type":18,"tag":119,"props":950,"children":951},{"class":121,"line":122},[952,956,961,966],{"type":18,"tag":119,"props":953,"children":954},{"style":891},[955],{"type":23,"value":894},{"type":18,"tag":119,"props":957,"children":958},{"style":897},[959],{"type":23,"value":960}," run",{"type":18,"tag":119,"props":962,"children":963},{"style":903},[964],{"type":23,"value":965}," -d",{"type":18,"tag":119,"props":967,"children":968},{"style":903},[969],{"type":23,"value":970}," \\\n",{"type":18,"tag":119,"props":972,"children":973},{"class":121,"line":131},[974,979,983],{"type":18,"tag":119,"props":975,"children":976},{"style":903},[977],{"type":23,"value":978},"  --name",{"type":18,"tag":119,"props":980,"children":981},{"style":897},[982],{"type":23,"value":911},{"type":18,"tag":119,"props":984,"children":985},{"style":903},[986],{"type":23,"value":970},{"type":18,"tag":119,"props":988,"children":989},{"class":121,"line":140},[990,995,1000],{"type":18,"tag":119,"props":991,"children":992},{"style":903},[993],{"type":23,"value":994},"  -p",{"type":18,"tag":119,"props":996,"children":997},{"style":897},[998],{"type":23,"value":999}," 80:3000",{"type":18,"tag":119,"props":1001,"children":1002},{"style":903},[1003],{"type":23,"value":970},{"type":18,"tag":119,"props":1005,"children":1006},{"class":121,"line":200},[1007],{"type":18,"tag":119,"props":1008,"children":1009},{"style":897},[1010],{"type":23,"value":1011},"  test-docker\n",{"type":18,"tag":19,"props":1013,"children":1014},{},[1015],{"type":23,"value":1016},"这条命令的含义是：",{"type":18,"tag":38,"props":1018,"children":1019},{},[1020,1031,1042,1053,1079],{"type":18,"tag":42,"props":1021,"children":1022},{},[1023,1029],{"type":18,"tag":115,"props":1024,"children":1026},{"className":1025},[],[1027],{"type":23,"value":1028},"docker run",{"type":23,"value":1030},"：根据镜像创建并启动一个容器。",{"type":18,"tag":42,"props":1032,"children":1033},{},[1034,1040],{"type":18,"tag":115,"props":1035,"children":1037},{"className":1036},[],[1038],{"type":23,"value":1039},"-d",{"type":23,"value":1041},"：让容器在后台运行。",{"type":18,"tag":42,"props":1043,"children":1044},{},[1045,1051],{"type":18,"tag":115,"props":1046,"children":1048},{"className":1047},[],[1049],{"type":23,"value":1050},"--name test-docker",{"type":23,"value":1052},"：给容器起一个明确的名字，后续可以直接用名字操作。",{"type":18,"tag":42,"props":1054,"children":1055},{},[1056,1062,1064,1070,1072,1077],{"type":18,"tag":115,"props":1057,"children":1059},{"className":1058},[],[1060],{"type":23,"value":1061},"-p 80:3000",{"type":23,"value":1063},"：把宿主机的 ",{"type":18,"tag":115,"props":1065,"children":1067},{"className":1066},[],[1068],{"type":23,"value":1069},"80",{"type":23,"value":1071}," 端口映射到容器内部的 ",{"type":18,"tag":115,"props":1073,"children":1075},{"className":1074},[],[1076],{"type":23,"value":606},{"type":23,"value":1078}," 端口。",{"type":18,"tag":42,"props":1080,"children":1081},{},[1082,1087],{"type":18,"tag":115,"props":1083,"children":1085},{"className":1084},[],[1086],{"type":23,"value":934},{"type":23,"value":1088},"：要运行的镜像名。",{"type":18,"tag":19,"props":1090,"children":1091},{},[1092,1094,1100,1102,1107,1109,1114],{"type":23,"value":1093},"端口映射是初学 Docker 时最容易混淆的地方。",{"type":18,"tag":115,"props":1095,"children":1097},{"className":1096},[],[1098],{"type":23,"value":1099},"80:3000",{"type":23,"value":1101}," 的左边是宿主机端口，右边是容器端口。访问服务器的 ",{"type":18,"tag":115,"props":1103,"children":1105},{"className":1104},[],[1106],{"type":23,"value":1069},{"type":23,"value":1108}," 端口时，流量会被转发到容器内部的 ",{"type":18,"tag":115,"props":1110,"children":1112},{"className":1111},[],[1113],{"type":23,"value":606},{"type":23,"value":1078},{"type":18,"tag":19,"props":1116,"children":1117},{},[1118],{"type":23,"value":1119},"也可以这样理解：",{"type":18,"tag":109,"props":1121,"children":1123},{"className":111,"code":1122,"language":23,"meta":7,"style":7},"浏览器访问服务器 80 端口\n        ↓\nDocker 转发到容器 3000 端口\n        ↓\n容器里的应用处理请求\n",[1124],{"type":18,"tag":115,"props":1125,"children":1126},{"__ignoreMap":7},[1127,1135,1143,1151,1158],{"type":18,"tag":119,"props":1128,"children":1129},{"class":121,"line":122},[1130],{"type":18,"tag":119,"props":1131,"children":1132},{},[1133],{"type":23,"value":1134},"浏览器访问服务器 80 端口\n",{"type":18,"tag":119,"props":1136,"children":1137},{"class":121,"line":131},[1138],{"type":18,"tag":119,"props":1139,"children":1140},{},[1141],{"type":23,"value":1142},"        ↓\n",{"type":18,"tag":119,"props":1144,"children":1145},{"class":121,"line":140},[1146],{"type":18,"tag":119,"props":1147,"children":1148},{},[1149],{"type":23,"value":1150},"Docker 转发到容器 3000 端口\n",{"type":18,"tag":119,"props":1152,"children":1153},{"class":121,"line":200},[1154],{"type":18,"tag":119,"props":1155,"children":1156},{},[1157],{"type":23,"value":1142},{"type":18,"tag":119,"props":1159,"children":1160},{"class":121,"line":444},[1161],{"type":18,"tag":119,"props":1162,"children":1163},{},[1164],{"type":23,"value":1165},"容器里的应用处理请求\n",{"type":18,"tag":19,"props":1167,"children":1168},{},[1169],{"type":23,"value":1170},"需要注意：默认情况下，发布端口可能会让外部网络访问到该服务。生产环境里，不要随手把数据库、Redis、内部管理服务直接映射到公网端口。如果只是想让本机 Nginx 反向代理访问应用，可以绑定到本地地址：",{"type":18,"tag":109,"props":1172,"children":1174},{"className":879,"code":1173,"language":881,"meta":7,"style":7},"docker run -d \\\n  --name test-docker \\\n  -p 127.0.0.1:3000:3000 \\\n  test-docker\n",[1175],{"type":18,"tag":115,"props":1176,"children":1177},{"__ignoreMap":7},[1178,1197,1212,1228],{"type":18,"tag":119,"props":1179,"children":1180},{"class":121,"line":122},[1181,1185,1189,1193],{"type":18,"tag":119,"props":1182,"children":1183},{"style":891},[1184],{"type":23,"value":894},{"type":18,"tag":119,"props":1186,"children":1187},{"style":897},[1188],{"type":23,"value":960},{"type":18,"tag":119,"props":1190,"children":1191},{"style":903},[1192],{"type":23,"value":965},{"type":18,"tag":119,"props":1194,"children":1195},{"style":903},[1196],{"type":23,"value":970},{"type":18,"tag":119,"props":1198,"children":1199},{"class":121,"line":131},[1200,1204,1208],{"type":18,"tag":119,"props":1201,"children":1202},{"style":903},[1203],{"type":23,"value":978},{"type":18,"tag":119,"props":1205,"children":1206},{"style":897},[1207],{"type":23,"value":911},{"type":18,"tag":119,"props":1209,"children":1210},{"style":903},[1211],{"type":23,"value":970},{"type":18,"tag":119,"props":1213,"children":1214},{"class":121,"line":140},[1215,1219,1224],{"type":18,"tag":119,"props":1216,"children":1217},{"style":903},[1218],{"type":23,"value":994},{"type":18,"tag":119,"props":1220,"children":1221},{"style":897},[1222],{"type":23,"value":1223}," 127.0.0.1:3000:3000",{"type":18,"tag":119,"props":1225,"children":1226},{"style":903},[1227],{"type":23,"value":970},{"type":18,"tag":119,"props":1229,"children":1230},{"class":121,"line":200},[1231],{"type":18,"tag":119,"props":1232,"children":1233},{"style":897},[1234],{"type":23,"value":1011},{"type":18,"tag":19,"props":1236,"children":1237},{},[1238],{"type":23,"value":1239},"这样外部用户不能直接访问容器端口，而是由宿主机上的 Nginx 统一接收请求后再转发。",{"type":18,"tag":26,"props":1241,"children":1243},{"id":1242},"一个更完整的项目结构",[1244],{"type":23,"value":1242},{"type":18,"tag":19,"props":1246,"children":1247},{},[1248,1250,1255,1257,1263,1265,1271],{"type":23,"value":1249},"如果项目里有前端、后端、AI 服务，就可以给每个服务写自己的 ",{"type":18,"tag":115,"props":1251,"children":1253},{"className":1252},[],[1254],{"type":23,"value":393},{"type":23,"value":1256},"，再用 ",{"type":18,"tag":115,"props":1258,"children":1260},{"className":1259},[],[1261],{"type":23,"value":1262},"compose.yaml",{"type":23,"value":1264}," 或 ",{"type":18,"tag":115,"props":1266,"children":1268},{"className":1267},[],[1269],{"type":23,"value":1270},"docker-compose.yml",{"type":23,"value":1272}," 统一管理。",{"type":18,"tag":109,"props":1274,"children":1276},{"className":111,"code":1275,"language":23,"meta":7,"style":7},"ai-drug-discovery-workbench\u002F\n├─ compose.yaml\n├─ backend\u002F\n│  └─ Dockerfile\n├─ ai-service\u002F\n│  └─ Dockerfile\n├─ frontend\u002F\n│  └─ Dockerfile\n└─ nginx\u002F\n   └─ default.conf\n",[1277],{"type":18,"tag":115,"props":1278,"children":1279},{"__ignoreMap":7},[1280,1288,1296,1304,1312,1320,1327,1335,1342,1350],{"type":18,"tag":119,"props":1281,"children":1282},{"class":121,"line":122},[1283],{"type":18,"tag":119,"props":1284,"children":1285},{},[1286],{"type":23,"value":1287},"ai-drug-discovery-workbench\u002F\n",{"type":18,"tag":119,"props":1289,"children":1290},{"class":121,"line":131},[1291],{"type":18,"tag":119,"props":1292,"children":1293},{},[1294],{"type":23,"value":1295},"├─ compose.yaml\n",{"type":18,"tag":119,"props":1297,"children":1298},{"class":121,"line":140},[1299],{"type":18,"tag":119,"props":1300,"children":1301},{},[1302],{"type":23,"value":1303},"├─ backend\u002F\n",{"type":18,"tag":119,"props":1305,"children":1306},{"class":121,"line":200},[1307],{"type":18,"tag":119,"props":1308,"children":1309},{},[1310],{"type":23,"value":1311},"│  └─ Dockerfile\n",{"type":18,"tag":119,"props":1313,"children":1314},{"class":121,"line":444},[1315],{"type":18,"tag":119,"props":1316,"children":1317},{},[1318],{"type":23,"value":1319},"├─ ai-service\u002F\n",{"type":18,"tag":119,"props":1321,"children":1322},{"class":121,"line":453},[1323],{"type":18,"tag":119,"props":1324,"children":1325},{},[1326],{"type":23,"value":1311},{"type":18,"tag":119,"props":1328,"children":1329},{"class":121,"line":462},[1330],{"type":18,"tag":119,"props":1331,"children":1332},{},[1333],{"type":23,"value":1334},"├─ frontend\u002F\n",{"type":18,"tag":119,"props":1336,"children":1337},{"class":121,"line":470},[1338],{"type":18,"tag":119,"props":1339,"children":1340},{},[1341],{"type":23,"value":1311},{"type":18,"tag":119,"props":1343,"children":1344},{"class":121,"line":479},[1345],{"type":18,"tag":119,"props":1346,"children":1347},{},[1348],{"type":23,"value":1349},"└─ nginx\u002F\n",{"type":18,"tag":119,"props":1351,"children":1352},{"class":121,"line":487},[1353],{"type":18,"tag":119,"props":1354,"children":1355},{},[1356],{"type":23,"value":1357},"   └─ default.conf\n",{"type":18,"tag":19,"props":1359,"children":1360},{},[1361,1363,1368],{"type":23,"value":1362},"这种结构的好处是：每个服务只关心自己的运行环境，整体启动则交给 ",{"type":18,"tag":115,"props":1364,"children":1366},{"className":1365},[],[1367],{"type":23,"value":269},{"type":23,"value":1369},"。例如后端可以使用 Java 或 Node.js，AI 服务可以使用 Python，前端可以使用 Nuxt，它们不用把所有运行环境都堆在宿主机上。",{"type":18,"tag":19,"props":1371,"children":1372},{},[1373],{"type":23,"value":1374},"一个简化的 Compose 文件可能长这样：",{"type":18,"tag":109,"props":1376,"children":1380},{"className":1377,"code":1378,"language":1379,"meta":7,"style":7},"language-yaml shiki shiki-themes github-dark","services:\n  frontend:\n    build: .\u002Ffrontend\n    expose:\n      - \"3000\"\n\n  backend:\n    build: .\u002Fbackend\n    expose:\n      - \"8080\"\n    environment:\n      NODE_ENV: production\n\n  nginx:\n    image: nginx:alpine\n    ports:\n      - \"80:80\"\n    volumes:\n      - .\u002Fnginx\u002Fdefault.conf:\u002Fetc\u002Fnginx\u002Fconf.d\u002Fdefault.conf:ro\n    depends_on:\n      - frontend\n      - backend\n","yaml",[1381],{"type":18,"tag":115,"props":1382,"children":1383},{"__ignoreMap":7},[1384,1399,1411,1429,1441,1454,1461,1473,1489,1500,1512,1524,1541,1548,1560,1578,1591,1604,1617,1630,1643,1656],{"type":18,"tag":119,"props":1385,"children":1386},{"class":121,"line":122},[1387,1393],{"type":18,"tag":119,"props":1388,"children":1390},{"style":1389},"--shiki-default:#85E89D",[1391],{"type":23,"value":1392},"services",{"type":18,"tag":119,"props":1394,"children":1396},{"style":1395},"--shiki-default:#E1E4E8",[1397],{"type":23,"value":1398},":\n",{"type":18,"tag":119,"props":1400,"children":1401},{"class":121,"line":131},[1402,1407],{"type":18,"tag":119,"props":1403,"children":1404},{"style":1389},[1405],{"type":23,"value":1406},"  frontend",{"type":18,"tag":119,"props":1408,"children":1409},{"style":1395},[1410],{"type":23,"value":1398},{"type":18,"tag":119,"props":1412,"children":1413},{"class":121,"line":140},[1414,1419,1424],{"type":18,"tag":119,"props":1415,"children":1416},{"style":1389},[1417],{"type":23,"value":1418},"    build",{"type":18,"tag":119,"props":1420,"children":1421},{"style":1395},[1422],{"type":23,"value":1423},": ",{"type":18,"tag":119,"props":1425,"children":1426},{"style":897},[1427],{"type":23,"value":1428},".\u002Ffrontend\n",{"type":18,"tag":119,"props":1430,"children":1431},{"class":121,"line":200},[1432,1437],{"type":18,"tag":119,"props":1433,"children":1434},{"style":1389},[1435],{"type":23,"value":1436},"    expose",{"type":18,"tag":119,"props":1438,"children":1439},{"style":1395},[1440],{"type":23,"value":1398},{"type":18,"tag":119,"props":1442,"children":1443},{"class":121,"line":444},[1444,1449],{"type":18,"tag":119,"props":1445,"children":1446},{"style":1395},[1447],{"type":23,"value":1448},"      - ",{"type":18,"tag":119,"props":1450,"children":1451},{"style":897},[1452],{"type":23,"value":1453},"\"3000\"\n",{"type":18,"tag":119,"props":1455,"children":1456},{"class":121,"line":453},[1457],{"type":18,"tag":119,"props":1458,"children":1459},{"emptyLinePlaceholder":423},[1460],{"type":23,"value":426},{"type":18,"tag":119,"props":1462,"children":1463},{"class":121,"line":462},[1464,1469],{"type":18,"tag":119,"props":1465,"children":1466},{"style":1389},[1467],{"type":23,"value":1468},"  backend",{"type":18,"tag":119,"props":1470,"children":1471},{"style":1395},[1472],{"type":23,"value":1398},{"type":18,"tag":119,"props":1474,"children":1475},{"class":121,"line":470},[1476,1480,1484],{"type":18,"tag":119,"props":1477,"children":1478},{"style":1389},[1479],{"type":23,"value":1418},{"type":18,"tag":119,"props":1481,"children":1482},{"style":1395},[1483],{"type":23,"value":1423},{"type":18,"tag":119,"props":1485,"children":1486},{"style":897},[1487],{"type":23,"value":1488},".\u002Fbackend\n",{"type":18,"tag":119,"props":1490,"children":1491},{"class":121,"line":479},[1492,1496],{"type":18,"tag":119,"props":1493,"children":1494},{"style":1389},[1495],{"type":23,"value":1436},{"type":18,"tag":119,"props":1497,"children":1498},{"style":1395},[1499],{"type":23,"value":1398},{"type":18,"tag":119,"props":1501,"children":1502},{"class":121,"line":487},[1503,1507],{"type":18,"tag":119,"props":1504,"children":1505},{"style":1395},[1506],{"type":23,"value":1448},{"type":18,"tag":119,"props":1508,"children":1509},{"style":897},[1510],{"type":23,"value":1511},"\"8080\"\n",{"type":18,"tag":119,"props":1513,"children":1514},{"class":121,"line":496},[1515,1520],{"type":18,"tag":119,"props":1516,"children":1517},{"style":1389},[1518],{"type":23,"value":1519},"    environment",{"type":18,"tag":119,"props":1521,"children":1522},{"style":1395},[1523],{"type":23,"value":1398},{"type":18,"tag":119,"props":1525,"children":1526},{"class":121,"line":504},[1527,1532,1536],{"type":18,"tag":119,"props":1528,"children":1529},{"style":1389},[1530],{"type":23,"value":1531},"      NODE_ENV",{"type":18,"tag":119,"props":1533,"children":1534},{"style":1395},[1535],{"type":23,"value":1423},{"type":18,"tag":119,"props":1537,"children":1538},{"style":897},[1539],{"type":23,"value":1540},"production\n",{"type":18,"tag":119,"props":1542,"children":1543},{"class":121,"line":845},[1544],{"type":18,"tag":119,"props":1545,"children":1546},{"emptyLinePlaceholder":423},[1547],{"type":23,"value":426},{"type":18,"tag":119,"props":1549,"children":1550},{"class":121,"line":853},[1551,1556],{"type":18,"tag":119,"props":1552,"children":1553},{"style":1389},[1554],{"type":23,"value":1555},"  nginx",{"type":18,"tag":119,"props":1557,"children":1558},{"style":1395},[1559],{"type":23,"value":1398},{"type":18,"tag":119,"props":1561,"children":1563},{"class":121,"line":1562},15,[1564,1569,1573],{"type":18,"tag":119,"props":1565,"children":1566},{"style":1389},[1567],{"type":23,"value":1568},"    image",{"type":18,"tag":119,"props":1570,"children":1571},{"style":1395},[1572],{"type":23,"value":1423},{"type":18,"tag":119,"props":1574,"children":1575},{"style":897},[1576],{"type":23,"value":1577},"nginx:alpine\n",{"type":18,"tag":119,"props":1579,"children":1581},{"class":121,"line":1580},16,[1582,1587],{"type":18,"tag":119,"props":1583,"children":1584},{"style":1389},[1585],{"type":23,"value":1586},"    ports",{"type":18,"tag":119,"props":1588,"children":1589},{"style":1395},[1590],{"type":23,"value":1398},{"type":18,"tag":119,"props":1592,"children":1594},{"class":121,"line":1593},17,[1595,1599],{"type":18,"tag":119,"props":1596,"children":1597},{"style":1395},[1598],{"type":23,"value":1448},{"type":18,"tag":119,"props":1600,"children":1601},{"style":897},[1602],{"type":23,"value":1603},"\"80:80\"\n",{"type":18,"tag":119,"props":1605,"children":1607},{"class":121,"line":1606},18,[1608,1613],{"type":18,"tag":119,"props":1609,"children":1610},{"style":1389},[1611],{"type":23,"value":1612},"    volumes",{"type":18,"tag":119,"props":1614,"children":1615},{"style":1395},[1616],{"type":23,"value":1398},{"type":18,"tag":119,"props":1618,"children":1620},{"class":121,"line":1619},19,[1621,1625],{"type":18,"tag":119,"props":1622,"children":1623},{"style":1395},[1624],{"type":23,"value":1448},{"type":18,"tag":119,"props":1626,"children":1627},{"style":897},[1628],{"type":23,"value":1629},".\u002Fnginx\u002Fdefault.conf:\u002Fetc\u002Fnginx\u002Fconf.d\u002Fdefault.conf:ro\n",{"type":18,"tag":119,"props":1631,"children":1633},{"class":121,"line":1632},20,[1634,1639],{"type":18,"tag":119,"props":1635,"children":1636},{"style":1389},[1637],{"type":23,"value":1638},"    depends_on",{"type":18,"tag":119,"props":1640,"children":1641},{"style":1395},[1642],{"type":23,"value":1398},{"type":18,"tag":119,"props":1644,"children":1646},{"class":121,"line":1645},21,[1647,1651],{"type":18,"tag":119,"props":1648,"children":1649},{"style":1395},[1650],{"type":23,"value":1448},{"type":18,"tag":119,"props":1652,"children":1653},{"style":897},[1654],{"type":23,"value":1655},"frontend\n",{"type":18,"tag":119,"props":1657,"children":1659},{"class":121,"line":1658},22,[1660,1664],{"type":18,"tag":119,"props":1661,"children":1662},{"style":1395},[1663],{"type":23,"value":1448},{"type":18,"tag":119,"props":1665,"children":1666},{"style":897},[1667],{"type":23,"value":1668},"backend\n",{"type":18,"tag":19,"props":1670,"children":1671},{},[1672,1674,1680,1681,1687],{"type":23,"value":1673},"在同一个 Compose 项目里，服务会加入默认网络，并且可以通过服务名互相访问。也就是说，Nginx 容器里可以把请求转发到 ",{"type":18,"tag":115,"props":1675,"children":1677},{"className":1676},[],[1678],{"type":23,"value":1679},"http:\u002F\u002Ffrontend:3000",{"type":23,"value":1264},{"type":18,"tag":115,"props":1682,"children":1684},{"className":1683},[],[1685],{"type":23,"value":1686},"http:\u002F\u002Fbackend:8080",{"type":23,"value":1688},"，而不是写死某个容器 IP。容器 IP 可能会变化，服务名才是更稳定的连接方式。",{"type":18,"tag":26,"props":1690,"children":1692},{"id":1691},"常用-docker-命令",[1693],{"type":23,"value":1694},"常用 Docker 命令",{"type":18,"tag":19,"props":1696,"children":1697},{},[1698],{"type":23,"value":1699},"初学阶段不需要背完所有命令，先掌握\"看状态、看日志、进容器、停服务、清资源\"这几类就够了。",{"type":18,"tag":1701,"props":1702,"children":1704},"h3",{"id":1703},"查看容器",[1705],{"type":23,"value":1703},{"type":18,"tag":109,"props":1707,"children":1709},{"className":879,"code":1708,"language":881,"meta":7,"style":7},"docker ps\ndocker ps -a\ndocker ps --format \"table {{.Names}}\\t{{.Status}}\\t{{.Ports}}\"\n",[1710],{"type":18,"tag":115,"props":1711,"children":1712},{"__ignoreMap":7},[1713,1725,1742],{"type":18,"tag":119,"props":1714,"children":1715},{"class":121,"line":122},[1716,1720],{"type":18,"tag":119,"props":1717,"children":1718},{"style":891},[1719],{"type":23,"value":894},{"type":18,"tag":119,"props":1721,"children":1722},{"style":897},[1723],{"type":23,"value":1724}," ps\n",{"type":18,"tag":119,"props":1726,"children":1727},{"class":121,"line":131},[1728,1732,1737],{"type":18,"tag":119,"props":1729,"children":1730},{"style":891},[1731],{"type":23,"value":894},{"type":18,"tag":119,"props":1733,"children":1734},{"style":897},[1735],{"type":23,"value":1736}," ps",{"type":18,"tag":119,"props":1738,"children":1739},{"style":903},[1740],{"type":23,"value":1741}," -a\n",{"type":18,"tag":119,"props":1743,"children":1744},{"class":121,"line":140},[1745,1749,1753,1758],{"type":18,"tag":119,"props":1746,"children":1747},{"style":891},[1748],{"type":23,"value":894},{"type":18,"tag":119,"props":1750,"children":1751},{"style":897},[1752],{"type":23,"value":1736},{"type":18,"tag":119,"props":1754,"children":1755},{"style":903},[1756],{"type":23,"value":1757}," --format",{"type":18,"tag":119,"props":1759,"children":1760},{"style":897},[1761],{"type":23,"value":1762}," \"table {{.Names}}\\t{{.Status}}\\t{{.Ports}}\"\n",{"type":18,"tag":19,"props":1764,"children":1765},{},[1766,1772,1774,1780],{"type":18,"tag":115,"props":1767,"children":1769},{"className":1768},[],[1770],{"type":23,"value":1771},"docker ps",{"type":23,"value":1773}," 只查看运行中的容器，",{"type":18,"tag":115,"props":1775,"children":1777},{"className":1776},[],[1778],{"type":23,"value":1779},"docker ps -a",{"type":23,"value":1781}," 会包含已经停止的容器。第三条命令可以用表格形式查看容器名称、状态和端口映射，更适合日常排查。",{"type":18,"tag":1701,"props":1783,"children":1785},{"id":1784},"查看和删除镜像",[1786],{"type":23,"value":1784},{"type":18,"tag":109,"props":1788,"children":1790},{"className":879,"code":1789,"language":881,"meta":7,"style":7},"docker images\ndocker images your-app\ndocker rmi your-app:v1\n",[1791],{"type":18,"tag":115,"props":1792,"children":1793},{"__ignoreMap":7},[1794,1806,1823],{"type":18,"tag":119,"props":1795,"children":1796},{"class":121,"line":122},[1797,1801],{"type":18,"tag":119,"props":1798,"children":1799},{"style":891},[1800],{"type":23,"value":894},{"type":18,"tag":119,"props":1802,"children":1803},{"style":897},[1804],{"type":23,"value":1805}," images\n",{"type":18,"tag":119,"props":1807,"children":1808},{"class":121,"line":131},[1809,1813,1818],{"type":18,"tag":119,"props":1810,"children":1811},{"style":891},[1812],{"type":23,"value":894},{"type":18,"tag":119,"props":1814,"children":1815},{"style":897},[1816],{"type":23,"value":1817}," images",{"type":18,"tag":119,"props":1819,"children":1820},{"style":897},[1821],{"type":23,"value":1822}," your-app\n",{"type":18,"tag":119,"props":1824,"children":1825},{"class":121,"line":140},[1826,1830,1835],{"type":18,"tag":119,"props":1827,"children":1828},{"style":891},[1829],{"type":23,"value":894},{"type":18,"tag":119,"props":1831,"children":1832},{"style":897},[1833],{"type":23,"value":1834}," rmi",{"type":18,"tag":119,"props":1836,"children":1837},{"style":897},[1838],{"type":23,"value":1839}," your-app:v1\n",{"type":18,"tag":19,"props":1841,"children":1842},{},[1843,1849,1851,1857],{"type":18,"tag":115,"props":1844,"children":1846},{"className":1845},[],[1847],{"type":23,"value":1848},"docker images",{"type":23,"value":1850}," 用来查看本机已有镜像。",{"type":18,"tag":115,"props":1852,"children":1854},{"className":1853},[],[1855],{"type":23,"value":1856},"docker rmi",{"type":23,"value":1858}," 用来删除镜像。如果某个镜像正在被容器使用，需要先停止并删除对应容器。",{"type":18,"tag":1701,"props":1860,"children":1862},{"id":1861},"启动容器",[1863],{"type":23,"value":1861},{"type":18,"tag":109,"props":1865,"children":1867},{"className":879,"code":1866,"language":881,"meta":7,"style":7},"docker run -d \\\n  --name my-app \\\n  -p 80:8080 \\\n  -v \u002Fdata:\u002Fapp\u002Fdata \\\n  -e DB_HOST=db.example.com \\\n  --restart unless-stopped \\\n  your-app:v1.0\n",[1868],{"type":18,"tag":115,"props":1869,"children":1870},{"__ignoreMap":7},[1871,1890,1906,1922,1939,1956,1973],{"type":18,"tag":119,"props":1872,"children":1873},{"class":121,"line":122},[1874,1878,1882,1886],{"type":18,"tag":119,"props":1875,"children":1876},{"style":891},[1877],{"type":23,"value":894},{"type":18,"tag":119,"props":1879,"children":1880},{"style":897},[1881],{"type":23,"value":960},{"type":18,"tag":119,"props":1883,"children":1884},{"style":903},[1885],{"type":23,"value":965},{"type":18,"tag":119,"props":1887,"children":1888},{"style":903},[1889],{"type":23,"value":970},{"type":18,"tag":119,"props":1891,"children":1892},{"class":121,"line":131},[1893,1897,1902],{"type":18,"tag":119,"props":1894,"children":1895},{"style":903},[1896],{"type":23,"value":978},{"type":18,"tag":119,"props":1898,"children":1899},{"style":897},[1900],{"type":23,"value":1901}," my-app",{"type":18,"tag":119,"props":1903,"children":1904},{"style":903},[1905],{"type":23,"value":970},{"type":18,"tag":119,"props":1907,"children":1908},{"class":121,"line":140},[1909,1913,1918],{"type":18,"tag":119,"props":1910,"children":1911},{"style":903},[1912],{"type":23,"value":994},{"type":18,"tag":119,"props":1914,"children":1915},{"style":897},[1916],{"type":23,"value":1917}," 80:8080",{"type":18,"tag":119,"props":1919,"children":1920},{"style":903},[1921],{"type":23,"value":970},{"type":18,"tag":119,"props":1923,"children":1924},{"class":121,"line":200},[1925,1930,1935],{"type":18,"tag":119,"props":1926,"children":1927},{"style":903},[1928],{"type":23,"value":1929},"  -v",{"type":18,"tag":119,"props":1931,"children":1932},{"style":897},[1933],{"type":23,"value":1934}," \u002Fdata:\u002Fapp\u002Fdata",{"type":18,"tag":119,"props":1936,"children":1937},{"style":903},[1938],{"type":23,"value":970},{"type":18,"tag":119,"props":1940,"children":1941},{"class":121,"line":444},[1942,1947,1952],{"type":18,"tag":119,"props":1943,"children":1944},{"style":903},[1945],{"type":23,"value":1946},"  -e",{"type":18,"tag":119,"props":1948,"children":1949},{"style":897},[1950],{"type":23,"value":1951}," DB_HOST=db.example.com",{"type":18,"tag":119,"props":1953,"children":1954},{"style":903},[1955],{"type":23,"value":970},{"type":18,"tag":119,"props":1957,"children":1958},{"class":121,"line":453},[1959,1964,1969],{"type":18,"tag":119,"props":1960,"children":1961},{"style":903},[1962],{"type":23,"value":1963},"  --restart",{"type":18,"tag":119,"props":1965,"children":1966},{"style":897},[1967],{"type":23,"value":1968}," unless-stopped",{"type":18,"tag":119,"props":1970,"children":1971},{"style":903},[1972],{"type":23,"value":970},{"type":18,"tag":119,"props":1974,"children":1975},{"class":121,"line":462},[1976],{"type":18,"tag":119,"props":1977,"children":1978},{"style":897},[1979],{"type":23,"value":1980},"  your-app:v1.0\n",{"type":18,"tag":19,"props":1982,"children":1983},{},[1984],{"type":23,"value":1985},"这是一条比较完整的启动命令：",{"type":18,"tag":38,"props":1987,"children":1988},{},[1989,2000,2025,2036,2047,2058],{"type":18,"tag":42,"props":1990,"children":1991},{},[1992,1998],{"type":18,"tag":115,"props":1993,"children":1995},{"className":1994},[],[1996],{"type":23,"value":1997},"--name my-app",{"type":23,"value":1999},"：给容器起一个名字，后续可以直接用名字操作它。",{"type":18,"tag":42,"props":2001,"children":2002},{},[2003,2009,2011,2016,2018,2024],{"type":18,"tag":115,"props":2004,"children":2006},{"className":2005},[],[2007],{"type":23,"value":2008},"-p 80:8080",{"type":23,"value":2010},"：把宿主机 ",{"type":18,"tag":115,"props":2012,"children":2014},{"className":2013},[],[2015],{"type":23,"value":1069},{"type":23,"value":2017}," 端口映射到容器 ",{"type":18,"tag":115,"props":2019,"children":2021},{"className":2020},[],[2022],{"type":23,"value":2023},"8080",{"type":23,"value":1078},{"type":18,"tag":42,"props":2026,"children":2027},{},[2028,2034],{"type":18,"tag":115,"props":2029,"children":2031},{"className":2030},[],[2032],{"type":23,"value":2033},"-v \u002Fdata:\u002Fapp\u002Fdata",{"type":23,"value":2035},"：挂载目录，用来持久化数据或提供配置文件。",{"type":18,"tag":42,"props":2037,"children":2038},{},[2039,2045],{"type":18,"tag":115,"props":2040,"children":2042},{"className":2041},[],[2043],{"type":23,"value":2044},"-e DB_HOST=db.example.com",{"type":23,"value":2046},"：注入环境变量。",{"type":18,"tag":42,"props":2048,"children":2049},{},[2050,2056],{"type":18,"tag":115,"props":2051,"children":2053},{"className":2052},[],[2054],{"type":23,"value":2055},"--restart unless-stopped",{"type":23,"value":2057},"：容器异常退出后自动重启，除非手动停止。",{"type":18,"tag":42,"props":2059,"children":2060},{},[2061,2067],{"type":18,"tag":115,"props":2062,"children":2064},{"className":2063},[],[2065],{"type":23,"value":2066},"your-app:v1.0",{"type":23,"value":2068},"：指定镜像和版本标签。",{"type":18,"tag":19,"props":2070,"children":2071},{},[2072,2074,2080,2082,2088,2090,2095,2097,2103,2105,2111,2112,2118],{"type":23,"value":2073},"这里不建议把 ",{"type":18,"tag":115,"props":2075,"children":2077},{"className":2076},[],[2078],{"type":23,"value":2079},"DB_HOST",{"type":23,"value":2081}," 写成 ",{"type":18,"tag":115,"props":2083,"children":2085},{"className":2084},[],[2086],{"type":23,"value":2087},"localhost",{"type":23,"value":2089},"，除非数据库就在同一个容器里。对容器来说，",{"type":18,"tag":115,"props":2091,"children":2093},{"className":2092},[],[2094],{"type":23,"value":2087},{"type":23,"value":2096}," 通常指容器自己，不是宿主机，也不是其他容器。多容器项目中，应该优先使用 Compose 服务名，例如 ",{"type":18,"tag":115,"props":2098,"children":2100},{"className":2099},[],[2101],{"type":23,"value":2102},"db",{"type":23,"value":2104},"、",{"type":18,"tag":115,"props":2106,"children":2108},{"className":2107},[],[2109],{"type":23,"value":2110},"redis",{"type":23,"value":2104},{"type":18,"tag":115,"props":2113,"children":2115},{"className":2114},[],[2116],{"type":23,"value":2117},"backend",{"type":23,"value":302},{"type":18,"tag":1701,"props":2120,"children":2122},{"id":2121},"停止和重启容器",[2123],{"type":23,"value":2121},{"type":18,"tag":109,"props":2125,"children":2127},{"className":879,"code":2126,"language":881,"meta":7,"style":7},"docker stop my-app\ndocker start my-app\ndocker restart my-app\ndocker stop $(docker ps -q)\n",[2128],{"type":18,"tag":115,"props":2129,"children":2130},{"__ignoreMap":7},[2131,2148,2164,2180],{"type":18,"tag":119,"props":2132,"children":2133},{"class":121,"line":122},[2134,2138,2143],{"type":18,"tag":119,"props":2135,"children":2136},{"style":891},[2137],{"type":23,"value":894},{"type":18,"tag":119,"props":2139,"children":2140},{"style":897},[2141],{"type":23,"value":2142}," stop",{"type":18,"tag":119,"props":2144,"children":2145},{"style":897},[2146],{"type":23,"value":2147}," my-app\n",{"type":18,"tag":119,"props":2149,"children":2150},{"class":121,"line":131},[2151,2155,2160],{"type":18,"tag":119,"props":2152,"children":2153},{"style":891},[2154],{"type":23,"value":894},{"type":18,"tag":119,"props":2156,"children":2157},{"style":897},[2158],{"type":23,"value":2159}," start",{"type":18,"tag":119,"props":2161,"children":2162},{"style":897},[2163],{"type":23,"value":2147},{"type":18,"tag":119,"props":2165,"children":2166},{"class":121,"line":140},[2167,2171,2176],{"type":18,"tag":119,"props":2168,"children":2169},{"style":891},[2170],{"type":23,"value":894},{"type":18,"tag":119,"props":2172,"children":2173},{"style":897},[2174],{"type":23,"value":2175}," restart",{"type":18,"tag":119,"props":2177,"children":2178},{"style":897},[2179],{"type":23,"value":2147},{"type":18,"tag":119,"props":2181,"children":2182},{"class":121,"line":200},[2183,2187,2191,2196,2200,2204,2209],{"type":18,"tag":119,"props":2184,"children":2185},{"style":891},[2186],{"type":23,"value":894},{"type":18,"tag":119,"props":2188,"children":2189},{"style":897},[2190],{"type":23,"value":2142},{"type":18,"tag":119,"props":2192,"children":2193},{"style":1395},[2194],{"type":23,"value":2195}," $(",{"type":18,"tag":119,"props":2197,"children":2198},{"style":891},[2199],{"type":23,"value":894},{"type":18,"tag":119,"props":2201,"children":2202},{"style":897},[2203],{"type":23,"value":1736},{"type":18,"tag":119,"props":2205,"children":2206},{"style":903},[2207],{"type":23,"value":2208}," -q",{"type":18,"tag":119,"props":2210,"children":2211},{"style":1395},[2212],{"type":23,"value":2213},")\n",{"type":18,"tag":19,"props":2215,"children":2216},{},[2217],{"type":23,"value":2218},"容器既可以通过名称操作，也可以通过容器 ID 操作。日常使用时，建议给重要容器都设置明确的名字。",{"type":18,"tag":1701,"props":2220,"children":2222},{"id":2221},"查看日志",[2223],{"type":23,"value":2221},{"type":18,"tag":109,"props":2225,"children":2227},{"className":879,"code":2226,"language":881,"meta":7,"style":7},"docker logs my-app\ndocker logs -f my-app\ndocker logs --tail 100 my-app\ndocker logs --since 1h my-app\n",[2228],{"type":18,"tag":115,"props":2229,"children":2230},{"__ignoreMap":7},[2231,2247,2267,2292],{"type":18,"tag":119,"props":2232,"children":2233},{"class":121,"line":122},[2234,2238,2243],{"type":18,"tag":119,"props":2235,"children":2236},{"style":891},[2237],{"type":23,"value":894},{"type":18,"tag":119,"props":2239,"children":2240},{"style":897},[2241],{"type":23,"value":2242}," logs",{"type":18,"tag":119,"props":2244,"children":2245},{"style":897},[2246],{"type":23,"value":2147},{"type":18,"tag":119,"props":2248,"children":2249},{"class":121,"line":131},[2250,2254,2258,2263],{"type":18,"tag":119,"props":2251,"children":2252},{"style":891},[2253],{"type":23,"value":894},{"type":18,"tag":119,"props":2255,"children":2256},{"style":897},[2257],{"type":23,"value":2242},{"type":18,"tag":119,"props":2259,"children":2260},{"style":903},[2261],{"type":23,"value":2262}," -f",{"type":18,"tag":119,"props":2264,"children":2265},{"style":897},[2266],{"type":23,"value":2147},{"type":18,"tag":119,"props":2268,"children":2269},{"class":121,"line":140},[2270,2274,2278,2283,2288],{"type":18,"tag":119,"props":2271,"children":2272},{"style":891},[2273],{"type":23,"value":894},{"type":18,"tag":119,"props":2275,"children":2276},{"style":897},[2277],{"type":23,"value":2242},{"type":18,"tag":119,"props":2279,"children":2280},{"style":903},[2281],{"type":23,"value":2282}," --tail",{"type":18,"tag":119,"props":2284,"children":2285},{"style":903},[2286],{"type":23,"value":2287}," 100",{"type":18,"tag":119,"props":2289,"children":2290},{"style":897},[2291],{"type":23,"value":2147},{"type":18,"tag":119,"props":2293,"children":2294},{"class":121,"line":200},[2295,2299,2303,2308,2313],{"type":18,"tag":119,"props":2296,"children":2297},{"style":891},[2298],{"type":23,"value":894},{"type":18,"tag":119,"props":2300,"children":2301},{"style":897},[2302],{"type":23,"value":2242},{"type":18,"tag":119,"props":2304,"children":2305},{"style":903},[2306],{"type":23,"value":2307}," --since",{"type":18,"tag":119,"props":2309,"children":2310},{"style":897},[2311],{"type":23,"value":2312}," 1h",{"type":18,"tag":119,"props":2314,"children":2315},{"style":897},[2316],{"type":23,"value":2147},{"type":18,"tag":19,"props":2318,"children":2319},{},[2320,2322,2328,2330,2336],{"type":23,"value":2321},"排查线上问题时，",{"type":18,"tag":115,"props":2323,"children":2325},{"className":2324},[],[2326],{"type":23,"value":2327},"docker logs -f",{"type":23,"value":2329}," 很常用，它会持续输出日志，效果类似 ",{"type":18,"tag":115,"props":2331,"children":2333},{"className":2332},[],[2334],{"type":23,"value":2335},"tail -f",{"type":23,"value":302},{"type":18,"tag":1701,"props":2338,"children":2340},{"id":2339},"进入容器",[2341],{"type":23,"value":2339},{"type":18,"tag":109,"props":2343,"children":2345},{"className":879,"code":2344,"language":881,"meta":7,"style":7},"docker exec -it my-app sh\ndocker exec -it my-app bash\ndocker exec my-app ls \u002Fapp\ndocker exec my-app env\n",[2346],{"type":18,"tag":115,"props":2347,"children":2348},{"__ignoreMap":7},[2349,2375,2399,2424],{"type":18,"tag":119,"props":2350,"children":2351},{"class":121,"line":122},[2352,2356,2361,2366,2370],{"type":18,"tag":119,"props":2353,"children":2354},{"style":891},[2355],{"type":23,"value":894},{"type":18,"tag":119,"props":2357,"children":2358},{"style":897},[2359],{"type":23,"value":2360}," exec",{"type":18,"tag":119,"props":2362,"children":2363},{"style":903},[2364],{"type":23,"value":2365}," -it",{"type":18,"tag":119,"props":2367,"children":2368},{"style":897},[2369],{"type":23,"value":1901},{"type":18,"tag":119,"props":2371,"children":2372},{"style":897},[2373],{"type":23,"value":2374}," sh\n",{"type":18,"tag":119,"props":2376,"children":2377},{"class":121,"line":131},[2378,2382,2386,2390,2394],{"type":18,"tag":119,"props":2379,"children":2380},{"style":891},[2381],{"type":23,"value":894},{"type":18,"tag":119,"props":2383,"children":2384},{"style":897},[2385],{"type":23,"value":2360},{"type":18,"tag":119,"props":2387,"children":2388},{"style":903},[2389],{"type":23,"value":2365},{"type":18,"tag":119,"props":2391,"children":2392},{"style":897},[2393],{"type":23,"value":1901},{"type":18,"tag":119,"props":2395,"children":2396},{"style":897},[2397],{"type":23,"value":2398}," bash\n",{"type":18,"tag":119,"props":2400,"children":2401},{"class":121,"line":140},[2402,2406,2410,2414,2419],{"type":18,"tag":119,"props":2403,"children":2404},{"style":891},[2405],{"type":23,"value":894},{"type":18,"tag":119,"props":2407,"children":2408},{"style":897},[2409],{"type":23,"value":2360},{"type":18,"tag":119,"props":2411,"children":2412},{"style":897},[2413],{"type":23,"value":1901},{"type":18,"tag":119,"props":2415,"children":2416},{"style":897},[2417],{"type":23,"value":2418}," ls",{"type":18,"tag":119,"props":2420,"children":2421},{"style":897},[2422],{"type":23,"value":2423}," \u002Fapp\n",{"type":18,"tag":119,"props":2425,"children":2426},{"class":121,"line":200},[2427,2431,2435,2439],{"type":18,"tag":119,"props":2428,"children":2429},{"style":891},[2430],{"type":23,"value":894},{"type":18,"tag":119,"props":2432,"children":2433},{"style":897},[2434],{"type":23,"value":2360},{"type":18,"tag":119,"props":2436,"children":2437},{"style":897},[2438],{"type":23,"value":1901},{"type":18,"tag":119,"props":2440,"children":2441},{"style":897},[2442],{"type":23,"value":2443}," env\n",{"type":18,"tag":19,"props":2445,"children":2446},{},[2447,2453,2455,2461,2463,2468],{"type":18,"tag":115,"props":2448,"children":2450},{"className":2449},[],[2451],{"type":23,"value":2452},"docker exec",{"type":23,"value":2454}," 可以在已经运行的容器里执行命令。基于 Alpine 的镜像通常只有 ",{"type":18,"tag":115,"props":2456,"children":2458},{"className":2457},[],[2459],{"type":23,"value":2460},"sh",{"type":23,"value":2462},"，Ubuntu、Debian 这类镜像通常可以使用 ",{"type":18,"tag":115,"props":2464,"children":2466},{"className":2465},[],[2467],{"type":23,"value":881},{"type":23,"value":302},{"type":18,"tag":1701,"props":2470,"children":2472},{"id":2471},"删除容器和镜像",[2473],{"type":23,"value":2471},{"type":18,"tag":109,"props":2475,"children":2477},{"className":879,"code":2476,"language":881,"meta":7,"style":7},"docker rm my-app\ndocker rmi your-app:v1\n",[2478],{"type":18,"tag":115,"props":2479,"children":2480},{"__ignoreMap":7},[2481,2497],{"type":18,"tag":119,"props":2482,"children":2483},{"class":121,"line":122},[2484,2488,2493],{"type":18,"tag":119,"props":2485,"children":2486},{"style":891},[2487],{"type":23,"value":894},{"type":18,"tag":119,"props":2489,"children":2490},{"style":897},[2491],{"type":23,"value":2492}," rm",{"type":18,"tag":119,"props":2494,"children":2495},{"style":897},[2496],{"type":23,"value":2147},{"type":18,"tag":119,"props":2498,"children":2499},{"class":121,"line":131},[2500,2504,2508],{"type":18,"tag":119,"props":2501,"children":2502},{"style":891},[2503],{"type":23,"value":894},{"type":18,"tag":119,"props":2505,"children":2506},{"style":897},[2507],{"type":23,"value":1834},{"type":18,"tag":119,"props":2509,"children":2510},{"style":897},[2511],{"type":23,"value":1839},{"type":18,"tag":19,"props":2513,"children":2514},{},[2515,2521,2523,2528,2530,2535],{"type":18,"tag":115,"props":2516,"children":2518},{"className":2517},[],[2519],{"type":23,"value":2520},"docker rm",{"type":23,"value":2522}," 删除容器，",{"type":18,"tag":115,"props":2524,"children":2526},{"className":2525},[],[2527],{"type":23,"value":1856},{"type":23,"value":2529}," 删除镜像。清理资源时一般先用 ",{"type":18,"tag":115,"props":2531,"children":2533},{"className":2532},[],[2534],{"type":23,"value":1779},{"type":23,"value":2536}," 找到停止的容器，再决定是否删除。",{"type":18,"tag":26,"props":2538,"children":2540},{"id":2539},"构建镜像时的-cpu-架构问题",[2541],{"type":23,"value":2542},"构建镜像时的 CPU 架构问题",{"type":18,"tag":19,"props":2544,"children":2545},{},[2546,2548,2554,2556,2562],{"type":23,"value":2547},"构建镜像时还要注意 CPU 架构。很多开发者使用 Apple Silicon Mac，比如 M1、M2、M3、M4，这类机器通常是 ",{"type":18,"tag":115,"props":2549,"children":2551},{"className":2550},[],[2552],{"type":23,"value":2553},"linux\u002Farm64",{"type":23,"value":2555}," 架构。而大多数云服务器、Intel\u002FAMD 服务器通常是 ",{"type":18,"tag":115,"props":2557,"children":2559},{"className":2558},[],[2560],{"type":23,"value":2561},"linux\u002Famd64",{"type":23,"value":2563}," 架构。",{"type":18,"tag":19,"props":2565,"children":2566},{},[2567],{"type":23,"value":2568},"常见架构可以这样理解：",{"type":18,"tag":38,"props":2570,"children":2571},{},[2572,2582],{"type":18,"tag":42,"props":2573,"children":2574},{},[2575,2580],{"type":18,"tag":115,"props":2576,"children":2578},{"className":2577},[],[2579],{"type":23,"value":2553},{"type":23,"value":2581},"：ARM 64 位架构，常见于 Apple Silicon Mac、部分 ARM 服务器、树莓派等。",{"type":18,"tag":42,"props":2583,"children":2584},{},[2585,2590],{"type":18,"tag":115,"props":2586,"children":2588},{"className":2587},[],[2589],{"type":23,"value":2561},{"type":23,"value":2591},"：x86_64 架构，常见于大多数云服务器和普通 Intel\u002FAMD 服务器。",{"type":18,"tag":19,"props":2593,"children":2594},{},[2595],{"type":23,"value":2596},"如果在 M 系列 Mac 上构建镜像，然后拿到 x86_64 云服务器上运行，就可能遇到架构不匹配的问题。部署到这类服务器时，可以显式指定目标平台：",{"type":18,"tag":109,"props":2598,"children":2600},{"className":879,"code":2599,"language":881,"meta":7,"style":7},"docker build --platform linux\u002Famd64 -t your-app:v1 .\n",[2601],{"type":18,"tag":115,"props":2602,"children":2603},{"__ignoreMap":7},[2604],{"type":18,"tag":119,"props":2605,"children":2606},{"class":121,"line":122},[2607,2611,2615,2620,2625,2629,2634],{"type":18,"tag":119,"props":2608,"children":2609},{"style":891},[2610],{"type":23,"value":894},{"type":18,"tag":119,"props":2612,"children":2613},{"style":897},[2614],{"type":23,"value":900},{"type":18,"tag":119,"props":2616,"children":2617},{"style":903},[2618],{"type":23,"value":2619}," --platform",{"type":18,"tag":119,"props":2621,"children":2622},{"style":897},[2623],{"type":23,"value":2624}," linux\u002Famd64",{"type":18,"tag":119,"props":2626,"children":2627},{"style":903},[2628],{"type":23,"value":906},{"type":18,"tag":119,"props":2630,"children":2631},{"style":897},[2632],{"type":23,"value":2633}," your-app:v1",{"type":18,"tag":119,"props":2635,"children":2636},{"style":897},[2637],{"type":23,"value":916},{"type":18,"tag":19,"props":2639,"children":2640},{},[2641,2643,2649],{"type":23,"value":2642},"如果需要同时支持多种架构，可以使用 ",{"type":18,"tag":115,"props":2644,"children":2646},{"className":2645},[],[2647],{"type":23,"value":2648},"docker buildx",{"type":23,"value":2650}," 构建多平台镜像，并推送到镜像仓库：",{"type":18,"tag":109,"props":2652,"children":2654},{"className":879,"code":2653,"language":881,"meta":7,"style":7},"docker buildx build \\\n  --platform linux\u002Famd64,linux\u002Farm64 \\\n  -t yourname\u002Fyour-app:v1 \\\n  --push .\n",[2655],{"type":18,"tag":115,"props":2656,"children":2657},{"__ignoreMap":7},[2658,2678,2695,2712],{"type":18,"tag":119,"props":2659,"children":2660},{"class":121,"line":122},[2661,2665,2670,2674],{"type":18,"tag":119,"props":2662,"children":2663},{"style":891},[2664],{"type":23,"value":894},{"type":18,"tag":119,"props":2666,"children":2667},{"style":897},[2668],{"type":23,"value":2669}," buildx",{"type":18,"tag":119,"props":2671,"children":2672},{"style":897},[2673],{"type":23,"value":900},{"type":18,"tag":119,"props":2675,"children":2676},{"style":903},[2677],{"type":23,"value":970},{"type":18,"tag":119,"props":2679,"children":2680},{"class":121,"line":131},[2681,2686,2691],{"type":18,"tag":119,"props":2682,"children":2683},{"style":903},[2684],{"type":23,"value":2685},"  --platform",{"type":18,"tag":119,"props":2687,"children":2688},{"style":897},[2689],{"type":23,"value":2690}," linux\u002Famd64,linux\u002Farm64",{"type":18,"tag":119,"props":2692,"children":2693},{"style":903},[2694],{"type":23,"value":970},{"type":18,"tag":119,"props":2696,"children":2697},{"class":121,"line":140},[2698,2703,2708],{"type":18,"tag":119,"props":2699,"children":2700},{"style":903},[2701],{"type":23,"value":2702},"  -t",{"type":18,"tag":119,"props":2704,"children":2705},{"style":897},[2706],{"type":23,"value":2707}," yourname\u002Fyour-app:v1",{"type":18,"tag":119,"props":2709,"children":2710},{"style":903},[2711],{"type":23,"value":970},{"type":18,"tag":119,"props":2713,"children":2714},{"class":121,"line":200},[2715,2720],{"type":18,"tag":119,"props":2716,"children":2717},{"style":903},[2718],{"type":23,"value":2719},"  --push",{"type":18,"tag":119,"props":2721,"children":2722},{"style":897},[2723],{"type":23,"value":916},{"type":18,"tag":19,"props":2725,"children":2726},{},[2727],{"type":23,"value":2728},"单平台构建适合个人项目或固定服务器架构；多平台构建适合要同时支持 x86_64 服务器、ARM 服务器或不同开发机器的项目。",{"type":18,"tag":26,"props":2730,"children":2732},{"id":2731},"docker-和-nginx-的关系",[2733],{"type":23,"value":2734},"Docker 和 Nginx 的关系",{"type":18,"tag":19,"props":2736,"children":2737},{},[2738],{"type":23,"value":2739},"Docker 负责打包和运行应用，Nginx 更常见的角色是接收外部请求、处理域名和路径转发、统一配置 HTTPS。",{"type":18,"tag":19,"props":2741,"children":2742},{},[2743,2745,2751],{"type":23,"value":2744},"没有 Nginx，服务器也可以部署多个项目，只要每个项目监听不同端口，外部就能通过 ",{"type":18,"tag":115,"props":2746,"children":2748},{"className":2747},[],[2749],{"type":23,"value":2750},"IP + 端口",{"type":23,"value":2752}," 访问它们。例如：",{"type":18,"tag":109,"props":2754,"children":2756},{"className":111,"code":2755,"language":23,"meta":7,"style":7},"http:\u002F\u002F服务器IP:3000\nhttp:\u002F\u002F服务器IP:8080\nhttp:\u002F\u002F服务器IP:9000\n",[2757],{"type":18,"tag":115,"props":2758,"children":2759},{"__ignoreMap":7},[2760,2768,2776],{"type":18,"tag":119,"props":2761,"children":2762},{"class":121,"line":122},[2763],{"type":18,"tag":119,"props":2764,"children":2765},{},[2766],{"type":23,"value":2767},"http:\u002F\u002F服务器IP:3000\n",{"type":18,"tag":119,"props":2769,"children":2770},{"class":121,"line":131},[2771],{"type":18,"tag":119,"props":2772,"children":2773},{},[2774],{"type":23,"value":2775},"http:\u002F\u002F服务器IP:8080\n",{"type":18,"tag":119,"props":2777,"children":2778},{"class":121,"line":140},[2779],{"type":18,"tag":119,"props":2780,"children":2781},{},[2782],{"type":23,"value":2783},"http:\u002F\u002F服务器IP:9000\n",{"type":18,"tag":19,"props":2785,"children":2786},{},[2787],{"type":23,"value":2788},"但是这种方式不适合正式网站。用户不会希望记住端口号，HTTPS 配置也会变得分散。",{"type":18,"tag":19,"props":2790,"children":2791},{},[2792,2794,2799,2800,2806],{"type":23,"value":2793},"加入 Nginx 后，可以让外部统一访问标准的 ",{"type":18,"tag":115,"props":2795,"children":2797},{"className":2796},[],[2798],{"type":23,"value":1069},{"type":23,"value":1264},{"type":18,"tag":115,"props":2801,"children":2803},{"className":2802},[],[2804],{"type":23,"value":2805},"443",{"type":23,"value":2807}," 端口，再由 Nginx 根据域名、子域名或路径转发到不同项目：",{"type":18,"tag":109,"props":2809,"children":2811},{"className":111,"code":2810,"language":23,"meta":7,"style":7},"blog.example.com  ->  frontend:3000\napi.example.com   ->  backend:8080\nai.example.com    ->  ai-service:9000\n",[2812],{"type":18,"tag":115,"props":2813,"children":2814},{"__ignoreMap":7},[2815,2823,2831],{"type":18,"tag":119,"props":2816,"children":2817},{"class":121,"line":122},[2818],{"type":18,"tag":119,"props":2819,"children":2820},{},[2821],{"type":23,"value":2822},"blog.example.com  ->  frontend:3000\n",{"type":18,"tag":119,"props":2824,"children":2825},{"class":121,"line":131},[2826],{"type":18,"tag":119,"props":2827,"children":2828},{},[2829],{"type":23,"value":2830},"api.example.com   ->  backend:8080\n",{"type":18,"tag":119,"props":2832,"children":2833},{"class":121,"line":140},[2834],{"type":18,"tag":119,"props":2835,"children":2836},{},[2837],{"type":23,"value":2838},"ai.example.com    ->  ai-service:9000\n",{"type":18,"tag":19,"props":2840,"children":2841},{},[2842,2844],{"type":23,"value":2843},"所以更准确的理解是：",{"type":18,"tag":68,"props":2845,"children":2846},{},[2847],{"type":23,"value":2848},"Nginx 不是 Docker 的替代品。Docker 负责运行应用，Nginx 负责把外部请求转发到正确的应用。",{"type":18,"tag":19,"props":2850,"children":2851},{},[2852,2854,2860,2862,2868],{"type":23,"value":2853},"如果 Nginx 直接安装在宿主机上，可以把容器端口绑定到 ",{"type":18,"tag":115,"props":2855,"children":2857},{"className":2856},[],[2858],{"type":23,"value":2859},"127.0.0.1",{"type":23,"value":2861},"，再让 Nginx 转发到本机端口。如果 Nginx 也在 Compose 里，则可以直接用服务名转发，例如 ",{"type":18,"tag":115,"props":2863,"children":2865},{"className":2864},[],[2866],{"type":23,"value":2867},"proxy_pass http:\u002F\u002Ffrontend:3000;",{"type":23,"value":302},{"type":18,"tag":26,"props":2870,"children":2872},{"id":2871},"上传服务器的一种流程",[2873],{"type":23,"value":2871},{"type":18,"tag":19,"props":2875,"children":2876},{},[2877],{"type":23,"value":2878},"如果不使用镜像仓库，也可以先在本地构建镜像，再把镜像文件上传到服务器。",{"type":18,"tag":19,"props":2880,"children":2881},{},[2882],{"type":23,"value":2883},"整体流程是：",{"type":18,"tag":109,"props":2885,"children":2887},{"className":111,"code":2886,"language":23,"meta":7,"style":7},"构建镜像 -> 保存镜像到文件 -> scp 上传到 Linux 服务器 -> 加载镜像 -> 运行容器\n",[2888],{"type":18,"tag":115,"props":2889,"children":2890},{"__ignoreMap":7},[2891],{"type":18,"tag":119,"props":2892,"children":2893},{"class":121,"line":122},[2894],{"type":18,"tag":119,"props":2895,"children":2896},{},[2897],{"type":23,"value":2886},{"type":18,"tag":19,"props":2899,"children":2900},{},[2901],{"type":23,"value":2902},"对应命令大致如下：",{"type":18,"tag":109,"props":2904,"children":2906},{"className":879,"code":2905,"language":881,"meta":7,"style":7},"# 本地构建镜像（注意指定目标平台）\ndocker build --platform linux\u002Famd64 -t your-app:v1 .\n\n# 保存镜像为文件\ndocker save your-app:v1 -o your-app-v1.tar\n\n# 上传到服务器\nscp your-app-v1.tar user@server:\u002Ftmp\u002F\n\n# 登录服务器\nssh user@server\n\n# 加载镜像\ndocker load -i \u002Ftmp\u002Fyour-app-v1.tar\n\n# 运行容器\ndocker run -d --name your-app -p 80:3000 your-app:v1\n",[2907],{"type":18,"tag":115,"props":2908,"children":2909},{"__ignoreMap":7},[2910,2919,2950,2957,2965,2991,2998,3006,3024,3031,3039,3052,3059,3067,3089,3096,3104],{"type":18,"tag":119,"props":2911,"children":2912},{"class":121,"line":122},[2913],{"type":18,"tag":119,"props":2914,"children":2916},{"style":2915},"--shiki-default:#6A737D",[2917],{"type":23,"value":2918},"# 本地构建镜像（注意指定目标平台）\n",{"type":18,"tag":119,"props":2920,"children":2921},{"class":121,"line":131},[2922,2926,2930,2934,2938,2942,2946],{"type":18,"tag":119,"props":2923,"children":2924},{"style":891},[2925],{"type":23,"value":894},{"type":18,"tag":119,"props":2927,"children":2928},{"style":897},[2929],{"type":23,"value":900},{"type":18,"tag":119,"props":2931,"children":2932},{"style":903},[2933],{"type":23,"value":2619},{"type":18,"tag":119,"props":2935,"children":2936},{"style":897},[2937],{"type":23,"value":2624},{"type":18,"tag":119,"props":2939,"children":2940},{"style":903},[2941],{"type":23,"value":906},{"type":18,"tag":119,"props":2943,"children":2944},{"style":897},[2945],{"type":23,"value":2633},{"type":18,"tag":119,"props":2947,"children":2948},{"style":897},[2949],{"type":23,"value":916},{"type":18,"tag":119,"props":2951,"children":2952},{"class":121,"line":140},[2953],{"type":18,"tag":119,"props":2954,"children":2955},{"emptyLinePlaceholder":423},[2956],{"type":23,"value":426},{"type":18,"tag":119,"props":2958,"children":2959},{"class":121,"line":200},[2960],{"type":18,"tag":119,"props":2961,"children":2962},{"style":2915},[2963],{"type":23,"value":2964},"# 保存镜像为文件\n",{"type":18,"tag":119,"props":2966,"children":2967},{"class":121,"line":444},[2968,2972,2977,2981,2986],{"type":18,"tag":119,"props":2969,"children":2970},{"style":891},[2971],{"type":23,"value":894},{"type":18,"tag":119,"props":2973,"children":2974},{"style":897},[2975],{"type":23,"value":2976}," save",{"type":18,"tag":119,"props":2978,"children":2979},{"style":897},[2980],{"type":23,"value":2633},{"type":18,"tag":119,"props":2982,"children":2983},{"style":903},[2984],{"type":23,"value":2985}," -o",{"type":18,"tag":119,"props":2987,"children":2988},{"style":897},[2989],{"type":23,"value":2990}," your-app-v1.tar\n",{"type":18,"tag":119,"props":2992,"children":2993},{"class":121,"line":453},[2994],{"type":18,"tag":119,"props":2995,"children":2996},{"emptyLinePlaceholder":423},[2997],{"type":23,"value":426},{"type":18,"tag":119,"props":2999,"children":3000},{"class":121,"line":462},[3001],{"type":18,"tag":119,"props":3002,"children":3003},{"style":2915},[3004],{"type":23,"value":3005},"# 上传到服务器\n",{"type":18,"tag":119,"props":3007,"children":3008},{"class":121,"line":470},[3009,3014,3019],{"type":18,"tag":119,"props":3010,"children":3011},{"style":891},[3012],{"type":23,"value":3013},"scp",{"type":18,"tag":119,"props":3015,"children":3016},{"style":897},[3017],{"type":23,"value":3018}," your-app-v1.tar",{"type":18,"tag":119,"props":3020,"children":3021},{"style":897},[3022],{"type":23,"value":3023}," user@server:\u002Ftmp\u002F\n",{"type":18,"tag":119,"props":3025,"children":3026},{"class":121,"line":479},[3027],{"type":18,"tag":119,"props":3028,"children":3029},{"emptyLinePlaceholder":423},[3030],{"type":23,"value":426},{"type":18,"tag":119,"props":3032,"children":3033},{"class":121,"line":487},[3034],{"type":18,"tag":119,"props":3035,"children":3036},{"style":2915},[3037],{"type":23,"value":3038},"# 登录服务器\n",{"type":18,"tag":119,"props":3040,"children":3041},{"class":121,"line":496},[3042,3047],{"type":18,"tag":119,"props":3043,"children":3044},{"style":891},[3045],{"type":23,"value":3046},"ssh",{"type":18,"tag":119,"props":3048,"children":3049},{"style":897},[3050],{"type":23,"value":3051}," user@server\n",{"type":18,"tag":119,"props":3053,"children":3054},{"class":121,"line":504},[3055],{"type":18,"tag":119,"props":3056,"children":3057},{"emptyLinePlaceholder":423},[3058],{"type":23,"value":426},{"type":18,"tag":119,"props":3060,"children":3061},{"class":121,"line":845},[3062],{"type":18,"tag":119,"props":3063,"children":3064},{"style":2915},[3065],{"type":23,"value":3066},"# 加载镜像\n",{"type":18,"tag":119,"props":3068,"children":3069},{"class":121,"line":853},[3070,3074,3079,3084],{"type":18,"tag":119,"props":3071,"children":3072},{"style":891},[3073],{"type":23,"value":894},{"type":18,"tag":119,"props":3075,"children":3076},{"style":897},[3077],{"type":23,"value":3078}," load",{"type":18,"tag":119,"props":3080,"children":3081},{"style":903},[3082],{"type":23,"value":3083}," -i",{"type":18,"tag":119,"props":3085,"children":3086},{"style":897},[3087],{"type":23,"value":3088}," \u002Ftmp\u002Fyour-app-v1.tar\n",{"type":18,"tag":119,"props":3090,"children":3091},{"class":121,"line":1562},[3092],{"type":18,"tag":119,"props":3093,"children":3094},{"emptyLinePlaceholder":423},[3095],{"type":23,"value":426},{"type":18,"tag":119,"props":3097,"children":3098},{"class":121,"line":1580},[3099],{"type":18,"tag":119,"props":3100,"children":3101},{"style":2915},[3102],{"type":23,"value":3103},"# 运行容器\n",{"type":18,"tag":119,"props":3105,"children":3106},{"class":121,"line":1593},[3107,3111,3115,3119,3124,3129,3134,3138],{"type":18,"tag":119,"props":3108,"children":3109},{"style":891},[3110],{"type":23,"value":894},{"type":18,"tag":119,"props":3112,"children":3113},{"style":897},[3114],{"type":23,"value":960},{"type":18,"tag":119,"props":3116,"children":3117},{"style":903},[3118],{"type":23,"value":965},{"type":18,"tag":119,"props":3120,"children":3121},{"style":903},[3122],{"type":23,"value":3123}," --name",{"type":18,"tag":119,"props":3125,"children":3126},{"style":897},[3127],{"type":23,"value":3128}," your-app",{"type":18,"tag":119,"props":3130,"children":3131},{"style":903},[3132],{"type":23,"value":3133}," -p",{"type":18,"tag":119,"props":3135,"children":3136},{"style":897},[3137],{"type":23,"value":999},{"type":18,"tag":119,"props":3139,"children":3140},{"style":897},[3141],{"type":23,"value":1839},{"type":18,"tag":19,"props":3143,"children":3144},{},[3145],{"type":23,"value":3146},"这种方式适合个人项目、小项目或刚开始学习部署的时候。它的优点是直观，不需要先配置镜像仓库；缺点是手工步骤多，版本管理和回滚不够方便。",{"type":18,"tag":19,"props":3148,"children":3149},{},[3150],{"type":23,"value":3151},"更正式的生产环境里，通常会把镜像推送到镜像仓库，例如 Docker Hub、GitHub Container Registry 或私有镜像仓库，然后让服务器直接拉取指定版本的镜像：",{"type":18,"tag":109,"props":3153,"children":3155},{"className":111,"code":3154,"language":23,"meta":7,"style":7},"本地或 CI 构建镜像 -> 推送到镜像仓库 -> 服务器拉取镜像 -> 重启容器或 Compose 项目\n",[3156],{"type":18,"tag":115,"props":3157,"children":3158},{"__ignoreMap":7},[3159],{"type":18,"tag":119,"props":3160,"children":3161},{"class":121,"line":122},[3162],{"type":18,"tag":119,"props":3163,"children":3164},{},[3165],{"type":23,"value":3154},{"type":18,"tag":19,"props":3167,"children":3168},{},[3169],{"type":23,"value":3170},"这样做更利于版本追踪、自动化部署和回滚。",{"type":18,"tag":26,"props":3172,"children":3174},{"id":3173},"入门时最容易踩的坑",[3175],{"type":23,"value":3173},{"type":18,"tag":3177,"props":3178,"children":3179},"ol",{},[3180,3208,3247,3268,3296],{"type":18,"tag":42,"props":3181,"children":3182},{},[3183,3195,3199,3201,3206],{"type":18,"tag":68,"props":3184,"children":3185},{},[3186,3188,3193],{"type":23,"value":3187},"把 ",{"type":18,"tag":115,"props":3189,"children":3191},{"className":3190},[],[3192],{"type":23,"value":2087},{"type":23,"value":3194}," 理解错",{"type":18,"tag":3196,"props":3197,"children":3198},"br",{},[],{"type":23,"value":3200},"在容器内部，",{"type":18,"tag":115,"props":3202,"children":3204},{"className":3203},[],[3205],{"type":23,"value":2087},{"type":23,"value":3207}," 通常指容器自己。容器访问宿主机、其他容器或外部数据库时，要根据网络环境使用正确地址。",{"type":18,"tag":42,"props":3209,"children":3210},{},[3211,3216,3219,3224,3226,3232,3234,3239,3241,3246],{"type":18,"tag":68,"props":3212,"children":3213},{},[3214],{"type":23,"value":3215},"端口方向写反",{"type":18,"tag":3196,"props":3217,"children":3218},{},[],{"type":18,"tag":115,"props":3220,"children":3222},{"className":3221},[],[3223],{"type":23,"value":1061},{"type":23,"value":3225}," 是 ",{"type":18,"tag":115,"props":3227,"children":3229},{"className":3228},[],[3230],{"type":23,"value":3231},"宿主机端口:容器端口",{"type":23,"value":3233},"。如果应用在容器里监听 ",{"type":18,"tag":115,"props":3235,"children":3237},{"className":3236},[],[3238],{"type":23,"value":606},{"type":23,"value":3240},"，右边就应该是 ",{"type":18,"tag":115,"props":3242,"children":3244},{"className":3243},[],[3245],{"type":23,"value":606},{"type":23,"value":302},{"type":18,"tag":42,"props":3248,"children":3249},{},[3250,3255,3258,3260,3266],{"type":18,"tag":68,"props":3251,"children":3252},{},[3253],{"type":23,"value":3254},"把敏感服务暴露到公网",{"type":18,"tag":3196,"props":3256,"children":3257},{},[],{"type":23,"value":3259},"数据库、Redis、内部管理后台不要随便 ",{"type":18,"tag":115,"props":3261,"children":3263},{"className":3262},[],[3264],{"type":23,"value":3265},"-p",{"type":23,"value":3267}," 到公网。能走内网或 Compose 网络的，就不要暴露到外部。",{"type":18,"tag":42,"props":3269,"children":3270},{},[3271,3276,3279,3281,3286,3288,3294],{"type":18,"tag":68,"props":3272,"children":3273},{},[3274],{"type":23,"value":3275},"镜像里复制了太多无关文件",{"type":18,"tag":3196,"props":3277,"children":3278},{},[],{"type":23,"value":3280},"忘记写 ",{"type":18,"tag":115,"props":3282,"children":3284},{"className":3283},[],[3285],{"type":23,"value":660},{"type":23,"value":3287}," 会让镜像变大，也可能把 ",{"type":18,"tag":115,"props":3289,"children":3291},{"className":3290},[],[3292],{"type":23,"value":3293},".env",{"type":23,"value":3295}," 等敏感文件打进镜像。",{"type":18,"tag":42,"props":3297,"children":3298},{},[3299,3311,3314,3316,3321,3322,3328],{"type":18,"tag":68,"props":3300,"children":3301},{},[3302,3304,3309],{"type":23,"value":3303},"只会 ",{"type":18,"tag":115,"props":3305,"children":3307},{"className":3306},[],[3308],{"type":23,"value":1028},{"type":23,"value":3310},"，不会看日志",{"type":18,"tag":3196,"props":3312,"children":3313},{},[],{"type":23,"value":3315},"容器启动失败时，先看 ",{"type":18,"tag":115,"props":3317,"children":3319},{"className":3318},[],[3320],{"type":23,"value":1779},{"type":23,"value":294},{"type":18,"tag":115,"props":3323,"children":3325},{"className":3324},[],[3326],{"type":23,"value":3327},"docker logs 容器名",{"type":23,"value":3329},"，通常比反复重启更有效。",{"type":18,"tag":26,"props":3331,"children":3333},{"id":3332},"总结",[3334],{"type":23,"value":3332},{"type":18,"tag":19,"props":3336,"children":3337},{},[3338],{"type":23,"value":3339},"Docker 入门可以先抓住这几件事：",{"type":18,"tag":3177,"props":3341,"children":3342},{},[3343,3348,3392,3410,3428,3438,3443],{"type":18,"tag":42,"props":3344,"children":3345},{},[3346],{"type":23,"value":3347},"镜像是静态的构建产物，容器是镜像运行起来后的实例。",{"type":18,"tag":42,"props":3349,"children":3350},{},[3351,3356,3358,3364,3365,3371,3372,3378,3379,3384,3385,3390],{"type":18,"tag":115,"props":3352,"children":3354},{"className":3353},[],[3355],{"type":23,"value":393},{"type":23,"value":3357}," 是构建镜像的说明书，",{"type":18,"tag":115,"props":3359,"children":3361},{"className":3360},[],[3362],{"type":23,"value":3363},"FROM",{"type":23,"value":2104},{"type":18,"tag":115,"props":3366,"children":3368},{"className":3367},[],[3369],{"type":23,"value":3370},"WORKDIR",{"type":23,"value":2104},{"type":18,"tag":115,"props":3373,"children":3375},{"className":3374},[],[3376],{"type":23,"value":3377},"COPY",{"type":23,"value":2104},{"type":18,"tag":115,"props":3380,"children":3382},{"className":3381},[],[3383],{"type":23,"value":636},{"type":23,"value":2104},{"type":18,"tag":115,"props":3386,"children":3388},{"className":3387},[],[3389],{"type":23,"value":647},{"type":23,"value":3391}," 是最常见的指令。",{"type":18,"tag":42,"props":3393,"children":3394},{},[3395,3401,3403,3408],{"type":18,"tag":115,"props":3396,"children":3398},{"className":3397},[],[3399],{"type":23,"value":3400},"docker build",{"type":23,"value":3402}," 用来构建镜像，",{"type":18,"tag":115,"props":3404,"children":3406},{"className":3405},[],[3407],{"type":23,"value":1028},{"type":23,"value":3409}," 用来启动容器。",{"type":18,"tag":42,"props":3411,"children":3412},{},[3413,3415,3420,3422,3427],{"type":23,"value":3414},"端口映射里，",{"type":18,"tag":115,"props":3416,"children":3418},{"className":3417},[],[3419],{"type":23,"value":3231},{"type":23,"value":3421},"，例如 ",{"type":18,"tag":115,"props":3423,"children":3425},{"className":3424},[],[3426],{"type":23,"value":1099},{"type":23,"value":302},{"type":18,"tag":42,"props":3429,"children":3430},{},[3431,3436],{"type":18,"tag":115,"props":3432,"children":3434},{"className":3433},[],[3435],{"type":23,"value":269},{"type":23,"value":3437}," 适合管理多容器项目，服务之间可以通过服务名访问。",{"type":18,"tag":42,"props":3439,"children":3440},{},[3441],{"type":23,"value":3442},"Nginx 不是 Docker 的替代品，它通常负责接收外部请求并转发到不同容器或服务。",{"type":18,"tag":42,"props":3444,"children":3445},{},[3446],{"type":23,"value":3447},"正式部署时，把镜像构建、推送、拉取和重启流程标准化，比直接在服务器上手动安装依赖更可靠。",{"type":18,"tag":19,"props":3449,"children":3450},{},[3451],{"type":23,"value":3452},"学 Docker 不需要一开始就把所有命令都背下来。先理解镜像、容器、Dockerfile、端口映射和日志查看，再拿一个真实项目从构建到部署跑通一遍，很多概念就会自然连起来。",{"type":18,"tag":26,"props":3454,"children":3456},{"id":3455},"参考资料",[3457],{"type":23,"value":3455},{"type":18,"tag":38,"props":3459,"children":3460},{},[3461,3473,3483,3493,3503,3513],{"type":18,"tag":42,"props":3462,"children":3463},{},[3464],{"type":18,"tag":3465,"props":3466,"children":3470},"a",{"href":3467,"rel":3468},"https:\u002F\u002Fdocs.docker.com\u002Fbuild\u002Fbuilding\u002Fbest-practices\u002F",[3469],"nofollow",[3471],{"type":23,"value":3472},"Docker Docs: Dockerfile best practices",{"type":18,"tag":42,"props":3474,"children":3475},{},[3476],{"type":18,"tag":3465,"props":3477,"children":3480},{"href":3478,"rel":3479},"https:\u002F\u002Fdocs.docker.com\u002Fget-started\u002Fdocker-concepts\u002Frunning-containers\u002Fpublishing-ports\u002F",[3469],[3481],{"type":23,"value":3482},"Docker Docs: Publishing and exposing ports",{"type":18,"tag":42,"props":3484,"children":3485},{},[3486],{"type":18,"tag":3465,"props":3487,"children":3490},{"href":3488,"rel":3489},"https:\u002F\u002Fdocs.docker.com\u002Fcompose\u002Fhow-tos\u002Fnetworking\u002F",[3469],[3491],{"type":23,"value":3492},"Docker Docs: Networking in Compose",{"type":18,"tag":42,"props":3494,"children":3495},{},[3496],{"type":18,"tag":3465,"props":3497,"children":3500},{"href":3498,"rel":3499},"https:\u002F\u002Fdocs.docker.com\u002Fbuild\u002Fbuilding\u002Fmulti-platform\u002F",[3469],[3501],{"type":23,"value":3502},"Docker Docs: Multi-platform builds",{"type":18,"tag":42,"props":3504,"children":3505},{},[3506],{"type":18,"tag":3465,"props":3507,"children":3510},{"href":3508,"rel":3509},"https:\u002F\u002Fdocs.docker.com\u002Freference\u002Fcli\u002Fdocker\u002Fimage\u002Fsave\u002F",[3469],[3511],{"type":23,"value":3512},"Docker Docs: docker image save",{"type":18,"tag":42,"props":3514,"children":3515},{},[3516],{"type":18,"tag":3465,"props":3517,"children":3520},{"href":3518,"rel":3519},"https:\u002F\u002Fdocs.docker.com\u002Freference\u002Fcli\u002Fdocker\u002Fimage\u002Fload\u002F",[3469],[3521],{"type":23,"value":3522},"Docker Docs: docker image load",{"type":18,"tag":3524,"props":3525,"children":3526},"style",{},[3527],{"type":23,"value":3528},"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);}",{"title":7,"searchDepth":131,"depth":131,"links":3530},[3531,3532,3533,3534,3535,3536,3537,3546,3547,3548,3549,3550,3551],{"id":28,"depth":131,"text":31},{"id":94,"depth":131,"text":97},{"id":279,"depth":131,"text":279},{"id":381,"depth":131,"text":384},{"id":862,"depth":131,"text":862},{"id":1242,"depth":131,"text":1242},{"id":1691,"depth":131,"text":1694,"children":3538},[3539,3540,3541,3542,3543,3544,3545],{"id":1703,"depth":140,"text":1703},{"id":1784,"depth":140,"text":1784},{"id":1861,"depth":140,"text":1861},{"id":2121,"depth":140,"text":2121},{"id":2221,"depth":140,"text":2221},{"id":2339,"depth":140,"text":2339},{"id":2471,"depth":140,"text":2471},{"id":2539,"depth":131,"text":2542},{"id":2731,"depth":131,"text":2734},{"id":2871,"depth":131,"text":2871},{"id":3173,"depth":131,"text":3173},{"id":3332,"depth":131,"text":3332},{"id":3455,"depth":131,"text":3455},"markdown","content:articles:devops:Docker.md","content","articles\u002Fdevops\u002FDocker.md","articles\u002Fdevops\u002FDocker","md",1779811687795]