런타임 버전 업데이트
CloudWatch 콘솔, AWS CloudFormation, AWS CLI 또는 AWS SDK를 사용하여 canary의 런타임 버전을 업데이트할 수 있습니다. CloudWatch 콘솔을 사용할 경우 한 번에 최대 5개의 canary를 업데이트할 수 있는데, canary 목록 페이지에서 canary를 선택한 다음, [작업(Actions)], [런타임 업데이트(Update Runtime)]를 선택하면 됩니다.
런타임 업데이트를 커밋하기 전에 먼저 업데이트를 테스트하여 업데이트를 확인할 수 있습니다. 런타임 버전을 업데이트할 때 CloudWatch 콘솔에서 모의 실행 시작 또는 나중에 검증 및 저장 옵션을 선택하여 구성 변경 사항과 함께 원래 카나리의 모의 실행을 생성합니다. 모의 실행은 카나리를 업데이트하고 실행하여 런타임 업데이트가 카나리에 안전한지 확인합니다. 새 런타임 버전의 카나리를 확인한 후에는 카나리의 런타임 버전을 업데이트합니다. 자세한 내용은 안전한 카나리 업데이트 수행 섹션을 참조하세요.
또는 CloudWatch 콘솔을 사용하여 카나리를 복제하고 해당 런타임 버전을 업데이트하여 업데이트를 확인할 수 있습니다. 이렇게 하면 원래 canary의 복제인 또 다른 canary가 생성됩니다. 새 런타임 버전의 canary를 확인한 후에는 원래 canary의 런타임 버전을 업데이트하고 복제 canary를 삭제할 수 있습니다.
또한 업그레이드 스크립트를 사용하여 여러 canary를 업데이트할 수도 있습니다. 자세한 내용은 canary 런타임 업그레이드 스크립트 단원을 참조하세요.
canary를 업그레이드했는데 canary가 실패한 경우 실패한 canary 문제 해결 단원을 참조하세요.
canary 런타임 업그레이드 스크립트
canary 스크립트를 지원되는 런타임 버전으로 업그레이드하려면 다음 스크립트를 사용합니다.
const AWS = require('aws-sdk'); // You need to configure your AWS credentials and Region. // https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html // https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html const synthetics = new AWS.Synthetics(); const DEFAULT_OPTIONS = { /** * The number of canaries to upgrade during a single run of this script. */ count: 10, /** * No canaries are upgraded unless force is specified. */ force: false }; /** * The number of milliseconds to sleep between GetCanary calls when * verifying that an update succeeded. */ const SLEEP_TIME = 5000; (async () => { try { const options = getOptions(); const versions = await getRuntimeVersions(); const canaries = await getAllCanaries(); const upgrades = canaries .filter(canary => !versions.isLatestVersion(canary.RuntimeVersion)) .map(canary => { return { Name: canary.Name, FromVersion: canary.RuntimeVersion, ToVersion: versions.getLatestVersion(canary.RuntimeVersion) }; }); if (options.force) { const promises = []; for (const upgrade of upgrades.slice(0, options.count)) { const promise = upgradeCanary(upgrade); promises.push(promise); // Sleep for 100 milliseconds to avoid throttling. await usleep(100); } const succeeded = []; const failed = []; for (let i = 0; i < upgrades.slice(0, options.count).length; i++) { const upgrade = upgrades[i]; const promise = promises[i]; try { await promise; console.log(`The update of ${upgrade.Name} succeeded.`); succeeded.push(upgrade.Name); } catch (e) { console.log(`The update of ${upgrade.Name} failed with error: ${e}`); failed.push({ Name: upgrade.Name, Reason: e }); } } if (succeeded.length) { console.group('The following canaries were upgraded successfully.'); for (const name of succeeded) { console.log(name); } console.groupEnd() } else { console.log('No canaries were upgraded successfully.'); } if (failed.length) { console.group('The following canaries were not upgraded successfully.'); for (const failure of failed) { console.log('\x1b[31m', `${failure.Name}: ${failure.Reason}`, '\x1b[0m'); } console.groupEnd(); } } else { console.log('Run with --force [--count <count>] to perform the first <count> upgrades shown. The default value of <count> is 10.') console.table(upgrades); } } catch (e) { console.error(e); } })(); function getOptions() { const force = getFlag('--force', DEFAULT_OPTIONS.force); const count = getOption('--count', DEFAULT_OPTIONS.count); return { force, count }; function getFlag(key, defaultValue) { return process.argv.includes(key) || defaultValue; } function getOption(key, defaultValue) { const index = process.argv.indexOf(key); if (index < 0) { return defaultValue; } const value = process.argv[index + 1]; if (typeof value === 'undefined' || value.startsWith('-')) { throw `The ${key} option requires a value.`; } return value; } } function getAllCanaries() { return new Promise((resolve, reject) => { const canaries = []; synthetics.describeCanaries().eachPage((err, data) => { if (err) { reject(err); } else { if (data === null) { resolve(canaries); } else { canaries.push(...data.Canaries); } } }); }); } function getRuntimeVersions() { return new Promise((resolve, reject) => { const jsVersions = []; const pythonVersions = []; synthetics.describeRuntimeVersions().eachPage((err, data) => { if (err) { reject(err); } else { if (data === null) { jsVersions.sort((a, b) => a.ReleaseDate - b.ReleaseDate); pythonVersions.sort((a, b) => a.ReleaseDate - b.ReleaseDate); resolve({ isLatestVersion(version) { const latest = this.getLatestVersion(version); return latest === version; }, getLatestVersion(version) { if (jsVersions.some(v => v.VersionName === version)) { return jsVersions[jsVersions.length - 1].VersionName; } else if (pythonVersions.some(v => v.VersionName === version)) { return pythonVersions[pythonVersions.length - 1].VersionName; } else { throw Error(`Unknown version ${version}`); } } }); } else { for (const version of data.RuntimeVersions) { if (version.VersionName === 'syn-1.0') { jsVersions.push(version); } else if (version.VersionName.startsWith('syn-nodejs-2.')) { jsVersions.push(version); } else if (version.VersionName.startsWith('syn-nodejs-puppeteer-')) { jsVersions.push(version); } else if (version.VersionName.startsWith('syn-python-selenium-')) { pythonVersions.push(version); } else { throw Error(`Unknown version ${version.VersionName}`); } } } } }); }); } async function upgradeCanary(upgrade) { console.log(`Upgrading canary ${upgrade.Name} from ${upgrade.FromVersion} to ${upgrade.ToVersion}`); await synthetics.updateCanary({ Name: upgrade.Name, RuntimeVersion: upgrade.ToVersion }).promise(); while (true) { await usleep(SLEEP_TIME); console.log(`Getting the state of canary ${upgrade.Name}`); const response = await synthetics.getCanary({ Name: upgrade.Name }).promise(); const state = response.Canary.Status.State; console.log(`The state of canary ${upgrade.Name} is ${state}`); if (state === 'ERROR' || response.Canary.Status.StateReason) { throw response.Canary.Status.StateReason; } if (state !== 'UPDATING') { return; } } } function usleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }