동아리 홈페이지 인프라 구축기
2023년 8월 01일저는 대학교 입학과 동시에 교내 보안 동아리에 가입하여 컴퓨터 보안과 많은 컴퓨터 지식들을 배웠습니다. 동아리는 학기 초마다 신입 회원을 가입 받고, 매주 진행하는 세미나 발표 자료와 스터디 자료를 업로드하는 홈페이지가 있습니다. 제가 동아리에 들어갈 당시 서버는 on-premise 형태로 전산실에 위치해 있었고 제로보드(이하 XE) 기반으로 웹 서비스를 운영하고 있었습니다. 동아리 홈페이지를 통해 자료를 공유하고 소소한 게임도 있어 편안하고 좋았습니다. 하지만 오래된 디자인, 새로운 기능 추가 및 수정의 어려움, 초기 서버 구축자의 인수인계 부재로 인한 XE 취약점 패치의 어려움, PHP 언어에 대한 부담과 XE에 대한 이해도 부족으로 홈페이지를 몇 년간 방치해둔 상태였습니다.
날이 가면 갈수록 홈페이지가 낡아지고 보안적으로 취약해져서 아예 새롭게 갈아엎고 싶다는 생각이 들었습니다. 때마침 동아리 회장님이 동아리 홈페이지 개발 이야기를 꺼내면서 작업에 참여하고 싶은 동아리원들을 모았고 저도 참여하게 되었습니다. 2021년도 겨울 방학부터 홈페이지 개발 작업을 시작한 이 프로젝트의 목표는, 2022년 3월에 입학할 새로운 동아리 후배들이 들어오기 전에 배포하는 것이었습니다. 이번 글은 제가 동아리 홈페이지 인프라 부분을 담당하면서 고민했던 과정의 이야기를 전해드리려합니다.

동아리 홈페이지의 가장 큰 문제점은 XE의 의존성이 강하여 추가적인 개발 및 유지보수가 어려웠다는 점이었습니다. XE가 사용하는 PHP 언어에 대한 부담, XE가 제공하는 DB 구조의 난해함, 오래된 XE 플러그인과 같은 XE가 만든 울타리가 답답했습니다. 동아리 팀원들끼리 회의한 결과, XE를 완전히 걷어내고 새롭게 홈페이지를 만들기로 하였습니다. 본격적인 개발에 앞서 다음의 기본적인 규칙을 정했습니다.
- 기획 총괄, 프론트(+디자인), 백(+DB 설계), 인프라 팀으로 구성
- 매주 팀장 회의를 진행하여 팀들 간의 상황 공유
- 중간에 다른 팀들 간의 공유 사항이 있으면 회의를 잡거나 슬랙으로 공유
- 프론트엔드는 React, 백엔드는 Spring Boot 도구로 개발 진행
- Git flow 방식으로 GitHub repository 관리
- PR reviewer, label, projects 규칙 설정
- 개발을 위한 정보 및 스터디 자료는 노션으로 공유
위와 같이 큰 틀만 정하고 세부적인 사항은 팀원 회의를 통해 정했습니다. 인프라 팀의 인원은 저 혼자라 주로 백엔드 팀과 같이 회의를 진행하면서 Git flow 개념 공유, commit message convetion, formatter 통일, 코드 리뷰 방식, 기능 개발 담당자 같은 것들을 정했습니다. 보다 나은 인프라 구조를 설계하기 위해서는 전체적인 상황을 알아야 한다고 생각해서 프론트엔드 팀과도 회의를 진행하면서 상황을 파악했습니다.

