CODESTATES BEB 9기 파이널 프로젝트 회고
1.? 프로젝트 소개
Clean Mile은 환경 보호 행사에 대한 정보를 한 곳에 모아서 접근성과 사용자 편의성을 증진시키고, 행사에 참여하는 사용자들에게 인증 배지(NFT)를 발급하여 활발한 참여를 유도하는 것을 목표로 하는 환경 캠페인 플랫폼입니다.
이 프로젝트는 환경 보호에 관심이 있는 사람들 간의 상호작용을 촉진하고, 자발적인 환경 보호 참여를 유도하여 도시 미관 훼손, 배수 시설 훼손, 생물 다양성 훼손, 대기 오염, 자원 고갈 등의 환경 문제를 해결하고 개선하는 데 기여하고자 하는 아이디어에서 시작하였습니다.
Github
https://github.com/codestates-beb/beb-09-clean-mile
사용자 클라이언트
관리자 클라이언트
2. ? 역할
- 팀장
- DevOps
- Frontend
3. ? 사용한 기술 스택
(1) Github 프로젝트 관리 도구 (이슈, 마일스톤, 칸반 보드)

선택한 이유
이전 프로젝트에서는 프로젝트의 주제와 전체/기능별 목표가 뚜렷하게 정해져 있어서 일정 관리의 필요성을 크게 느끼지 못했습니다. 그러나 이번에는 바닥에서부터 기획을 시작하여 한 달이라는 기간 동안 개발, 테스트 그리고 배포 단계를 거쳐야 했습니다. 각 단계가 언제 시작되고 마무리될지 보장이 없었으므로 ‘이 기간 동안 최소 요구사항을 구현하고 테스트로 넘어갈 수 있어야 해’와 같은 구체적인 목표가 필요했습니다. 그래서 팀원들과 의논하여 노션 템플릿과 깃허브를 일정 관리 도구 후보로 선정하였습니다. 결과적으로, 팀원 모두가 깃허브에 더 익숙해지기 위해서 깃허브로 일정을 관리하자는 의견에 수렴하여 깃허브 이슈, 마일스톤 그리고 칸반 보드를 사용하기로 결정했습니다.
사용처
- 태스크 카드만 사용하여 깃허브 이슈를 생성하였고 그 외의 이슈들은 디스코드 채널을 통해 해결
- 마일스톤은 ‘최소요구사항 구현’과 ‘테스트 및 배포’로 나누어 태스크 카드를 그룹화
- 칸반 보드는 Todo, In Progress, In Review, Done 4단계로 나누어 태스크 카드의 상태를 관리
- 태스크 카드는 일일 작업량을 묶어 미리미리 생성해 놓는 식으로 관리하기로 하였으나, 프로젝트 후반부로 가면서 실시간으로 피드백이나 오류 수정사항을 반영하기 위해 시간 단위의 작은 묶음으로 태스크 카드를 생성하여 관리
- 태스크 카드에 명시된 작업들이 완료되면 Pull Request를 통해 dev 브랜치에 병합함과 동시에 태스크 카드를 종결 처리
깃허브를 활용하여 일정을 관리하는 것이 처음이었고 생소했기 때문에 너무 복잡한 구성과 절차는 오히려 다른 부분에서 생산성을 저하시킬 수 있다고 판단하여 전체적인 구성을 간소화하였습니다.
좋은 점
- 무엇을 했고 무엇을 해야 하는지가 명확하게 보입니다.
- 단기 목표를 설정하고 이를 달성하기 위한 생산성이 일정하게 유지됩니다.
- Github Actions를 활용하여 태스크 카드와 브랜치를 함께 관리할 수 있습니다.
아쉬운 점
- 이슈가 생성된 시점과 종결 처리된 시점을 시각적으로 한눈에 확인할 수 있으면 좋을 것 같습니다.
보완할 점
- 태스크 카드에 우선순위 부여하기
- 프로젝트의 주제와 목적을 실현하는데 우선적으로 필요한 기능들에 높은 우선순위를 부여하고 프로젝트를 진행했다면 핵심적인 오류를 확인하고 수정하는 것이 더 수월했을 것 같습니다.

(2) Github Actions

