취득 목적

회사에서 서버를 호스팅하는데 AWS를 사용하고 있다. AWS 의 각 제품에 대한 지식을 활용하여 우리 팀에 특화된 다양한 요구사항(비용, 운영 오버헤드, 작업시간)에 최적화된 의사결정을 하고, 규정준수 요청에 대응할 수 있을 것이라는 기대를 가지고 있다. Amazon Q와 (준비하며 알게 된) Trusted Advisor 와 같은 지원 기능을 함께 활용하면 더 큰 효과를 볼 수 있을 것 같다. 

 

준비 방법

 

서버 개발자로 일하면서 네트워크와 컴퓨터 과학 지식은 가지고 있다고 판단하였다. 또한 AWS의 일부 제품(EC2, Lambda Aurora, S3, Cloud Front, Event Bridge, SQS, VPC, Secrets Manager) 을 사용하고 연동하며 퍼블릭 클라우드 개념과 큰 그림은 알고 있다고 판단하였다. 

 

그래서 나는 별도의 개념 강의 없이 덤프 문제를 풀며 준비를 하는 중이다. 다만 시험 통과만이 목적이 아니라 지식을 얻기 위한 목적도 있기 때문에, 답 뿐 아니라 오답 선지에 있는 제품의 사용 목적과 왜 주어진 요구사항의 답이 되기에 부적절하거나 덜 적절한지를 정리했다. 이렇게 하니 다른 문제를 풀 때 간접적으로 도움이 되기도 한다. 이렇게 1~200, 500~800번까지 약 500문제 정도를 반복해서 학습했다.

 

채점 스크립트를 만들어서 추가 확인이 필요하거나 틀린 문제를 모아서 다시보기도 했다.

HTML과 JavaScript로 만든 채점도구

 

 

결과와 후기

 

실제 시험은 덤프와 비교하여 답/오답이 명확하게 갈리는 선지가 제공되어 수월하게 풀었고, 확실하지 않은 문제 수가 10개 정도 되었다.

비영어권 지원자를 위핸 30분 추가 제공을 신청하지 못해서 걱정했는데, 3번정도 검토를 할 수 있었기에 꼭 신청하지는 않아도 될 것 같다.

오히려 검토하다가 ecs 전용 config 서비스 등의 공부하며 못들어본 선지를 정답으로 선택해서 틀린 것도 있을 것 같아, 조금 아쉽다.

강남 센터에서 시험을 보았는데, 하필 시위가 있어 소음이 매우 심했으므로 다음 번에는 다른 센터를 이용할 것 같다.

 

 

서론

EKS를 알아보던 중 EKS Fargate에서 사용하는 Firecracker을 우선 조사해보기로 했다. Firecracker는 AWS lambda, EKS 등에서 사용하는 경량화 VM 기반 가상화 기술이다.

 

경량화 VM 가상화가 필요한 이유

Lambda는 여러 고객의 코드를 같은 물리 서버 위에서 실행하는데, 고객마다 올리는 코드는 신뢰할 수 없으므로 각 함수는 보안적으로 완전히 분리되어야 한다. 이는 도커와 같은 컨테이너 기술로는 구현할 수 없다. EKS 를 Fargate 모드(Pod 단위로 서버리스처럼 사용)로 사용할 경우 비슷한 보안상의 이유로 보다 커널수준 격리가 필요한다. Firecracker는 VM을 이용해 커널까지 격리되는 완전한 운영체제 수준의 격리를 제공하면서도 성능 저하를 최소화할 수 있다.

Firecracker 가 가벼운 이유

커널까지 격리하는데도 속도가 느리지 않은 이유는 복잡한 하드웨어 에뮬레이션 없기 때문. 

전통적인 VM은 컴퓨터 시스템 전체를 가상화하는 것이 목적이었지만, 그렇지 않다면 생략하여 최소한의 장치(Virtio)만 제공할 수 있음

  • Virtio는 가상 머신 환경에서 표준화된 가상 디바이스 인터페이스로, 실제 하드웨어 대신 커널이 직접 입출력을 다뤄주는 방식

KVM

Firecracker는 KVM(커널 기반 가상화) 위에서 동작함.

