
드디어 길고 길었던 데브옵스 부트캠프 파이널 프로젝트가 끝났다... 프로젝트한다고 바빠서 근 2주동안 블로깅을 못했는데 회고로 작성해보려한다.
시나리오
- 글로벌 트래픽이 증가하였으며, 특정 국가의 이용자로부터 웹사이트 로딩이 느리다는 불만이 나오고 있습니다.
- K-POP 아이돌로부터 발생하는 각종 사안에 따라, 순간적으로 트래픽이 급증하는 형태를 보입니다. 종종 다운 타임이 발생합니다.
- 가장 큰 문제 중 하나는 모니터링 시스템의 부재입니다.
- 개발 조직도 큰 문제입니다. 이전에는 전문 개발자가 투입되지 않았던 터라, 개발 중인 제품이 곧바로 production 수준에 배포되거나, 충분한 테스트를 거치지 못한 채로 릴리즈되는 경우가 많았습니다.
요구사항
- 게시판 개발을 담당하는 개발 조직이 DevOps 문화에 잘 따르도록 배포 정책을 수립해야 합니다.
- 즉, git branch 및 릴리즈 여부에 따라 dev/staging/production 수준이 분리되어야 합니다.
- 모든 서버는 컨테이너 환경에서 구현되어야 합니다.
- 서버 및 데이터베이스는 AZ 단위의 가용성이 확보되어야 합니다.
- 순간적인 트래픽 증가에 대응해야 합니다.
- 모니터링 시스템을 구축하거나, CloudWatch 대시보드를 만들어서 모니터링해야 합니다.
- 주로 국가별 트래픽 및 응답시간을 확인할 수 있어야 합니다.
- 글로벌 트래픽 대응을 위한 방안을 제시해야 합니다.
- IaC화가 진행되어야 합니다.
인프라 아키텍처

전체적인 인프라 구성은 먼저 요구사항에서 모든 서버는 컨테이너 환경에서 구현해야하하는 요구 사항에서 바로 떠오른게 EKS와 ECS였다
처음에는 쿠버네티스를 이용할까도 생각했지만 팀프로젝트라는 점에서 결국 모든 팀원분을이 잘알고 사용해봤던 ECS를 선택하게되었다.
또한 갑자기 트래픽이 급증할때를 대비해 ecs자체 오토스케일링을 사용했는데 CPU사용률이 증가하면 경보를 통해 스케일 아웃과 스케일 인 할 수있도록 만들었는데 관리자 입장에서 스케일링되는걸 알 필요가 있다생각해 따로 람다를 통해 슬렉으로 알림을 받을 수 있게 했다.
모니터링으로는 사실 처음에 많은 고민을했었다 쿠버네티스를 사용했을때는 프로메테우스 그라파나 조합으로 이미 매트릭을 수집하고 시각화할 수 있게 잘해놨지만 ECS를 사용하면서 어떻게 할지 감이 안왔다 검색하면 EFK, ELK등 많은것들이 나왔지만 오픈소스 이기도 하고 ECS랑 사용한 레퍼런스도 많이 나오질 않았다... 대부분 쿠버네티스와... 결국에는 클라우드워치가 지표나 로그들을 수집하니까 오픈소스인 그라파나를 통해서 시각화를 하는게 어떨까라는 의견을 냈다 찾아보던중 AWS에서 매니지드 그라파나가 있어서 선택하게되었다.
데이터베이스도 요구사항으로 서버 및 데이터베이스는 AZ 단위의 가용성이 확보되어야한다해서 처음에는 그냥 RDS를 사용할까도 생각했지만 RDS는 Multi-AZ에서 인스턴스를 실행하지 않는점에서 Multi-AZ에서 실행되며 가용성이 높고 자동 장애 조치 기능이있는
Aurora를 선택했다.
사실 아키텍처에대해 할말이 많지만 따로 트러블 슈팅을 통해 나머지 리소스에대해 얘기해보겠다
IaC 배포 아키텍처

Terraform은 스테이트나 변수 등을 terraform cloud를 통해 세팅하고 워크스페이스를 만들어서 프론트엔드를 위한 인프라 배포, 백엔드를 위한 인프라 배포를 나눠 구성했다 솔직히 처음에 s3 + DynamoDB를 이용한 백엔드를 구성 할까도 생각했는데 보면 볼 수록 관리하기 힘들다고 생각이 들었다 그래서 terraform cloud를 선택한건데 마땅한 레퍼런스가 없어서 초반에 애를 먹었다 장점도 있지만 살짝 불편한.. 조금 계륵 같은 느낌이였다..
트러블 슈팅
내가 이번 프로젝트에서 맡은 작업으로는 프론트엔드와 백엔드, 그리고 백엔드와 데이터베이스를 위한 전체적인 IaC(그라파나와 ECR은 따로 IaC화 하지않았다)였다.
정말 알짜배기로만 설명해보겠다
1.ALB Network Mappings
api 요청이 ALB 까지 도달하지 못하는 이슈 발생
에러메시지: The selected subnet does not have a route to an internet gateway. This means that your load balancer will not receive internet traffic.
You can proceed with this selection; however, for internet traffic to reach your load balancer, you must update the subnet’s route table in the VPC console
문제원인으로는 처음 콘솔에서 ECS를 생성과 함께 ALB를 생성하는 경우 ALB Network Mapping은 자동으로 ECS 클러스터가 존재하는 서브넷으로 매핑이된다. 또한 로드벨런서가 internet facing인경우 퍼블릭 서브넷으로 매핑이되어있어야했다. 우리가 구성한 아키텍처에서 ECS 클러스터가 프라이빗 서브넷에 존재하기때문에 프라이빗 서브넷으로 매핑이되어 인터넷 트래픽을 수신 할 수없었다.
문제 해결로는 ec2콘솔에서 로드벨런서를 선택하고 네트워크 매팅탭에서 서브넷 편집해서 퍼블릭 서브넷으로 매핑하면된다.
이부분은 아래의 테라폼에서도 같다

2. Aurora RDS 엔드포인트는 어떻게 관리하나?
분명 RDS 엔드포인트는 민감정보이며 보안상으로도 안전하게 관리해야하는데 맞다 그래서 Secret manager를 선택했다.
처음에는 terraform으로 apply 하고 destroy하니까 분명 엔드포인트도 바뀌겠지라는 생각이였어서 그러면 아래의 코드처럼 rds 클러스터의 엔드포인트를 뽑아서 넣으면 되는거 아닌가? 해서 진행을했었다.

처음 apply를 해서 문제없었는데 이제 destory를 하고 apply를 해서 다시 테스트해보니 이미 삭제된이름이여서 사용이 불가능하다는거였다... 생각치 못한게 시크릿 메니저는 삭제하고 7~30일 동안 보관되서 똑같은 이름으로는 사용이 불가능하다는 문제였다.. 그래서 계속 바꿔서 apply를 할려다보니 이건 내가 방향성을 잘못 잡은 느낌이들었는데 아무리 인프라를 다시 삭제하고 올려봐도 rds의 엔드포인트는 변화가 없었던 것이였다... 그래서 그냥 콘솔에서 시크릿메니저로 전에 만든 rds의 엔드포인트로 세팅하고 resource 블럭이 아닌 data블럭을 사용해서 시크릿메니저를 불러서 apply를 하고 destory를 반복해도 문제가없이 해결되었다.

인프라가 돌아가는데 문제는없었지만 솔직히 찜찜했다 왜 rds 클러스터를 삭제하고 다시 만들어도 엔드포인트가 바뀌지않는가.. aws 공식문서를 찾아봐도 정확하게 내가 원하는 답을 얻지는 못했다... 그래서 혹시나 하는마음에 gpt에게 물어봤다

뭔가 시원하게 해결된 느낌은 아니였지만 그래도 그럴듯하다??? 라는 느낌이였는데 좀더 자세하고 정확하게 알아봐야할거같다 참고로 사용자 지정 엔드포인트를 사용하면 된다고 하는데 이부분도 찾아봐야겠다
3. ecs-작업정의.json.tpl...
항상 terraform으로 만들기전에 항상 콘솔로 직접 만들어보고 코드를 짜기시작한다 ECS를 terraform으로 하는중에 테스크 데피니션을 file로 넣거나 따로 하드코딩해서 넣는걸로 알고있었다 그래서 미리 콘솔에서 만들아놨던 테스크 데피니션 json파일을 그대로 복사해서 사용할려니까 아래의 에러가 발생했다... 나는 분명 있는거 그대로 사용한것 뿐인데...

근데 에러를 잘보면 []로 전체를 감싸야 하는데 그냥 {} 객체타입으로 되어있어서 생겼던 문제였다.. 고쳐서 실행하는데 그래도 문제가 발생했다... 알고보니 위에서 말한것처럼 그대로 사용해서 문제였다