선택한 이유
이번 프로젝트의 기획 초반에 일정 관리를 위해 Github를 사용하기로 결정하면서 ‘이슈를 생성할 때 브랜치를 자동으로 생성하는 방법’을 적용해 보고자 관련 자료를 찾아보면서 Github Actions를 자연스럽게 사용하게 되었습니다. 사실은 이전에 CI/CD 도구인 Jenkins의 기초 사용법을 학습하면서 다른 CI/CD 도구에 대한 소개란을 통해 Github Actions 또한 Github에서 제공하는 CI/CD 도구라는 것을 알게 되었습니다. 이전부터 프로젝트 빌드 및 배포의 자동화에 관심이 있어서 Github Actions를 꼭 사용해보고 싶었는데, 우연이 필연이 되었다고 해야 될까요?
사용처
- 깃허브 이슈 생성 시 이슈 번호와 이슈 레이블에 따라 자동으로 브랜치를 생성하는 작업
- 특정 브랜치에 push가 발생할 때마다 도커 이미지를 빌드하고 Amazon ECR private repository에 푸시하는 작업
배포 과정을 자동화하는 것은 AWS와 Terraform을 학습하는 과정에 집중하기 위해 아쉽게도 제외하였습니다.

좋은 점
- 클라우드에서 워크플로우가 실행되므로 별도의 설정 없이 간단하게 사용가능 합니다.
- 실시간으로 로그가 출력되고 오류가 발생한 부분을 시각적으로 강조해 주므로 디버깅하기 편합니다.
- Marketplace를 통해 공유가 가능합니다.
아쉬운 점
- 코드 변경이 아닌 문서 수정 건에 대해서도 워크플로우가 불필요하게 자동으로 실행됩니다.
- 공식 문서가 어렵습니다.
보완할 점
- 배포 과정까지 자동화하기
(3) Docker

선택한 이유
우선 로컬 환경에서 클라이언트와 서버의 연결을 테스트하기 위해 Docker를 사용했습니다. 라이브러리나 프로그램을 로컬에 직접 설치하고 실행하는 경우에는 버전 문제나 호환성 문제가 종종 나타납니다. 이러한 문제들은 특히 팀으로 작업을 할 때 종잡을 수 없는 곳에서 발생하곤 하는데, Docker를 사용하면 이미지를 빌드하고 격리된 환경에서 동일한 상태의 컨테이너를 실행할 수 있으므로 앞서 설명한 오류들로부터 비교적 자유롭습니다. 도커를 사용한 다른 이유는 빌드 결과물을 직접 사용하는 것보다 Docker 컨테이너를 실행시키는 것이 더 가볍고 쉽게 서비스를 제공할 수 있는 방법이기 때문입니다. 그 외에 클라이언트의 정적 배포가 어려운 경우(ex. SSR이 적용되어 있는 Next.js 프로젝트)에도 Docker를 사용하여 이미지를 빌드하고 컨테이너로 실행할 수 있습니다.
사용처
- 로컬 환경에서 docker compose를 사용하여 node.js 서버 이미지 빌드 및 실행
- 로컬 환경에서 스마트 컨트랙트 배포 및 테스트를 위해 docker compose를 사용하여 Ganache 실행
- 배포 환경에서 필요한 이미지 빌드 및 인스턴스 내부에서 컨테이너 실행
사용 후기
도커는 매번 새로 설치할 필요도 없고 복잡한 환경설정도 필요 없고 이미지만 있으면 docker run 명령어로 격리된 환경에서 컨테이너 실행이 가능합니다. 이렇게 편리한 도커를 만든 개발자는 신이 아닐까요? 그런 의미에서 TOEIC이나 TOEFL 같은 어학 자격시험이 취업시장에서 필수 스펙이 된 것처럼 도커도 모든 개발자가 필수로 익혀야 할 기술 스택이라고 생각합니다. 도커가 없는 세계선은 상상만 해도 끔찍합니다. ?
(4) AWS