KVM은 리눅스 커널에 내장된 하이퍼바이저 기능으로, 하드웨어 가상화 지원을 이용해서 VM을 돌리는 엔진

 

EKS와 Firecracker

EKS 모드

  • EC2 모드: EC2 인스턴스 안에서 컨테이너를 띄움
  • Fargate 모드: 파드 단위로 서버리스처럼 동작함. Firecracker 사용해서 파드를 MicroVM 위에서 띄움

참고

https://www.youtube.com/watch?v=BIRv2FnHJAg

https://firecracker-microvm.github.io/

배경

우리 서비스는 웹과 앱을 모두 운영하고 있는데, 웹 사용성을 고려하여 업로드 한 대용량 이미지가 일부 구형 기기에서 앱 크래시를 일으키는 이슈가 있었다.

요약

CloudFront(CDN)와 Lambda@Edge를 활용하여 클라이언트로부터 받은 파라미터에 따라 S3에 저장된 원본 이미지를 람다(AWS 서버리스 앱)가 리사이즈 하도록 했다.

구조와 흐름

유저가 CDN에 이미지를 원하는 크기와 함깨 요청하면 뷰어 요청에 트리거되는 람다(좌측 상단)가 요청 URL의 크기 정보를 CDN 과 S3에서 사용되는 경로로 변환하여 CDN에 전달한다.

  • 이 경로의 이미지가 있으면 CDN에서 바로 이미지를 응답한다.
  • 이 경로의 이미지가 없으면 CDN은 요청을 S3에 전달하고, S3은 응답한다.
    • 이 때 오리진 응답에 트리거되는 람다(우측 하단)가 실행된다.
      • S3로부터 403 코드를 응답받으면(대부분의 경우) CDN은 요청 URL 로부터 원본 이미지 경로를 파싱하여 S3에 재요청하고 이를 리사이즈한다.
      • 1MB미만이면 유저에게 응답하고, 그렇지 않은 경우 S3에 저장 후 해당 경로로 리다이렉트한다.

(참고) 전반적인 구조

작업순서

  1. CloudFront 생성
  2. CloudFront 의 오리진에 기존 S3 연결
  3. 기존 이미지 요청 시 사용하던 도메인을 S3 에서 CloudFront로 변경
  4. Lambda@Edge 2개 생성
  5. Lambda@Edge의 트리거에 각 CloudFront 뷰어요청, 오리진(S3) 응답 등록
  6. Lambda@Edge 모두 S3에 접근할 수 있도록 람다 IAM role 생성하여 Trust Relationship(신뢰관계) 설정 확인
  7. Lambda@Edge 배포 (serverless 프레임워크 사용)

기타, 회고

Lambda@Edge 와 연결된 CloudWatch와 로그는 연결된 CloudFront가 요청을 받은 리전(Edge)에서만 확인할 수 있다. 이 부분을 놓쳐 코드가 제대로 동작하는지 확인하는 데 헤맸다.

Lambda@Edge는 Lambda 와 비교하여 실행시간(5초), 응답 크기(1MB), 메모리(기본값 128MB) 등 더 많은 제한이 있어 까다로웠다.

아래 링크의 코드와 달리 S3에서 파일이 없는 경우 404가 아닌 403 코드를 응답하여 디버깅하는 데 오래 걸렸다.

 

 

참고

https://aws.amazon.com/blogs/networking-and-content-delivery/resizing-images-with-amazon-cloudfront-lambdaedge-aws-cdn-blog/

배경

얼마 전 데이터가 약 30만 건인 테이블에 컬럼을 추가하는 작업을 진행했다. 문제는 컬럼 추가에 20분이 넘게 걸렸고, full-text 인덱스가 있어 Online DDL 또한 불가능한 상황이었다.

요약

AWS RDS의 블루/그린 배포 기능을 활용하여 테이블 락으로 인한 서비스 장애 없이 컬럼을 추가하였다.

  • 블루/그린 배포는 상용환경(블루)와 동일한 분리된 환경(그린)을 새로 생성하여 변경을 테스트 한 후, 트래픽을 그린환경으로 전환하고 블루환경을 제거함으로써 상용 데이터베이스 배포 시의 예상치 못한 장애를 방지하는 전략이다. 이번 작업에서는 논리적 복제를 사용하였다. 

작업 순서

  1. 논리적 복제 설정: RDS 클러스터 파라미터 그룹에 binlog_format=ROW 설정
  2. 논리적 복제 적용
    1. reader 인스턴스 1대 증설 (*)
    2. writer로 승격할 reader 를 writer 스펙으로 맞춘뒤 우선순위 tier 0 으로 설정
    3. writer 인스턴스 failover (안전한 재부팅, 5초 이내의 다운타임이 있었다)
    4. reader 인스턴스 failiover 또는 하나씩 재부팅
    5. reader 인스턴스 제거
  3. 블루/그린 배포 환경 생성
  4. 그린 환경에 접속하여 컬럼 추가 DDL 실행
  5. 블루/그린 환경 전환(switch over)
  6. (올드)블루 환경 및 블루/그린 환경 제거

기타, 회고

기존의 DB 클러스터의 파라미터 그룹에 논리적 복제(binlog_format: ROW)가 가능하지 않도록 설정되어 있었고, 이 설정은 정적(static) 이었기에 변경 뒤 적용되기 위해서는 인스턴스 재시작이 불가피했다. 그래도 다운타임을 최소화하기 위해 쓰기 인스턴스의 경우 재시작 대신 장애조치(failover)를 사용하였다(이는 Multi-AZ배포만 가능하며, 이 전에 쓰기 인스턴스로 승격될 읽기 인스턴스의 failover priority를 1로 설정하였다). *읽기 인스턴스의 경우 파라미터 그룹 변경 후에 새로 생성하고 기존 인스턴스를 삭제하는 방법을 사용했다(읽기 인스턴스 개수가 감소한 순간 나머지 읽기 인스턴스로 트래픽이 몰리고, session이 쌓여 읽기 인스턴스가 다시 추가된 이후에도 복구되지 않을 수 있다).

주의할 점은 쓰기 인스턴스와 읽기 인스턴스의 타입이 다른 경우 다시 한 번 failover가 필요하다는 점이다. failover 는 본래 장애 발생 시 다른 대기(읽기) 인스턴스를 주(쓰기) 인스턴스로 승격시킴으로써 가용성을 높이는 기능인데, RDS 서비스 중단 없이 구성 변경을 적용하기 위해 사용되기도 한다.

 

참고

https://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/UserGuide/blue-green-deployments-overview.html#blue-green-deployments-major-steps

배경

우리 회사에서는 AWS를 사용하여 서비스를 운영하고 있다. API 서버는 Node.js를 플랫폼으로 하여 ElasticBeanstalk 을 사용하고 있는데, 2025년 7월에 현재 사용중인 Node.js 18 버전이 지원 종료되어, 22 버전으로 업그레이드하였다.

요약

운영 중인 서비스에 영향 없이 버전을 업그레이드해야 했다. Route53을 활용하여 RDS 의 블루/그린 배포와 유사한 방법으로 진행할 수 있었다.

작업 순서

1. .nvmrc와 관련 의존성 업그레이드를 위한 package.json과 package-lock.json 수정

2. Elastic Beanstalk - 해당 애플리케이션에서 Node.js v22 플랫폼의 환경 신규 생성

3. 서버와 연결된 데이터베이스 보안그룹의 인바운드 규칙에 신규 환경의 EC2 보안그룹 추가

4. 변경사항 배포

   4-1. 이 단계 이전에 CodePipeline 배포 단계의 타겟 환경을 신규 환경으로 변경하였다.

5. 신규 환경의 헬스체크, API 호출 테스트

6. Route53 에서 서버 도메인의 환경을 신규 환경으로 변경

7. 모니터링

   7-1. 서비스 접속하여 동작을 확인 및 기존 인스턴스 액세스 로그가 더 이상 없는 것을 확인했다.

8. 기존 환경 제거(Terminate)

기타 사항, 회고

환경의 구성(Configuration) 중 인스턴스 타입(예: t3micro) 을 실수로 기존 환경과 다르게 생성하여, 6번 작업 이후에 추가로 수정 하는 과정에서 또한 서버 다운타임이 발생하지 않도록 구성 Update, Monitoring and logging 하위의 배포 전략을 RollingWithAdditionalBatch로 설정하였다.(이 때, Batch 크기는 Instance Traffic and Scaling 하위의 Capacity 의 최소 인스턴스 보다 작거나 같아야 한다.) 이렇게 설정하면 인스턴스가 추가로 생성된 후 업데이트되고, 기존 인스턴스가 제거되어 다운타임 없이 인스턴스 타입 업데이트가 가능하며, 이 과정은 Elastic Beankstalk 콘솔의 Event 탭에서 확인할 수 있다.

 