이미 테스크 데피니션 리소스에서 세부 내용을 정의했는데 또세팅하려다보니 충돌때문에 문제가 생겼던것이였다.
아래 코드를 보면 처음에 오른쪽 json파일을 보면 오른쪽과 다르게 정의되어있는게 더있는데 캡쳐라서 짤렸지만 많은것들이 세팅되어있었다 근데 이상태에서 확장명을 tpl로 바꾸고 [] 감싸서 변수 할당해서 사용하려하니까 문제였던거다 아래사항은 따로 내가 정의해주는데...
그래서 아래부분은 지워버리고 왼쪽나와있는 파일 처럼 바꿔서 해결했다

4. 코그니토
처음 코그니토를 사용하는데 많은 레퍼런스가 없어서 찾는데 시간을 많이 썻다. 그래도 구글링의 힘으로 찾게되었는데 일단 내가 이해한 코그니토는 원래 백엔드에서 회원가입 인증&인가 로직을 처리하는데 이부분을 aws로 책임을 분리시킨다는 것으로 이해하게되었다.
일단 생각한 방법으로는 코그니토가 인증인가를 수행하게되니까 로그인을 하게되면 토큰을 발행하고 토큰을 통해 프론트로부터 받게되면 토큰을 토대로 특정 이름을 리턴해서 게시글을 작성할때 작성자로 db에 들어가게하면 되지않을까?? 였다
아래의 코드를 짜다가 테스트를 해보니 게시글 작성자가 난수로 나오게되는 이문제는 로그인한 사용자가 메인페이지를 확인했을때 내가 어떤 글을 작성했는지 알아보기 어렵다.

처음에 회원가입을 할때 아래의 코드처럼 email만을 받았어서 그냥 위의 코드를 Username이 아닌 email을 리턴하게 할까도 했지만 넓은 관점으로 봤을때 email도 개인정보니까 그냥 코그니토 사용자 풀에서 따로 별칭으로 닉네임을 추가하는 방법을 선택했다.

회원가입할때 email과 nickname을 받고 아래의 코드를 보면 getUserId는 닉네임을 리턴하게된다 getUserId 함수는 처음 게시글을 삭제할때와 수정, 삭제 할때 실행되는 함수이다. 테스트 결과 내가 원하는 방식처럼 모든 게시글을 불러올때 게시글을 작성한 작성자가 닉네임으로 나올 수 있었다.

코그니토를 사용하면서 느낀점으로는 개발자 입장에서 보면 정말 안쓸 이유가 전혀없었다 대부분 회원가입할때 특수문자나 유니크한 아이디등 따로 예외처리하는 과정이 필요한데 이부분은 cognito콘솔에서 따로 해결이 가능하다.
또한 나는 닉네임이나 email을 사용했는데 이것 말고도 cognito 사용자 풀을 처음 생성할때 필수 속성을 선택 할 수 있으며 커스텀으로 만들수 있다 이러한 정의 말고도 많은 정의들이있으며 이번 프로젝트를 진행하면서 코그니토의 정말 일부분만 사용했다 생각해 이부분도 더 공부해야겠다.
5.옵셔널 체이닝
리엑트로 코딩하면서 생겼던 문제로는 서버로 부터 받은 데이터를 가져올때 어떻게 에러가 발생하지않고 가져오는가였다

