切換語言為:簡體
用Docker快速部署pm2和nuxt前端專案

用Docker快速部署pm2和nuxt前端專案

  • 爱糖宝
  • 2024-06-15
  • 2127
  • 0
  • 0

背景

之前做專案一直使用單頁應用方式部署前端,是時候遷移到服務端渲染框架了

今天不討論怎麼寫SSR程式碼,透過幾種服務端渲染方案比較,我還是傾向使用成熟框架nuxt

今天我們討論下,怎麼使用nuxt快速部署,要解決下面幾個問題:

  • nuxt專案打包後使用nodejs監聽http服務,動態渲染html頁面,使用pm2執行nodejs服務端,這裏放到docker容器裡面,可以單節點獲取叢集模式

  • 前端介面轉發到後端需要nginx,上面pm2已經有容器了,那nginx另外開一個容器嗎,我渲染把pm2和nginx放到一個容器裡面執行

  • 需要一個容器,要求是已經安裝好 pm2 \ nginx \ pnpm 軟體包

  • docker容器執行多個程式,這裏是pm2和nginx,需要透過shell指令碼啟動,並且最後一個應用需要駐留前臺,否則容器會直接退出

原始碼 https://gitee.com/rootegg/nuxtweb,使用效果看最後一章驗證

認識 nuxt

新建專案

pnpm dlx nuxi@latest init <project-name>

打包

pnpm run build

如下圖,build 之後生成 .output 目錄,測試初始化專案生成後能正常構建

用Docker快速部署pm2和nuxt前端專案

思路

上面已經看到 .output 目錄下有 server 和 public , 我沒用 pnpm做包管理器,pm2執行server下nodejs服務端,用nginx做pm2和後端介面轉發,將nginx的80埠拋出去

  • 第一步我們需要一個乾淨的docker容器,裡面已經安裝好 pnpm \ pm2 \ nginx

  • 第二步編寫shell啟動指令碼同時啟動nginx和pm2

  • 第三步複製 .output 打包後內容到容器中,分別執行 pm2 和 nginx

構建乾淨容器

所有的容器都需要來源一個初始容器,這裏我們選擇 alpine:3.19,上海時區,最終我已經構建好一個容器裡面包含 nodepnpmyarn, pm2, python3, nginx

/app # node -v
v20.12.2
/app # npm -v
10.5.0
/app # yarn -v
1.22.19
/app # pnpm -v
9.3.0
/app # pm2 -v
5.3.1
/app # python -V
Python 3.11.9
/app # nginx -v
nginx version: nginx/1.24.0
/app #

公開的可以直接用容器地址:

ccr.ccs.tencentyun.com/rootegg/node:21.7.3-pm2-nginx-alpine

Dockerfile檔案很長,具體可以看 gitee.com/rootegg/cic…

編寫shell啟動指令碼

我們知道在Dockerfile裡面CMD和ENTRYPOINT可以作為啟動命令,啟動需要的應用程式,比如

比如啟動nginx

FROM nginx

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

CMD中寫的 nginx -g daemon off;,意思就是啟動nginx容器,並 -g daemon off; 保留在前臺不退出,否則容器會關閉

比如啟動pm2

# 基礎映象用的我已經封裝好的node映象
FROM ccr.ccs.tencentyun.com/rootegg/node:21.7.3-alpine
LABEL description="from ccr.ccs.tencentyun.com/rootegg/node:21.7.3-alpine, extend python3 pm2"

# 安裝python3,因為pm2需要python,並用阿里雲映象
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk add --update --no-cache curl make gcc jq py3-configobj py3-pip py3-setuptools python3 python3-dev ca-certificates g++

# 安裝 pm2
RUN npm install pm2 -g

# 丟擲埠
EXPOSE 80 443 43554 3000

# 啟動
CMD ["pm2-runtime", "start", "ecosystem.config.js"]

CMD中用的pm2-runtime,而不是pm2啟動,因為pm2-runtime是專門為容器開發的,爲了保留在前臺不關閉容器,否則用 pm2命令會不保留前臺直接關閉容器

融合nginx和pm2

下面這些都已經放入到我公開的容器中了,只需要使用即可,這一章可以跳過,看最後怎麼使用這個容器即可。

ccr.ccs.tencentyun.com/rootegg/node:21.7.3-pm2-nginx-alpine

我們需要4個檔案:

  • app.js 是 pm2 運動的nodejs檔案

  • Dockerfile 是構建docker映象檔案

  • ecosystem.config.js 是pm2啟動指令碼

  • start.sh 是容器CMD啟動指令碼,同時啟動nginx和pm2

用Docker快速部署pm2和nuxt前端專案

app.js

這個檔案沒啥說的,就是nodejs啟動http服務監聽3000埠,返回 hello world 文字

const http = require(`http`);

const server = http.createServer((req, res) => {

  const response = "hello world";
  
  res.writeHead(200);
  
  res.end(response);
  
});

server.listen(3000, () => {
    console.log(`Server is running on http://localhost:3000/`);
});

Dockerfile

安裝 nginx,pm2已經過了,增加另外三個檔案內容,最後一句 CMD 就是啟動指令碼,在指令碼裡在啟動nginx和pm2,因為CMD不能啟動多個程式,雖然可以寫多個CMD,但是隻有最後一個CMD有效,所以只能透過啟動shell指令碼的方式來啟動多個應用程式

FROM ccr.ccs.tencentyun.com/rootegg/node:20.12.2-pm2-alpine

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

RUN apk add --update --no-cache nginx

RUN npm install -g pnpm

WORKDIR /app

COPY ./start.sh ./start.sh

COPY ./ecosystem.config.js ./ecosystem.config.js

COPY ./app.js ./app.js

RUN chmod 777 ./start.sh

CMD ["sh", "./start.sh"]

ecosystem.config.js

標準pm2配置檔案

module.exports = {
  apps : [{
    name   : "app",
    script : "./app.js"
  }]
}

start.sh

啟動指令碼,啟動nginx,這裏不能用 nginx -g daemon off;,因為nginx後面還有pm2,只有pm2要保留在前臺,nginx要執行在後臺,只有有一個應用是在前臺,其他都要在後臺執行

#!/bin/bash

nginx

pm2-runtime start ecosystem.config.js

正式使用封裝的容器

新建Nuxt專案

剛纔已經新建好專案,只需要在根目錄增加一個 Docker 檔案即可,其他都不用動

關鍵是使用 ccr.ccs.tencentyun.com/rootegg/node:21.7.3-pm2-nginx-alpine,裡面環境都已經安裝好了

用Docker快速部署pm2和nuxt前端專案

# compile stage
FROM ccr.ccs.tencentyun.com/rootegg/node:21.7.3-pm2-nginx-alpine as build-stage

WORKDIR /appinstall

COPY package*.json pnpm-lock.yaml ./

RUN pnpm install

COPY . .

RUN pnpm run build

# production stage
FROM ccr.ccs.tencentyun.com/rootegg/node:21.7.3-pm2-nginx-alpine as production-stage

WORKDIR /app

COPY --from=build-stage /appinstall/.output/ .

RUN echo -e "module.exports = { \n\
  apps: [{ \n\
    name: 'app', \n\
    exec_mode: 'cluster', \n\
    instances: 'max', \n\
    script: './server/index.mjs' \n\
  }] \n\
}" > ./ecosystem.config.js

RUN echo -e "server {  \n\
    listen       80; \n\
    location /api/ { \n\
        proxy_pass  http://172.16.0.10:8080/api/; \n\
    } \n\
    location / { \n\
        proxy_pass  http://127.0.0.1:3000/; \n\
    } \n\
    gzip on; \n\
    gzip_min_length 1k; \n\
    gzip_http_version 1.1; \n\
    gzip_comp_level 6; \n\
    gzip_types text/plain application/x-javascript text/css application/xml application/javascript; \n\
    gzip_vary on; \n\
    access_log  /var/log/nginx/access.log ; \n\
} " > /etc/nginx/http.d/default.conf

驗證效果

上面新建nuxt專案後,只增加了一個Dockerfile檔案,專案上傳gitee倉庫

原始碼 https://gitee.com/rootegg/nuxtweb

在伺服器上構建專案

用Docker快速部署pm2和nuxt前端專案

# 克隆原始碼
git clone https://gitee.com/rootegg/nuxtweb.git

# 進入資料夾
cd nuxtweb

# 構建映象,test.com是隨便取的
docker build -t test.com/nuxtweb:v1 .

# build成功後執行映象
docker run -d -p 50080:80 test.com/nuxtweb:v1

# 檢視容器狀態
docker ps

進入容器檢視 pm2 叢集

用Docker快速部署pm2和nuxt前端專案

在網頁上,輸入ip和50080埠,我們來測試下效果,成功

用Docker快速部署pm2和nuxt前端專案

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.