서론

얼마전 실무에서 CloudFront 에 Lambda@Edge, S3를 연동하여 S3 -> CloudFront 응답을 트리거로 설정한 람다가 실행되어 이미지 리사이징을 처리한 경험이 있었다.

당시 가장 어려웠던 점이 서비스 연동을 위한 권한 설정이었기에, 정리해보고자 한다.


IAM

IAM(Identity and Access Management): AWS 리소스에 대한 액세스를 제어할 수 있는 서비스

주요 개념

  • 유저: 개별 ID
  • 그룹: 유저 모음
  • 정책: 권한 설명서
  • 역할: 임시가면

정책 (Policy)

  • 무엇을 할 수 있는가가 적힌 JSON 문서 (예: S3 읽기 가능)
  • 종류: Managed vs Inline
    • AWS Managed Policy: AWS가 미리 만들어둔 정책 (예: AdministratorAccess). 여러 명에게 재사용 가능.
    • Inline Policy: 특정 사용자/역할에 붙여둔 정책. 삭제하면 같이 사라짐.
  • 정책을 붙일 수 있는곳 = 자격증명
    • IAM 유저, IAM 그룹, IAM 역할
    • IAM 유저에게 정책을 부여하는법
      • 유저에게 정책을 직접 붙인다 (=인라인)
      • 역할에 정책을 붙인 다음 유저가 정책을 assume(추측하다 보다는 책임을 맡다, 특정한 모습을 취하다의 뉘앙스)하도록 함: 권장!

역할 (Role)

  • 그런데 역할이라는 개념이 굳이 왜 필요할까?
    • AWS 서비스(EC2, Lambda 등)에도 정책을 붙이고 싶은데, 이들은 자격증명에 해당하지 않으므로 정책을 직접 붙일 수 없음
    • 계정 간 이동: 다리 역할 (Cross-Account)
    • 재사용성: 여러 정책을 묶어서 하나의 단위처럼 관리 가능
  •  구성 요소
    • Trust Policy(신뢰 정책)
      • 생성 시 설정 
      • 이 역할을 사용하는 것을 허용하는 주체(=principal)
        • IAM 유저, IAM 역할(역할 Chaining 가능), AWS 서비스
    • Permission Policy(권한 정책)
      • 역할(Role) 생성 후 붙임
      • 이 역할을 통해 할 수 있는 작업
        • 예: s3 객체 get/put 등
// 신뢰정책 예
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "lambda.amazonaws.com",
          "edgelambda.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
// 권한 정책 예
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}

예시

서비스 A가 B에 접근하기 위해 할 일

1. IAM 역할 생성 - 신뢰정책에 A 포함, 권한 정책에 B 포함 

2. A 에 IAM 역할 연결

3. (선택- 보안 강화) B 의 리소스기반 정책에 생성한 역할의 ARN을 추가함

 

 


참고

  • 최소권한정책
    • 서비스는 기본적으로 다른 서비스에 대해 아무 권한도 가지고 있지 않으며, 명시적으로 권한을 부여해야 함
기본적으로 모든 요청을 거부합니다. (일반적으로, AWS 계정 루트 사용자 증명을 사용하여 해당 계정의 리소스를 요청하는 경우는 항상 허용됩니다.)권한 정책(자격 증명 기반 또는 리소스 기반)에 포함된 명시적 허용은 이 기본 작동을 재정의합니다. 
  • ARN(Amazon Resource Name)
    • AWS 리소스를 식별
Amazon 리소스 이름(ARN)은 AWS 리소스를 고유하게 식별합니다. IAM 정책, Amazon Relational Database Service(RDS) 태그 및 API 호출과 같은 모든 AWS에서 리소스를 명료하게 지정해야 하는 경우 ARN이 필요합니다. [링크]

 

출처

https://docs.aws.amazon.com/

+ Recent posts