데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      AWS CDK 실전 활용기: Vision AI모델을 위한 API 서비스 구축 경험 공유

      자니큐 25.07.16
      666 3 1
      DEVOTEE 요약
      본 블로그는 AWS CDK를 활용해 Vision AI API 서비스를 구축한 사례와 노하우를 공유합니다. 주요 아키텍처 구성 요소로는 API Gateway, Lambda, S3, DynamoDB 등이 있으며, 스택 분리, 환경별 설정 관리, 비용 최적화, 모니터링 및 CI/CD 파이프라인 구축 등의 실무 경험이 포함되어 있습니다. 이를 통해 배포 시간 단축, 비용 절감 및 장애 대응 속도 개선과 같은 성과를 얻었으며, 향후 CDK Pipelines와 Custom Constructs 활용 등 개선 방안을 제시합니다.
      DEVOTEE 추천 블로그

      안녕하세요! 아주 오래 전 2021년에 올린 글('AWS의 IaC Framework CDK 소개')에서 AWS CDK의 기본 개념과 장점에 대해 소개드렸는데요.

      오랜시간이 지났지만 ^^;; 글 후반부에 이야기 드렸었던 만큼 실제 프로젝트에서 CDK를 활용한 경험을 공유하고자 합니다.

      이 글을 통해 지금은 조금 아웃데이트되었지만 Vision AI모델을 AWS상에서 서빙하는 API 서비스를 AWS CDK로 구축하는데 필요한 사례와 노하우를 공유하려고 합니다.


      프로젝트 개요

      저희가 구축한 Vision AI API 서비스는 다음과 같은 아키텍처로 구성되어 있습니다:

      • API Gateway: RESTful API 엔드포인트 제공

      • Lambda Functions: 이미지 처리 및 AI 모델 실행

      • S3 Buckets: 이미지 저장 및 모델 파일 관리

      • DynamoDB: 메타데이터 및 처리 결과 저장

      • CloudFront: 정적 리소스 배포

      • Cognito: API 인증 및 권한 관리


      CDK 프로젝트 구조 설계

      1. 스택 분리 전략

      처음에는 모든 리소스를 하나의 스택에 넣었다가, 관리의 어려움을 겪고 다음과 같이 분리했습니다:

      // lib/stacks/network-stack.ts
      export class NetworkStack extends cdk.Stack {
        public readonly vpc: ec2.Vpc;
        
        constructor(scope: Construct, id: string, props?: cdk.StackProps) {
          super(scope, id, props);
          
          this.vpc = new ec2.Vpc(this, 'VisionAIVpc', {
            maxAzs: 2,
            natGateways: 1,
          });
        }
      }
      
      // lib/stacks/storage-stack.ts
      export class StorageStack extends cdk.Stack {
        public readonly imageBucket: s3.Bucket;
        public readonly modelBucket: s3.Bucket;
        
        constructor(scope: Construct, id: string, props?: cdk.StackProps) {
          super(scope, id, props);
          
          this.imageBucket = new s3.Bucket(this, 'ImageBucket', {
            versioned: true,
            lifecycleRules: [{
              id: 'delete-old-versions',
              noncurrentVersionExpiration: cdk.Duration.days(30),
            }],
          });
          
          this.modelBucket = new s3.Bucket(this, 'ModelBucket', {
            encryption: s3.BucketEncryption.S3_MANAGED,
          });
        }
      }
      
      // lib/stacks/api-stack.ts
      export class ApiStack extends cdk.Stack {
        constructor(
          scope: Construct, 
          id: string, 
          props: ApiStackProps
        ) {
          super(scope, id, props);
          
          // API Gateway와 Lambda 함수들 정의
        }
      }

      2. 환경별 설정 관리

      개발, 스테이징, 프로덕션 환경을 효율적으로 관리하기 위해 설정 파일을 분리했습니다:

      // config/env-config.ts
      export interface EnvConfig {
        account: string;
        region: string;
        vpcCidr: string;
        lambdaMemory: number;
        apiThrottling: {
          rateLimit: number;
          burstLimit: number;
        };
      }
      
      export const envConfigs: Record<string, EnvConfig> = {
        dev: {
          account: '123456789012',
          region: 'ap-northeast-2',
          vpcCidr: '10.0.0.0/16',
          lambdaMemory: 1024,
          apiThrottling: {
            rateLimit: 100,
            burstLimit: 200,
          },
        },
        prod: {
          account: '987654321098',
          region: 'ap-northeast-2',
          vpcCidr: '10.1.0.0/16',
          lambdaMemory: 3008,
          apiThrottling: {
            rateLimit: 1000,
            burstLimit: 2000,
          },
        },
      };

      실전 팁과 트릭

      1. Lambda Layer 활용

      Vision AI 모델의 의존성이 크기 때문에 Lambda Layer를 적극 활용했습니다:

      const aiModelLayer = new lambda.LayerVersion(this, 'AIModelLayer', {
        code: lambda.Code.fromAsset('layers/ai-model'),
        compatibleRuntimes: [lambda.Runtime.PYTHON_3_9],
        description: 'Vision AI model dependencies',
      });
      
      const imageProcessor = new lambda.Function(this, 'ImageProcessor', {
        runtime: lambda.Runtime.PYTHON_3_9,
        code: lambda.Code.fromAsset('src/lambdas/image-processor'),
        handler: 'index.handler',
        layers: [aiModelLayer],
        memorySize: props.config.lambdaMemory,
        timeout: cdk.Duration.minutes(5),
        environment: {
          MODEL_BUCKET: props.modelBucket.bucketName,
        },
      });

      2. 비용 최적화 전략

      Auto Scaling 설정

      const scalableTarget = imageProcessor.addAlias('live').addAutoScaling({
        minCapacity: 1,
        maxCapacity: 100,
      });
      
      scalableTarget.scaleOnUtilization({
        utilizationTarget: 0.75,
      });

      S3 라이프사이클 규칙

      imageBucket.addLifecycleRule({
        id: 'move-to-ia',
        transitions: [{
          storageClass: s3.StorageClass.INFREQUENT_ACCESS,
          transitionAfter: cdk.Duration.days(30),
        }],
      });

      3. 모니터링 및 알람 설정

      CloudWatch 대시보드와 알람을 코드로 정의하여 일관성을 유지했습니다:

      const dashboard = new cloudwatch.Dashboard(this, 'VisionAIDashboard', {
        dashboardName: `vision-ai-${props.envName}`,
      });
      
      const apiErrors = new cloudwatch.Alarm(this, 'APIErrors', {
        metric: api.metricServerError(),
        threshold: 10,
        evaluationPeriods: 1,
      });
      
      // SNS 토픽으로 알람 전송
      apiErrors.addAlarmAction(
        new cloudwatchActions.SnsAction(alarmTopic)
      );


      배포 자동화

      GitHub Actions를 활용한 CI/CD 파이프라인을 구성했습니다:

      name: Deploy CDK
      
      on:
        push:
          branches: [main, develop]
      
      jobs:
        deploy:
          runs-on: ubuntu-latest
          steps:
            - uses: actions/checkout@v3
            
            - name: Setup Node.js
              uses: actions/setup-node@v3
              with:
                node-version: '18'
                
            - name: Install dependencies
              run: npm ci
              
            - name: Run tests
              run: npm test
              
            - name: Deploy to AWS
              env:
                AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
                AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
              run: |
                ENV_NAME=${{ github.ref == 'refs/heads/main' && 'prod' || 'dev' }}
                npx cdk deploy --all --require-approval never -c env=$ENV_NAME


      트러블슈팅 경험

      1. Lambda 콜드 스타트 개선

      Vision AI 모델 로딩으로 인한 콜드 스타트가 심각했습니다. 다음과 같이 해결했습니다:

      // Provisioned Concurrency 설정
      const provisionedConcurrency = imageProcessor.currentVersion.addAlias('provisioned', {
        provisionedConcurrentExecutions: 5,
      });
      
      // 워밍업 Lambda 추가
      const warmer = new lambda.Function(this, 'Warmer', {
        runtime: lambda.Runtime.NODEJS_18_X,
        code: lambda.Code.fromInline(`
          exports.handler = async () => {
            // API 호출하여 Lambda 워밍업
          };
        `),
        handler: 'index.handler',
      });
      
      // EventBridge로 5분마다 실행
      new events.Rule(this, 'WarmerRule', {
        schedule: events.Schedule.rate(cdk.Duration.minutes(5)),
        targets: [new targets.LambdaFunction(warmer)],
      });

      2. 크로스 스택 참조 문제

      스택 간 리소스 참조 시 순환 의존성 문제가 발생했습니다:

      // 잘못된 예
      // storage-stack.ts
      this.bucket.grantRead(props.apiLambda); // apiLambda는 다른 스택에서 생성
      
      // 올바른 예
      // api-stack.ts에서 처리
      props.storageBucket.grantRead(this.apiLambda);

      3. CDK 버전 관리

      팀원 간 CDK 버전 불일치로 인한 문제를 해결하기 위해:

      // package.json
      {
        "devDependencies": {
          "aws-cdk": "2.100.0",
          "aws-cdk-lib": "2.100.0",
          "constructs": "^10.0.0"
        },
        "overrides": {
          "aws-cdk-lib": "2.100.0"
        }
      }


      성과와 교훈

      성과

      • 배포 시간 단축: 수동 배포 대비 90% 시간 단축

      • 인프라 비용 절감: 환경별 최적화로 30% 비용 절감

      • 장애 대응 속도 향상: 코드 기반 롤백으로 5분 내 복구 가능

      교훈

      1. 작게 시작하기: 처음부터 완벽한 구조를 만들려 하지 말고 점진적으로 개선

      2. 테스트 작성의 중요성: CDK 테스트로 배포 전 문제 발견

      3. 문서화: 팀원들을 위한 CDK 패턴과 가이드라인 문서 작성 필수


      다음 단계

      이후에 좀 더 고도화된 시스템을 위해 다음과 같은 개선사항을 생각해볼 수 있습니다:

      • CDK Pipelines 도입으로 더 정교한 CI/CD 구현

      • Custom Constructs 개발로 재사용성 향상

      • Multi-Region 배포 지원

      • FinOps 도구 통합으로 비용 최적화 자동화


      마치며

      AWS CDK는 단순히 CloudFormation의 대체재가 아닌, 인프라를 소프트웨어처럼 다룰 수 있게 해주는 강력한 도구입니다.

      초기 학습 곡선은 있지만, 한번 익숙해지면 인프라 관리의 효율성이 크게 향상됩니다.

      다음 포스트에서는 CDK Custom Constructs를 활용한 재사용 가능한 컴포넌트 개발에 대해 다루어보겠습니다.

      질문이나 공유하고 싶은 경험이 있으시다면 댓글로 남겨주세요!


      참고 자료

      태그: #AWS #CDK #IaC #ServerlessArchitecture #VisionAI #CloudNative #DevOps

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      자니큐 님의 최신 블로그

      더보기

      DEVOTEE 추천 블로그

      동영상 기고하기