나는 데브옵스 부트캠프에서 팀 프로젝트를 맡았다. 프로젝트는 특정 주제
에 대해 AWS
를 활용하여 최적의 클라우드 인프라
를 구축하는 것이 주 목표였고 이에 맞춰 프로젝트를 완료하였다. 이번 글에서는 맡았던 프로젝트를 설명하고 프로젝트 진행 과정에서 어려웠던 점과 중점적으로 고려했던 사안을 공유하려 한다.
프로젝트 주제는 간단히 말하자면 마라톤 대회 기록 시스템
이다. 마라톤 대회에 사람들이 대회 참가를 신청하고 달리기 시간을 기록할 수 있도록 클라우드상에 백엔드 시스템를 구축
하는 것이 프로젝트의 목표였다.
약 10일간 (23.6.13 ~ 23.6.30
) 진행하였다.
아키텍쳐 다이어그램
, 테라폼
, CI / CD
, 백엔드 소스
가 있습니다.
인프라 아키텍처는 아래의 그림과 같이 설계하였다.
주요 백엔드 컴퓨팅 리소스로는 ECS
와 Fargate
를 선택하였다. ECS
와 Fargate
의 경우 오토 스케일링
과 필요한 만큼의 컴퓨팅 리소스 용량 선택 가능
및 손쉬운 배포
부분에서 강점을 가져 선택하였다. 간단히 비교해보았을 때에 Fargate
가 EC2
에 비해서 동일 CPU, Memory 기준 비용이 약 2배 가량 더 비쌌지만 오히려 Fargate
가 비용 효율적일 수 있다고 한다. Fargate
가 컨테이너 기준 리소스 효율이 더 좋기 때문이라고 한다 (링크 참조). 그 외에도 EC2
의 경우 특정 CPU 퍼센트 사용량
이상을 사용하면 비용이 부과될 수 있는 여지가 있다. 그에 반해 Fargate
는 CPU 퍼센트 사용량
에 대한 제한이 없는 것으로 보인다. 따라서 Fargate
사용에 따른 비용 부담이 덜어질 수 있을 것으로 보인다.
그 밖에도 Lambda
또한 사용하였는데, Lambda
의 경우 콜드 스타트
의 단점을 가지지만 실행되는 시간만큼만 비용을 지불하기에 비용 효율적
인 장점을 가진다. 콜드 스타트
라는 약점이 있기에 빠른 응답시간을 주지 않아도 되는 시스템에 사용하였는데, 예를 들어 점수 추가
시스템을 람다
로 구현하였다. 점수 추가
기능은 사용자가 응답을 기다리지 않아도 되는
프로세스에 있기에 콜드 스타트
의 문제가 크게 문제가 되지 않아 람다
가 적합하다고 판단하였다.
엄밀히 말하자면 사실 람다 서비스는 콜드 스타트를 줄일 수 있도록 미리 프로비져닝된 상태를 유지하는 기능을 제공한다. 따라서 트래픽이 많이 발생하지 않는 프로젝트 초기에는 람다만을 통해 인프라를 진행하기도 한다고 한다.
RDS
와 NoSQL
를 모두 사용하였다. 대회/기록
을 저장하는 DB 로는 RDS (MySQL)
을 선택하였다. 대회/기록
데이터의 경우 데이터의 일관성이 중요하다고 판단하여 선택하게 되었다. 유저 정보
를 저장하는 DB 로는 NoSQL (DynamoDB)
를 선택하였는데, 이는 유저 정보
의 경우 추후 비정형의 데이터를 다루는 것을 고려하였기 때문이다.
SQS
를 생성하여 각 서비스간의 통신 과정에서 메세지가 유실될 수 있는 상황을 방지하고자 하였다. 메세지가 정상적으로 처리되지 못했을 경우 실패한 메세지를 DLQ
로 이동하도록 하여 실패한 메세지가 추후 처리할 수 있도록 여지를 남겨두었다.
모니터링 시각화는 그라파나
를 사용하였으며 모니터링 대상은ECS
및 RDS
로 선정하였다. 이를 통해 현재 서버가 얼마만큼의 부하를 감당할 수 있으며 반응 시간은 적합한 지를 검토할 수 있도록 하였다.
CPU 사용률 Metric
은 클라우드 와치
를 통해 획득하였으며 응답의 총 소요시간 Mextic
의 경우, k6
에서 나온 메트릭 정보 (e.g. http_req_duration) 를 influx db
에 저장한 결과를 추출하여 얻을 수 있었다.
아래와 같이 가용 영역을 두군데 이상으로 설정하여 가용성을 확보하려 하였다.
AWS Budget
서비스를 이용하여 지정한 예산을 초과하면 이메일을 통해 정보를 받을 수 있도록 하였다.
지정된 브랜치에 PR
이 Merge
가 되면 GitHub Actions
은 머지된 코드
를 기반으로 도커 이미지
를 생성하고 ECR
저장소에 저장한다. 저장이 완료되면 GitHub Actions
는 운용중인 ECS
의 Task 정의
부분에서 도커 이미지 경로
명세를 새로 저장된 도커 이미지 경로
로 변경한다. 이를 통해 ECS
가 새로 개정된 Task 정의
에 맞춰 자동으로 배포를 진행하도록 하였다.
ECS
, ALB
, DB
, VPC Endpoint
, VPC 환경(VPC, Subnet, SG)
부분을 테라폼으로 작성하였다. 생성만 해둬도 비용 지출되는 리소스
를 우선적으로 테라폼으로 바꿔주었다. 테라폼을 통해 인프라 리소스를 손쉽게 생성/제거
할 수 있게 되어 테스트 환경을 운용할 필요가 없을 때는 리소스를 삭제하였으며 테스트 환경 조성에 필요한 비용이 기존 예상보다 70% 이상 줄었다.
초기 아키텍처 구현에는 FARGATE
가 퍼블릭 서브넷
에 존재했다. 그러나 보안상으로 봤을 때 프라이빗 서브넷
에 있는 것이 적절하여 FARGATE
를 프라이빗 서브넷
에 위치하도록 변경하였는데 프로비져닝
단계에서 아래와 같은 사진과 함께 실패하였다.
원인은 FARGATE
가 있는 프라이빗 서브넷
은 VPC 외부
로의 접근이 차단되어 있어 ECR
로부터 이미지를 받아오지 못하기 때문이었다. 이를 해결하기 위한 방법으로는 크게 VPC 엔드포인트
와 NAT GATEWAY
가 있었는데 비용과 보안 등을 고려해봤을 때 VPC 엔드포인트
를 사용하는 것이 효율적이라 판단하여 VPC 엔드포인트
를 사용하였다.
VPC 엔드포인트
와NAT GATEWAY
비용 비교 분석 결과, VPC 엔드포인트가 약 2배 가량 저렴했다.
위의 그림과 같이 VPC 엔드포인트
를 사용하면 VPC
외부에 존재하는 AWS 서비스
에 접근할 수 있었고 ECR
로부터 도커 이미지를 받아오기 위해서는 아래의 4개의 VPC 엔드포인트
를 설정해주어야 했다.
com.amazonaws.ap-northeast-2.s3
com.amazonaws.ap-northeast-2.ecr.api
com.amazonaws.ap-northeast-2.ecr.dkr
com.amazonaws.ap-northeast-2.logs
그러나 4개의 VPC 엔드포인트
지정했음에도 ECR
로부터 도커 이미지를 획득하지 못했는데 원인은 보안 그룹
에 있었다. VPC 엔드포인트
의 보안 그룹
의 아웃바운드
설정이 모두 막혀 있어 VPC 엔드포인트
가 VPC 외부
에서 정보를 받아오지 못했던 것이다. 따라서 보안 그룹
의 아웃바운드
에 대해 포트와 IP 를 모두 허용
하여 AWS ECR
로부터의 트래픽을 받을 수 있도록 해주자 프라이빗 서브넷
에서도 성공적으로 프로비져닝
이 이루어질 수 있었다.
이와 관련한 더 자세한 트러블 슈팅 기록은 아래의 블로그에서 작성하였다.
프라이빗 서브넷에서 ECR 에 접속할 때 필요한 VPC 엔드포인트 설정 (feat: terraform)
초기 인프라 구성으로는 FARGATE
가 SQS
에 메세지 송신이 필요할 경우 사용자의 액세스키
를 FARGATE
의 환경변수에 넣어줌을 통하여 권한을 부여하였다. 하지만, 이러한 방식으로 권한을 부여하게 될 경우 사용하지 않는 불필요한 권한까지 리소스가 소유할 뿐 아니라 액세스 키가 실수에 의해 외부에 공개될 여지가 있는 보안상의 문제가 있었다. 따라서 임시 자격 증명 방식
을 선택하였다. 임시 자격 증명 방식
을 사용하면 리소스에 제한적인 권한을 수행할 수 있는 역할을 부여하도록 하여 리소스가 의도하지 않은 실행을 하지 않도록 예방하고 리소스가 IAM 유저의 엑세스키를 소지하지 않기에 보안상 이점을 얻을 수 있다.
그러나 리소스
에 역할을 부여
하고 엑세스 키를 FARGATE
에서 지우고 테스트 해보니 정상적으로 SQS 메세지
가 전달되지 않는 현상이 있었고, 원인은 소스코드
였다.
자격 증명 방식
은 변경하였지만 SQS
에 메세지를 보내는 코드는 여전히 엑세스 키
를 이용하는 함수를 사용하고 있었기 때문이었다.
// 해당 라이브러리에서 update 함수를 사용할 시 엑세스 키가 존재하지 않는다는 에러 발생
import AWS from "aws-sdk";
AWS.config.update({region: 'ap-northeast-2'});
해당 라이브러리를 사용하는 대신 사용자의 엑세스 키
를 사용하지 않는 라이브러리
를 아래의 소스코드
처럼 적용해본 결과 성공적으로 SQS
에 메세지를 보낼 수 있었다.
import { SQSClient, SendMessageCommand } from "@aws-sdk/client-sqs";
const client = new SQSClient({ region: "ap-northeast-2" });
const sendMessage = async () => {
// Create an SQS service object
await client.send(new SendMessageCommand({...}));
}
초기 예상 프로젝트의 비용은 약 74 달러
내외였으며, (예상: 2주 소요, 월 148 달러)
실제 프로젝트 진행 결과 약 51달러
를 지출하였다. (실제: 1주 소요, 월 196 달러)
다양한 요인이 지출 비용에 영향을 주었는데 그 중 2가지 요인은 공유하려 한다.
테라폼을 통한 인프라 구성
프로젝트 초기에는 고려되지 못했던 인프라 리소스 (VPC ENDPOINT)
첫째는 테라폼을 통한 인프라 구성
이다. 테라폼
을 통해 인프라 구성해놓으니 테스트 시간을 제외하면 리소스를 생성해놓고 있지 않아도 되었다. 따라서 견적서로는 하루에 8시간 동안
리소스를 켜놓는 것을 가정하여 계산했지만 테라폼으로 빠르게 만들어놓아서 실제로는 하루에 2~3 시간
동안만 켜놓아도 되었기에 비용 지출을 최소화할 수 있었다.
둘째로는 프로젝트 초기에는 고려되지 못했던 인프라 리소스
추가가 있다. 고려되지 못했던 리소스는 VPC ENDPOINT
였는데 인프라 구성상 필요한 리소스였고 비용이 대략 월 48 달러
가 필요하였기에 비용 지출 증가에 영향을 끼쳤다. 실제 업무 프로젝트 진행 시에는 의도치 않은 비용에 대해 더욱 민감하게 생각해볼 필요가 있을 것 같다.
아래의 사진은 프로젝트 초기의 예상 비용 견적서이다.
초기 예상 견적
으로 월 약 148 USD
가 나왔다. 위 사진에 나와있는 예상 견적 사진에 나와있는 비용은 VPC 엔드포인트
를 사용하기 전 에 계산했던 비용이며, 프로젝트에서 사용한 VPC 엔드포인트 4개
를 추가 시 약 48 USD
의 비용 (링크 참조)이 추가되어 월 196 USD
가 나온다.
테스트를 위해 운용 시에는 테라폼을 통해 리소스 생성/해제가 자유로워 비용을 50% 이상 줄일 수 있었다.
아래의 사진은 실제 비용 지출 그래프이다. 총 51달러
가 사용된 것을 확인할 수 있다.
프로젝트를 수행함에 있어서 이전까지 배웠던 지식들
을 블로그로 기록했던 게 프로젝트에 많은 도움이 되었다. 프로젝트에서 필요한 업무들이 있으면 내가 이전에 블로그로 정리한 내용
들을 다시 보고 필요한 것들을 뽑아내곤 하였다. 블로그
의 장점을 다시 한번 느끼게 되었다. 기록하는 것이 온전히 내가 아는 것들을 되짚어 보는 시간
이었을 뿐만 아니라 나만의 오픈 북
이되어 좋았다.
한편으로는 나 자신이 게을렀던 것이 아쉬었다. 프로젝트가 생각보다 빠르게 완성이 되어갔었는데, 그래서 그런지 이정도면 됐지
하고 쉬는 경우가 종종 있었다. 외부에서 주어진 목표
를 빨리 수행했다고 끝이 아니라 자기 자신에게 목표를 설정하고 부여
할 줄 알아야 되는데 그저, 쉴 수 있어 좋네
하고 생각을 멈춘 것이 아쉬웠다. 이제 곧 다음주면 부트캠프를 수료하기 때문에 더욱 더 나 스스로에게 미션을 부여하는데에 익숙해져야될 것 같다.
참고자료: