[CD] GitHub Actions - S3와 Lambda 함수를 통한 배포

석형원·2024년 8월 25일

project

목록 보기
8/11

[CD] GitHub Actions - Shell Script를 통한 배포

초기에는 위 포스팅처럼 Shell Script를 통해 배포를 진행하려했으나,
이 방법의 경우 단일 EC2 인스턴스에 대해서만 배포를 하기 때문에 이를 수정해줄 필요가 있었습니다.

왜냐하면 프로젝트 진행 중 Celery Executor의 장점을 살리고자 Auto Scaling Group을 통해,
Airflow Worker 환경이 구성된 EC2 인스턴스를 자동으로 늘어나게 만들었기 때문입니다.

따라서, 자동으로 생성되는 인스턴스들에 대한 배포도 추가 해줘야한다는 것이죠.

그래서 제가 생각한 방법은 다음과 같습니다.

  1. Github Actions을 통해 Github Repo의 dags 폴더에 변화가 감지되면 S3에 sync
  2. 1번 작업이 완료가 되었다면, 특정 lambda 함수를 호출
  3. 이 Lambda 함수는 S3로부터 실행 중인 EC2 인스턴스들에게 dags 파일을 배포

Github Actions

name: 'Build and upload to S3 Bucket & Deploy to EC2 with Lambda'

# dags폴더 내로 PR 혹은 Push가 되면 trigger
on:
  workflow_dispatch:
  push:
    paths:
      - 'dags/**'
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      # CI 서버에서 repo로부터 코드를 내려받을 수 있도록 함
      - uses: actions/checkout@v3.3.0
        with:
          ref: main

      # AWS IAM 계정을 등록 (EC2FullAccess 필수)
      # AWS CLI 사용을 위함
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-2

      - name: Upload S3
        run:
          # aws cli로 dags 폴더에 있는 파일들을 S3로 업로드
          # --delete : 원본 경로에서 삭제될 시 S3에서도 삭제
          aws s3 sync --delete dags s3://${{ secrets.AWS_S3_BUCKET_NAME }}

  deploy:
    # 위의 S3 적재 과정이 완료된 후에 동작
    needs: build
    runs-on: ubuntu-latest

    steps:
      # AWS IAM 계정을 등록 (EC2FullAccess 필수)
      # AWS CLI 사용을 위함
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-2

      - name: Update dags
        run: |
          aws lambda invoke --function-name ${{ secrets.AWS_LAMBDA_FUNC }} --cli-connect-timeout 60 response.json

Lambda 함수

import boto3
from botocore.exceptions import ClientError

# Github Actions를 통해 Trigger 되는 함수
# SSM을 통해 Airflow가 동작하는 EC2 (AutoScaleGroup 포함)에 접근
# AWS CLI 명령을 통해 S3에 저장된 dags 버킷의 내용을 sync

# 필요한 IAM Policy
"""
- AmazonEC2FullAccess

- AmazonSSMFullAccess

- AutoScalingFullAccess

- AWSLambdaBasicExecutionRole
"""

region = 'ap-northeast-2'
# AutoScalingGroup에 속하지 않은 EC2 인스턴스
instance_ids = ['i-07d478a96d7af433c']
ec2 = boto3.client('ec2', region_name=region)
as_client = boto3.client('autoscaling', region_name=region)
ssm = boto3.client('ssm')
AWS_S3_BUCKET_NAME = 'team-ariel-1-dags'
EC2_PATH = '/home/ubuntu/airflow/dags'

def lambda_handler(event, context):
    as_groups = as_client.describe_auto_scaling_groups(
        AutoScalingGroupNames=[
            'ariel-1-auto-worker'
    ])
	
    # AutoScalingGroup에 속하는 EC2 인스턴스들을 추가
    for i in as_groups['AutoScalingGroups']:
        for k in i['Instances']:
            instance_ids.append(k['InstanceId'])
            print(k['InstanceId'])
                    
    print(instance_ids)
    for instance_id in instance_ids:
        try :
            response = ssm.send_command(
                InstanceIds = [instance_id],
                # SSM을 통한 aws cli 명령을 사용
                DocumentName="AWS-RunShellScript",
                Parameters={
                    'commands': [
                        f'aws s3 sync --delete s3://{AWS_S3_BUCKET_NAME} {EC2_PATH}'
                    ]
                }
            )
            
        except ClientError as e:
            print(f"[ERROR] Error transferring file to EC2 instance {instance_id}: {str(e)}")
            return {'statusCode': 500, 'body': f'Failed to deploy : {str(e)}'}
    
    return {
        'statusCode': 200,
        'body': 'deploy process completed.'
    }

동작 방식

위 Lambda 함수는 주석에 작성된 대로, Github Actions를 통해 Trigger 되는 함수입니다.

Airflow의 메인 시스템을 담당하는 EC2 인스턴스 한개와
Airflow의 Worker를 담당하는 AutoScalingGroup 내의 모든 EC2 인스턴스의 id를 list에 집어넣고,

SSM을 통해서 list 내의 모든 인스턴스들에 대해 순차적으로
AWS CLI 명령으로 S3에 저장된 dags 버킷의 내용을 sync시켜줍니다.

profile
데이터 엔지니어를 꿈꾸는 거북이, 한걸음 한걸음

0개의 댓글