인프라 팀은 저 혼자라 제가 하고 싶은 일들을 다소 제약 없이 할 수 있었습니다. 빈 캔버스에 원하는 그림을 그릴 수 있다는 장점이 있었지만 자칫 잘못하면 이도 저도 아닌 그림이 될 수 있다고 생각했습니다. 펜을 들고 첫 그림을 그리기 전에 저의 ‘역할’이 뭔지 고민해 보았습니다. 고민하여 다다른 결론은 인프라(혹은 DevOps 용어로도 불리는)의 역할은 개발자들이 인프라에 신경 쓰지 않고 개발에만 집중할 수 있는 환경을 만드는 것으로 생각했습니다. 달리 말하면 ‘개발하는 거 빼고 전부 다’라고 생각했습니다.
동아리 홈페이지 구축을 위해 처음으로 한 일은 전체적인 인프라 구성도 생각입니다. 제가 가진 모든 지식을 동원하여 ‘어떻게 하면 개발자와 동아리 홈페이지를 이용하는 사용자에게 신뢰를 줄 수 있는 인프라를 제공할 수 있을까?’에 대한 고민했습니다. 다음과 같은 기준을 세우고 인프라를 어떻게 설계할지 고민했습니다.
- 동아리 입장
- 보안 측면으로 안전한가?
- 서버 비용이 적절한가?
- 유지 보수가 용이한가?
- 추후 확장이 가능한가?
- 개발자 입장
- 개발 서버가 있는가?
- 배포가 안정적인가?
- 롤백을 할 수 있는가?
- 사용자 입장
- 홈페이지가 안정적인가?
제가 스스로 만든 요구 사항들을 종합하여 전체적인 인프라 구조도를 그려보았습니다.

저는 동아리 홈페이지 구축 전까지 public cloud 보다는 on-premise 서버 환경을 선호했습니다. 매월 청구되는 돈을 한 푼이라도 줄이기 위해 서버 비용을 지원해 주지 않는 이상, 방구석에 전기만 주면 24시간 돌아가는 라즈베리파이나 Intel NUC 같은 개인 서버 환경을 주로 사용했습니다. 개인 서버는 얼마든지 제 마음대로 지지고 볶고 해도 되지만 정전이나 알 수 없는 이유로 서버가 한 번씩 내려가는 문제가 있었습니다. 내려간 서버를 다시 올리기 위해서는 직접 서버 전원을 켜줘야 했습니다. 실제 서비스를 운영한다면 이는 심각한 상황으로 클라이언트(이하 사용자), 개발자 모두 신뢰받지 못하는 서버 환경이라 생각했습니다. 서버 비용은 동아리 회비로 결제 되기도 하고 24시간 365일 안정적으로 서버를 보장할 수 있는 public cloud를 쓰기로 했습니다. 여러 public cloud 중 참고할 만한 여러 문서가 있는 AWS를 선택했습니다.

물론 라즈베리파이, Intel NUC를 구입하는 초기 비용이 있지만 얼마든지 서버를 괴롭(?)혀도 된다는 심리적 안정감이 public cloud보다는 개인 서버를 선호하게 된 거 같습니다. 하지만 경제적으로 받쳐준다면 public cloud를 선호할 거 같습니다 😜
초기 홈페이지를 구축하는데는 EC2, S3, ECR 3가지 AWS 서비스를 사용했습니다. DB를 따로 빼서 관리하고 백업도 해주는 RDS 사용을 고려했지만 EC2에 직접 DB 컨테이너를 올려 AWS 비용을 줄이는 방식을 선택했습니다. 초기에는 EC2에 NGINX를 활용하여 정적 파일을 서비스 했지만 후에 CloudFront와 S3 서비스로 Web Server 부분을 분리했습니다.
마음 같아선 ALB, NLB도 붙이고 private subnet도 적용하고 NGINX 대신 API Gateway로 바꾸고 RDS도 쓰고 살짝 과장해서 EKS 서비스도 쓰고 싶었지만 ‘정말 이 서비스들이 필요한가?’에 대해 고민하고 합리적인 생각을 하려고 노력했습니다.
EC2 인스턴스 사양을 고르는 일도 중요합니다. 서비스를 돌리는데 어느 인스턴스 타입이 적당한 사양인지 파악해야 비용을 낭비하지 않기 때문입니다. 이는 경험적으로 겪어봐야 알 수 있는 부분이라 개발을 진행하면서 적합한 인스턴스 사양을 찾았습니다. 동아리 홈페이지를 돌리기 위해 nginx, app(Spring Boot), db(MySQL), redis 4개의 컨테이너를 띄웁니다. 이 컨테이너들을 안정적으로 띄우는데 t3.small 타입(vCPU 2, RAM 2GB), swap 메모리 2GB, gp2 SSD 30GB가 적합했습니다. 잦은 트래픽이 없었기도 했고 저와 홈페이지를 만든 개발자들의 노력으로 현재까지 한 번도 서버가 내려간 적이 없었습니다. 아 참, 그리고 비용을 줄이기 위해 예약 인스턴스(선결제 없음)도 챙기는 일도 잊지 않았습니다 🤭

구축할 환경이 생겼으니 그 다음으로는 어떻게 서비스를 구축할 건지에 대해 생각했습니다. React, Spring Boot를 포함한 모든 서비스는 컨테이너로 관리했습니다. 컨테이너로 관리하면 어느 컴퓨터 환경이든 일관성을 보장받을 수 있어 새로운 서버 환경 구축(ex. 개발 서버 환경, 자동 배포 환경), scale-out 등에 대비할 수 있다고 생각했습니다. 무엇보다도 컨테이너로 관리하면, 로컬 환경에서 마음껏 테스트 할 수 있고, 서버 배포할 때 로컬에 적용한 환경을 그대로 적용할 수 있다는 점이 좋았습니다.
사용자의 요청 처리는 NGINX가 처리하도록 했습니다. nginx 컨테이너를 만들고 그 안에 정적 파일(React 빌드물)을 두어 사용자가 정적 파일을 가지고 웹 브라우저로 렌더링 된 페이지를 볼 수 있도록 했습니다. 백엔드 통신은 NGINX의 reverse proxy 기능으로 app 컨테이너와 통신하도록 구성했습니다. 추가적으로 TLS/SSL를 발급해주는 Let’s Encrypt 이용하여 TLS/SSL 적용, 일정 시간 동안 임의적인 다수 request 요청을 막기 위해 limit_req
지시자 사용, 특정 도메인에 대한 cors 허용, 경우에 따라 특정 ip만 통신하도록 하는 등의 보안적인 설정도 해주었습니다.
Let’s Encrypt으로부터 생성된 TLS/SSL 인증 파일과 NGINX 설정 파일을 docker 볼륨으로 관리하면 보다 편하게 NGINX를 운영할 수 있습니다. NGINX 돌리기 전 nginx -t
명령어로 설정 파일에 이상이 없는지 꼭 확인하세요!
백엔드 인프라 구성은 app, db, redis 이름의 컨테이너 3개로 구성하였으며, 백엔드 팀과 회의를 하면서 구체적인 도구(gradle, jdk, db 버전 등)들의 종류와 버전을 정했습니다. 도구들의 종류와 버전에 맞는 도커 이미지를 만들고 아래와 같이 서버를 운영하면서 필요한 설정을 추가했습니다.
- prod, dev 환경 마다 다르게 적용되어야 할 중요 정보 env화
- 컨테이너를 띄울 때 서비스 자동 실행
- 한글(locale), 한국 시간(timezone) 설정
다음으로는 배포와 관련한 고민을 했습니다. 개발자들이 작성한 코드가 운영 서버(production server)로 배포하기 전에 개발 서버(development server)에 배포하여, 개발자들이 만든 기능이 정상 작동하는지 확인할 수 있도록 했습니다. Git flow 브랜치 전략으로 develop 브랜치는 개발 서버로 배포하고 main 브랜치는 운영 서버로 배포를 구성을 할 수 있어서 궁합도 좋았습니다.