위의 코드에서 서버로부터 Articles라는 변수로 데이터를 가져와서 currentPosts로 데이터를 뿌려주는 상태이다 처음에는 그냥 했던 방식대로 json 데이터는 Articles.data.data하면 문제없을거라 생각했는데 에러가 발생했었다... 알고보니 아직 로딩 중인 상태여서 서버의 데이터를 읽어오지 못해서 생긴 에러였다.. 그래서 이걸 해결하고자 구글링을했는데 옵셔널 체이닝을 찾게되었다.
먼저 옵셔널 체이닝은 옵셔널 체이닝 연산자(?.)는 객체의 속성이나 메서드를 호출하기 전에 해당 객체가 null 또는 undefined인지 확인하고, 해당 객체가 null 또는 undefined인 경우에는 undefined를 반환하는데 따라서 옵셔널 체이닝을 사용하면 TypeError 예외를 방지할 수 있다.
즉 서버에서 데이터를 받지못했는데 코드를 실행하다보니 에러가 발생한것이였다 그렇기 때문에 ? 옵셔널 체이닝을 통해 예외처리를 했다.
만약 옵셔널 체이닝을 사용하지않는다면 아래의 코드처럼 코드의 길이도 길어지고 객체의 속성이나 메서드가 여러단계로 중첩된 경우라면 if문을 중첩해야하는데 이렇게되면 가독성이 떨어지게 된다
if (Articles && Articles.data && Articles.data.data) {
currentPosts = Articles.data.data;
} else {
currentPosts = [];
}
처음 옵셔널 체이닝을 사용해봐서 그런지 아직 어떤상황에는 써야하는지 말아야하는지를 정확하게 몰라서 이부분은 더 공부를 해봐야할거같다
아쉬운점
프로젝트를 진행하면서 terraform cloud를 사용했는데 정확하게 organization을 나누지도 못했고 특히 특정 리소스를 삭제방지 옵션을 사용하지 못한점이였다 로컬에서 destory를 할때 특정 리소스는 제외하고 싶을때 제외하고 삭제 할 수있었는데 terraform cloud에서는 사용하지 못했다 그러다보니 destory하고 apply하는 과정에서 많은 시간을 소비했다 분명 방법이 있는데 내가 못찾는건지 아니면 정말 방법이 없는건지 이부분은 공식 문서를 더 찾아보거나 아니면 애초에 workspace를 따로 네트워크, ecs, rds 부분으로 놔눠서 의존성을 낮추는 방법도 괜찮은 방법같다.
비용적인문제에서도 아쉬움이 많았다 제공된 예산이있었지만 우리는 넘어버렸다 처음에 아키텍처를 구성하고 aws calculator를 사용해서 견적을 냈는데도 생각과는 다르게 과금이 발생했다 무료인줄 알고 사용했는데 과금이되었다거나 왜 사용하지 않은거 같은부분에서 비용이 발생했는가였는데 이건 좀더 신중하고 리소스별 비용을 더 자세하게 공부할 필요를 느꼇다.. 예상 비용이 솔직히 제일 어려운거같다 인프라를 구성해아하는 아키텍트로써 비용효율적을 항상 고민해야하는데 이부분은 아키텍트로써의 숙제인거같다.
aws IAM도 문제였다 우리팀원들은 하나의 계정에서 각각 사용자를 만들어서 IAM 사용자를 만들어서 로그인했는데 모든 사용자가 관리자권한을 갖고있었다.. aws 에서도 최소 권한부여 원칙을 권장하고있지만 우리는 그원칙을깨고 사용중이였다. 이렇게 되었을때 내가 만들어놓은 리소스를 다른 사용자가 실수로 삭제했을 경우가 발생할수있는데 이러한 상황은 누구도 원하지않을것이다. 그러므로 각각 맡은 파트별로 권한을 부여해서 사용하는게 바람직하다고 생각이든다... 또한 리소스 기반 정책에 불필요한 권한까지 들어가있으며 "*" 이런식으로
모든 리소스 권한을 갖게 한것들이 몇몇 있었다.
후기
트러블 슈팅도 그렇고 새롭게 알게된 지식도 엄청 많지만 이글에서 모든걸 적기에는 회고의 방향성과 맞지않다고생각해 앞으로 그부분은 따로 블로깅으로 채우려한다.
분명 길었으면 길었던 짧다면 짧은 4개월이 지나갔다.. 항상 느끼는거지만 나는 아직도 부족하다 그러다보니 스스로에게 답답함을 느끼기도한다 그래도 그답답함때문에 더욱 노력하게되는거같다. 이번 파이널 프로젝트에서 팀장을 맡았는데 팀장으로써 본분을 잘했는지 잘은 모르겠지만 나머지 팀원분들이 잘 따라와주셔서 너무 고마웠다. 참고로 어디서 생긴 소문인지 모르겠는데 내가 빡세게한다라고 였는데... 맞는거같기도하고.. 우리는 주말 일요일에도 모였다 ㅎㅎㅎㅎㅎㅎㅎ 그래도 한분도 빠짐없이 싫은소리없이 잘 따라와주셨다.
이제 다음주부터 이력서 준비와 면접 준비하는데 이제 시작인거같다. 그래도 프로젝트 처음 구상한대로 잘 끝낸거같아서 뿌듯하다.
'회고' 카테고리의 다른 글
[프로젝트 회고] 코드스테이츠 DOB 3번째project (0) | 2023.02.22 |
---|