1、Dockerfile文件
# 第一阶段:构建环境
FROM node:18 AS builder
# 设置工作目录
WORKDIR /app
# 复制 package.json 和 package-lock.json
COPY package*.json ./
# 安装依赖
RUN npm install && \
npm cache clean --force
# 复制项目文件(包括 .puppeteerrc.cjs)
COPY . .
# 创建缓存目录并设置权限
RUN mkdir -p /app/.cache/puppeteer && chmod -R 777 /app/.cache
# 第二阶段:运行环境
FROM node:18
# 设置环境变量
ENV LANG=en_US.UTF-8
ENV PPTRUSER_UID=10042
ENV PUPPETEER_CACHE_DIR=/home/pptruser/.cache/puppeteer
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
# 安装字体和系统依赖
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-khmeros \
fonts-kacst fonts-freefont-ttf \
fonts-font-awesome \
fonts-noto-color-emoji \
dbus dbus-x11 \
libnss3 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libdrm2 \
libxkbcommon0 \
libxcomposite1 \
libxdamage1 \
libxrandr2 \
libgbm1 \
libasound2 \
libatspi2.0-0 \
libxshmfence1 \
libx11-xcb1 \
libglib2.0-0 \
libgtk-3-0 \
libcups2 \
libxcb-dri3-0 \
libxtst6 \
libxss1 \
libpci3 \
libpango-1.0-0 \
libcairo2 \
libgdk-pixbuf2.0-0 \
libfreetype6 \
libharfbuzz0b \
libfontconfig1 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# 创建非 root 用户
RUN groupadd -r pptruser && useradd -u $PPTRUSER_UID -rm -g pptruser -G audio,video pptruser
# 设置工作目录
WORKDIR /app
# 从构建环境复制依赖和项目文件
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app .
# 创建输出目录并设置权限
RUN mkdir -p /app/output && chmod -R 777 /app/output
RUN chown -R pptruser:pptruser /app/output
# 安装 Chromium
RUN npx puppeteer browsers install chrome
# 设置缓存目录权限
RUN mkdir -p $PUPPETEER_CACHE_DIR && chown -R pptruser:pptruser $PUPPETEER_CACHE_DIR
# 切换到非 root 用户
USER pptruser
# 暴露端口
EXPOSE 3000
# 启动应用
CMD ["node", "app.js"]
2、项目根目录下创建 puppeteerrc.cjs
const { join } = require('path');
/**
* @type {import("puppeteer").Configuration}
*/
module.exports = {
// 将 Puppeteer 的缓存目录更改为项目目录下的 .cache/puppeteer
cacheDirectory: join(__dirname, '.cache', 'puppeteer'),
};
3、使用 puppeteer
const puppeteer = require('puppeteer');
let browser;
const initBrowser = async () => {
if (!browser) {
const executablePath = puppeteer.executablePath();
console.log('Executable Path:', executablePath);
browser = await puppeteer.launch({
executablePath: executablePath,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
}
return browser;
};
const closeBrowser = async () => {
if (browser) {
await browser.close();
browser = null;
}
};
module.exports = {
initBrowser,
closeBrowser,
};