개발 서버를 따로 두어 운영 서버에 배포하기 전에 미연의 사고를 방지할 수 있는 장점이 있지만, 추가적인 서버가 필요하여 비용이 든다는 점과 main 브랜치와 develop 브랜치 사이의 코드 최신화 차이가 생기는 단점이 있었습니다. 이 문제를 해결하기 위해 Trunk Based Development 방식이 있었지만 개발팀과 회의한 결과 main, develop 브랜치를 활용하는 Git flow 방식을 채택하였습니다.
한 대의 EC2에 운영, 개발 환경을 둘 수 있었지만, 비용이 증가함에 불구하고 EC2 2대로 운영, 개발 서버를 따로 둔 이유는 운영 서버에 쓰이는 자원은 오로지 사용자한테 쾌적한 서버 환경을 제공하기 위함도 있고 혹여나 개발 쪽 코드나 배포를 진행하면서 조금이라도 운영 서버에 영향을 끼칠 수 있는 부분을 제거하기 위해 따로 두는 선택을 하였습니다.
초기 개발 서버는 SSL을 적용하지 않는 서버였지만, 서브 도메인(ex. dev.domain.com)을 부여하고 SSL을 적용했습니다. 개발 서버 인프라 구성은 운영 서버와 동일하며 최대한 운영 서버 환경과 비슷하도록 환경을 구성하여 운영 서버 배포를 진행해도 오류가 없도록 일관성을 유지하도록 노력했습니다.
약 3개월 동안 개발이 순조롭게 진행되어 목표였던 3월에 무사히 배포를 마칠 수 있었습니다. 감격스러운 운영 서버 배포를 마치고 서비스를 운영하는데 큰 이상은 없었습니다. 하지만 몇 가지 아쉬운 부분이 있었는데 바로 자동 배포와 관련한 부분이었습니다. 개발자의 코드 업데이트가 있을 때마다 수동으로 배포를 진행해 주었는데 이 과정이 지겹고 귀찮았습니다. 이를 해결하기 위해 GitHub Actions를 도입했습니다. 이와 관련하여 자동 배포와 관련된 이야기와 자동 배포 고도화 이야기 글로 따로 정리하였으니 궁금하신 분은 글을 참고하면 좋을 거 같습니다. 자동 배포 시스템까지 도입하니 정말 더할 나위 없는 인프라 시스템을 갖춘 느낌이었습니다.
이외에도 AWS 계정 해킹이 되어 과금 되는 사고가 너무나도 무서워 root, admin, cicd, dev IAM 계정으로 나누고 모든 계정에 MFA를 통해 로그인 하도록 설정했습니다. Prometheus와 Grafana도 도입하여 모니터링 시스템도 도입하였으나 지표들을 유의미하게 분석하고 활용하지 못하여 모니터링 시스템은 필요할 때마다 AWS에서 제공하는 CloudWatch를 참고하고 있습니다. 주기적으로 해킹 대회인 동아리 CTF 대회가 열리는데 바이너리 파일을 실행과 exploit 할 환경과 웹 해킹 문제 환경을 위한 인프라를 구축하기도 했습니다.
2021년 12월부터 시작해서 현재, 2023년 8월까지 개발, 운영, 고도화를 하면서 수많은 삽질과 경험을 했습니다. 1년 반 이상 동아리 인프라를 담당하면서 다음과 같은 생각을 했습니다.
- 인프라는 재밌다
- 다양한 분야(프론트, 백, DB, 시스템, 네트워크 등등)를 접하고 시야가 넓어지면 인프라 이해에 큰 도움이 된다
- 오버 엔지니어링으로 다루지 못했던 더 큰 인프라 구조를 만지고 운영해 보고 싶다(ex. Terraform, k8s, argoCD, 로깅 등등)
- 보안적으로 튼튼한 인프라 구조를 구성해보고 싶다(ex. private subnet 활용, 효율적인 DDoS 예방 등등)
- 인프라 협업 경험을 해보고 싶다
- 나를 위해서, 다음 후임자를 위해 문서화는 중요하다
물론 아직 동아리 홈페이지에 대해 부족한 점과 아쉬운 점도 있습니다. 인프라 구축에만 집중한 나머지 문서화에 신경 쓰지 못한 점, DB 스키마 업데이트 시 자동으로 cicd용 도커 이미지 업데이트가 필요한 점, 모니터링과 로깅 활용이 미흡한 점들이 있습니다. 제가 할 수 있는 선에서 기여하면서 더 큰 인프라를 운영하기 위한 개인적인 욕심으로 이에 필요한 공부도 하면서 인프라에 대한 지식을 넓히고 있습니다. 앞으로 어떤 문제를 만나 어떻게 안전하고 인프라적으로 해결하게 될까요?