[AWS] CodeDeploy: Lambda ๋กค๋ง ๋ฐฐํฌ

๋žŒ๋‹ค๋Š” ์—ฌ๋Ÿฌ๋ชจ๋กœ ์ •๋ง ํŽธ๋ฆฌํ•œ ์„œ๋น„์Šค ์ค‘ ํ•˜๋‚˜๋‹ค.
์ „๋ฐ˜์ ์ธ ๊ด€๋ฆฌ๋น„์šฉ์ด ๊ฑฐ์˜ ์—†๋‹ค๋Š” ๊ฒƒ๋„ ๊ทธ๋ ‡์ง€๋งŒ, ๋ฐฐํฌ๋„ ์ •๋ง ํŽธํ•˜๊ธด ํ•˜๋‹ค.
๊ทธ๋ƒฅ ์•„๋ž˜์ฒ˜๋Ÿผ ์†Œ์Šค๋งŒ ์••์ถ•ํ•ด์„œ ์˜ฌ๋ฆฌ๋ฉด ๋์ด๋‹ˆ ๋ง์ด๋‹ค.

๊ฒŒ๋‹ค๊ฐ€ ์ด์— ๋”ฐ๋ฅธ ์ƒˆ ๋ฒ„์ „ ์ „ํ™˜๋„ ์ƒ๋‹นํžˆ ๋น ๋ฅด๊ณ , ์†Œ์Šค๊ฐ€ ๋ฐ”๋€๋‹ค๊ณ  ์„œ๋น„์Šค๊ฐ€ ์ค‘๊ฐ„์— ๋Š๊ธฐ์ง€๋„ ์•Š๋Š”๋‹ค.

ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ ๊ทธ๋ƒฅ ๋ฌด์ž‘์ • ์˜ฌ๋ฆฌ๊ณ  ๋งˆ๋Š” ๊ฒƒ์€ ์ข€.. ์•„์‰ฌ์šด ์ ์ด ์žˆ๋‹ค.
๋งŒ์— ํ•˜๋‚˜๋ผ๋„ ์ƒˆ๋กœ ์˜ฌ๋ฆฌ๋Š” ์†Œ์Šค์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•˜๋‚˜? ๋ฐฐํฌ์‹œ์— ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ•œ๋ฒˆ๋” ์ตœ์ข… ์ ๊ฒ€์„ ํ•ด์•ผ ํ•˜์ง€ ์•Š๋‚˜?

๊ทธ๋ž˜์„œ ํ•„์š”ํ•œ ๊ฒƒ์ด [๋กค๋ง ๋ฐฐํฌ]๋ผ๋Š” ๊ฒƒ์ด๋‹ค.
๋กค๋ง ๋ฐฐํฌ๋Š” ์ƒˆ ๋ฒ„์ „์„ ์˜ฌ๋ฆฌ๋”๋ผ๋„ ์ƒˆ ๋ฒ„์ „์ด ์ž˜ ๋™์ž‘ํ• ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ณ , ์ž˜ ๋™์ž‘ํ•˜๋Š”๊ฒŒ ํ™•์ธ๋˜๋ฉด ๋ฒ„์ „์„ ๊ต์ฒดํ•˜๋˜, ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋ฐฐํฌ๋ฅผ ์ทจ์†Œํ•˜๋Š” ๊ธฐ๋ฒ•์ด๋‹ค.

Code Deploy๋ฅผ ํ†ตํ•ด ์ด๋ฅผ ์ ์šฉํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.




๋žŒ๋‹ค ๋ฒ„์ „ ์ƒ์„ฑ

๋žŒ๋‹ค๋Š” ๋ณ„๋‹ค๋ฅธ ์„ค์ •์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด LATEST ํ•˜๋‚˜์˜ ๋ฒ„์ „๋งŒ ์กด์žฌํ•˜๋‚˜, ๋กค๋ง ๋ฐฐํฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด ๋ฒ„์ „์„ ์ œ๋Œ€๋กœ ๋ช…์‹œํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

