AWS-CICD

CodeDeploy 성공 시 Lambda로 AMI 생성 및 ASG 롤링 업데이트 자동화 – 조건부 트리거 설정까지!

backend 따라쟁이 2025. 3. 27. 23:18

배포가 끝이 아니라 시작입니다. 운영 환경까지 자동으로 정비되는 DevOps 파이프라인을 구축해보세요.


🧩 시나리오

CI/CD 환경에서 CodeDeploy를 통해 EC2 인스턴스에 애플리케이션을 성공적으로 배포한 후, 다음을 자동으로 처리하고 싶습니다.

  • 배포된 인스턴스를 기준으로 최신 AMI 생성
  • Launch Template의 새로운 버전 생성 및 적용
  • ASG에서 새 AMI를 기반으로 인스턴스 순차 교체(Rolling Update)

하지만 조건이 있습니다.

여러 CodeDeploy 프로젝트 중에서도 특정 애플리케이션과 배포 그룹에서만 이 Lambda가 실행되길 원합니다.


✅ 전체 아키텍처

[CodeDeploy]
    │
    ▼ (성공 시 이벤트)
[EventBridge (조건 필터링)]
    │
    ▼
[Lambda]
 ├─ AMI 생성
 ├─ Launch Template 새 버전 생성
 └─ Auto Scaling Group Rolling Update​

🔧 Lambda 함수 생성 및 설정 (콘솔 기준)

  1. Lambda 서비스 → 함수 생성
    • 이름: CreateAmiAndUpdateAsg
    • 런타임: Python 3.9
    • 역할: 기존 역할 사용 또는 새 역할 생성
  2. 환경 변수 설정
    • LAUNCH_TEMPLATE_NAME: 예) my-launch-template
    • ASG_NAME: 예) my-asg-group
  3. 코드 등록 및 배포
    • Lambda 콘솔 내 편집기에서 전체 코드 복사하여 붙여넣고 배포
  4. IAM 정책 추가
    • Lambda 실행 역할에 아래 권한을 포함해야 합니다:

[ 권한1 : CodeDeploy 정보 획득 관련 권한 ]

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "codedeploy:ListDeploymentInstances",
                "codedeploy:GetDeploymentInstance",
                "codedeploy:GetDeployment",
                "codedeploy:GetDeploymentGroup"
            ],
            "Resource": [
                "arn:aws:codedeploy:{리전}:{게정ID}:deploymentgroup:{애플리케이션}/{배포그룹}",
                "arn:aws:codedeploy:{리전}:{게정ID}:deployment:{애플리케이션}/*"
            ]
        }
    ]
}

 

[ 권한2 : AMI 생성과 ASG launch Template 업데이트 권한 ]

{
  "Action": [
    "ec2:CreateImage",
    "ec2:Describe*",
    "ec2:CreateLaunchTemplateVersion",
    "autoscaling:UpdateAutoScalingGroup",
    "autoscaling:StartInstanceRefresh"
  ],
  "Effect": "Allow",
  "Resource": "*"
}​

 

(그림1) Lambda 함수의 권한에서 역할 이름 클릭

(그림2) 역할에 할당된 권한 정책 클릭
(그림3) 정책 편집기를 통해 IAM관련 정책 추가


🧪 Lambda 전체 코드

 

 

import boto3
import datetime

codedeploy = boto3.client('codedeploy')
ec2 = boto3.client('ec2')
autoscaling = boto3.client('autoscaling')

