[{"data":1,"prerenderedAt":1897},["ShallowReactive",2],{"page-/post/hono/hono-docker-pm2":3,"surrounding-page":1888},{"id":4,"title":5,"author":6,"body":7,"date":1875,"description":98,"extension":1876,"group":6,"lastmod":1877,"meta":1878,"navigation":147,"path":1879,"rawbody":1880,"seo":1881,"showTitle":5,"stem":1882,"tags":1883,"versions":1885,"__hash__":1887},"content/post/Hono/hono-docker-pm2.md","【Hono】部署篇 Docker+pm2部署",null,{"type":8,"value":9,"toc":1866},"minimark",[10,13,26,29,34,40,55,67,74,85,89,92,610,616,635,645,658,702,708,732,739,742,748,752,759,765,768,877,880,883,886,991,994,1006,1009,1012,1015,1018,1028,1031,1036,1074,1083,1088,1102,1134,1139,1145,1163,1168,1186,1192,1195,1205,1211,1214,1247,1272,1275,1294,1324,1327,1331,1350,1353,1362,1380,1387,1390,1405,1408,1417,1420,1440,1449,1466,1471,1493,1496,1517,1520,1537,1543,1610,1613,1651,1654,1683,1689,1699,1702,1717,1720,1736,1747,1752,1772,1775,1786,1793,1798,1801,1806,1818,1842,1856,1859,1862],[11,12],"br",{},[14,15,16,17,21,22,25],"p",{},"项目开发完后，要部署到服务器上才能正常使用，这里我分享一下",[18,19,20],"code",{},"docker","和",[18,23,24],{},"pm2","两种方式的部署。",[14,27,28],{},"以下经验来自于**我日常的折腾中，适合入门，非企业级操作。**仅用于分享！",[30,31,33],"h2",{"id":32},"docker部署","Docker部署",[14,35,36,37,39],{},"用",[18,38,20],{},"的话，也算有两种运行方式。",[14,41,42,43,46,47,50,51,54],{},"先在本地",[18,44,45],{},"build","，然后打",[18,48,49],{},"tag","，然后",[18,52,53],{},"push","上去。",[14,56,57,58,66],{},"把包",[59,60,61,62,65],"strong",{},"发布到",[18,63,64],{},"dockerhub","或你的对应的云服务商的容器镜像服务","上（比如阿里云）后",[14,68,69,70,73],{},"一种是使用",[18,71,72],{},"docker run"," 附带一些参数进行启动",[14,75,76,77,80,81,84],{},"另一种使用",[18,78,79],{},"docker-compose.yml","配置参数，用",[18,82,83],{},"docker compose","命令重新拉取最新的镜像并重启。",[30,86,88],{"id":87},"dockerfile","Dockerfile",[14,90,91],{},"这个dockerfile来自Bun的官方，然后我又加了一些自己的需求，可以做一下参考",[93,94,99],"pre",{"className":95,"code":96,"language":97,"meta":98,"style":98},"language-shell shiki shiki-themes github-light","# use the official Bun image\n# see all versions at https://hub.docker.com/r/oven/bun/tags\nFROM oven/bun:1 AS base\nWORKDIR /usr/src/app\n\n# install dependencies into temp directory\n# this will cache them and speed up future builds\nFROM base AS install\nRUN mkdir -p /temp/dev\nCOPY package.json bun.lockb /temp/dev/\nRUN cd /temp/dev && bun install --frozen-lockfile\n\n# install with --production (exclude devDependencies)\nRUN mkdir -p /temp/prod\nCOPY package.json bun.lockb /temp/prod/\nRUN cd /temp/prod && bun install --frozen-lockfile --production\n\n# copy node_modules from temp directory\n# then copy all (non-ignored) project files into the image\nFROM base AS prerelease\nCOPY --from=install /temp/dev/node_modules node_modules\nCOPY . .\n\n# [optional] tests & build\nENV NODE_ENV=production\n# RUN bun test\nRUN bun run build\n\n# copy production dependencies and source code into final image\nFROM base AS release\n\n# 一个后端node/bun服务运行,必须需要node_modules\n# 以及打包后的入口\n# 如果存在环境变量配置, 还需要复制环境变量配置文件\nCOPY --from=install /temp/prod/node_modules node_modules\nCOPY --from=prerelease /usr/src/app/out/index.js .\nCOPY --from=prerelease /usr/src/app/package.json .\nCOPY --from=prerelease /usr/src/app/.env .\nCOPY --from=prerelease /usr/src/app/.env.production .\n\n# 此处是为了把日志和数据库持久化, 方便备份和查看\n# 创建日志目录和数据库目录\nRUN mkdir -p /usr/src/app/prod-logs && chmod -R 777 /usr/src/app/prod-logs\nRUN mkdir -p /usr/src/app/db && chmod -R 777 /usr/src/app/db\n\nENV NODE_ENV=production\n# run the app\nUSER bun\nEXPOSE 4775/tcp\nENTRYPOINT [ \"bun\", \"run\", \"index.js\" ]\n","shell","",[18,100,101,110,116,133,142,149,155,161,174,190,205,229,234,240,252,264,286,291,297,303,315,329,340,345,351,360,366,380,385,391,403,408,414,420,426,438,451,463,475,487,492,498,504,530,553,558,565,571,580,589],{"__ignoreMap":98},[102,103,106],"span",{"class":104,"line":105},"line",1,[102,107,109],{"class":108},"sAwPA","# use the official Bun image\n",[102,111,113],{"class":104,"line":112},2,[102,114,115],{"class":108},"# see all versions at https://hub.docker.com/r/oven/bun/tags\n",[102,117,119,123,127,130],{"class":104,"line":118},3,[102,120,122],{"class":121},"s7eDp","FROM",[102,124,126],{"class":125},"sYBdl"," oven/bun:1",[102,128,129],{"class":125}," AS",[102,131,132],{"class":125}," base\n",[102,134,136,139],{"class":104,"line":135},4,[102,137,138],{"class":121},"WORKDIR",[102,140,141],{"class":125}," /usr/src/app\n",[102,143,145],{"class":104,"line":144},5,[102,146,148],{"emptyLinePlaceholder":147},true,"\n",[102,150,152],{"class":104,"line":151},6,[102,153,154],{"class":108},"# install dependencies into temp directory\n",[102,156,158],{"class":104,"line":157},7,[102,159,160],{"class":108},"# this will cache them and speed up future builds\n",[102,162,164,166,169,171],{"class":104,"line":163},8,[102,165,122],{"class":121},[102,167,168],{"class":125}," base",[102,170,129],{"class":125},[102,172,173],{"class":125}," install\n",[102,175,177,180,183,187],{"class":104,"line":176},9,[102,178,179],{"class":121},"RUN",[102,181,182],{"class":125}," mkdir",[102,184,186],{"class":185},"sYu0t"," -p",[102,188,189],{"class":125}," /temp/dev\n",[102,191,193,196,199,202],{"class":104,"line":192},10,[102,194,195],{"class":121},"COPY",[102,197,198],{"class":125}," package.json",[102,200,201],{"class":125}," bun.lockb",[102,203,204],{"class":125}," /temp/dev/\n",[102,206,208,210,213,216,220,223,226],{"class":104,"line":207},11,[102,209,179],{"class":121},[102,211,212],{"class":125}," cd",[102,214,215],{"class":125}," /temp/dev",[102,217,219],{"class":218},"sgsFI"," && ",[102,221,222],{"class":121},"bun",[102,224,225],{"class":125}," install",[102,227,228],{"class":185}," --frozen-lockfile\n",[102,230,232],{"class":104,"line":231},12,[102,233,148],{"emptyLinePlaceholder":147},[102,235,237],{"class":104,"line":236},13,[102,238,239],{"class":108},"# install with --production (exclude devDependencies)\n",[102,241,243,245,247,249],{"class":104,"line":242},14,[102,244,179],{"class":121},[102,246,182],{"class":125},[102,248,186],{"class":185},[102,250,251],{"class":125}," /temp/prod\n",[102,253,255,257,259,261],{"class":104,"line":254},15,[102,256,195],{"class":121},[102,258,198],{"class":125},[102,260,201],{"class":125},[102,262,263],{"class":125}," /temp/prod/\n",[102,265,267,269,271,274,276,278,280,283],{"class":104,"line":266},16,[102,268,179],{"class":121},[102,270,212],{"class":125},[102,272,273],{"class":125}," /temp/prod",[102,275,219],{"class":218},[102,277,222],{"class":121},[102,279,225],{"class":125},[102,281,282],{"class":185}," --frozen-lockfile",[102,284,285],{"class":185}," --production\n",[102,287,289],{"class":104,"line":288},17,[102,290,148],{"emptyLinePlaceholder":147},[102,292,294],{"class":104,"line":293},18,[102,295,296],{"class":108},"# copy node_modules from temp directory\n",[102,298,300],{"class":104,"line":299},19,[102,301,302],{"class":108},"# then copy all (non-ignored) project files into the image\n",[102,304,306,308,310,312],{"class":104,"line":305},20,[102,307,122],{"class":121},[102,309,168],{"class":125},[102,311,129],{"class":125},[102,313,314],{"class":125}," prerelease\n",[102,316,318,320,323,326],{"class":104,"line":317},21,[102,319,195],{"class":121},[102,321,322],{"class":185}," --from=install",[102,324,325],{"class":125}," /temp/dev/node_modules",[102,327,328],{"class":125}," node_modules\n",[102,330,332,334,337],{"class":104,"line":331},22,[102,333,195],{"class":121},[102,335,336],{"class":125}," .",[102,338,339],{"class":125}," .\n",[102,341,343],{"class":104,"line":342},23,[102,344,148],{"emptyLinePlaceholder":147},[102,346,348],{"class":104,"line":347},24,[102,349,350],{"class":108},"# [optional] tests & build\n",[102,352,354,357],{"class":104,"line":353},25,[102,355,356],{"class":121},"ENV",[102,358,359],{"class":125}," NODE_ENV=production\n",[102,361,363],{"class":104,"line":362},26,[102,364,365],{"class":108},"# RUN bun test\n",[102,367,369,371,374,377],{"class":104,"line":368},27,[102,370,179],{"class":121},[102,372,373],{"class":125}," bun",[102,375,376],{"class":125}," run",[102,378,379],{"class":125}," build\n",[102,381,383],{"class":104,"line":382},28,[102,384,148],{"emptyLinePlaceholder":147},[102,386,388],{"class":104,"line":387},29,[102,389,390],{"class":108},"# copy production dependencies and source code into final image\n",[102,392,394,396,398,400],{"class":104,"line":393},30,[102,395,122],{"class":121},[102,397,168],{"class":125},[102,399,129],{"class":125},[102,401,402],{"class":125}," release\n",[102,404,406],{"class":104,"line":405},31,[102,407,148],{"emptyLinePlaceholder":147},[102,409,411],{"class":104,"line":410},32,[102,412,413],{"class":108},"# 一个后端node/bun服务运行,必须需要node_modules\n",[102,415,417],{"class":104,"line":416},33,[102,418,419],{"class":108},"# 以及打包后的入口\n",[102,421,423],{"class":104,"line":422},34,[102,424,425],{"class":108},"# 如果存在环境变量配置, 还需要复制环境变量配置文件\n",[102,427,429,431,433,436],{"class":104,"line":428},35,[102,430,195],{"class":121},[102,432,322],{"class":185},[102,434,435],{"class":125}," /temp/prod/node_modules",[102,437,328],{"class":125},[102,439,441,443,446,449],{"class":104,"line":440},36,[102,442,195],{"class":121},[102,444,445],{"class":185}," --from=prerelease",[102,447,448],{"class":125}," /usr/src/app/out/index.js",[102,450,339],{"class":125},[102,452,454,456,458,461],{"class":104,"line":453},37,[102,455,195],{"class":121},[102,457,445],{"class":185},[102,459,460],{"class":125}," /usr/src/app/package.json",[102,462,339],{"class":125},[102,464,466,468,470,473],{"class":104,"line":465},38,[102,467,195],{"class":121},[102,469,445],{"class":185},[102,471,472],{"class":125}," /usr/src/app/.env",[102,474,339],{"class":125},[102,476,478,480,482,485],{"class":104,"line":477},39,[102,479,195],{"class":121},[102,481,445],{"class":185},[102,483,484],{"class":125}," /usr/src/app/.env.production",[102,486,339],{"class":125},[102,488,490],{"class":104,"line":489},40,[102,491,148],{"emptyLinePlaceholder":147},[102,493,495],{"class":104,"line":494},41,[102,496,497],{"class":108},"# 此处是为了把日志和数据库持久化, 方便备份和查看\n",[102,499,501],{"class":104,"line":500},42,[102,502,503],{"class":108},"# 创建日志目录和数据库目录\n",[102,505,507,509,511,513,516,518,521,524,527],{"class":104,"line":506},43,[102,508,179],{"class":121},[102,510,182],{"class":125},[102,512,186],{"class":185},[102,514,515],{"class":125}," /usr/src/app/prod-logs",[102,517,219],{"class":218},[102,519,520],{"class":121},"chmod",[102,522,523],{"class":185}," -R",[102,525,526],{"class":185}," 777",[102,528,529],{"class":125}," /usr/src/app/prod-logs\n",[102,531,533,535,537,539,542,544,546,548,550],{"class":104,"line":532},44,[102,534,179],{"class":121},[102,536,182],{"class":125},[102,538,186],{"class":185},[102,540,541],{"class":125}," /usr/src/app/db",[102,543,219],{"class":218},[102,545,520],{"class":121},[102,547,523],{"class":185},[102,549,526],{"class":185},[102,551,552],{"class":125}," /usr/src/app/db\n",[102,554,556],{"class":104,"line":555},45,[102,557,148],{"emptyLinePlaceholder":147},[102,559,561,563],{"class":104,"line":560},46,[102,562,356],{"class":121},[102,564,359],{"class":125},[102,566,568],{"class":104,"line":567},47,[102,569,570],{"class":108},"# run the app\n",[102,572,574,577],{"class":104,"line":573},48,[102,575,576],{"class":121},"USER",[102,578,579],{"class":125}," bun\n",[102,581,583,586],{"class":104,"line":582},49,[102,584,585],{"class":121},"EXPOSE",[102,587,588],{"class":125}," 4775/tcp\n",[102,590,592,595,598,601,604,607],{"class":104,"line":591},50,[102,593,594],{"class":121},"ENTRYPOINT",[102,596,597],{"class":218}," [ ",[102,599,600],{"class":125},"\"bun\",",[102,602,603],{"class":125}," \"run\",",[102,605,606],{"class":125}," \"index.js\"",[102,608,609],{"class":125}," ]\n",[14,611,612,613,615],{},"有几个",[18,614,87],{},"内需要注意的点：",[617,618,619,623,629,632],"ul",{},[620,621,622],"li",{},"如果你有env文件，记得也把env复制进去",[620,624,625,626],{},"如果你的日志等文件持久化了（放在了一个自定义的目录下），记得",[59,627,628],{},"分配读写权限",[620,630,631],{},"记得设置ENV NODE_ENV=xxx",[620,633,634],{},"分阶段构建不是必须的",[14,636,637,638,640,641,644],{},"另外，",[18,639,87],{},"中用到了",[18,642,643],{},"bun run build","这个命令",[14,646,647,648,651,652,655,656],{},"要注意，",[18,649,650],{},"bun build"," 需要指定 ",[18,653,654],{},"--target"," 为 ",[18,657,222],{},[93,659,663],{"className":660,"code":661,"language":662,"meta":98,"style":98},"language-json shiki shiki-themes github-light","\"scripts\": {\n    \"dev\": \"bun run --hot src/index.ts\",\n    \"build\": \"bun build src/index.ts --outdir out --target=bun\"\n  },\n","json",[18,664,665,673,687,697],{"__ignoreMap":98},[102,666,667,670],{"class":104,"line":105},[102,668,669],{"class":125},"\"scripts\"",[102,671,672],{"class":218},": {\n",[102,674,675,678,681,684],{"class":104,"line":112},[102,676,677],{"class":185},"    \"dev\"",[102,679,680],{"class":218},": ",[102,682,683],{"class":125},"\"bun run --hot src/index.ts\"",[102,685,686],{"class":218},",\n",[102,688,689,692,694],{"class":104,"line":118},[102,690,691],{"class":185},"    \"build\"",[102,693,680],{"class":218},[102,695,696],{"class":125},"\"bun build src/index.ts --outdir out --target=bun\"\n",[102,698,699],{"class":104,"line":135},[102,700,701],{"class":218},"  },\n",[14,703,704,705,707],{},"编写完",[18,706,87],{},"以及打包命令后，没必要去服务器验证，可以在本地验证。",[93,709,711],{"className":95,"code":710,"language":97,"meta":98,"style":98},"docker build ./ -t your_name --load\n",[18,712,713],{"__ignoreMap":98},[102,714,715,717,720,723,726,729],{"class":104,"line":105},[102,716,20],{"class":121},[102,718,719],{"class":125}," build",[102,721,722],{"class":125}," ./",[102,724,725],{"class":185}," -t",[102,727,728],{"class":125}," your_name",[102,730,731],{"class":185}," --load\n",[14,733,734,735,738],{},"打包后，直接在",[18,736,737],{},"docker desktop","中点击运行，输入你自定义的端口号、本地挂载路径等就可以了。",[14,740,741],{},"如果有错误的话，就直接在desktop看日志，解决完明显的问题后再往服务器上发。",[14,743,744,745,747],{},"但是如果很多类似：端口号、挂载地址、环境变量需要配置时，光在开始这一步就会感觉非常麻烦。所以还是配一个",[18,746,83],{},"比较方便",[30,749,751],{"id":750},"docker-compose","Docker Compose",[14,753,754,755,758],{},"小水管服务器最好还是不要在服务器上跑**",[18,756,757],{},"docker build","** ，真是很容易就卡死。",[14,760,761,762,764],{},"在项目根目录下新建",[18,763,750],{},"配置文件",[14,766,767],{},"docker-compose.prod.yml",[93,769,773],{"className":770,"code":771,"language":772,"meta":98,"style":98},"language-yaml shiki shiki-themes github-light","version: '3.8'\n# 正式服务器打包\nservices:\n  hono:\n    container_name: 'hono'\n    # 填写发布后的镜像\n    image: 'xxxxxxx'\n    ports:\n      - '4775:4775'\n    restart: on-failure\n    volumes:\n      - /home/db/hono:/usr/src/app/db\n      - /home/log/hono:/usr/src/app/prod-logs\n\n","yaml",[18,774,775,786,791,799,806,816,821,831,838,846,856,863,870],{"__ignoreMap":98},[102,776,777,781,783],{"class":104,"line":105},[102,778,780],{"class":779},"shJU0","version",[102,782,680],{"class":218},[102,784,785],{"class":125},"'3.8'\n",[102,787,788],{"class":104,"line":112},[102,789,790],{"class":108},"# 正式服务器打包\n",[102,792,793,796],{"class":104,"line":118},[102,794,795],{"class":779},"services",[102,797,798],{"class":218},":\n",[102,800,801,804],{"class":104,"line":135},[102,802,803],{"class":779},"  hono",[102,805,798],{"class":218},[102,807,808,811,813],{"class":104,"line":144},[102,809,810],{"class":779},"    container_name",[102,812,680],{"class":218},[102,814,815],{"class":125},"'hono'\n",[102,817,818],{"class":104,"line":151},[102,819,820],{"class":108},"    # 填写发布后的镜像\n",[102,822,823,826,828],{"class":104,"line":157},[102,824,825],{"class":779},"    image",[102,827,680],{"class":218},[102,829,830],{"class":125},"'xxxxxxx'\n",[102,832,833,836],{"class":104,"line":163},[102,834,835],{"class":779},"    ports",[102,837,798],{"class":218},[102,839,840,843],{"class":104,"line":176},[102,841,842],{"class":218},"      - ",[102,844,845],{"class":125},"'4775:4775'\n",[102,847,848,851,853],{"class":104,"line":192},[102,849,850],{"class":779},"    restart",[102,852,680],{"class":218},[102,854,855],{"class":125},"on-failure\n",[102,857,858,861],{"class":104,"line":207},[102,859,860],{"class":779},"    volumes",[102,862,798],{"class":218},[102,864,865,867],{"class":104,"line":231},[102,866,842],{"class":218},[102,868,869],{"class":125},"/home/db/hono:/usr/src/app/db\n",[102,871,872,874],{"class":104,"line":236},[102,873,842],{"class":218},[102,875,876],{"class":125},"/home/log/hono:/usr/src/app/prod-logs\n",[14,878,879],{},"在配置文件内写好所有的配置，很直观。",[14,881,882],{},"如果是在本地的话可以再新建一个",[14,884,885],{},"docker-compose.dev.yml",[93,887,889],{"className":770,"code":888,"language":772,"meta":98,"style":98},"version: '3.8'\n# 开发环境测试打包\nservices:\n  hono:\n    container_name: 'hono'\n    build:\n      context: ./\n      dockerfile: ./Dockerfile\n    ports:\n      - '4775:4775'\n    restart: on-failure\n    volumes:\n      - /Users/your_name/your_dir/databases/hono-db:/usr/src/app/db\n      - /Users/your_name/your_dir/databases/hono-logs:/usr/src/app/prod-logs\n\n",[18,890,891,899,904,910,916,924,931,941,951,957,963,971,977,984],{"__ignoreMap":98},[102,892,893,895,897],{"class":104,"line":105},[102,894,780],{"class":779},[102,896,680],{"class":218},[102,898,785],{"class":125},[102,900,901],{"class":104,"line":112},[102,902,903],{"class":108},"# 开发环境测试打包\n",[102,905,906,908],{"class":104,"line":118},[102,907,795],{"class":779},[102,909,798],{"class":218},[102,911,912,914],{"class":104,"line":135},[102,913,803],{"class":779},[102,915,798],{"class":218},[102,917,918,920,922],{"class":104,"line":144},[102,919,810],{"class":779},[102,921,680],{"class":218},[102,923,815],{"class":125},[102,925,926,929],{"class":104,"line":151},[102,927,928],{"class":779},"    build",[102,930,798],{"class":218},[102,932,933,936,938],{"class":104,"line":157},[102,934,935],{"class":779},"      context",[102,937,680],{"class":218},[102,939,940],{"class":125},"./\n",[102,942,943,946,948],{"class":104,"line":163},[102,944,945],{"class":779},"      dockerfile",[102,947,680],{"class":218},[102,949,950],{"class":125},"./Dockerfile\n",[102,952,953,955],{"class":104,"line":176},[102,954,835],{"class":779},[102,956,798],{"class":218},[102,958,959,961],{"class":104,"line":192},[102,960,842],{"class":218},[102,962,845],{"class":125},[102,964,965,967,969],{"class":104,"line":207},[102,966,850],{"class":779},[102,968,680],{"class":218},[102,970,855],{"class":125},[102,972,973,975],{"class":104,"line":231},[102,974,860],{"class":779},[102,976,798],{"class":218},[102,978,979,981],{"class":104,"line":236},[102,980,842],{"class":218},[102,982,983],{"class":125},"/Users/your_name/your_dir/databases/hono-db:/usr/src/app/db\n",[102,985,986,988],{"class":104,"line":242},[102,987,842],{"class":218},[102,989,990],{"class":125},"/Users/your_name/your_dir/databases/hono-logs:/usr/src/app/prod-logs\n",[14,992,993],{},"使用本地的dockerfile来打包验证",[93,995,997],{"className":95,"code":996,"language":97,"meta":98,"style":98},"docker-compose up\n",[18,998,999],{"__ignoreMap":98},[102,1000,1001,1003],{"class":104,"line":105},[102,1002,750],{"class":121},[102,1004,1005],{"class":125}," up\n",[14,1007,1008],{},"这样就不用重复敲很多配置了。",[14,1010,1011],{},"测试没问题，可以正常运行后，就可以去发布了",[30,1013,1014],{"id":1014},"发布到容器镜像服务",[14,1016,1017],{},"在各家的云服务商的后台，都可以找到各自的容器镜像服务。",[14,1019,1020,1021,1024,1025,1027],{},"因为",[18,1022,1023],{},"dockhub","被墙了，直接在大陆的服务器上是拉不下来",[18,1026,1023],{},"的镜像的，所以要想分版本的发布，就需要用云服务商自己的容器镜像服务。",[14,1029,1030],{},"以下以阿里云为例。",[14,1032,1033],{},[59,1034,1035],{},"登录",[93,1037,1039],{"className":95,"code":1038,"language":97,"meta":98,"style":98},"sudo docker login --username=\u003Cyour username> registry.cn-beijing.aliyuncs.com\n",[18,1040,1041],{"__ignoreMap":98},[102,1042,1043,1046,1049,1052,1055,1059,1062,1065,1068,1071],{"class":104,"line":105},[102,1044,1045],{"class":121},"sudo",[102,1047,1048],{"class":125}," docker",[102,1050,1051],{"class":125}," login",[102,1053,1054],{"class":185}," --username=",[102,1056,1058],{"class":1057},"sD7c4","\u003C",[102,1060,1061],{"class":185},"your",[102,1063,1064],{"class":125}," usernam",[102,1066,1067],{"class":218},"e",[102,1069,1070],{"class":1057},">",[102,1072,1073],{"class":125}," registry.cn-beijing.aliyuncs.com\n",[14,1075,1076],{},[59,1077,1078,1079,1082],{},"注意：后面的地址",[18,1080,1081],{},"registry.cn-beijing.aliyuncs.com","，可以在你的阿里云后台找到",[14,1084,1085],{},[59,1086,1087],{},"打包",[14,1089,1090,1091,1094,1095,1098,1099,1101],{},"打包的时候也有一个坑，就是要注意服务器的",[18,1092,1093],{},"platform","，在本地打包和push前就要加上参数。 比如我这里是",[18,1096,1097],{},"linux/amd64","。（你可以先不管，等在服务器上运行时，会提示你报错信息，然后再根据提示加上",[18,1100,1093],{},"参数重新打包发布也可以。）",[93,1103,1105],{"className":95,"code":1104,"language":97,"meta":98,"style":98},"docker buildx build ./ -t your_name --load --platform linux/amd64 (对应阿里云ubuntu服务器)\n",[18,1106,1107],{"__ignoreMap":98},[102,1108,1109,1111,1114,1116,1118,1120,1122,1125,1128,1131],{"class":104,"line":105},[102,1110,20],{"class":121},[102,1112,1113],{"class":125}," buildx",[102,1115,719],{"class":125},[102,1117,722],{"class":125},[102,1119,725],{"class":185},[102,1121,728],{"class":125},[102,1123,1124],{"class":185}," --load",[102,1126,1127],{"class":185}," --platform",[102,1129,1130],{"class":125}," linux/amd64",[102,1132,1133],{"class":218}," (对应阿里云ubuntu服务器)\n",[14,1135,1136],{},[59,1137,1138],{},"打Tag",[14,1140,1141,1142],{},"打标签前，需要在阿里云控制台里，先创建好自己的命名空间，假设我这里是",[18,1143,1144],{},"zzstudio1",[93,1146,1148],{"className":95,"code":1147,"language":97,"meta":98,"style":98},"docker tag memoz registry.cn-beijing.aliyuncs.com/zzstudi1/your_name:latest\n",[18,1149,1150],{"__ignoreMap":98},[102,1151,1152,1154,1157,1160],{"class":104,"line":105},[102,1153,20],{"class":121},[102,1155,1156],{"class":125}," tag",[102,1158,1159],{"class":125}," memoz",[102,1161,1162],{"class":125}," registry.cn-beijing.aliyuncs.com/zzstudi1/your_name:latest\n",[14,1164,1165],{},[59,1166,1167],{},"发布",[93,1169,1171],{"className":95,"code":1170,"language":97,"meta":98,"style":98},"docker push --platform linux/amd64 registry.cn-beijing.aliyuncs.com/zzstudi1/your_name:latest\n",[18,1172,1173],{"__ignoreMap":98},[102,1174,1175,1177,1180,1182,1184],{"class":104,"line":105},[102,1176,20],{"class":121},[102,1178,1179],{"class":125}," push",[102,1181,1127],{"class":185},[102,1183,1130],{"class":125},[102,1185,1162],{"class":125},[14,1187,1188],{},[1189,1190,1191],"em",{},"此时本地操作已经完成，登录到云服务器再去拉取和运行发布好的镜像",[14,1193,1194],{},"不得不说，有墙是真难受，万一有网络问题，还容易卡住。",[14,1196,1197,1198,1200,1201,1204],{},"发布成功后，再去回头看我们",[18,1199,767],{},"的配置的",[18,1202,1203],{},"image","，就是此时发布的镜像了。",[14,1206,1207,1208,1210],{},"只要这个",[18,1209,767],{},"文件在服务器上，就可以运行起来了。后续如果需要更新，则需要在本地重复上述的，打包、打Tag、发布流程",[14,1212,1213],{},"然后在服务器重启即可",[93,1215,1217],{"className":95,"code":1216,"language":97,"meta":98,"style":98},"# 先停止\ndocker-compose down \ndocker-compose up --build -d\n",[18,1218,1219,1224,1234],{"__ignoreMap":98},[102,1220,1221],{"class":104,"line":105},[102,1222,1223],{"class":108},"# 先停止\n",[102,1225,1226,1228,1231],{"class":104,"line":112},[102,1227,750],{"class":121},[102,1229,1230],{"class":125}," down",[102,1232,1233],{"class":218}," \n",[102,1235,1236,1238,1241,1244],{"class":104,"line":118},[102,1237,750],{"class":121},[102,1239,1240],{"class":125}," up",[102,1242,1243],{"class":185}," --build",[102,1245,1246],{"class":185}," -d\n",[14,1248,1249,1250,1252,1253,1256,1257,1256,1260,1263,1264,1271],{},"注意：",[18,1251,83],{},"是可以管理多个镜像的，如果你要同时使用",[18,1254,1255],{},"redis","、",[18,1258,1259],{},"mysql",[18,1261,1262],{},"nginx","等，都可以统一管理，详细使用可以看我这篇**",[1265,1266,1270],"a",{"href":1267,"rel":1268},"https://mp.weixin.qq.com/s/UNxFJvZNrZyCnDKFQyApsQ",[1269],"nofollow","《使用Docker Compose部署Nest应用》","**，里面有详细的配置说明",[30,1273,1274],{"id":1274},"小结一下",[1276,1277,1278],"blockquote",{},[1279,1280,1281],"ol",{},[620,1282,1283,1284,1287,1288,1290,1291],{},"配置",[18,1285,1286],{},"package.json","中的",[18,1289,45],{},"命令，注意",[18,1292,1293],{},"--taget=bun",[1279,1295,1296,1302,1311,1318],{},[620,1297,1298,1299,1301],{},"参考bun官方示例，编写",[18,1300,88],{},"，构建，然后把项目打上版本号，打包发布到指定平台",[620,1303,1304,1305,1307,1308,1310],{},"服务器上只装",[18,1306,20],{},"，服务都使用",[18,1309,20],{},"运行",[620,1312,1313,1314,1317],{},"编写多个",[18,1315,1316],{},"docker-compose.*.yml","文件，配置不同环境的策略，拉取指定平台指定版本的镜像",[620,1319,1320,1321,1323],{},"后续使用",[18,1322,83],{},"命令进行更新和重新运行",[14,1325,1326],{},"再来看一下pm2部署有什么不同",[30,1328,1330],{"id":1329},"pm2部署","PM2部署",[14,1332,1333,1334,1336,1337,1256,1340,1256,1343,1346,1347,1349],{},"使用",[18,1335,24],{},"运行项目，需要在服务器安装相应的环境（",[18,1338,1339],{},"Bun",[18,1341,1342],{},"Pm2",[18,1344,1345],{},"Git","），后续有其他服务也使用",[18,1348,24],{},"进行管理就可以了。",[14,1351,1352],{},"就是不像docker似的，环境隔离起来，换服务器方便一些。",[14,1354,1355,1356,1358,1359,1361],{},"但是国内这个环境其实用",[18,1357,20],{},"还麻烦一些，如果能一股脑丝滑的发步到",[18,1360,64],{},"上就会轻松很多。",[14,1363,1364,1365,1367,1368,1371,1372,1375,1376,1379],{},"所以我一般如果选择了",[18,1366,24],{},"部署，就相当于在服务器上安装了一圈环境（包括",[18,1369,1370],{},"Nginx","），配置过一遍后，后续使用",[18,1373,1374],{},"git","提交代码，提交代码后再通过",[18,1377,1378],{},"ssh","在服务器打包和重启一下对应服务。",[14,1381,1382,1383,1386],{},"以下是一些基本命令，安装node、bun、nginx等，且只在",[18,1384,1385],{},"Ubuntu","验证过。",[14,1388,1389],{},"安装node20.x版本",[93,1391,1393],{"className":95,"code":1392,"language":97,"meta":98,"style":98},"curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh\nsudo bash nodesource_setup.sh\n",[18,1394,1395,1400],{"__ignoreMap":98},[102,1396,1397],{"class":104,"line":105},[102,1398,1399],{"class":121},"curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh\n",[102,1401,1402],{"class":104,"line":112},[102,1403,1404],{"class":121},"sudo bash nodesource_setup.sh\n",[14,1406,1407],{},"使用apt安装",[93,1409,1411],{"className":95,"code":1410,"language":97,"meta":98,"style":98},"sudo apt install nodejs\n",[18,1412,1413],{"__ignoreMap":98},[102,1414,1415],{"class":104,"line":105},[102,1416,1410],{"class":121},[14,1418,1419],{},"安装完成后验证",[93,1421,1423],{"className":95,"code":1422,"language":97,"meta":98,"style":98},"node -v\nnpm -v\n",[18,1424,1425,1433],{"__ignoreMap":98},[102,1426,1427,1430],{"class":104,"line":105},[102,1428,1429],{"class":121},"node",[102,1431,1432],{"class":185}," -v\n",[102,1434,1435,1438],{"class":104,"line":112},[102,1436,1437],{"class":121},"npm",[102,1439,1432],{"class":185},[14,1441,1442,1443,1445,1446],{},"安装",[18,1444,222],{},"，先安装",[18,1447,1448],{},"unzip",[93,1450,1452],{"className":95,"code":1451,"language":97,"meta":98,"style":98},"sudo apt install unzip\n",[18,1453,1454],{"__ignoreMap":98},[102,1455,1456,1458,1461,1463],{"class":104,"line":105},[102,1457,1045],{"class":121},[102,1459,1460],{"class":125}," apt",[102,1462,225],{"class":125},[102,1464,1465],{"class":125}," unzip\n",[14,1467,1468,1469],{},"再安装",[18,1470,222],{},[93,1472,1474],{"className":95,"code":1473,"language":97,"meta":98,"style":98},"curl -fsSL https://bun.sh/install | bash\n",[18,1475,1476],{"__ignoreMap":98},[102,1477,1478,1481,1484,1487,1490],{"class":104,"line":105},[102,1479,1480],{"class":121},"curl",[102,1482,1483],{"class":185}," -fsSL",[102,1485,1486],{"class":125}," https://bun.sh/install",[102,1488,1489],{"class":1057}," |",[102,1491,1492],{"class":121}," bash\n",[14,1494,1495],{},"设置国内镜像",[93,1497,1499],{"className":95,"code":1498,"language":97,"meta":98,"style":98},"npm config set registry https://registry.npmmirror.com/\n",[18,1500,1501],{"__ignoreMap":98},[102,1502,1503,1505,1508,1511,1514],{"class":104,"line":105},[102,1504,1437],{"class":121},[102,1506,1507],{"class":125}," config",[102,1509,1510],{"class":125}," set",[102,1512,1513],{"class":125}," registry",[102,1515,1516],{"class":125}," https://registry.npmmirror.com/\n",[14,1518,1519],{},"安装PM2",[93,1521,1523],{"className":95,"code":1522,"language":97,"meta":98,"style":98},"npm install pm2@latest -g\n",[18,1524,1525],{"__ignoreMap":98},[102,1526,1527,1529,1531,1534],{"class":104,"line":105},[102,1528,1437],{"class":121},[102,1530,225],{"class":125},[102,1532,1533],{"class":125}," pm2@latest",[102,1535,1536],{"class":185}," -g\n",[14,1538,1333,1539,1542],{},[18,1540,1541],{},"ecosystem.config.js"," （在项目根目录下新建）（内容非常简单，在官网复制就可以）",[93,1544,1546],{"className":95,"code":1545,"language":97,"meta":98,"style":98},"pm2 start ecosystem.config.js\n\npm2 stop ecosystem.config.js\n\npm2 reload ecosystem.config.js\n\npm2 restart ecosystem.config.js\n\npm2 delete ecosystem.config.js\n\n\n",[18,1547,1548,1558,1562,1571,1575,1584,1588,1597,1601],{"__ignoreMap":98},[102,1549,1550,1552,1555],{"class":104,"line":105},[102,1551,24],{"class":121},[102,1553,1554],{"class":125}," start",[102,1556,1557],{"class":125}," ecosystem.config.js\n",[102,1559,1560],{"class":104,"line":112},[102,1561,148],{"emptyLinePlaceholder":147},[102,1563,1564,1566,1569],{"class":104,"line":118},[102,1565,24],{"class":121},[102,1567,1568],{"class":125}," stop",[102,1570,1557],{"class":125},[102,1572,1573],{"class":104,"line":135},[102,1574,148],{"emptyLinePlaceholder":147},[102,1576,1577,1579,1582],{"class":104,"line":144},[102,1578,24],{"class":121},[102,1580,1581],{"class":125}," reload",[102,1583,1557],{"class":125},[102,1585,1586],{"class":104,"line":151},[102,1587,148],{"emptyLinePlaceholder":147},[102,1589,1590,1592,1595],{"class":104,"line":157},[102,1591,24],{"class":121},[102,1593,1594],{"class":125}," restart",[102,1596,1557],{"class":125},[102,1598,1599],{"class":104,"line":163},[102,1600,148],{"emptyLinePlaceholder":147},[102,1602,1603,1605,1608],{"class":104,"line":176},[102,1604,24],{"class":121},[102,1606,1607],{"class":125}," delete",[102,1609,1557],{"class":125},[14,1611,1612],{},"安装Nginx",[93,1614,1616],{"className":95,"code":1615,"language":97,"meta":98,"style":98},"sudo apt install nginx\n\nsystemctl status nginx\nsystemctl start nginx\n",[18,1617,1618,1629,1633,1643],{"__ignoreMap":98},[102,1619,1620,1622,1624,1626],{"class":104,"line":105},[102,1621,1045],{"class":121},[102,1623,1460],{"class":125},[102,1625,225],{"class":125},[102,1627,1628],{"class":125}," nginx\n",[102,1630,1631],{"class":104,"line":112},[102,1632,148],{"emptyLinePlaceholder":147},[102,1634,1635,1638,1641],{"class":104,"line":118},[102,1636,1637],{"class":121},"systemctl",[102,1639,1640],{"class":125}," status",[102,1642,1628],{"class":125},[102,1644,1645,1647,1649],{"class":104,"line":135},[102,1646,1637],{"class":121},[102,1648,1554],{"class":125},[102,1650,1628],{"class":125},[14,1652,1653],{},"配置防火墙",[93,1655,1657],{"className":95,"code":1656,"language":97,"meta":98,"style":98},"sudo ufw allow 'Nginx HTTP'\nsudo ufw allow 'Nginx HTTPS'\n",[18,1658,1659,1672],{"__ignoreMap":98},[102,1660,1661,1663,1666,1669],{"class":104,"line":105},[102,1662,1045],{"class":121},[102,1664,1665],{"class":125}," ufw",[102,1667,1668],{"class":125}," allow",[102,1670,1671],{"class":125}," 'Nginx HTTP'\n",[102,1673,1674,1676,1678,1680],{"class":104,"line":112},[102,1675,1045],{"class":121},[102,1677,1665],{"class":125},[102,1679,1668],{"class":125},[102,1681,1682],{"class":125}," 'Nginx HTTPS'\n",[14,1684,1685,1686],{},"主配置文件：",[18,1687,1688],{},"/etc/nginx/nginx.conf",[14,1690,1691,1692,1695,1696],{},"站点配置文件目录：",[59,1693,1694],{},"/etc/nginx/sites-available"," 和 ",[59,1697,1698],{},"/etc/nginx/sites-enabled",[14,1700,1701],{},"测试nginx配置",[93,1703,1705],{"className":95,"code":1704,"language":97,"meta":98,"style":98},"sudo nginx -t\n",[18,1706,1707],{"__ignoreMap":98},[102,1708,1709,1711,1714],{"class":104,"line":105},[102,1710,1045],{"class":121},[102,1712,1713],{"class":125}," nginx",[102,1715,1716],{"class":185}," -t\n",[14,1718,1719],{},"重启nginx",[93,1721,1723],{"className":95,"code":1722,"language":97,"meta":98,"style":98},"sudo systemctl reload nginx\n",[18,1724,1725],{"__ignoreMap":98},[102,1726,1727,1729,1732,1734],{"class":104,"line":105},[102,1728,1045],{"class":121},[102,1730,1731],{"class":125}," systemctl",[102,1733,1581],{"class":125},[102,1735,1628],{"class":125},[14,1737,1738,1739,1742,1743,1746],{},"关于",[59,1740,1741],{},"git建裸库","，大家可以自行搜索相关文章，我也是按之前搜出来的一篇文章来建的，如果有懒得搜的，也可以直接",[59,1744,1745],{},"私信","我要教程。",[14,1748,1749],{},[59,1750,1751],{},"最终，你的服务器上的项目文件夹内要具备：",[617,1753,1754,1757,1763,1769],{},[620,1755,1756],{},"node_modules 是的，后端项目不同于前端，也是需要node_modules才能正常运行的",[620,1758,1759,1760],{},"package.json 用于",[59,1761,1762],{},"安装和更新node_modules",[620,1764,1765,1768],{},[18,1766,1767],{},"env","文件环境变量配置",[620,1770,1771],{},"打包且压缩后的JS文件/文件夹，如：server/index.js",[14,1773,1774],{},"此时在你的服务器环境下运行就可以了",[93,1776,1780],{"className":1777,"code":1778,"language":1779,"meta":98,"style":98},"language-typescript shiki shiki-themes github-light","pm2 start ecosystem.config.js\n","typescript",[18,1781,1782],{"__ignoreMap":98},[102,1783,1784],{"class":104,"line":105},[102,1785,1778],{"class":218},[14,1787,1788,1789,1792],{},"而关于重启、多实例运行等都在一个",[18,1790,1791],{},"config.js","里配置",[14,1794,1795],{},[59,1796,1797],{},"启动后，验证项目是否可以被正常请求，数据库读写是否正常，日常是否在正常记录就可以了",[30,1799,1800],{"id":1800},"总结",[14,1802,1803],{},[59,1804,1805],{},"对于我来说，选择其中一种方式部署，意味着后续其他服务都用这一种方式进行部署。",[14,1807,1808,1809,1811,1812,1814,1815,1817],{},"如果使用了",[18,1810,20],{},"，那我只在服务器上把",[18,1813,20],{},"装好，所有服务都通过",[18,1816,20],{},"来打包、分版本、发布、拉取、运行、重启。",[14,1819,1808,1820,1822,1823,1256,1826,1256,1828,1256,1830,1256,1832,1834,1835,1837,1838,1841],{},[18,1821,24],{},"，我会在服务器上直接装一遍",[18,1824,1825],{},"Node",[18,1827,1339],{},[18,1829,1345],{},[18,1831,1370],{},[18,1833,24],{},"，后续通过",[18,1836,1374],{},"管理代码，通过",[18,1839,1840],{},"git tag/branch","或是代码内管理版本，ssh工具在服务器打包代码pm2来运行和重启。",[14,1843,1844,1845,1256,1848,1851,1852,1855],{},"当然有很多其他运维工具",[18,1846,1847],{},"gitea",[18,1849,1850],{},"jenkins","等等，我看过后感觉都不太适合我这种",[59,1853,1854],{},"处于探索而非运营阶段","的小水管服务器折腾。",[14,1857,1858],{},"如果真的有业务，着急搭建，我觉得花点钱找个靠谱的人弄都行，不用费这种心。",[14,1860,1861],{},"以上就是全部内容啦👏👏",[1863,1864,1865],"style",{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}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 pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .shJU0, html code.shiki .shJU0{--shiki-default:#22863A}",{"title":98,"searchDepth":112,"depth":112,"links":1867},[1868,1869,1870,1871,1872,1873,1874],{"id":32,"depth":112,"text":33},{"id":87,"depth":112,"text":88},{"id":750,"depth":112,"text":751},{"id":1014,"depth":112,"text":1014},{"id":1274,"depth":112,"text":1274},{"id":1329,"depth":112,"text":1330},{"id":1800,"depth":112,"text":1800},"2025-02-10T00:00:00.000Z","md","2025-05-15T00:00:00.000Z",{},"/post/hono/hono-docker-pm2","---\ntitle: 【Hono】部署篇 Docker+pm2部署\ndate: 2025-02-10\nlastmod: 2025-05-15\ntags: [\"Hono\"]\nversions: [\"hono@4.5.11\"]\nshowTitle: 【Hono】部署篇 Docker+pm2部署\n---\n\u003Cbr />\n\n项目开发完后，要部署到服务器上才能正常使用，这里我分享一下`docker`和`pm2`两种方式的部署。\n\n以下经验来自于\\*\\*我日常的折腾中，适合入门，非企业级操作。\\*\\*仅用于分享！\n\n## Docker部署\n\n用`docker`的话，也算有两种运行方式。\n\n先在本地`build`，然后打`tag`，然后`push`上去。\n\n把包**发布到`dockerhub`或你的对应的云服务商的容器镜像服务**上（比如阿里云）后\n\n一种是使用`docker run` 附带一些参数进行启动\n\n另一种使用`docker-compose.yml`配置参数，用`docker compose`命令重新拉取最新的镜像并重启。\n\n## Dockerfile\n\n这个dockerfile来自Bun的官方，然后我又加了一些自己的需求，可以做一下参考\n\n```shell\n# use the official Bun image\n# see all versions at https://hub.docker.com/r/oven/bun/tags\nFROM oven/bun:1 AS base\nWORKDIR /usr/src/app\n\n# install dependencies into temp directory\n# this will cache them and speed up future builds\nFROM base AS install\nRUN mkdir -p /temp/dev\nCOPY package.json bun.lockb /temp/dev/\nRUN cd /temp/dev && bun install --frozen-lockfile\n\n# install with --production (exclude devDependencies)\nRUN mkdir -p /temp/prod\nCOPY package.json bun.lockb /temp/prod/\nRUN cd /temp/prod && bun install --frozen-lockfile --production\n\n# copy node_modules from temp directory\n# then copy all (non-ignored) project files into the image\nFROM base AS prerelease\nCOPY --from=install /temp/dev/node_modules node_modules\nCOPY . .\n\n# [optional] tests & build\nENV NODE_ENV=production\n# RUN bun test\nRUN bun run build\n\n# copy production dependencies and source code into final image\nFROM base AS release\n\n# 一个后端node/bun服务运行,必须需要node_modules\n# 以及打包后的入口\n# 如果存在环境变量配置, 还需要复制环境变量配置文件\nCOPY --from=install /temp/prod/node_modules node_modules\nCOPY --from=prerelease /usr/src/app/out/index.js .\nCOPY --from=prerelease /usr/src/app/package.json .\nCOPY --from=prerelease /usr/src/app/.env .\nCOPY --from=prerelease /usr/src/app/.env.production .\n\n# 此处是为了把日志和数据库持久化, 方便备份和查看\n# 创建日志目录和数据库目录\nRUN mkdir -p /usr/src/app/prod-logs && chmod -R 777 /usr/src/app/prod-logs\nRUN mkdir -p /usr/src/app/db && chmod -R 777 /usr/src/app/db\n\nENV NODE_ENV=production\n# run the app\nUSER bun\nEXPOSE 4775/tcp\nENTRYPOINT [ \"bun\", \"run\", \"index.js\" ]\n```\n\n有几个`dockerfile`内需要注意的点：\n\n* 如果你有env文件，记得也把env复制进去\n\n* 如果你的日志等文件持久化了（放在了一个自定义的目录下），记得**分配读写权限**\n\n* 记得设置ENV NODE\\_ENV=xxx\n\n* 分阶段构建不是必须的\n\n另外，`dockerfile`中用到了`bun run build`这个命令\n\n要注意，`bun build` 需要指定 `--target` 为 `bun`\n\n```json\n\"scripts\": {\n    \"dev\": \"bun run --hot src/index.ts\",\n    \"build\": \"bun build src/index.ts --outdir out --target=bun\"\n  },\n```\n\n编写完`dockerfile`以及打包命令后，没必要去服务器验证，可以在本地验证。\n\n```shell\ndocker build ./ -t your_name --load\n```\n\n打包后，直接在`docker desktop`中点击运行，输入你自定义的端口号、本地挂载路径等就可以了。\n\n如果有错误的话，就直接在desktop看日志，解决完明显的问题后再往服务器上发。\n\n但是如果很多类似：端口号、挂载地址、环境变量需要配置时，光在开始这一步就会感觉非常麻烦。所以还是配一个`docker compose`比较方便\n\n## Docker Compose\n\n小水管服务器最好还是不要在服务器上跑\\*\\*`docker build`\\*\\* ，真是很容易就卡死。\n\n在项目根目录下新建`docker-compose`配置文件\n\ndocker-compose.prod.yml\n\n```yaml\nversion: '3.8'\n# 正式服务器打包\nservices:\n  hono:\n    container_name: 'hono'\n    # 填写发布后的镜像\n    image: 'xxxxxxx'\n    ports:\n      - '4775:4775'\n    restart: on-failure\n    volumes:\n      - /home/db/hono:/usr/src/app/db\n      - /home/log/hono:/usr/src/app/prod-logs\n\n```\n\n在配置文件内写好所有的配置，很直观。\n\n如果是在本地的话可以再新建一个\n\ndocker-compose.dev.yml\n\n```yaml\nversion: '3.8'\n# 开发环境测试打包\nservices:\n  hono:\n    container_name: 'hono'\n    build:\n      context: ./\n      dockerfile: ./Dockerfile\n    ports:\n      - '4775:4775'\n    restart: on-failure\n    volumes:\n      - /Users/your_name/your_dir/databases/hono-db:/usr/src/app/db\n      - /Users/your_name/your_dir/databases/hono-logs:/usr/src/app/prod-logs\n\n```\n\n使用本地的dockerfile来打包验证\n\n```shell\ndocker-compose up\n```\n\n这样就不用重复敲很多配置了。\n\n测试没问题，可以正常运行后，就可以去发布了\n\n## 发布到容器镜像服务\n\n在各家的云服务商的后台，都可以找到各自的容器镜像服务。\n\n因为`dockhub`被墙了，直接在大陆的服务器上是拉不下来`dockhub`的镜像的，所以要想分版本的发布，就需要用云服务商自己的容器镜像服务。\n\n以下以阿里云为例。\n\n**登录**\n\n```shell\nsudo docker login --username=\u003Cyour username> registry.cn-beijing.aliyuncs.com\n```\n\n**注意：后面的地址`registry.cn-beijing.aliyuncs.com`，可以在你的阿里云后台找到**\n\n**打包**\n\n打包的时候也有一个坑，就是要注意服务器的`platform`，在本地打包和push前就要加上参数。 比如我这里是`linux/amd64`。（你可以先不管，等在服务器上运行时，会提示你报错信息，然后再根据提示加上`platform`参数重新打包发布也可以。）\n\n```shell\ndocker buildx build ./ -t your_name --load --platform linux/amd64 (对应阿里云ubuntu服务器)\n```\n\n**打Tag**\n\n打标签前，需要在阿里云控制台里，先创建好自己的命名空间，假设我这里是`zzstudio1`\n\n```shell\ndocker tag memoz registry.cn-beijing.aliyuncs.com/zzstudi1/your_name:latest\n```\n\n**发布**\n\n```shell\ndocker push --platform linux/amd64 registry.cn-beijing.aliyuncs.com/zzstudi1/your_name:latest\n```\n\n*此时本地操作已经完成，登录到云服务器再去拉取和运行发布好的镜像*\n\n不得不说，有墙是真难受，万一有网络问题，还容易卡住。\n\n发布成功后，再去回头看我们`docker-compose.prod.yml`的配置的`image`，就是此时发布的镜像了。\n\n只要这个`docker-compose.prod.yml`文件在服务器上，就可以运行起来了。后续如果需要更新，则需要在本地重复上述的，打包、打Tag、发布流程\n\n然后在服务器重启即可\n\n```shell\n# 先停止\ndocker-compose down \ndocker-compose up --build -d\n```\n\n注意：`docker compose`是可以管理多个镜像的，如果你要同时使用`redis`、`mysql`、`nginx`等，都可以统一管理，详细使用可以看我这篇\\*\\*[《使用Docker Compose部署Nest应用》](https://mp.weixin.qq.com/s/UNxFJvZNrZyCnDKFQyApsQ)\\*\\*，里面有详细的配置说明\n\n## 小结一下\n\n> 1. 配置`package.json`中的`build`命令，注意`--taget=bun`\n\n1. 参考bun官方示例，编写`Dockerfile`，构建，然后把项目打上版本号，打包发布到指定平台\n2. 服务器上只装`docker`，服务都使用`docker`运行\n3. 编写多个`docker-compose.*.yml`文件，配置不同环境的策略，拉取指定平台指定版本的镜像\n4. 后续使用`docker compose`命令进行更新和重新运行\n\n再来看一下pm2部署有什么不同\n\n## PM2部署\n\n使用`pm2`运行项目，需要在服务器安装相应的环境（`Bun`、`Pm2`、`Git`），后续有其他服务也使用`pm2`进行管理就可以了。\n\n就是不像docker似的，环境隔离起来，换服务器方便一些。\n\n但是国内这个环境其实用`docker`还麻烦一些，如果能一股脑丝滑的发步到`dockerhub`上就会轻松很多。\n\n所以我一般如果选择了`pm2`部署，就相当于在服务器上安装了一圈环境（包括`Nginx`），配置过一遍后，后续使用`git`提交代码，提交代码后再通过`ssh`在服务器打包和重启一下对应服务。\n\n以下是一些基本命令，安装node、bun、nginx等，且只在`Ubuntu`验证过。\n\n安装node20.x版本\n\n```shell\ncurl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh\nsudo bash nodesource_setup.sh\n```\n\n使用apt安装\n\n```shell\nsudo apt install nodejs\n```\n\n安装完成后验证\n\n```shell\nnode -v\nnpm -v\n```\n\n安装`bun`，先安装`unzip`\n\n```shell\nsudo apt install unzip\n```\n\n再安装`bun`\n\n```shell\ncurl -fsSL https://bun.sh/install | bash\n```\n\n设置国内镜像\n\n```shell\nnpm config set registry https://registry.npmmirror.com/\n```\n\n安装PM2\n\n```shell\nnpm install pm2@latest -g\n```\n\n使用`ecosystem.config.js` （在项目根目录下新建）（内容非常简单，在官网复制就可以）\n\n```shell\npm2 start ecosystem.config.js\n\npm2 stop ecosystem.config.js\n\npm2 reload ecosystem.config.js\n\npm2 restart ecosystem.config.js\n\npm2 delete ecosystem.config.js\n\n\n```\n\n安装Nginx\n\n```shell\nsudo apt install nginx\n\nsystemctl status nginx\nsystemctl start nginx\n```\n\n配置防火墙\n\n```shell\nsudo ufw allow 'Nginx HTTP'\nsudo ufw allow 'Nginx HTTPS'\n```\n\n主配置文件：`/etc/nginx/nginx.conf`\n\n站点配置文件目录：**/etc/nginx/sites-available** 和 **/etc/nginx/sites-enabled**\n\n测试nginx配置\n\n```shell\nsudo nginx -t\n```\n\n重启nginx\n\n```shell\nsudo systemctl reload nginx\n```\n\n关于**git建裸库**，大家可以自行搜索相关文章，我也是按之前搜出来的一篇文章来建的，如果有懒得搜的，也可以直接**私信**我要教程。\n\n**最终，你的服务器上的项目文件夹内要具备：**\n\n* node\\_modules 是的，后端项目不同于前端，也是需要node\\_modules才能正常运行的\n\n* package.json 用于**安装和更新node\\_modules**\n\n* `env`文件环境变量配置\n\n* 打包且压缩后的JS文件/文件夹，如：server/index.js\n\n此时在你的服务器环境下运行就可以了\n\n```typescript\npm2 start ecosystem.config.js\n```\n\n而关于重启、多实例运行等都在一个`config.js`里配置\n\n**启动后，验证项目是否可以被正常请求，数据库读写是否正常，日常是否在正常记录就可以了**\n\n## 总结\n\n**对于我来说，选择其中一种方式部署，意味着后续其他服务都用这一种方式进行部署。**\n\n如果使用了`docker`，那我只在服务器上把`docker`装好，所有服务都通过`docker`来打包、分版本、发布、拉取、运行、重启。\n\n如果使用了`pm2`，我会在服务器上直接装一遍`Node`、`Bun`、`Git`、`Nginx`、`pm2`，后续通过`git`管理代码，通过`git tag/branch`或是代码内管理版本，ssh工具在服务器打包代码pm2来运行和重启。\n\n当然有很多其他运维工具`gitea`、`jenkins`等等，我看过后感觉都不太适合我这种**处于探索而非运营阶段**的小水管服务器折腾。\n\n如果真的有业务，着急搭建，我觉得花点钱找个靠谱的人弄都行，不用费这种心。\n\n以上就是全部内容啦👏👏\n",{"title":5,"description":98},"post/Hono/hono-docker-pm2",[1884],"Hono",[1886],"hono@4.5.11","VCIM4xY0xivWlb5fCXR-_KaAhnL0-2j6hAe-jxeviL4",[1889,1893],{"title":1890,"path":1891,"stem":1892},"OpenClaw 安装入门（Windows）","/post/zzao/openclaw/openclaw-install-windows","post/zzao/openclaw/openclaw-install-windows",{"title":1894,"path":1895,"stem":1896},"假设你是AI，你的Skill应该是什么样的","/post/zzao/ai-skill-structure","post/zzao/ai-skill-structure",1779005086183]