รัน NextPDF บนแพลตฟอร์ม serverless
ภาพรวมโดยสังเขป
หัวข้อที่มีชื่อว่า “ภาพรวมโดยสังเขป”เอนจิน core ของ NextPDF แบบ native ที่ทำงานในกระบวนการเป็นเวิร์กโหลด serverless ที่เกือบสมบูรณ์แบบ มันคือ PHP ล้วนที่รันอยู่ภายในกระบวนการของคุณ — composer require nextpdf/core สร้างเอกสาร แล้วรับไบต์ ไม่มีไบนารีภายนอกให้ spawn ไม่มีเบราว์เซอร์ headless ไม่มี daemon ให้คอยรักษาให้ทำงาน และไม่มี socket ไปยังบริการ sidecar ฟังก์ชันที่สร้าง PDF เริ่มแบบ cold รัน PHP ของคุณ คืนไบต์ แล้วออก สิ่งนี้แมปได้อย่างสะอาดกับ AWS Lambda (ผ่านรันไทม์ Bref), Google Cloud Run และ AWS App Runner
หน้านี้ครอบคลุมการดีพลอยเอนจิน native นั้นไปยังรันไทม์ทั้งสามนี้ และชุดข้อจำกัดจริงเล็ก ๆ ที่มันกำหนด:
- ไฟล์ระบบของรันไทม์ ไม่ทนทาน: Lambda รับประกันเพียง
/tmpที่เขียนได้ ขณะที่รันไทม์คอนเทนเนอร์ (Cloud Run, App Runner) มีไฟล์ระบบแบบ ephemeral ที่ขอบเขตอยู่ที่คอนเทนเนอร์ — ไม่ว่าทางใด ฟอนต์ต้องเดินทางอยู่ภายในแพ็กเกจหรืออิมเมจที่ดีพลอย และต้อง ลงทะเบียนใน PHP (เอนจินไม่อ่านตัวแปรสภาพแวดล้อม font-path) - cold start ต้องจ่ายค่า autoloading และการวอร์มอัปฟอนต์ใด ๆ ดังนั้นให้วอร์ม
FontRegistryครั้งเดียวต่อคอนเทนเนอร์ ไม่ใช่ต่อการเรียกใช้ - ขนาดแพ็กเกจ หน่วยความจำ และ timeout ต้องกำหนดขนาดให้พอดีกับ build ไม่ใช่ต่อคำขอเล็กน้อย
หน้านี้สำหรับเอนจิน native เท่านั้น Chrome bridge (writeHtmlChrome ผ่านแพ็กเกจ nextpdf/artisan ที่แนะนำ) เป็นเรื่องที่ต่างออกไปและหนักกว่า: มัน shell out ไปยัง Chromium แบบ headless ผ่าน symfony/process ซึ่ง Lambda zip แบบธรรมดาหรือคอนเทนเนอร์แบบบางไม่มี การรัน Chromium บน Lambda หมายถึง custom layer ที่มีเบราว์เซอร์และไลบรารีที่ใช้ร่วม แพ็กเกจที่ใหญ่ขึ้นมาก และ cold start ที่นานขึ้นมาก — อยู่นอกขอบเขตที่นี่ เอนจินเปล่าไม่ต้องการสิ่งเหล่านั้นเลย
ก่อนเริ่ม ให้ยืนยันว่าชิ้นส่วนเหล่านี้พร้อมแล้ว:
- แอปพลิเคชันของคุณมี
composer.jsonและcomposer.lockที่ commit แล้ว โดยมีnextpdf/coreเป็น dependency - คุณมีไฟล์ฟอนต์ที่ตั้งใจจะฝัง และคุณได้รับอนุญาตให้ฝังมัน
- คุณมี toolchain สำหรับเป้าหมายของคุณ — Bref CLI และเฟรมเวิร์ก
serverlessสำหรับ Lambda หรือ container build สำหรับ Cloud Run / App Runner
เหตุใดเอนจิน native จึงเหมาะกับ serverless
หัวข้อที่มีชื่อว่า “เหตุใดเอนจิน native จึงเหมาะกับ serverless”อ่านตรงจากแพ็กเกจ nextpdf/core ต้องการ php: >=8.4 <9.0 และส่วนขยาย PHP ชุดเล็ก ๆ — ext-mbstring, ext-intl, ext-gd, ext-openssl, ext-zlib และ ext-curl Bref PHP layer มาตรฐานรวมทุกตัวเหล่านี้ ส่วนอิมเมจคอนเทนเนอร์ทางการ php:8.4 ให้ openssl, curl และ zlib มาในตัว แต่ mbstring, gd และ intl ไม่ ถูกรวมมา — ต้องติดตั้ง system dependency และเปิดใช้ส่วนขยายด้วย docker-php-ext-install (ดูคู่มือดีพลอยด้วย Docker) บน Bref ไม่มีอะไรแปลกที่ต้องคอมไพล์ บนเส้นทางคอนเทนเนอร์ คุณเปิดใช้สามส่วนขยายนั้นในการ build อิมเมจสำหรับเอนจิน เปล่า
สิ่งที่ทำให้ความเหมาะนี้สะอาดคือสิ่งที่เอนจิน ไม่ ทำ:
- ไม่มี subprocess สำหรับเส้นทาง core การสร้างเอกสารและเรียก
getPdfData()เป็น PHP ในกระบวนการตั้งแต่ต้นจนจบ dependencysymfony/processมีไว้สำหรับ Chrome bridge ที่เป็นทางเลือก ไม่ใช่สำหรับการเรนเดอร์ native — การสร้าง PDF แบบ native ไม่เคย spawn กระบวนการ - ไม่มีสถานะที่คงอยู่ การเรียกใช้แต่ละครั้งสร้างเอกสารใหม่และคืนไบต์ ไม่มีสิ่งใดต้องอยู่รอดระหว่างคำขอ ยกเว้นคอนเทนเนอร์ที่อุ่น ซึ่งคุณใช้ประโยชน์สำหรับการวอร์มฟอนต์ (ด้านล่าง) แต่ไม่เคยพึ่งพาเพื่อความถูกต้อง
- ไม่ต้องมีไดเรกทอรีทำงานที่เขียนได้ เอนจินสร้าง PDF ในหน่วยความจำและคืนเป็นสตริง มันแตะดิสก์ก็ต่อเมื่อ คุณ เรียก
save()เท่านั้น บน serverless คุณไม่ทำ — คุณคืนไบต์ — ดังนั้นการขาดไฟล์ระบบที่ทนทานจึงไม่เคยกัดเส้นทาง build
ข้อจำกัดยากหนึ่งเดียว: ไม่มีไฟล์ระบบที่เขียนได้และทนทาน
หัวข้อที่มีชื่อว่า “ข้อจำกัดยากหนึ่งเดียว: ไม่มีไฟล์ระบบที่เขียนได้และทนทาน”ไฟล์ระบบที่ดีพลอยไม่ทนทาน แต่โมเดลต่างกันตามรันไทม์ AWS Lambda รับประกันเพียง /tmp ที่เขียนได้ (512 MB โดยค่าเริ่มต้น กำหนดได้สูงสุดถึง 10 GB) ส่วนที่เหลือของไฟล์ระบบฟังก์ชันเป็นแบบอ่านอย่างเดียว รันไทม์คอนเทนเนอร์ (Cloud Run, App Runner) มีไฟล์ระบบที่เขียนได้แบบ ephemeral ที่ขอบเขตอยู่ที่คอนเทนเนอร์ แทนโมเดลแบบ /tmp-only — แต่สิ่งใดที่เขียนที่นั่นจะหายไปเมื่อคอนเทนเนอร์ถูกรีไซเคิล ดังนั้นมันคือพื้นที่ชั่วคราว ไม่ใช่ที่จัดเก็บ ในทุกกรณี ให้เลือก /tmp หรือ volume ที่กำหนดไว้สำหรับการ stage และไม่เคยพึ่งพาการเขียนไปยัง path ของอิมเมจแอปพลิเคชันเป็นที่จัดเก็บที่ทนทาน ตามมาด้วยผลสองข้อ
อย่าเรียก save() โดยคาดหวังผลลัพธ์ที่ทนทาน NextPDF\Core\Document เปิดเผยทั้ง save(string $path): void และ getPdfData(): string บน serverless คุณใช้ getPdfData() แล้วคืนหรืออัปโหลดไบต์ — อย่าถือว่าการเขียนไปยังไดเรกทอรีแอปพลิเคชันเป็นที่จัดเก็บถาวร หากคุณต้อง stage ไฟล์ (ตัวอย่างเช่น เพื่ออัปโหลดแบบ multipart ไปยัง object storage) ให้เขียนใต้ /tmp (หรือ volume ที่กำหนดไว้) แล้วเก็บกวาด โดยจำไว้ว่าบนคอนเทนเนอร์ที่อุ่น พื้นที่ชั่วคราวนี้คงอยู่ข้ามการเรียกใช้และนับรวมกับขีดจำกัดขนาดของมัน
use NextPDF\Core\Document;
// Right for serverless: get the bytes, return or upload them.$pdf = $document->getPdfData(); // string of PDF bytes, built in memory
// Avoid on serverless: save() writes to disk. On Lambda the application// directory is read-only; on Cloud Run / App Runner it is writable but// ephemeral (lost on container recycle). Neither is durable storage.// $document->save('/var/task/out.pdf'); // not durable — return the bytes insteadอย่าติดตั้งฟอนต์ OS ขณะรันไทม์ และอย่าพึ่งพาการค้นพบฟอนต์อัตโนมัติ ให้รวมไฟล์ฟอนต์ของคุณสำหรับการใช้งานจริง บน Lambda ไฟล์ระบบแบบอ่านอย่างเดียวบล็อก apt-get install fonts-* ทันที บนรันไทม์คอนเทนเนอร์ การติดตั้งขณะรันไทม์ใด ๆ จะลงบนไฟล์ระบบแบบ ephemeral และหายไปในการรีไซเคิลครั้งถัดไป และมันก็ไม่ช่วยอยู่ดี เพราะเอนจิน native ไม่อ่านฟอนต์ OS/fontconfig — มันรีโซลฟ์ฟอนต์เฉพาะจากไฟล์ที่คุณลงทะเบียน ดังนั้นสำหรับการใช้งานจริง ไฟล์ฟอนต์ต้องเดินทางไปอยู่ภายในอาร์ติแฟกต์ที่ดีพลอย หากคุณตั้งใจดึงไฟล์ฟอนต์เข้าไปใน /tmp หรือ volume ที่กำหนดไว้ คุณต้องลงทะเบียนมันอย่างชัดเจนกับ font registry และยอมรับต้นทุน cold-start และความน่าเชื่อถือที่เพิ่มขึ้น — มันไม่ใช่รูปแบบที่แนะนำสำหรับการใช้งานจริง
รวมและลงทะเบียนฟอนต์ในแพ็กเกจหรืออิมเมจ
หัวข้อที่มีชื่อว่า “รวมและลงทะเบียนฟอนต์ในแพ็กเกจหรืออิมเมจ”เอนจิน native รีโซลฟ์ฟอนต์จาก ไฟล์ฟอนต์ ผ่าน NextPDF\Typography\FontRegistry ไม่ใช่จาก fontconfig หรือฟอนต์ที่ติดตั้งใน OS บน serverless นี่เป็นสิ่งที่ต่อรองไม่ได้: ไม่มีไฟล์ระบบที่คงอยู่ให้วางฟอนต์หลังดีพลอย ดังนั้นมันจึงเดินทางไปอยู่ภายในแพ็กเกจ (Lambda zip หรือ layer) หรือภายในอิมเมจ (Cloud Run / App Runner)
รวมไฟล์ .ttf / .otf / .ttc ของคุณไว้ใต้ไดเรกทอรีหนึ่งในโปรเจกต์ของคุณ — resources/fonts/ เป็นแบบแผน — เพื่อให้มันถูกรวมเข้าในอาร์ติแฟกต์ จากนั้นลงทะเบียนไดเรกทอรีนั้นใน PHP เอนจิน ไม่ อ่านตัวแปรสภาพแวดล้อม font-path: NEXTPDF_FONTS_PATH เป็นค่าเริ่มต้นของคีย์การกำหนดค่า fonts_path ของแพ็กเกจ nextpdf/laravel (env('NEXTPDF_FONTS_PATH', resource_path('fonts'))) และถูกใช้เฉพาะโดยการรวมเฟรมเวิร์กนั้น ไม่ใช่โดย nextpdf/core ฟังก์ชันเปล่าต้องสร้าง registry ด้วยไดเรกทอรีที่รวมไว้:
use NextPDF\Typography\FontRegistry;use NextPDF\Core\DocumentFactory;use NextPDF\Graphics\ImageRegistry;
// Register the directory the deployment artifact bundled the fonts into.// On Lambda/Bref the code root is /var/task; adjust for your runtime.$registry = new FontRegistry(__DIR__ . '/resources/fonts');// (equivalently, $registry->addFontDirectory(__DIR__ . '/resources/fonts');)
$factory = new DocumentFactory($registry, new ImageRegistry(maxCacheBytes: 0));$document = $factory->create();นั่นคือเรื่องทั้งหมดของ serverless สำหรับฟอนต์ กฎการตั้งชื่อไฟล์ registry API ฉบับเต็ม และการจัดการไฟล์ระบบที่ไม่ทนทานอยู่ในหน้าเฉพาะ — อย่าทำซ้ำที่นี่ อ่านจัดเตรียมฟอนต์สำหรับเอนจิน native ในการใช้งานจริง สำหรับรูปแบบฉบับเต็ม แล้วลงทะเบียนไดเรกทอรีเดียวกับที่คุณรวมไว้ คู่มือดีพลอยด้วย Docker ครอบคลุมการรวมฝั่งอิมเมจที่เทียบเท่าสำหรับกรณี Cloud Run / App Runner
cold start: วอร์ม FontRegistry ครั้งเดียวต่อคอนเทนเนอร์
หัวข้อที่มีชื่อว่า “cold start: วอร์ม FontRegistry ครั้งเดียวต่อคอนเทนเนอร์”cold start ต้องจ่ายค่า PHP bootstrap, autoloader ที่ปรับให้เหมาะของ Composer และการแยกวิเคราะห์ฟอนต์ใด ๆ ที่ build แรกกระตุ้น คุณเลี่ยง bootstrap ไม่ได้ แต่คุณย้ายงานฟอนต์ออกจากเส้นทางร้อนและนำกลับมาใช้ซ้ำข้ามการเรียกใช้ที่อุ่นได้
สร้าง FontRegistry และ DocumentFactory ครั้งเดียว นอก handler เพื่อให้มันอยู่ตลอดอายุของคอนเทนเนอร์และถูกนำกลับมาใช้ซ้ำในทุกการเรียกใช้ที่อุ่น เลือกได้ที่จะเรียก warmup() ด้วยไฟล์ฟอนต์ที่คุณรู้ว่าจะใช้ เพื่อให้มันถูกแยกวิเคราะห์ระหว่างการเริ่มต้น แทนที่จะเป็นในการเรนเดอร์ครั้งแรก จากนั้น lock() registry เพื่อให้สถานะที่แยกวิเคราะห์แล้วถูกแช่แข็งและไม่มีการกลายพันธุ์ต่อการเรียกใช้ใดเข้ามาแย่งชิงได้:
use NextPDF\Typography\FontRegistry;use NextPDF\Core\DocumentFactory;use NextPDF\Graphics\ImageRegistry;
// Container-scoped, built once at cold start (module scope, not per request).$fontsDir = __DIR__ . '/resources/fonts';$registry = new FontRegistry($fontsDir);
// Parse the fonts you will actually use now, so the first render does not.$registry->warmup([ $fontsDir . '/liberation/LiberationSans-Regular.ttf', $fontsDir . '/liberation/LiberationSans-Bold.ttf',]);
// Freeze the parsed state for the life of the warm container.$registry->lock();
$factory = new DocumentFactory($registry, new ImageRegistry(maxCacheBytes: 0));
// Each invocation: fresh document from the shared, warm factory.$handler = static function (array $event) use ($factory): string { $document = $factory->create(); $document->addPage(); $document->cell(0, 10, 'Hello from serverless', newLine: true);
return $document->getPdfData();};เรียก warmup() ก่อน lock() — registry ถูกแช่แข็งเมื่อ lock แล้ว ดังนั้น warmup หลังจากนั้นจะ raise ข้อผิดพลาดการกำหนดค่า ให้ถือว่าฟอนต์ที่โหลดล้มเหลวตอน warmup เป็น ข้อผิดพลาดเวลาดีพลอย ไม่ใช่รายละเอียดขณะรันไทม์: ตรวจสอบว่าทุก path ฟอนต์ที่คุณตั้งใจจะวอร์มมีอยู่จริงและแยกวิเคราะห์ได้ตอนเริ่มต้น และให้ดีพลอย (หรือ health check ของคุณ) ล้มเหลวหากมีตัวใดไม่ผ่าน แทนที่จะปล่อยให้ path ที่พิมพ์ผิดโผล่มาภายหลังเป็นกลีฟที่หาย ให้รายการ warmup จำกัดอยู่ที่ฟอนต์ที่การเรียกใช้ทั่วไปต้องการ การวอร์มตระกูลใหญ่ที่คุณแทบไม่ใช้แค่ทำให้ทุก cold start ยาวขึ้น
ฟังก์ชัน Bref บน AWS Lambda
หัวข้อที่มีชื่อว่า “ฟังก์ชัน Bref บน AWS Lambda”Bref ให้รันไทม์ PHP สำหรับ Lambda เป็น layer ที่เผยแพร่และปลั๊กอิน serverless.yml รันไทม์ php-84 มาพร้อมส่วนขยายที่ nextpdf/core ต้องการอยู่แล้ว ดังนั้นคุณดีพลอยโค้ดและฟอนต์ แล้วชี้ฟังก์ชันไปยัง handler serverless.yml แบบขั้นต่ำ:
service: nextpdf-serverless
provider: name: aws region: us-east-1 runtime: provided.al2023
plugins: - ./vendor/bref/bref
functions: generate: handler: handler.php description: Generate a PDF with the native NextPDF engine runtime: php-84 memorySize: 1024 # size to the build; see "Sizing" below timeout: 30 # seconds; raise for large documents # The Lambda filesystem is read-only except /tmp. Fonts ship in the # package under resources/fonts and are registered in the handler.handler สร้างเอกสารด้วย factory ที่อุ่นและขอบเขตอยู่ที่คอนเทนเนอร์ แล้วคืนไบต์ สำหรับ HTTP API ให้คืนแบบ base64-encoded ด้วย content type application/pdf เพื่อให้ API Gateway ปฏิบัติต่อ body เป็นไบนารี สำหรับทริกเกอร์แบบ invoke หรือ queue ให้อัปโหลดไบต์ไปยัง object storage แล้วคืนคีย์:
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;use NextPDF\Graphics\ImageRegistry;use NextPDF\Typography\FontRegistry;
// --- Cold-start: built once per container, reused across warm invocations. ---$fontsDir = __DIR__ . '/resources/fonts';$registry = new FontRegistry($fontsDir);$registry->warmup([$fontsDir . '/liberation/LiberationSans-Regular.ttf']);$registry->lock();$factory = new DocumentFactory($registry, new ImageRegistry(maxCacheBytes: 0));
// --- Per-invocation handler. ---return static function (array $event) use ($factory): array { $document = $factory->create(); $document->addPage(); $document->cell(0, 10, 'Invoice', newLine: true);
// getPdfData() materializes the whole PDF in memory and returns it. $bytes = $document->getPdfData();
return [ 'statusCode' => 200, 'isBase64Encoded' => true, 'headers' => ['Content-Type' => 'application/pdf'], 'body' => base64_encode($bytes), ];};ตรวจสอบว่าแพ็กเกจมีสภาพแวดล้อมที่สมบูรณ์ก่อนเดินสายทราฟฟิกเข้ามา nextpdf/core มากับ CLI ที่ติดตั้งไว้ที่ vendor/bin/nextpdf ซึ่งคำสั่ง doctor รายงานเกี่ยวกับส่วนขยายที่เอนจินต้องการพอดี รันมันครั้งหนึ่งกับอิมเมจหรือ layer รันไทม์เดียวกันเพื่อยืนยันว่ามี PHP 8.4 และทุกส่วนขยายที่จำเป็นอยู่ครบ
Cloud Run และ App Runner
หัวข้อที่มีชื่อว่า “Cloud Run และ App Runner”Cloud Run และ App Runner รัน คอนเทนเนอร์ แทนฟังก์ชันแบบ zip ดังนั้น build คืออิมเมจ Docker จากบรรจุแอปพลิเคชัน NextPDF ลงคอนเทนเนอร์ ไม่ใช่แพ็กเกจ Bref ข้อจำกัดของเอนจิน native เหมือนกัน: รวมฟอนต์เข้าในอิมเมจ ลงทะเบียนไดเรกทอรีที่รวมไว้ใน PHP รันแบบไม่มีสิทธิ์พิเศษ และถือว่าไฟล์ระบบไม่ทนทาน ต่างจากโมเดลแบบ /tmp-only ของ Lambda คอนเทนเนอร์ Cloud Run / App Runner มีไฟล์ระบบที่เขียนได้แบบ ephemeral ที่ขอบเขตอยู่ที่คอนเทนเนอร์ — แต่มันถูกรีเซ็ตในทุกการรีไซเคิล ดังนั้นใช้ /tmp (tmpfs บน Cloud Run) หรือ volume ที่กำหนดไว้สำหรับงานชั่วคราว และไม่เคยพึ่งพาการเขียนไปยัง path ของอิมเมจแอปพลิเคชันเป็นที่จัดเก็บที่ทนทาน
ความแตกต่างจาก Lambda เป็นเชิงปฏิบัติการ ไม่ใช่เชิงโครงสร้าง:
- คอนเทนเนอร์อยู่ในสภาพอุ่นข้ามคำขอได้ ภายใต้การตั้งค่า concurrency ดังนั้นการวอร์ม
FontRegistry/DocumentFactoryที่ขอบเขตอยู่ที่คอนเทนเนอร์ด้านบนจึงคุ้มค่าข้ามหลายคำขอ ไม่ใช่แค่การเรียกใช้ครั้งถัดไป - คุณให้บริการผ่าน HTTP (FPM หรือ PHP server SAPI ในตัว) แทน invoke event ดังนั้นคุณคืนไบต์ผ่านการตอบสนองของเฟรมเวิร์ก สำหรับเอกสารขนาดใหญ่ ให้คืนเป็นการตอบสนองแบบสตรีม — ดูสตรีม PDF ขนาดใหญ่ที่สร้างขึ้นเป็นการตอบสนอง HTTP
- timeout ของคำขอและหน่วยความจำ ถูกตั้งบนบริการ (Cloud Run service timeout / memory; การกำหนดค่า instance ของ App Runner) แทนต่อฟังก์ชัน
ทุกอย่างที่เหลือ — ชุดส่วนขยาย การลงทะเบียนฟอนต์ การเรียก output getPdfData() — เป็นโค้ดเดียวกับ handler ของ Lambda
การกำหนดขนาด: แพ็กเกจ หน่วยความจำ และ timeout
หัวข้อที่มีชื่อว่า “การกำหนดขนาด: แพ็กเกจ หน่วยความจำ และ timeout”- ขนาดแพ็กเกจและอิมเมจ อาร์ติแฟกต์พา
vendor/(สำหรับ production เท่านั้น — ติดตั้งด้วย--no-dev) และฟอนต์ที่คุณรวมไว้ ฟอนต์มีน้ำหนักมากที่สุด: ตระกูล CJK ฉบับเต็มมีขนาดหลายสิบเมกะไบต์ ให้ส่งเฉพาะฟอนต์ที่คุณเรนเดอร์จริงเพื่อให้แพ็กเกจ Lambda อยู่ใต้ขีดจำกัดและอิมเมจเล็ก ซึ่งยังทำให้ cold start สั้นลงด้วย ตระกูล Liberation ที่มากับชุด (resources/fonts/liberation/) มีขนาดเล็กและครอบคลุมการแทนที่ Helvetica แบบ metric-compatible - หน่วยความจำ
getPdfData()สร้างเอกสาร ทั้งฉบับ ในหน่วยความจำและคืนเป็นสตริงเดียว ดังนั้นหน่วยความจำสูงสุดจึงเท่ากับขนาดของ PDF ที่เสร็จแล้วหนึ่งฉบับบวกกับ working set ของ build โดยประมาณ ให้กำหนดขนาดหน่วยความจำของฟังก์ชัน/คอนเทนเนอร์ให้พอดีกับเอกสารที่ใหญ่ที่สุดที่คุณสร้าง ไม่ใช่ค่าเฉลี่ย บน Lambda หน่วยความจำยังปรับ CPU ตาม ดังนั้นหน่วยความจำที่มากขึ้นมักหมายถึง build ที่เร็วขึ้นและการรันที่ถูกลงแม้อัตราต่อมิลลิวินาทีจะสูงขึ้น — วัดทั้งสองอย่าง เอกสารไม่กี่หน้าสบาย ๆ ที่ 512–1024 MB เอกสารที่มีรูปภาพมากหรือหลายหน้าต้องการมากกว่านั้น - timeout build ไม่ใช่การถ่ายโอนที่ครองงบประมาณคำขอ ตั้ง timeout ของฟังก์ชันให้เหนือเวลา build กรณีเลวร้ายสุดพร้อมส่วนเผื่อ หากเอกสารใหญ่พอที่จะเสี่ยง timeout ให้ย้ายการสร้างไปยังทริกเกอร์แบบ asynchronous (Lambda ที่ขับด้วย queue หรือ Cloud Run job) ที่เขียนผลลัพธ์ไปยัง object storage แทนการบล็อกคำขอแบบ synchronous
- ขนาด
/tmpหากคุณ stage สิ่งใดใต้/tmpให้คำนึงถึงขีดจำกัดขนาดของมันและจำไว้ว่ามันคงอยู่ข้ามการเรียกใช้ที่อุ่น — เก็บกวาด มิฉะนั้นคอนเทนเนอร์ที่อยู่นานจะค่อย ๆ เติมจนเต็ม
กรณีขอบและจุดที่ควรระวัง
หัวข้อที่มีชื่อว่า “กรณีขอบและจุดที่ควรระวัง”- ไม่มี
save()ที่ทนทานไปยังไดเรกทอรีแอป ไฟล์ระบบที่ดีพลอยไม่ทนทาน — ไดเรกทอรีแอปของ Lambda เป็นแบบอ่านอย่างเดียว (มีเพียง/tmpที่รับการเขียน) และไฟล์ระบบคอนเทนเนอร์ Cloud Run / App Runner เขียนได้แต่เป็นแบบ ephemeral ให้ใช้getPdfData()แล้วคืน/อัปโหลดไบต์ stage ใต้/tmpหรือ volume ที่กำหนดไว้หากจำเป็น - อย่าพึ่งพาการค้นพบฟอนต์อัตโนมัติ อย่าติดตั้งฟอนต์ OS ขณะรันไทม์ และอย่าพึ่งพาการค้นพบฟอนต์อัตโนมัติ ให้รวมไฟล์ฟอนต์ของคุณสำหรับการใช้งานจริง เอนจิน native ไม่อ่านฟอนต์ OS/fontconfig — มันรีโซลฟ์เฉพาะไฟล์ที่คุณลงทะเบียน หากคุณตั้งใจดึงไฟล์ฟอนต์เข้าไปใน
/tmpหรือ volume ที่กำหนดไว้ คุณต้องลงทะเบียนมันอย่างชัดเจนกับ font registry และยอมรับต้นทุน cold-start และความน่าเชื่อถือที่เพิ่มขึ้น ให้รวมและลงทะเบียนไฟล์ ดูหน้าฟอนต์ที่ลิงก์ไว้ด้านบน NEXTPDF_FONTS_PATHไม่ทำอะไรเลยสำหรับเอนจินเปล่า มันเป็นค่าเริ่มต้นการกำหนดค่าของnextpdf/laravelไม่ใช่ตัวแปรที่nextpdf/coreอ่าน handler Bref เปล่าที่ตั้งเฉพาะตัวแปรนั้นจะไม่ลงทะเบียนฟอนต์ใดและเรนเดอร์เป็น tofu- Chrome bridge ไม่เหมาะกับฟังก์ชันแบบธรรมดา
writeHtmlChromeต้องการ Chromium แบบ headless และเส้นทาง subprocess ของsymfony/processการวาง Chromium บน Lambda ต้องใช้ custom layer ที่มีเบราว์เซอร์และไลบรารีของมัน แพ็กเกจที่ใหญ่ขึ้นมาก และ cold start ที่นาน เอนจิน native และwriteHtmlไม่ต้องการสิ่งเหล่านั้นเลย — ให้เลือกใช้มันบน serverless - ต้นทุน cold-start คือ autoload บวกการแยกวิเคราะห์ฟอนต์ ใช้
--optimize-autoloaderในการติดตั้ง production และวอร์ม registry ครั้งเดียวต่อคอนเทนเนอร์ อย่าวอร์มฟอนต์ที่คุณแทบไม่ใช้ - API Gateway ต้องการการจัดการไบนารี คืน
isBase64Encoded: trueพร้อมContent-Type: application/pdfและกำหนดค่า API ให้ปฏิบัติต่อapplication/pdfเป็น binary media type มิฉะนั้นไคลเอนต์จะได้รับไบต์ที่เสียหาย - Premium และ ionCube เป็นเรื่องของอาร์ติแฟกต์ที่หนักกว่า build NextPDF Pro / Enterprise ที่เข้ารหัสด้วย ionCube ต้องการ ionCube Loader ที่ตรงกับ PHP build ในรันไทม์พอดี ซึ่ง Bref layer มาตรฐานไม่มี นั่นอยู่นอกขอบเขตของการดีพลอย serverless แบบ core
หมายเหตุด้านความปลอดภัย
หัวข้อที่มีชื่อว่า “หมายเหตุด้านความปลอดภัย”- อย่าส่ง dev dependency ติดตั้งด้วย
--no-devเพื่อไม่ให้เครื่องมือทดสอบและวิเคราะห์เข้าไปในแพ็กเกจหรืออิมเมจของฟังก์ชัน - ตรวจสอบอินพุตก่อนสร้าง การ build PDF ที่ขับด้วยอินพุตคำขอเป็นช่องทางทำหน่วยความจำหมด ให้ปฏิเสธอินพุตที่อยู่นอกช่วงหรือใหญ่เกินที่ขอบเขตก่อนงาน build ใดเริ่มทำงาน และจำกัด concurrency เพื่อไม่ให้ทราฟฟิกสูงคูณหน่วยความจำสูงสุดจนกลายเป็นความล้มเหลวจากหน่วยความจำหมด
- เก็บฟอนต์และไลเซนส์ออกจากอาร์ติแฟกต์สาธารณะ รวมเฉพาะฟอนต์ที่คุณได้รับอนุญาตให้ฝัง และไม่เคยอบไฟล์ไลเซนส์ premium เข้าในอิมเมจหรือ layer ที่ push สู่สาธารณะ — ให้จัดหามันขณะรันไทม์ผ่านค่าสภาพแวดล้อมหรือ secret manager แทน
- สิทธิ์น้อยที่สุด ให้ฟังก์ชัน/บริการมีเฉพาะสิทธิ์ IAM ที่จำเป็น (ตัวอย่างเช่น สิทธิ์เขียนไปยัง output bucket เดียว) และรันคอนเทนเนอร์แบบไม่มีสิทธิ์พิเศษตามที่คู่มือ Docker แสดง
ความสอดคล้องตามมาตรฐาน
หัวข้อที่มีชื่อว่า “ความสอดคล้องตามมาตรฐาน”คู่มือนี้ไม่อ้างมาตรฐานเชิงบรรทัดฐานใด ข้อเท็จจริงของแพลตฟอร์มอ่านตรงจากแพ็กเกจ nextpdf/core: ข้อจำกัด php: >=8.4 <9.0 และส่วนขยายที่จำเป็น ext-mbstring, ext-intl, ext-gd, ext-openssl, ext-zlib และ ext-curl Bref PHP-8.4 runtime layer มาตรฐานรวมทั้งหกตัว อิมเมจทางการ php:8.4 ให้ openssl, curl และ zlib แต่ mbstring, gd และ intl ต้องติดตั้งและเปิดใช้ในการ build อิมเมจด้วย docker-php-ext-install (ดูหน้า Docker) การเรียก output คือพื้นผิว core จริง NextPDF\Core\Document::getPdfData(): string (พี่น้องฝั่งดิสก์ของมันคือ save(string $path): void) ฟอนต์ลงทะเบียนผ่าน NextPDF\Typography\FontRegistry — อาร์กิวเมนต์คอนสตรักเตอร์ไดเรกทอรีของมัน / addFontDirectory() พร้อม warmup(array $fontFiles) และ lock() สำหรับรูปแบบ cold-start — เดินสายผ่าน NextPDF\Core\DocumentFactory::create() NEXTPDF_FONTS_PATH เป็นคีย์การกำหนดค่า fonts_path ของแพ็กเกจ nextpdf/laravel (env('NEXTPDF_FONTS_PATH', resource_path('fonts'))) ไม่ใช่ตัวแปรที่ nextpdf/core อ่าน คำสั่ง doctor ของ CLI nextpdf ถูกประกาศเป็น "bin": ["bin/nextpdf"] ในแพ็กเกจและติดตั้งที่ vendor/bin/nextpdf ในแอปที่ใช้งาน ชื่อรันไทม์ Bref และพฤติกรรมของ AWS Lambda / Cloud Run / App Runner เป็นฟีเจอร์ที่ผู้ให้บริการเหล่านั้นมีเอกสารกำกับ
ดูเพิ่มเติม
หัวข้อที่มีชื่อว่า “ดูเพิ่มเติม”- บรรจุแอปพลิเคชัน NextPDF ลงคอนเทนเนอร์: อิมเมจ production ที่ใช้สำหรับเป้าหมาย Cloud Run / App Runner
- จัดเตรียมฟอนต์สำหรับเอนจิน native ในการใช้งานจริง: การตั้งชื่อไฟล์ฟอนต์ registry API และรูปแบบ warmup-and-lock ที่หน้านี้พึ่งพา
- สตรีม PDF ขนาดใหญ่ที่สร้างขึ้นเป็นการตอบสนอง HTTP: โมเดลหน่วยความจำสำหรับการคืนเอกสารที่สร้างแล้วผ่าน HTTP บน Cloud Run / App Runner
- เรนเดอร์ที่ edge ด้วย Cloudflare: เมื่อฟังก์ชันในกระบวนการไม่ใช่รันไทม์ที่เหมาะสม