def lambda_handler(event, context):
    print("Received event:", event)

    deployment_id = event['detail']['deploymentId']
    application_name = event['detail']['application']
    deployment_group = event['detail']['deploymentGroup']
    deployment_state = event['detail']['state']

    if deployment_state != "SUCCESS":
        print("Deployment not successful. Exiting.")
        return

    # 1️⃣ 배포에 포함된 인스턴스 ID 목록 조회
    instance_ids = []
    next_token = ''
    while True:
        if next_token:
            response = codedeploy.list_deployment_instances(
                deploymentId=deployment_id,
                nextToken=next_token
            )
        else:
            response = codedeploy.list_deployment_instances(
                deploymentId=deployment_id
            )
        instance_ids.extend(response['instancesList'])
        next_token = response.get('nextToken')
        if not next_token:
            break

    print("Target instance IDs:", instance_ids)

    if not instance_ids:
        print("No instances found in this deployment.")
        return

    # 2️⃣ 첫 번째 인스턴스 기준으로 AMI 생성 (원하면 loop로 전부 생성 가능)
    target_instance_id = instance_ids[0]
    timestamp = datetime.datetime.utcnow().strftime('%Y%m%d%H%M%S')
    ami_name = f"AppImage-{timestamp}"

    ami_response = ec2.create_image(
        InstanceId=target_instance_id,
        Name=ami_name,
        NoReboot=True
    )
    new_ami_id = ami_response['ImageId']
    print(f"New AMI created: {new_ami_id}")

    # 3️⃣ 기존 Launch Template 가져오기
    lt_response = ec2.describe_launch_templates(
        Filters=[
            {'Name': 'tag:Application', 'Values': [application_name]}
        ]
    )

    if not lt_response['LaunchTemplates']:
        print("No Launch Template found for application.")
        return

    launch_template = lt_response['LaunchTemplates'][0]
    launch_template_id = launch_template['LaunchTemplateId']

    # 4️⃣ Launch Template 버전 생성
    version_response = ec2.create_launch_template_version(
        LaunchTemplateId=launch_template_id,
        SourceVersion='$Latest',
        LaunchTemplateData={
            'ImageId': new_ami_id
        }
    )
    new_version = version_response['LaunchTemplateVersion']['VersionNumber']
    print(f"New Launch Template version created: {new_version}")

    # 5️⃣ ASG 업데이트
    asg_response = autoscaling.describe_auto_scaling_groups()
    for asg in asg_response['AutoScalingGroups']:
        if asg.get('LaunchTemplate', {}).get('LaunchTemplateId') == launch_template_id:
            asg_name = asg['AutoScalingGroupName']
            autoscaling.update_auto_scaling_group(
                AutoScalingGroupName=asg_name,
                LaunchTemplate={
                    'LaunchTemplateId': launch_template_id,
                    'Version': str(new_version)
                }
            )
            print(f"ASG '{asg_name}' updated with new LT version.")

    print("Lambda execution completed.")

🎯 EventBridge 규칙 생성 – 특정 CodeDeploy만 트리거

Lambda 콘솔에서는 이벤트 패턴을 직접 입력할 수 없기 때문에, EventBridge 콘솔에서 직접 규칙을 생성합니다.

  1. EventBridge → 규칙 생성
  2. 이름: codedeploy-success-filtered
  3. 이벤트 패턴 입력 (JSON):
{
  "source": ["aws.codedeploy"],
  "detail-type": ["CodeDeploy Deployment State-change Notification"],
  "detail": {
    "state": ["SUCCESS"],
    "application": ["my-codedeploy-app"],
    "deploymentGroupName": ["backend-production"]
  }
}
(그림) EventBridge에서 규칙 만들기 예시

 

(그림2) Lambada함수에 구성탭에서 앞에서 만든 규칙을 "트리거 추가"를 통해 추가한 예시
  1. 대상: Lambda 함수 → CreateAmiAndUpdateAsg 선택

✅ 이렇게 하면 특정 배포 성공 시에만 Lambda가 실행됩니다!


💰 비용은 언제 발생할까?

  • 이벤트 대기 중 상태는 과금되지 않습니다.
  • 실제로 Lambda 함수가 호출되어 실행될 때만 요금이 발생합니다.
  • EventBridge는 월 10만 건 무료, Lambda는 월 100만 건 무료 호출까지 제공되어 테스트 단계에서는 거의 무료로 이용 가능!

✅ 마무리

이 구조를 통해 우리는 다음을 달성했습니다:

  • 배포 성공 이후 운영환경을 최신 상태로 자동 유지
  • AMI/Launch Template/ASG 연동을 통한 무중단 롤링 업데이트
  • 여러 배포 중 특정 배포만 선별하여 트리거
  • 과금 걱정 없는 서버리스 자동화 구성

📌  [참고] 환경설정 중 오류에 대한 해결 방안 

[Troubleshooting ] EventBridge 규칙을 통해 Lambda 함수 호출, 함수 실행 권한 및 환경 설정 문제 해결하기https://backend-java.tistory.com/59

 

[Troubleshooting ] EventBridge 규칙을 통해 Lambda 함수 호출, 함수 실행 권한 및 환경 설정 문제 해결하기

♨ EventBridge 규칙에서 Lambda함수 호출에 실패할때 조치 방법EventBridge 규칙(Rule) 설정 확인:이벤트 패턴(Event Pattern): CodeDeploy 배포 성공 이벤트(CodeDeploy Deployment State Change, detail.state가 SUCCESS인 경우)

backend-java.tistory.com