๋ฒ„์ „์ด ์—†๋Š” ์ƒํƒœ๋ผ๋ฉด ๋ฒ„์ „ ํƒญ์— ๋“ค์–ด๊ฐ€์„œ ๋ฒ„์ „์„ 2๊ฐœ ๋งŒ๋“ค์–ด์ฃผ์ž.

์šฐ๋ฆฌ๋Š” ์—ฌ๊ธฐ์„œ ๋ฒ„์ „ 1์ด ๊ธฐ์กด์˜ ์†Œ์Šค. ๋ฒ„์ „ 2๊ฐ€ ์ƒˆ๋กœ ๋ฐฐํฌํ•  ๋ฒ„์ „์˜ ์†Œ์Šค๋ผ๊ณ  ๊ฐ€์ •ํ•˜๊ฒ ๋‹ค.




๋žŒ๋‹ค ๋ณ„์นญ ์ƒ์„ฑ

๋กค๋ง ๋ฐฐํฌ๋ฅผ ์ œ๋Œ€๋กœ ์ ์šฉํ•˜๋ ค๋ฉด ๋žŒ๋‹ค์— ๋ณ„์นญ์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.
์ƒˆ๋กœ์šด ๋ฒ„์ „์˜ ๋žŒ๋‹ค๊ฐ€ ๊ณ„์† ์˜ฌ๋ผ์˜ค๋”๋ผ๋„ ์ตœ์ข… ์—”๋“œํฌ์ธํŠธ๋Š” ํ•˜๋‚˜์—ฌ์•ผ ํ•˜์ง€ ์•Š๊ฒ ๋Š”๊ฐ€? ๊ทธ๊ฑธ ์žก์•„์ฃผ๋Š” ๊ฒƒ์ด ๋ณ„์นญ์ด๋‹ค.

์ €๊ธฐ ๋ณ„์นญ ํƒญ์— ๋ณด๋ฉด ๋ณ„์นญ ์ƒ์„ฑ ๋ฒ„ํŠผ์ด ์žˆ๋‹ค.

์ด๋ฆ„์€ ์ ๋‹นํžˆ ์ž˜ ์ง€์–ด์ค€๋‹ค.
์—ฌ๊ธฐ์„œ๋Š” 1 ๋ฒ„์ „์˜ ๋ณ„์นญ์œผ๋กœ ๋งŒ๋“ค ๊ฒƒ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ด ๋ณ„์นญ์„ ํ†ตํ•ด ์ตœ์ข… ๋ฐฐํฌ๋ฅผ ํ•˜๋ฉด ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

API GateWay๋กœ Api ์—ด์–ด์ฃผ๊ณ  ์“ฐ๋ฉด ๋˜๋Š”๋ฐ, ์ฃผ์˜ํ•  ์ ์€ ์ด๋Ÿด๋•Œ ๊ทธ๋ƒฅ ํ•จ์ˆ˜๋ช…์„ ์ ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ๋ณ„์นญ์˜ ARN์„ ๋„ฃ์–ด์ค˜์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์ด๋ ‡๊ฒŒ ๋ง์ด๋‹ค.




Code Deploy ์•ฑ ์ƒ์„ฑ

Code Deploy์— ๋“ค์–ด๊ฐ€์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ์„ ์„ ํƒ, ํ”Œ๋žซํผ์„ ๋žŒ๋‹ค๋กœ ํ•˜๊ณ  ์ƒ์„ฑํ•œ๋‹ค.


๊ทธ๋Ÿผ ์ด๋ ‡๊ฒŒ ๋ฐฐํฌ ๊ด€๋ฆฌ ํŽ˜์ด์ง€๊ฐ€ ์ƒ๊ฒจ๋‚  ๊ฒƒ์ด๋‹ค.

๊ทธ๋Ÿผ ์ด์ œ ๋ฐฐํฌ ๊ทธ๋ฃน์„ ์ƒ์„ฑํ•ด์„œ


์ €๊ธฐ์— ์„œ๋น„์Šค ์—ญํ• ์„ ๋งŒ๋“ค์–ด์„œ arn์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.




์„œ๋น„์Šค ์—ญํ•  ์ƒ์„ฑ

๋ฐฐํฌ๊ทธ๋ฃน์— ์‚ฌ์šฉํ•  ์—ญํ• ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ์ €๊ฑธ ๊ณจ๋ผ์„œ


์ •์ฑ…์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด 2๊ฐœ ์—ฐ๊ฒฐํ•ด์ฃผ๊ณ 

์‹ ๋ขฐ๊ด€๊ณ„์— codedeploy ๋„๋ฉ”์ธ์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

๊ทธ๋Ÿผ ์ด๋ ‡๊ฒŒ ์ƒ์„ฑ์ด ์ž˜ ๋  ๊ฒƒ์ด๋‹ค.




๋กค๋ฐฑ ์„ค์ •

๋งŒ์•ฝ ์ƒˆ๋กœ๋งŒ๋“  ๋žŒ๋‹ค ๋ฒ„์ „์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ๋กค๋ฐฑ์„ ์‹œ์ผœ์•ผ ํ•˜์ง€ ์•Š๊ฒ ๋Š”๊ฐ€.
๋ฐ‘์— ๊ณ ๊ธ‰์—์„œ ๋กค๋ฐฑ ๋น„ํ™œ์„ฑํ™”๋ฅผ ํ•ด์ œํ•˜๊ณ  ๋กค๋ฐฑ์„ ์„ค์ •ํ•ด์ฃผ์ž.

์ด๋ ‡๊ฒŒ ํ•ด์„œ CodeDeploy ์•ฑ์„ ๋งŒ๋“ค์–ด์ฃผ๋ฉด ๋œ๋‹ค.




๋ฒ„ํ‚ท ์ƒ์„ฑ

์ด๊ฒŒ ๋‹ค๊ฐ€ ์•„๋‹ˆ๋‹ค.
๋ฐฐํฌํ• ๋•Œ๋งˆ๋‹ค ๋ฒ„์ „์„ ์–ด๋–ป๊ฒŒ ์˜ฌ๋ฆด์ง€ ๊ทธ๋Ÿฐ๊ฑธ ์ •์˜ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๊ฑธ appspec ํŒŒ์ผ์ด๋ผ๊ณ  ํ•œ๋‹ค.

๊ทธ๊ฑธ ์ €์žฅํ•ด๋†“์„ S3 ๋ฒ„ํ‚ท์„ ๋งŒ๋“ค์–ด์ฃผ์ž.

๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ˜•์‹์œผ๋กœ ๋ฐฐํฌ ์„ค์ •ํŒŒ์ผ์„ ์จ์„œ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

version: 0.0
Resources:
  - myLambdaFunction:
      Type: AWS::Lambda::Function
      Properties:
        Name: "express_test"
        Alias: "rolling"
        CurrentVersion: "7"
        TargetVersion: "8"
Hooks:
  - BeforeAllowTraffic: "code-deploy-check"

์—ฌ๊ธฐ์„œ Name์€ ๋ง ๊ทธ๋Œ€๋กœ ํ•จ์ˆ˜๋ช…, Alias๋Š” ์•„๊นŒ ๋งŒ๋“  ๋ณ„์นญ.
Current๋Š” ํ˜„์žฌ ๋ฐฐํฌ๋˜์–ด์žˆ๋Š” ๋ฒ„์ „. TargetVersion์€ ๋ฐฐํฌํ•  ๋ฒ„์ „์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  BeforeAllowTraffic๋Š” ํŠธ๋ž˜ํ”ฝ์„ ์˜ฎ๊ธฐ๊ธฐ ์ „์— ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ๊ฑธ์–ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.
๊ฐ’์œผ๋กœ ๋“ค์–ด๊ฐ€๋Š”๊ฑด ํ•จ์ˆ˜๋ช…์ด๋‹ค.
์ €๊ธฐ์„œ ์†Œ์Šค์˜ ์ •์ƒ์ž‘๋™์— ๋Œ€ํ•œ ๊ฒ€์ฆ์„ ํ•˜๋ฉด ๋œ๋‹ค.




Health Check์šฉ ํ›… ํ•จ์ˆ˜

ํ›… ํ•จ์ˆ˜๋Š” ๋Œ€๋žต ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

'use strict';

const aws = require('aws-sdk');
const codedeploy = new aws.CodeDeploy({apiVersion: '2014-10-06'});

exports.handler = async (event, context, callback) => {
    //Read the DeploymentId from the event payload.
    var deploymentId = event.DeploymentId;

    //Read the LifecycleEventHookExecutionId from the event payload
    var lifecycleEventHookExecutionId = event.LifecycleEventHookExecutionId;

    /*
    ... ์—ฌ๊ธฐ์„œ ๊ฒ€์ฆ.
    */

    // Prepare the validation test results with the deploymentId and
    // the lifecycleEventHookExecutionId for CodeDeploy.
    var params = {
        deploymentId: deploymentId,
        lifecycleEventHookExecutionId: lifecycleEventHookExecutionId,
        status: 'Succeeded' // status can be 'Succeeded' or 'Failed'
    };

    //const bar = await codedeploy.getDe

    // Pass CodeDeploy the prepared validation test results.
    codedeploy.putLifecycleEventHookExecutionStatus(params, function(err, data) {
        if (err) {
            // ๊ฒ€์ฆ ์‹คํŒจ
            callback('Validation test failed');
        } else {
            // ๊ฒ€์ฆ ์„ฑ๊ณต
            callback(null, 'Validation test succeeded');
        }
    });
};

์ด๊ฑด ๊ณต์‹๋ฌธ์„œ์—์„œ ์ œ๊ณตํ•˜๋Š” ํ…œํ”Œ๋ฆฟ์ด๊ณ , ๋‚˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ–ˆ๋‹ค.

๋žŒ๋‹ค์˜ target version์„ ํ˜ธ์ถœํ•ด์„œ ์˜ค๋ฅ˜๊ฐ€ ๋‚˜๋ฉด putLifecycleEventHookExecutionStatus๋กœ ์‹คํŒจํ–ˆ๋‹ค๊ณ  ์ด๋ฒคํŠธ๋ฅผ ๋‚ ๋ ค์ฃผ๊ณ , ๋ฌธ์ œ์—†์œผ๋ฉด putLifecycleEventHookExecutionStatus์— ์„ฑ๊ณต์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์ด๋‹ค.

'use strict';

const aws = require('aws-sdk');
const codedeploy = new aws.CodeDeploy({apiVersion: '2014-10-06'});
const lambda = new aws.Lambda();

exports.handler = async (event, context, callback) => {
    // ์ด ๊ฐ’์€ BeforeAllowTraffic๋กœ ๊ฑธ๋ฉด ์ž๋™์œผ๋กœ ๋“ค์–ด์˜ด
    const deploymentId = event.DeploymentId;
    const lifecycleEventHookExecutionId = event.LifecycleEventHookExecutionId;

    // ์ฒดํฌ์šฉ ํ˜ธ์ถœ
    const response = await lambda
		.invoke({
			FunctionName: 'express_test:9', //๋ฒ„์ „์€ ๋ฐฐํฌ์ค‘์ธ target ๋ฒ„์ „์ด ๋“ค์–ด๊ฐ€๊ฒŒ ํ•ด์ฃผ๋ฉด ๋จ.
			Payload: JSON.stringify({}),
		})
		.promise()

	console.log('response: ', response)

	if(response.FunctionError !=='Unhandled') {
	    console.log('์„ฑ๊ณต')
	    await codedeploy.putLifecycleEventHookExecutionStatus({
            deploymentId: deploymentId,
            lifecycleEventHookExecutionId: lifecycleEventHookExecutionId,
            status: 'Succeeded'
        }).promise();

        callback(null, 'Validation test succeeded');
	} 
	else {
	    console.log('์‹คํŒจ')
	    await codedeploy.putLifecycleEventHookExecutionStatus({
            deploymentId: deploymentId,
            lifecycleEventHookExecutionId: lifecycleEventHookExecutionId,
            status: 'Failed' 
        }).promise();

        callback('Validation test failed');
	}
};

๋žŒ๋‹ค ์—ญํ• ์— CodeDeploy์™€ LambdaInvoke ๊ถŒํ•œ์„ ๊ฑธ์–ด์ฃผ๊ณ , ๋ฉ”๋ชจ๋ฆฌ์™€ ์‹คํ–‰์‹œ๊ฐ„ ์ œํ•œ์„ ์ข€ ๋Š˜๋ ค์ค˜์•ผ ํ•œ๋‹ค.

์—ฌ๊ธฐ์„œ ๋‚˜๋Š” ๋‹จ์ˆœํ•˜๊ฒŒ ๋ฉ”์ธ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋œจ๋Š”์ง€ ์•„๋‹Œ์ง€๋งŒ ๊ฒ€์‚ฌํ–ˆ์ง€๋งŒ, ์ƒํ™ฉ์— ๋”ฐ๋ผ์„œ ๋” ๋งŽ์€ ๊ฒ€์ฆ์„ ํ•ด์•ผํ•  ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.




๋ฐฐํฌ ์ƒ์„ฑ

์ด์ œ ๋ฐฐํฌ ์„ค์ •์„ ๋งŒ๋“ค์–ด๋ณด์ž.

์ด๋ฆ„์„ ์ง“๊ณ , ์œ„์—์„œ ๋งŒ๋“  ๋ฐฐํฌ์šฉ ์„ค์ •ํŒŒ์ผ์„ ์—ฐ๊ฒฐํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
s3๋กœ ๋ฐ›์•„์™€๋„ ๋˜๊ณ , ํŽธ์ง‘๊ธฐ๋กœ ๊ทธ๋ƒฅ ํ…์ŠคํŠธ๋ฅผ ๋ฐ•์„ ์ˆ˜๋„ ์žˆ๋‹ค.


๊ทธ๋ฆฌ๊ณ  ๋ฐฐํฌ ๊ตฌ์„ฑ๊ณผ ๋กค๋ฐฑ ๊ตฌ์„ฑ์„ ์„ค์ •ํ•ด์ค€๋‹ค.
์ด์™•์ด๋ฉด ๋กค๋ฐฑ์€ ๋˜๊ฒŒ ํ•ด๋‘๋Š”๊ฒŒ ์ข‹๊ฒ ๊ณ ...

๋ฐฐํฌ ๊ตฌ์„ฑ์€ ํ•„์š”์— ๋”ฐ๋ผ ๋‹ค์Œ ๋ฆฌ์ŠคํŠธ ์ค‘์— ๊ณ ๋ฅด๋ฉด ๋œ๋‹ค.

๋‚˜๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ์นด๋‚˜๋ฆฌ๊ฐ€ ์ข‹์€ ๊ฒƒ ๊ฐ™๋‹ค.

๊ทธ๋ž˜์„œ ์ด๋ ‡๊ฒŒ ๋‹ค ํ†ต๊ณผํ•˜๋ฉด ์ž˜ ๋ฐฐํฌ๊ฐ€ ๋œ ๊ฒƒ์ด๋‹ค.

์ ‘์†๋„ ์ž˜ ๋˜๋ฉด ์„ฑ๊ณต์ด๋‹ค.

๋งŒ์•ฝ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์†Œ์Šค์— ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š” ์ฑ„๋กœ ๋ฐฐํฌ๋ฅผ ์‹œ๋„ํ•œ๋‹ค๋ฉด

ํ›… ํ•จ์ˆ˜์—์„œ failed๋ฅผ ๋‚ ๋ฆฌ๋ฏ€๋กœ ๋ฐฐํฌ๊ฐ€ ์ทจ์†Œ๋˜๊ณ  ๋กค๋ฐฑ์ด ์ˆ˜ํ–‰๋  ๊ฒƒ์ด๋‹ค.

๊ทธ๋ ‡๋‹ค.


์ฐธ์กฐ
https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/lambda-rolling-deployments.html
https://docs.aws.amazon.com/codedeploy/latest/userguide/tutorial-lambda-sam.html
https://docs.aws.amazon.com/codedeploy/latest/userguide/getting-started-create-service-role.html
https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/reference-appspec-file-example.html
https://ystatit.medium.com/aws-codedeploy-basic-walk-through-lambda-cf3be01d3e06
https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html#appspec-hooks-lambda