原文作者:tanhe123
原文連結:
https://developer.aliyun.com/article/727915?spm=a2c6h.12873581.0.0.5729115eLl6St3&groupCode=cloudnative 更多雲原生技術資訊可關注 阿裡巴巴雲原生技術圈Puppeteer 是什麼?
puppeteer 官網的介紹如下:
Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol . Puppeteer runs headless by default, but can be configured to run full (non-headless) Chrome or Chromium.
通俗描述就是:Puppeteer 可以将 Chrome 或者 Chromium 以無界面的方式運作(當然也可以運作在有界面的伺服器上),然後可以通過代碼控制浏覽器的行為,即使是非界面的模式運作,Chrome 或 Chromium 也可以在記憶體中正确渲染網頁的内容。
那麼 Puppeteer 能做什麼呢?其實有很多地方都可以受用 Puppeteer,比如:
- 生成網頁截圖或者 PDF
- 抓取 SPA(Single-Page Application) 進行伺服器渲染(SSR)
- 進階爬蟲,可以爬取大量異步渲染内容的網頁
- 模拟鍵盤輸入、表單自動送出、登入網頁等,實作 UI 自動化測試
- 捕獲站點的時間線,以便追蹤你的網站,幫助分析網站性能問題
本文選擇截圖場景作為示範。
如何快速部署一個分布式 Puppeteer Web 應用?
為了快速部署分布式 Puppeteer Web 應用,這裡我們選擇
函數計算服務。
函數計算(Function Compute): 函數計算是一個事件驅動的服務,通過函數計算,使用者無需管理伺服器等運作情況,隻需編寫代碼并上傳。函數計算準備計算資源,并以彈性伸縮的方式運作使用者代碼,而使用者隻需根據實際代碼運作所消耗的資源進行付費。函數計算更多資訊 參考
有了函數計算服務,我們這裡目标是搭建一個分布式應用,但做的事情其實很簡單,那就是寫好業務代碼,部署到函數計算,僅此而已。
使用函數計算後,我們的系統架構圖如下:
效果示範
可以直接通過以下連結檢視效果:
https://1911504709953557.cn-hangzhou.fc.aliyuncs.com/2016-08-15/proxy/puppeteer-test/html2png/?url=https://www.aliyun.com/product/fcPS:第一次請求可能會有幾秒的冷啟動時間,通過使用
預留模式可以完全去除冷啟動,由于超出本文範圍,這裡不再闡述。
搭建步驟步驟:
整體流程如下圖所示:
其中,需要我們操作的隻有 Fun Init、Fun Install 以及 Fun Deploy 指令,每個的步驟内容都會由這三個指令自動完成。
1. 工具安裝
安裝 Fun 工具:
建議直接從這裡下載下傳二進制可執行程式,解壓後即可直接使用。
下載下傳位址安裝 Docker:
可以按照
這裡介紹的方法進行安裝。
2. 初始化項目:
通過 Fun 工具,使用下面的指令可以快速初始化一個 Puppeteer Web 應用的腳手架:
fun init -n puppeteer-test http-trigger-node-puppeteer
其中
-n puppeteer-test
表示初始化項目的目錄名稱,
http-trigger-node-puppeteer
表示要使用的模闆名稱,可以省略該名稱,省略後,可以從終端提示的清單中自行選擇需要的模闆。
執行完畢後,可以看到如下的目錄結構:
.
├── index.js
├── package.json
└── template.yml
相比較于傳統的 puppeteer 應用,這裡僅僅多了一個
template.yml檔案,用于描述函數計算的資源。
而 index.js 就是我們的業務代碼了,可以按照
Puppeteer 官方幫助文檔的要求書寫自己的業務代碼,這裡不再重複闡述,核心代碼如下:
const browser = await puppeteer.launch({
headless: true,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
]
});
const page = await browser.newPage();
await page.emulateTimezone('Asia/Shanghai');
await page.goto('https://www.baidu.com', {
'waitUntil': 'networkidle2'
});
await page.screenshot({ path: '/tmp/example', fullPage: true, type: 'png' });
await browser.close();
package.json 内容如下:
{
... ...
"dependencies": {
"puppeteer": "^2.0.0"
},
... ...
}
可以看到,在 package.json 中聲明了 puppeteer 的依賴。這個也是我們使用 node 開發時的标準做法,并無特别之處。
3. 一鍵安裝依賴
puppeteer 的安裝,即使是在傳統的 linux 機器上,也不是那麼的輕松。因為 puppeteer 本身依賴了非常多的
系統庫,要安裝哪些系統庫、如何安裝這些系統庫成了一個比較頭痛的問題。
好在函數計算指令行工具
Fun已經內建了 Puppeteer 的解決方案,隻要 package.json 中包含了 puppeteer 依賴,然後使用 fun install -d 即可一鍵安裝所有系統依賴。
fun install -d
4. 本地運作、調試函數
Puppeteer 的本地運作、調試方法與
這裡介紹的完全一緻,我們就不再重複介紹。我們這裡隻示範下運作效果:
5. 一鍵部署應用
基本上所有的 FaaS 平台為了減小應用的冷啟動,都會設定代碼包的限制,函數計算也不例外。而 puppeteer 自身已經達到了 350M 左右,連同其系統依賴已經達到了 450M。如何将 450M 體積的函數部署到 FaaS 平台是一個比較頭痛而且繁瑣的問題。
函數計算的指令行工具 Fun 現在原生支援了這種大依賴部署(3.1.1 版本僅支援 node runtime)。不需要任何額外操作,僅僅執行 fun deploy:
$ fun deploy
fun 會自動完成依賴的部署。而當檢測到打包的依賴超過了平台的限制時,會進入到配置向導,幫助使用者自動化地配置。
我們這裡推薦的路徑是當提示是否由 Fun 自動幫助 NAS 管理是,輸入 yes,然後提示提示是否使用 NasConfig: Auto 自動處理 NAS 時,也選擇是,之後就不需要做其他的事情,等待函數部署成功即可。
如果有其他的需求,比如想使用自己已經存在的 NAS 服務,可以在提示使用
NasConfig: Auto時,輸入 no,這樣就會進入到相應的流程。更詳細的說明,請參考下面的 FAQ。
FAQ
在安裝 puppeteer 時,Fun 都做了哪些事情?
puppeteer 本身是一個 npm 包,它的安裝是非常簡單的,通過 npm install 即可。這裡的問題在于,puppeteer 依賴了 chromium,而 chromium 又依賴一些系統庫。是以 npm install 後,還會觸發下載下傳 chromium 的操作。這裡使用者經常遇到的問題,主要是:
- 由于 chromium 的體積比較大,是以經常遇到網絡問題導緻下載下傳失敗。
- npm 僅僅隻下載下傳 chromium,chromium 依賴的系統庫并不會自動安裝。使用者還需要自行查找缺失的依賴進行安裝。
Fun 做的優化主要是:
- 通過檢測網絡環境,對于國内使用者,會幫助配置 淘寶 NPM 鏡像 實作加速下載下傳的效果。
- 自動為使用者安裝 chromium 所缺失的依賴庫。
Fun 是如何把大依賴部署到函數計算的?不是有代碼包大小的限制嗎?
基本上所有的 FaaS 為了優化函數冷啟動,都會加入函數代碼包大小的限制。函數計算也不例外。但是,Fun 通過内置 NAS(阿裡雲檔案存儲) 解決方案,可以一鍵幫使用者建立、配置 NAS,并上傳依賴到 NAS 上。而函數計算在運作時,可以自動從 NAS 讀取到函數依賴。
為了幫助使用者自動化地完成這些操作,Fun 内置了一個向導(3.1.1 版本僅支援 node,後續會支援更多,歡迎
github issue提需求),在檢測到代碼體積大小超過平台限制時,會提示是否由 Fun 将其改造成 NAS 的方案,整個向導的邏輯如下:
- 詢問是否使用 Fun 來自動化的配置 NAS 管理依賴?(如果回答是,則進入向導,回答否,則繼續釋出流程)
- 檢測使用者的 yml 中是否已經配置了 NAS
- 如果已經配置,則提示使用者選擇已經配置的 NAS 存儲函數依賴
- 如果沒有配置,則提示使用者是否使用 自動建立 NAS 配置
- 如果選擇了是,則幫助使用者自動配置 nas、vpc 資源。
- 如果選擇了否,則列出使用者目前 NAS 控制台上已經有的 NAS 資源,讓使用者選擇
- 無論上面使用哪種方式,最終都會在 template.yml 生成 NAS 以及 VPC 相關的配置
- 根據語言檢測,比如 node runtime,會将 node_modules 以及 .fun/root 目錄映射到 nas 目錄(通過 .nas.yml 實作)
- 自動執行 fun nas sync 幫使用者把本地的依賴上傳到 NAS 服務
- 自動執行 fun deploy,幫使用者把代碼上傳到函數計算
- 提示幫助資訊,對于 HTTP Trigger 的,提示函數的 Endpoint,直接打開浏覽器通路即可看到效果
是否可以指定 puppeteer 的版本?
可以的,隻需要修改 package.json 中的 puppeteer 的版本,重新安裝即可。
函數計算執行個體中的時區采用的 UTC,是否有辦法改為中原標準時間?
某些網頁的顯示效果是和時區挂鈎的,時區不同,可能會導緻顯示的内容有差異。使用本文介紹的方法,可以非常容易的使用 puppeteer 的最新版本,而在 puppeteer 的最新版本 2.0 提供了一個新的 API
page.emulateTimezone(timezoneId), 可以非常容易的修改時區。
如果 Puppeteer 後續版本更新後,依賴更多的系統依賴,本文介紹的方法還适用嗎?
Fun 内置了 .so 缺失檢測機制,當在本地調試運作時,會智能地根據報錯識别出缺失的依賴庫,然後精準地給出安裝指令,可以做到一鍵安裝。
如果添加了新的依賴,如何更新?
如果添加了新的依賴,比如 node_modules 目錄添加了新的依賴庫,隻需要重新執行 fun nas sync 進行同步即可。
如果修改了代碼,隻需要使用 fun deploy 重新部署即可。由于大依賴和代碼通過 NAS 進行了分離,依賴通常不需要頻繁變化,是以調用的頻率比較低,而 fun deploy 的由于沒有了大依賴,部署速度也會非常的快。
除了本文介紹的方法還有哪些方法可以一鍵安裝 puppeteer?
Fun 提供了非常多的依賴安裝方式,除了本文介紹的将依賴直接聲明在 package.json 中,然後通過 fun install -d 的方式安裝外,還有很多其他方法,他們均有各自适用的場景:
- 指令式安裝 。比如
。這種安裝方式的好處是即使對 fun 不了解的使用者也可以傻瓜式的使用。fun install -f functionName -p npm puppeteer
- 聲明式安裝 。這種安裝方式的好處是提供了類 Dockerfile 的體驗,Dockerfile 的大部分指令在這裡都是可以直接使用的。通過這種方式聲明的依賴,可以通過直接送出到版本倉庫。他人拉取代碼後,也可以一鍵安裝所有依賴。
- 互動環境安裝 。這種安裝方式的好處是提供了類似傳統實體機的安裝體驗。在互動環境中,大部分 linux 指令都是可以使用的,而且可以不斷試錯。
總結
本文介紹了一種比較簡單易行地從零開始搭建分布式 Puppeteer Web 服務的方法。利用該方法,可以做到不需要關心如何安裝依賴、也不需要關系如何上傳依賴,順滑地完成部署。
部署完成後,即可享受函數計算帶來的優勢,即:
- 無需采購和管理伺服器等基礎設施,隻需專注業務邏輯的開發,可以大幅縮短項目傳遞時間和人力成本
- 提供日志查詢、性能監控、報警等功能快速排查故障
- 免運維,毫秒級别彈性伸縮,快速實作底層擴容以應對峰值壓力,性能優異
- 成本極具競争力
“ 阿裡巴巴雲原生 關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的技術圈。”