선린인터넷고등학교 선린톤 개발에 참여했고 그 과정들이에요.

HADMARINE·2021년 7월 10일
4

선린톤 개발기

목록 보기
1/1
post-thumbnail

누구세요?

저는 선린인터넷고등학교에 3학년으로 재학중인 Node.js, C# 서버 애플리케이션 개발과, CI/CD, 서버 스케일링등 인프라 매니징을 주로 개발하고 있는 HADMARINE 이에요. 반가워요 :)

선린톤?

선린톤은 매년 7월 경, 여름방학 시즌에 진행되는 선린인터넷고등학교내 해커톤이에요. 올해로 벌써 7회째를 맞이하는데요. 모든 대회들이 다 그렇듯 코로나19로 인해 아쉽게도 작년부터 전면 온라인으로 진행되었어요. (ㅠㅠ)
하지만 그럴수록 우리 개발자들이 더욱 빛나는 법! 저는 이 기회에 선린톤 스탭으로 참여하여 선린톤 내 인프라를 개발해보기로 했어요.

선린톤 웹사이트를 개발하다

매년 선린톤의 메인 페이지는 우리의 눈을 행복하게 만들어 주는데요. 올해도 메인 페이지를 제작을 했어요.
저는 프론트엔드쪽은 다른 팀원에게 맡겨두고, 서버 애플리케이션 개발과 인프라, CI/CD 를 구축했어요.

서버 애플리케이션

저는 서버를 단시간에 안정적인 코드를 작성할 수 있어요. 그 이유는 제가 코딩을 잘해서가 아니고, 제가 만들어둔 탄탄한 라이브러리들과 보일러플레이트 코드들 덕분이라고 생각해요.
보통 외주를 맡아보면 Node.JS 로 개발된 서버들은 같은 일을 하는 코드라도 모양이 정말 다른데요. 이는 Javascript의 표현의 자유도가 높아서 그런 것 같아요. 하지만 이는 서버 개발자 입장으로써는 악몽과도 같아요. 유지보수가 힘들 뿐더러, 보통 모양이 다르다 함은...

이런 경우가 종종 있거든요. (안됩니다..)
저는 이런 문제들과, 앞에서 말했던 코드의 통일성을 가져가기 위해서, Controller 객체를 만들었어요.
Class를 생성하고, Controller 데코레이터 (@) 를 작성해주면 그 class 는 Controller 객체가 돼요.
그리고 안에 멤버 함수들을 작성하고, 여러 데코레이터를 작성해주었어요.

기본적으로 리퀘스트를 받는 방법들을 정의하는 데코레이터들 (GET, POST 등과 엔드포인트),
날것의 응답을 해줄 것인지 (ReturnRawData)
Null을 반환했을 때 에러를 반환할 것인지 (NoErrorOnNull),
기존의(날것의) Express Handler 를 사용할 것인지 (UseCustomHandler),
Middleware 설정 함수 (SetMiddleware)
등의 상황에 맞는 데코레이터를 적절히 사용하면 기존의 기능들을 조금 더 편하고, 안전하게 구현할 수 있어요.

또한 매번 Request 에서 데이터를 받을 때 검증 해야하는 절차를 자동화했어요. Typescript TypeGuard 를 이용하여 검증하였고, 검증한 뒤 데이터를 적절한 포맷으로 변환해요.
(Object, Number, Date, Any, NotNull, Function, String, Array, Boolean 형을 지원해요.)

이러한 자잘한 기능들을 한 패키지에 모아서 배포한 것이 Express-Quick-Builder 에요. 이번 선린톤 서버에도 이 패키지를 사용해서 개발 시간을 반 이상 단축시켰어요. 궁금하신 분들은 한번 구경해보세요.

실제 제가 제작한 패키지를 이용해 서버 애플리케이션에 들어간 코드입니다.

하지만...

같은 참가자가 열번 이상 쿼리에 나타나는 증상이 있었어요. 이 글을 쓰는 오늘 아침에 고쳤습니다.

위와 같은 자잘하지만 치명적인 버그들이 조금 있었는데, 빠듯한 시간으로 인해 Test Coverage Percentage 를 올리지 못한 것이 원인인 것 같아요. 곧 선린톤 관련 다른 프로젝트를 연이어 진행할 예정인데 이 때는 Test Coverage 를 95% 이상으로 끌어올리는게 목표에요.

인프라 관리 및 CI/CD

실서버 인프라 관리는 이번이 두번째에요. 인프라 관리는 항상 새로운 문제에 직면해서 힘들기도 하지만 그만큼 여러 분야의 지식을 많이 얻는것 같아 만들고 나면 가장 보람되는 일이기도 해요. 특히 순간 트래픽이 많은 서비스를 잘 막아내면 그 만한 쾌감이 없다고 생각해요.

이번에 선린톤 신청 트래픽은 Load Balancer 에 기록된 트래픽 기준, 최대 128회/분, 최대 약 460MB/분 의 트래픽이 발생했어요. 마지막까지 ELB 5XX 에러는 0을 기록하면서 트래픽을 성공적으로 방어해냈어요! 👏

