本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
撰寫 Node.js Canary 指令碼
主題
從頭開始建立 CloudWatch Synthetics Canary
下面是基本 Synthetics Canary 指令碼的範例。此指令碼作為成功執行傳遞,並傳回一個字串。若想查看失敗的 Canary 看起來是什麼樣子,請將 let fail = false;
變更為 let fail = true;
。
您必須定義 Canary 指令碼的進入點函數。若要了解如何將檔案上傳至指定為 Canary 的 Amazon S3 位置ArtifactS3Location
,請在 下建立這些檔案,the /tmp folder. After the script runs, the pass/fail status and the duration metrics are published to CloudWatch and the files under /tmp並上傳至 S3。
const basicCustomEntryPoint = async function () { // Insert your code here // Perform multi-step pass/fail check // Log decisions made and results to /tmp // Be sure to wait for all your code paths to complete // before returning control back to Synthetics. // In that way, your canary will not finish and report success // before your code has finished executing // Throw to fail, return to succeed let fail = false; if (fail) { throw "Failed basicCanary check."; } return "Successfully completed basicCanary checks."; }; exports.handler = async () => { return await basicCustomEntryPoint(); };
接下來,我們將展開指令碼以使用 Synthetics 記錄,並使用 撥打電話 AWS SDK。為了示範目的,此指令碼會建立 Amazon DynamoDB 用戶端,並呼叫 DynamoDB listTables API。它會記錄對請求的回應,並根據請求是否成功,記錄通過或是失敗。
const log = require('SyntheticsLogger'); const AWS = require('aws-sdk'); // Require any dependencies that your script needs // Bundle additional files and dependencies into a .zip file with folder structure // nodejs/node_modules/
additional files and folders
const basicCustomEntryPoint = async function () { log.info("Starting DynamoDB:listTables canary."); let dynamodb = new AWS.DynamoDB(); var params = {}; let request = await dynamodb.listTables(params); try { let response = await request.promise(); log.info("listTables response: " + JSON.stringify(response)); } catch (err) { log.error("listTables error: " + JSON.stringify(err), err.stack); throw err; } return "Successfully completed DynamoDB:listTables canary."; }; exports.handler = async () => { return await basicCustomEntryPoint(); };
包裝 Node.js Canary 檔案
如果您使用 Simple Storage Service (Amazon S3) 位置上傳 Canary 指令碼,則 zip 檔案應在此資料夾結構下包含指令碼:nodejs/node_modules/
。myCanaryFilename.js file
如果您有多個.js
檔案,或者您有指令碼依賴的相依性,您可以將它們全部綁定到包含資料夾結構 的單一ZIP檔案中nodejs/node_modules/
。如果您是使用 myCanaryFilename.js file and other folders and files
syn-nodejs-puppeteer-3.4
或更高版本,您可以選擇將 Canary 檔案放在另一個資料夾中,並像這樣建立資料夾結構:nodejs/node_modules/
。myFolder
/myCanaryFilename.js file and other folders and files
處理常式名稱
請務必將 Canary 的指令碼進入點 (處理常式) 設定為 myCanaryFilename.functionName
,以符合指令碼進入點的檔案名稱。如果您使用的執行時間早於 syn-nodejs-puppeteer-3.4
,則 functionName
必須為 handler
。如果您使用的是 syn-nodejs-puppeteer-3.4
或更高版本,您可以選擇任何函數名稱作為處理常式。如果您使用的是 syn-nodejs-puppeteer-3.4
或更高版本,您還可以選擇將 Canary 存放在單獨的資料夾 (例如 nodejs/node_modules/myFolder/my_canary_filename
) 中。如果將其存放在單獨的資料夾中,請在指令碼進入點中指定該路徑,例如 myFolder/my_canary_filename.functionName
。
變更現有的 Puppeteer 指令碼以作為 Synthetics Canary 使用
本節介紹如何採用 Puppeteer 指令碼和修改它們以作為 Synthetics Canary 指令碼執行。如需 Puppeteer 的詳細資訊,請參閱 Puppeteer v1API.14.0
我們將從這個 Puppeteer 指令碼範例開始:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://example.com'); await page.screenshot({path: 'example.png'}); await browser.close(); })();
轉換步驟如下:
建立和匯出
handler
函數。處理常式是指令碼的進入點函數。如果您使用的執行時間早於syn-nodejs-puppeteer-3.4
,則處理常式函數必須命名為handler
。如果您使用的是syn-nodejs-puppeteer-3.4
或更高版本,函數可以具有任何名稱,但其必須與指令碼中使用的名稱相同。另外,如果您使用的是syn-nodejs-puppeteer-3.4
或更高版本,您可以將指令碼存放在任何資料夾下,並將該資料夾指定為處理常式名稱的一部分。const basicPuppeteerExample = async function () {}; exports.handler = async () => { return await basicPuppeteerExample(); };
使用
Synthetics
相依性。var synthetics = require('Synthetics');
使用
Synthetics.getPage
函數來取得 PuppeteerPage
物件。const page = await synthetics.getPage();
Synthetics.getPage function 傳回的頁面物件具有 page.on
request
response
和用於記錄requestfailed
的事件。Synthetics 也會為頁面上的請求和回應設定HAR檔案產生,並將 Canary 新增至頁面上傳出請求ARN的使用者代理標頭。
指令碼現在已準備好作為 Synthetics Canary 執行。這是更新後的指令碼:
var synthetics = require('Synthetics'); // Synthetics dependency const basicPuppeteerExample = async function () { const page = await synthetics.getPage(); // Get instrumented page from Synthetics await page.goto('https://example.com'); await page.screenshot({path: '/tmp/example.png'}); // Write screenshot to /tmp folder }; exports.handler = async () => { // Exported handler function return await basicPuppeteerExample(); };
環境變數
建立 Canary 時,您可以使用環境變數。這允許您編寫單一 Canary 指令碼,然後使用具有不同數值的指令碼來快速建立具有類似任務的多個 Canary。
例如,假設您的組織在軟體開發的不同階段擁有諸如 prod
、dev
和 pre-release
之類的端點,並且您需要建立 Canary 來測試這些端點。您可以撰寫測試軟體的單一 Canary 指令碼,然後在建立三個 Canary 的每一個 Canary 時,為端點環境變數指定不同的數值。然後,當您建立 Canary 時,您可以指定要用於環境變數的指令碼和數值。
環境變數名稱可包含字母、數字和底線字元。其必須以字母開頭,且至少有兩個字元。環境變數的總大小不能超過 4 KB。您無法指定任何 Lambda 保留環境變數作為環境變數的名稱。如需有關保留環境變數的詳細資訊,請參閱執行時間環境變數。
重要
環境變數索引鍵和值未加密。請勿在其中存放敏感資訊。
以下範例指令碼使用了兩個環境變數。這個指令碼可用於檢查網頁是否可用的 Canary。它使用環境變數來參數化其檢查URL的 及其使用的 CloudWatch Synthetics 日誌層級。
以下函數會將 LogLevel
設定為 LOG_LEVEL
環境變數的數值。
synthetics.setLogLevel(process.env.LOG_LEVEL);
此函數會將 URL
設定為 URL
環境變數的數值。
const URL = process.env.URL;
這是完整的指令碼。當您使用此指令碼建立 Canary 時,您可以指定要用於 LOG_LEVEL
和 URL
環境變數的數值。
var synthetics = require('Synthetics'); const log = require('SyntheticsLogger'); const pageLoadEnvironmentVariable = async function () { // Setting the log level (0-3) synthetics.setLogLevel(process.env.LOG_LEVEL); // INSERT URL here const URL = process.env.URL; let page = await synthetics.getPage(); //You can customize the wait condition here. For instance, //using 'networkidle2' may be less restrictive. const response = await page.goto(URL, {waitUntil: 'domcontentloaded', timeout: 30000}); if (!response) { throw "Failed to load page!"; } //Wait for page to render. //Increase or decrease wait time based on endpoint being monitored. await page.waitFor(15000); await synthetics.takeScreenshot('loaded', 'loaded'); let pageTitle = await page.title(); log.info('Page title: ' + pageTitle); log.debug('Environment variable:' + process.env.URL); //If the response status code is not a 2xx success code if (response.status() < 200 || response.status() > 299) { throw "Failed to load page!"; } }; exports.handler = async () => { return await pageLoadEnvironmentVariable(); };
將環境變數傳遞給指令碼
若要在主控台中建立 Canary 時將環境變數傳遞至指令碼,請在主控台的 Environment variables (環境變數) 區段中指定環境變數的金鑰和數值。如需詳細資訊,請參閱建立 Canary。
若要透過 API或 傳遞環境變數 AWS CLI,請使用 RunConfig
區段中的 EnvironmentVariables
參數。以下是建立 Canary 的範例 AWS CLI 命令,該 Canary 使用兩個具有 Environment
和 金鑰的環境變數Region
。
aws synthetics create-canary --cli-input-json '{ "Name":"nameofCanary", "ExecutionRoleArn":"roleArn", "ArtifactS3Location":"s3://amzn-s3-demo-bucket-123456789012-us-west-2", "Schedule":{ "Expression":"rate(0 minute)", "DurationInSeconds":604800 }, "Code":{ "S3Bucket": "canarycreation", "S3Key": "cwsyn-mycanaryheartbeat-12345678-d1bd-1234-abcd-123456789012-12345678-6a1f-47c3-b291-123456789012.zip", "Handler":"pageLoadBlueprint.handler" }, "RunConfig": { "TimeoutInSeconds":60, "EnvironmentVariables": { "Environment":"Production", "Region": "us-west-1" } }, "SuccessRetentionPeriodInDays":13, "FailureRetentionPeriodInDays":13, "RuntimeVersion":"syn-nodejs-2.0" }'
將您的 Canary 與其他 AWS 服務整合
所有 Canary AWS SDK都可以使用 程式庫。您可以在撰寫 Canary 以整合 Canary 與其他 AWS 服務時使用此程式庫。
要這麼做,您需要新增下面的程式碼到您的 Canary。對於這些範例, AWS Secrets Manager 會用作 Canary 正在整合的服務。
匯入 AWS SDK。
const AWS = require('aws-sdk');
為您整合 AWS 的服務建立用戶端。
const secretsManager = new AWS.SecretsManager();
使用 用戶端對此服務進行API呼叫。
var params = { SecretId: secretName }; return await secretsManager.getSecretValue(params).promise();
下面的 Canary 指令碼程式碼片段示範了與 Secrets Manager 整合的詳細範例。
var synthetics = require('Synthetics'); const log = require('SyntheticsLogger'); const AWS = require('aws-sdk'); const secretsManager = new AWS.SecretsManager(); const getSecrets = async (secretName) => { var params = { SecretId: secretName }; return await secretsManager.getSecretValue(params).promise(); } const secretsExample = async function () { let URL = "<URL>"; let page = await synthetics.getPage(); log.info(`Navigating to URL: ${URL}`); const response = await page.goto(URL, {waitUntil: 'domcontentloaded', timeout: 30000}); // Fetch secrets let secrets = await getSecrets("secretname") /** * Use secrets to login. * * Assuming secrets are stored in a JSON format like: * { * "username": "<USERNAME>", * "password": "<PASSWORD>" * } **/ let secretsObj = JSON.parse(secrets.SecretString); await synthetics.executeStep('login', async function () { await page.type(">USERNAME-INPUT-SELECTOR<", secretsObj.username); await page.type(">PASSWORD-INPUT-SELECTOR<", secretsObj.password); await Promise.all([ page.waitForNavigation({ timeout: 30000 }), await page.click(">SUBMIT-BUTTON-SELECTOR<") ]); }); // Verify login was successful await synthetics.executeStep('verify', async function () { await page.waitForXPath(">SELECTOR<", { timeout: 30000 }); }); }; exports.handler = async () => { return await secretsExample(); };
強制您的 Canary 使用靜態 IP 地址
您可以設定 Canary,以便使用靜態 IP 地址。
若要強制 Canary 使用靜態 IP 地址
建立新的 VPC。如需詳細資訊,請參閱DNS搭配使用您的 VPC。
建立新的網際網路閘道。如需詳細資訊,請參閱將網際網路閘道新增至您的 VPC。
在新的 內建立公有子網路VPC。
將新的路由表新增至 VPC。
在新的路由表中新增一個路由,而該路由從
0.0.0.0/0
移至網際網路閘道。將新的路由表與公有子網路建立關聯。
建立彈性 IP 地址。如需詳細資訊,請參閱彈性 IP 地址。
建立新的NAT閘道,並將其指派給公有子網路和彈性 IP 地址。
在 內建立私有子網路VPC。
將路由新增至VPC預設路由表,從
0.0.0.0/0
前往NAT閘道建立 Canary。