如何将自定义Puppeteer脚本与Puppeteer Docker镜像结合使用?
问题描述
我在本地Windows开发环境用Puppeteer写了一个接收HTML生成PDF的Express脚本,代码如下:
const express = require('express'); const app = express(); app.use(express.json()); const PORT = 3000; app.listen(PORT, () => { console.log("running on port:", PORT); }); const puppeteer = require('puppeteer'); app.post('/generate-pdf', (req, res) => { const htmlString = req.body.htmlString; (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.setContent(JSON.parse(htmlJson)); let pathToFolder = "/path/to/saved-pdf-folder"; let fileName = `pdf_${Date.now()}.pdf`; await page.pdf({ path: `${path}/${fileName}, printBackground: true }); await browser.close(); })(); res.send({ message: 'file generated successfully.' }); });
现在要把这个脚本部署到Docker生产环境,使用官方Puppeteer镜像,但遇到问题:脚本与Docker中Puppeteer的安装目录分离时,const puppeteer = require('puppeteer');无法正常工作,该如何解决?
解决方案
1. 基于官方Puppeteer镜像构建服务
官方Puppeteer镜像已预装Puppeteer及Chrome/Chromium等所有依赖,只需将代码和项目依赖整合到镜像中即可。
首先创建package.json(若未存在):
{ "name": "pdf-generator", "version": "1.0.0", "dependencies": { "express": "^4.18.2", "puppeteer": "^21.0.0" }, "scripts": { "start": "node index.js" } }
注:package.json中puppeteer版本建议与官方镜像内置版本一致,避免兼容性问题。
2. 编写Dockerfile
以官方Puppeteer镜像为基础,复制代码并安装项目依赖:
# 指定官方Puppeteer镜像版本,可根据需求调整 FROM ghcr.io/puppeteer/puppeteer:21.0.0 # 设置容器内工作目录 WORKDIR /app # 复制依赖配置文件 COPY package*.json ./ # 安装项目依赖(镜像已内置Puppeteer,此步骤主要安装express等其他依赖) RUN npm install # 复制Express脚本代码到容器内 COPY index.js . # 暴露服务端口 EXPOSE 3000 # 启动服务 CMD ["npm", "start"]
3. 修正并适配Express脚本
先修复原代码的语法错误,再适配Docker环境:
const express = require('express'); const app = express(); const fs = require('fs'); const path = require('path'); const puppeteer = require('puppeteer'); app.use(express.json()); const PORT = process.env.PORT || 3000; app.post('/generate-pdf', async (req, res) => { try { const htmlString = req.body.htmlString; // 定义PDF存储目录,确保目录存在 const pdfDir = path.join(__dirname, 'pdf'); if (!fs.existsSync(pdfDir)) { fs.mkdirSync(pdfDir, { recursive: true }); } const fileName = `pdf_${Date.now()}.pdf`; const pdfPath = path.join(pdfDir, fileName); // 适配Docker沙箱环境的Puppeteer启动配置 const browser = await puppeteer.launch({ args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage' ] }); const page = await browser.newPage(); // 修复原代码变量错误:使用htmlString而非未定义的htmlJson await page.setContent(htmlString); // 修复原代码语法错误:补全括号与引号 await page.pdf({ path: pdfPath, printBackground: true }); await browser.close(); res.send({ message: 'file generated successfully.', pdfPath: pdfPath }); } catch (error) { console.error('PDF生成失败:', error); res.status(500).send({ message: 'PDF生成失败', error: error.message }); } }); app.listen(PORT, () => { console.log("running on port:", PORT); });
关键调整点:
- 修复原代码的变量、语法错误
- 添加Docker沙箱环境下Puppeteer的启动参数
- 动态适配容器端口,确保PDF存储目录存在
- 增加错误捕获逻辑,提升服务稳定性
4. 构建并运行Docker容器
执行以下命令完成部署:
# 构建Docker镜像 docker build -t pdf-generator . # 运行容器,可选挂载本地目录同步生成的PDF文件 docker run -p 3000:3000 -v $(pwd)/pdf:/app/pdf pdf-generator
关于require('puppeteer')的问题解决
官方Puppeteer镜像已将Puppeteer安装在容器的node_modules中,通过Dockerfile将项目代码与依赖整合后,require('puppeteer')会优先加载项目本地node_modules中的版本(与镜像内置版本兼容),或直接使用镜像全局安装的版本,只要代码位于容器工作目录内,即可正常加载。
内容的提问来源于stack exchange,提问作者pileup
相关产品推荐
相关产品推荐