Frontend Deployment : AWS S3 + AWS Cloudfront

프론트엔드 서비스는 후술할 CircleCI 로 배포 자동화를 하여 S3에 업로드 하고, Cloudfront Invalidation 을 진행해요. Cloudfront 에 저희 도메인의 Certificate 를 적용해서 HTTPS 통신을 구축했습니다.

Backend Deployment : AWS EC2 + Auto Scaling

백엔드 서버는 AWS EC2에 배포해요. t3.small 인스턴스에 배포했어요.
오토 스케일링은 백엔드 서버의 CPU 점유율이 60%가 넘어가면 새로운 인스턴스를 Launch 하도록 설정했어요. 하지만 아직까지 그정도의 로드가 생기지 않아서 실제로 Launch 된 적은 없어요. 나중에 더 좋은 기회, 더 많은 트래픽을 관리할 수 있을 때 다시 연구해 보도록 할게요.

Database : AWS DocumentDB

Database는 친숙한 MongoDB를 사용했어요.
이번에 처음에는 MongoDB Atlas 를 사용하려고 했어요. 그러나 여기저기에서 중구난방으로 관리하는 것보다 한 곳에서 집중적으로 관리하는 편이 나을 것 같아서, 결정적으로는 제가 MongoDB Atlas 에서 DB 인스턴스를 생성했을 때 중대한 오류가 발생해서 인스턴스가 생성이 되지도 않고 삭제도 되지 않았는데, 신뢰도가 떨어져 DocumentDB 를 사용하게 된 것 같아요.

CI/CD for Backend : AWS CodePipeline

CodePipeline 사용해보는건 두번째인데요. 콘솔이 조금 바뀌어서 적응하는데 시간이 조금 걸렸어요. 적응하고 나니 사용하기 훨씬 편리해졌더라고요.

이번에는 저번에 사용해보지 않았던 Docker를 사용해봤어요. Docker 이미지를 생성한 뒤에, 빌드 환경으로 세팅해서 빌드했답니다.

배포는 Load Balancer 를 배포 타겟으로 지정했어요. 이렇게 설정하면 AutoScaling 으로 인해 새 인스턴스가 등록되면 자동으로 그 인스턴스도 배포 타겟이 돼요.

배포하는데 평균 20분정도 소요되는 것 같아요.
빌드는 대략 2분 30초정도 소요돼요. 그리고 나서 인스턴스에 배포를 하게 되는데, 저희는 Blue-Green 배포를 적용하지 않아서 (딱히 필요성을 느끼지 못했어요. 배포가 엄청 자주되는 시스템이 아니거든요.) 배포를 진행할 때 인스턴스의 절반을 배포 모드로 전환하여 배포를 해요.
하나의 그룹을 배포하는데 시간이 9분정도 걸리는데 그 중 타겟 인스턴스를 로드밸런서에서 Detach 하는데 시간이 5분정도 걸려요. (이미 온 요청을 끊기지 않게 주는 시간 같아요.) 이후 필요한 패키지들을 설치하고, 이미 빌드가 되어 온 파일들을 PM2 로 실행시켜줘요. 실행이 완료되면 Localhost 로 테스트 요청을 보내 제대로 서버가 켜졌는지 검증하고, 검증이 완료되면 배포모드에서 서비스 모드로 전환해요. 첫번째 그룹이 끝나면 두번째 그룹도 같은 작업을 반복해요.

이렇게 설정해두면 배포가 훨씬 간단해지고 조금 더 작은 단위의 커밋을 즉각적으로 적용할 수 있답니다 :)

CI/CD for Frontend: CircleCI

프론트엔드 배포는 CircleCI 를 사용했는데요. 그 이유는 CodePipeline 이 세팅하기가 굉장히 번거롭고 기능이 많지 않은 데 반해, CircleCI 는 Config 파일을 커밋하고, Project 를 follow 하는 것만으로도 세팅을 할 수 있기 때문입니다.
Github Hook 이 발생하면 CircleCI 에서 해당 커밋을 Clone해서 패키지 설치, 테스트, 빌드, S3 빌드 소스 변경, Cloudflare invalidation 을 순차적으로 진행하게 됩니다.

배운 점

이번에 구축한 서버의 한달 총 비용이 200$ 정도 소요되더라고요. 제일 큰 건 DocumentDB 가 한달에 비용이 100$ 정도 발생했어요. 가장 작은 인스턴스로 운영하는데도 이정도 비용이 들더라고요. 지금도 코스트를 조금 줄일 수 있는지 연구하고 있어요.
결국엔 인프라 관리라는 것은, 서버가 다운되지 않는 범위 내에서, 코스트를 최대한 줄이는 것이 궁극적인 목표라고 느꼈어요.

마지막으로

모두 자신의 목표에 정진하느라 바쁜 와중에도 프로젝트에 헌신적으로 참여해준 팀원들, 선린톤 총괄, 이왕렬 학과장님께 감사드립니다.

P.S:

웹사이트 구경하고 싶으시면 한번 들어가 보세요!
sunrin.dev <- 현재는 작동하지 않습니다

profile
Abroad the world!

0개의 댓글