선택한 이유
https://news.mt.co.kr/mtview.php?no=2023072009282381857
가장 잘 나가니까. 처음에는 Github 학생팩에서 제공해 주는 Digital Ocean 100달러 무료 크레딧(~눈앞에 아른거리고 있습니다만)~을 사용해서 프로젝트를 배포하려고 했습니다. 그러나 Digital Ocean은 유럽이나 북미를 제외하고는 점유율이 굉장히 낮고 한국에 데이터 센터가 존재하지 않을뿐더러 국내에서 이 서비스를 사용한다는 기업은 들어본 적이 없습니다. 아무리 공짜가 좋다지만 우선은 국내 취업을 목표로 잡고 있는 입장으로서 이래서는 면접에서 관련된 질문을 받아도 곤란하므로 클라우드 서비스로서 범용성 및 인지도가 가장 뛰어난 AWS를 선택했습니다.
사용처
- 객체를 저장하기 위한 S3 버킷을 생성하고 CloundFront를 통해 S3 버킷에 저장된 객체 전달
- HTTPS 통신을 지원하기 위해 Route53 도메인 구입 및 ACM 인증서 발급
- ECR private repository를 생성하여 컨테이너 이미지 저장
- 서비스 제공에 필요한 EC2 인스턴스 및 오토스케일링 그룹 생성
- 서비스 부하 분산을 위해 ELB(ALB) 적용

인프라에 대한 고민
초기 구상은 EC2 인스턴스를 2개 띄워서 컨테이너 오케스트레이션 도구인 Docker Swarm으로 컨테이너를 관리하는 것이었습니다. 그러나 제 경험상 Docker Swarm을 사용해 scale out 된 서비스로 들어간 요청은 적절하게 분산되는 것이 아니라 동일한 요청이 서비스의 모든 컨테이너로 전달되어 그 수만큼 응답으로 돌아오는 것으로 알고 있습니다. 이를 해결하기 위해서는 Nginx를 사용해서 부하를 분산한다든가 해야 될 텐데 저는 그보다 쉬운 길을 선택했습니다. 바로 ALB(Application Load Balancer)를 사용하는 것입니다. ALB와 오토스케일링 그룹을 사용하면 그만큼 비용은 추가되지만 앞의 Docker Swarm과 같은 상황은 발생하지 않을 것이라 확신했습니다. 그 외에 EKS를 사용하여 쿠버네티스 클러스터를 구성하는 것도 고려를 해봤습니다. 그러나 다른 것들까지 하면서 쿠버네티스의 러닝 커브를 견뎌낼 자신이 없었고 무엇보다 EKS의 시간당 0.1달러를 감당할 수 없을 것 같아서 쓸쓸히 발걸음을 돌려야만 했습니다…

좋은 점
- 관련된 자료를 찾기가 수월합니다.
- 인풋(돈) 대비 아웃풋이 확실합니다.
아쉬운 점
- AWS 자체적으로 시각화된 템플릿을 제공해 주면 좋을 것 같습니다.
보완할 점
- 네트워크 공부 (CIDR, IP, DNS, DNS Record 등)
- 클라이언트를 제외하고 서버로 들어가는 요청을 제한하는 방법 탐색
(5) Terraform

