EB는 인프라에 대해 자세히 알지 못해도 프로덕션 수준의 어플리케이션을 운영할 수 있다. 다양한 환경을 구성할 수 있고, Auto Scaling 기능을 통해 트래픽에 따라 인스턴스 수를 증감할 수도 있다. 그리고 모니터링 기능도 꽤 쓸만하다.
다만 언제나 그렇듯 높은 추상화 수준을 적용하게 되면 편리하게 사용할 수 있는 이점이 있지만 입맛에 맞게 인스턴스를 구성하기 어렵다.
특히 골치 아픈 부분이 로그를 확인해보고 싶은 순간인데 빈스톡 이 친구가 뭔가 열심히 작업을 진행하고 있을 때 로그를 요청하게 되면 내가 준비될 때까지 기다리라며 단방향 통보를 하고 로그를 보여주지 않는다.
결국 가만히 기다렸다가 이 친구의 상태가 돌아오면 그 때 로그를 확인할 수 있다. 사실 기다리면 되긴 하지만 얘가 좀 무겁고 느려서 정말 답답하다. 더불어 상태 트래킹도 솔직히 잘 안되는 거 같다.
그래도 특별한 툴 없이도 빠르게 CI/CD를 구축할 수 있는 장점이 있으니 빠르게 한번 구축해보자. 참고로 필자는 빠르게 뚝딱 서버를 만들기 위해서 NestJS를 사용했고, aws-cli를 사용하지 않고 콘솔로 인프라를 구성했다.
작업 절차는 아래와 같다.
- NestJS 어플리케이션 생성
- docker-compose 구성
- Elastic Beanstalk 환경 구성
- GitHub Actions workflow 파일 작성
중간에 정상적으로 진행이 잘 안되는 경우가 있을 수 있으니 완성된 코드가 올라가 있는 repository를 공유할테니 잘 대조해가면서 진행하길 바란다.
🚀 NestJS 어플리케이션 생성
간단한 NestJS 어플리케이션을 생성하기 위해서 @nestjs/cli
를 사용해서 프로젝트를 구축해보자. 만약 해당 패키지가 설치되어 있지 않다면 아래와 같이 커맨드를 입력해서 설치하고 서버를 돌려보자
브라우저에서 hello world를 잘 확인하고 왔다면 아주 간단한 컨트롤러를 하나 만들어줘야 한다. 이 컨트롤러는 EB 환경에서 어플리케이션이 정상적으로 살아있는지 체크하는 역할을 한다.
이제 배포되는 과정에서 작업이 끝나면 EB는 우리의 어플리케이션이 정상적으로 동작하고 있는지 이 친구를 통해 알 수 있게 된다.
🐳 docker-compose 구성
🐋 도커 이미지 빌드
그럼 이제 우리가 뚝딱 완성한 서버 어플리케이션을 컨테이너로 한번 띄워보기 위해 매우 간단한 Dockerfile
을 생성해보자
참고로 npm ci
명령어는 package-lock.json
파일을 확인하고 의존성 모듈을 구성하는 역할을 한다.
자세한 docker 명령어는 이곳에서 확인하자
이제 Dockerfile을 정의했으니 이 친구를 이용해 이미지를 빌드하고 결과를 확인해보자
성공적으로 빌드된 것을 확인했다면 이제 로컬에 해당 이미지를 컨테이너로 띄워 정상적으로 동작하는지 확인해보자. 로컬 3000번 포트로 접속했을 때 hello world 텍스트가 보인다면 성공이다!
📮 docker-compose 파일 작성
참고로 이 게시글 자체가 docker-compose 구성 & EB 배포라는 주제로 쓰여졌기 때문에 이 부분을 다루는 것이지 만약 멀티 컨테이너로 구성할 필요가 없는 경우에는 이번 단계를 스킵해도 괜찮다.
먼저 MySQL 컨테이너를 사용하기 위해서 특정 환경 변수를 담을 수 있는 .env
파일을 구성해보자.
MySQL 컨테이너의 자세한 정보는 공식 도커이미지에서 확인할 수 있으니 참고하길 바란다.
나는 간단하게 캐싱 서버와 RDB 서버를 구축하기 위해 아래와 같이docker-compose.yml
파일을 구성했다.
이제 멀티 컨테이너를 docker-compose 명령어로 띄워보자. 참고로 포트가 80:3000으로 매핑되어 있기 때문에 이번엔 그냥 localhost로 접근하여 확인해야한다.
활성화된 컨테이너를 확인해볼 수 있는 ps
명령어를 사용해 3개의 컨테이너가 모두 정상적으로 올라갔는지 체크해보자.
이렇게 어플리케이션 수준에서 우리가 할 수 있는 작업들은 모두 완료되었다!
🚧 Elastic Beanstalk 환경 구축
시작하기 전에 언급했듯이 이 게시물에서는 AWS 콘솔을 이용해 직접 환경을 하나하나 구축한다. 먼저 콘솔 검색창에 Elastic Beanstalk을 입력하고 어플리케이션을 생성해보자.
1. 적당한 이름을 지어주고, 아래와 같이 플랫폼을 Docker로 선택한 후 추가 옵션 구성을 클릭
2. 소프트웨어 구성 항목에서 환경 변수 입력
이 단계에서 우리가 맨처음 MySQL 컨테이너를 구성하기 위한 변수들을 입력할 것이다. 아래와 같이 입력해준다.
3. 어플리케이션 생성 버튼을 클릭해서 환경 구성
정말 간단하게 기본적인 EB 구성을 끝마쳤다. 인바운드 규칙에 기본적으로 80번 포트가 열려있기 때문에 보안 그룹도 따로 수정할 필요가 없다. 만약 https처럼 기본 포트가 80번 포트가 아닌 친구들의 인바운드를 허용해주기 위해서는 보안그룹 수정이 필요하다는 걸 잊지말자!
🐈⬛ GitHub Actions workflow 파일 작성
GitHub Actions는 GitHub에서 제공하는 workflow 서비스이다. 앱을 빌드하고 테스트하고 배포하는 과정 등을 workflow 파일을 생성하여 쉽게 구성할 수 있다.
프로젝트 root에서 아래 커맨드를 입력하자
이후 release.yml
파일에 아래와 같이 입력해보자.
해당 코드에서 application_name과 environmnet_name에 본인의 EB 어플리케이션명과 환경명을 입력해줘야 하는 걸 잊지말자
해당 workflow은 우리 프로젝트를 zip 파일로 압축해서 EB로 배포하는 역할을 한다. 이렇게 EB로 우리 소스코드를 보내면 알아서 docker 플랫폼에 올라갈 우리 어플리케이션을 셋업해준다.
🔒 GitHub Secrets 추가
마지막으로 해당 workflow가 동작할 때 이용할 환경 변수들을 셋팅해줘야 한다. 여기서 우리가 사용할 값은 AWS Access Key ID, AWS Secret Access Key이다. 만약 이러한 값들이 없다면 IAM에서 키를 받을 수 있으니 참고하길 바란다.
GitHub Repository Setting에 가면 좌측 메뉴에서 Secrets라는 메뉴를 찾을 수 있다. 해당 페이지에 진입해서 New repository secret 버튼을 클릭하여 환경 변수들을 추가해주자
🙏 배포 시작!
이후 여태까지 작업한 내용을 main 브랜치에 병합하고 remote 브랜치에 반영하면 workflow가 돌아가는 것을 확인할 수 있다.
이제 AWS 콘솔로 돌아가보면 귀여운 고래가 녹색 신호를 받아 너무 기쁜 나머지 등으로 컨테이너를 뿜는 모습을 볼 수 있을 것이다!
💡 맺으며
간만에 EB에 배포하면서 어김없이 삽질이 있었다. 생각보다 docker-compose로 EB에 배포하는 국내 포스팅이 없는 거 같아서 이런 과정들을 정리해두면 다른 사람들이 좀 도움을 얻을 수 있지 않을까 하는 마음에 작성해보았다. 아 그리고 연습삼아 진행했다면 EB 환경을 종료하고 어플리케이션을 삭제하는 것을 절대 잊지 말자. 제때 끄지 않으면 매달 치킨 두마리가 사라질 수도 있으니깐..!