선택한 이유
지난 5월 중순쯤이었을까요? 부트캠프 동기들과 함께 꾸려나가고 있던 발표 스터디에서 어떤 주제로 발표를 하면 좋을까 고민을 하면서 자료를 찾아보다가 Udemy에서 ‘Terraform for the Absolute Beginners with Labs’라는 강의를 발견하였습니다. ‘Terraform이 IaC(Infrastructure as Code) 도구라고 하는데, 인프라를 어떻게 코드로 관리한다는 거지?’ 싶어서 호기심에 강의를 구매해서 들었습니다. 실제로 Terraform을 사용해 보니 terraform apply****나 terraform destroy 와 같은 간단한 명령어를 통해 코드로 정의된 리소스를 자동으로 생성하고 삭제할 수 있다는 점이 굉장히 매력적이었습니다. 그리고 프로젝트 관점에서 인프라를 스크립트로 작성해 놓거나 관련 정보를 전혀 공개하지 않는 것보다 깃허브 저장소에 인프라를 코드로 저장해서 남겨놓으면 방문자의 입장에서 이해하기도 쉽고 더 흥미로울 것 같아서 Terraform을 사용하기로 결정했습니다.
사용처
- AWS 인프라 구성 자동화
좋은 점
- 코드와 상태 파일(terraform.tfstate)을 통해 어떤 리소스가 적용되어 있는지 한눈에 확인할 수 있습니다.
- 인프라를 자동으로 생성하고 제거할 수 있습니다.
- 리소스 간의 의존성이 테라폼에 의해 자동으로 제어됩니다.
- Terraform Registry를 통해 다양한 provider와 module을 불러올 수 있습니다.
아쉬운 점
- AWS Console에서 리소스를 생성하는 것보다 직관성이 떨어집니다.
보완할 점
- Terraform Backend 설정
- 클라이언트를 제외하고 서버로 들어가는 요청을 제한하는 방법 탐색
첨언
앞서 Terraform을 사용한 이유로 소개하지는 않았지만 가장 중요한 이유인 비용 절감 효과를 기대하고 있습니다. 팀원들이 모두 취업할 때까지 기약 없는 약속을 위해 AWS 인프라를 살려놓는 비용…을 생각해 보자면 죽음만큼 아찔해집니다. 그래서 저는 언제든지 인프라를 파괴하고 다시 살릴 수 있는 테라폼을 선택했습니다. 모든 것은 계획대로 ?
(6) Next.js

선택한 이유
https://github.com/devias-io/material-kit-react
프로젝트 기획 단계에서 프런트엔드 볼륨이 예상보다 커져서 사용자와 관리자 클라이언트를 분리하기로 하였고 이것을 팀원 한 명이 전담하기에는 너무 양이 많은 관계로 제가 관리자 클라이언트를 담당하기로 했습니다. 그런데 제가 프런트엔드 쪽은 개발 경험이 적어서 바닥에서부터 UI와 기능을 구현하기에는 너무 시간도 오래 걸릴 것 같아서 템플릿을 사용했습니다. 템플릿도 React로만 구성된 것과 Next.js를 사용하는 것으로 나뉘었는데 저는 Next.js의 디렉터리 구조를 통해 라우팅을 하는 기능이 굉장히 간편해 보여서 Next.js가 설정된 템플릿을 선택했습니다.
사용처
- admin 클라이언트 UI 및 기능 구현
좋은 점
- react-router-dom 라이브러리를 사용하는 것에 비해 라우팅이 굉장히 간단합니다.
- standalone 모드를 적용하여 프로젝트를 빌드하면 용량을 아주 크게 줄일 수 있습니다.
아쉬운 점
- 러닝 커브가 높습니다. 라우팅을 제외하고 캐싱이나 SSR 등의 좋은 기능들을 대부분 사용해보지 못했습니다.
보완할 점
- 솔직히 프런트엔드 포지션을 지망하지는 않아서 Next.js를 다시 만질 일이 있을까 싶지만, 그래도 기회가 된다면 Next.js의 다른 기능들을 익혀보고 싶습니다.
4. ? 프로젝트 기여 내역
- 코드 리뷰 (백엔드, 스마트 컨트랙트 위주)
- 오류 해결 다수
- github actions를 사용하여 태스크 카드 생성 시 자동으로 브랜치 생성
- github actions를 사용하여 도커 이미지를 빌드하고 Amazon ECR 프라이빗 리포지토리에 푸시
- Next.js standalone 모드로 빌드
- Mongo Atlas Cluster vpc와 AWS vpc 피어링 설정
- Terraform을 사용하여 AWS 인프라 구성 자동화
- Admin 클라이언트 UI 구성 및 기능 구현
5. ? 남은 과제 및 향후 보완점
- 클라이언트를 제외하고 서버로 들어가는 요청을 제한하는 방법
- AWS vpc와 Mongo Atlas Cluster vpc 간의 vpc 피어링 후에 프라이빗 인스턴스에서 MongoDB에 접속하는 방법
- CI/CD 파이프라인 구성
- 로그인 후 주기적 refresh 요청 설정
- qr 스캔 동시성 문제
- 백엔드 리팩토링
- MongoDB transaction 적용
- 토큰 이코노미 구체화
- 인스턴스 및 서비스 모니터링
6. ? 느낀 점
7. ? 참고 자료
작성 중…