Workfolio - AWS(ALB)

eslerkang·2021년 12월 19일
0

Workfolio

목록 보기
1/4
post-thumbnail

Workfolio

개요

1차 프로젝트가 끝난지 3일만에(금요일에 끝나서 월요일에 시작..) 2차 프로젝트를 시작하게 되었다. 이번 프로젝트는 스테이폴리오라는 숙소 대여 사이트를 클론하는 프로젝트를 하게 되었다. 이름에서 대략적으로 유추가 가능하듯이 숙소 대신 오피스(워크스페이스) 대여 서비스로 기획을 변경하여 진행했으며 저작권 없는 이미지, 랜덤 문장/이름 등을 통해 구현하게 되었다.

PM

감사하게도 이번 프로젝트는 내가 낸 아이디어가 아니었음에도 PM을 맡아 진행하게 되어서 전반적인 기획부터 일정 관리까지의 업무를 맡아 해볼 수 있게 되었다. 할 말은 많지만 이번 포스트는 Workfolio를 배포하기 위한 백앤드 서버를 구성하며(AWS/Docker) 만났던 문제들과 구성한 서버에 대해 설명하게 위함이므로 프로젝트 마무리 글 혹은 다른 포스트를 통해 얘기하도록 하겠다.

AWS와 도커

1차 프로젝트에서는 EC2 하나(기본 VPC, 기본 IGW 등을 사용해 실질적으로 건드린 설정은 아무것도 없었다)에 RDS 하나를 사용해 AWS를 사용했으나 '사용'만 했다고 볼 수 있는 수준이었다. 2차 프로젝트(Workfolio)에서는 AWS를 좀 더 제대로 사용해보고 싶었기에 서버 환경을 구성하는 것부터 시작해서 AWS의 기능들을 다수 사용해보고 싶었다.


구성한 모양은 위의 다이어그램과 같다.

간단하게 설명하자면 back-vpc라는 vpc 안(10.0.0.0/16)에 northeast-2a와 northeast-2c의 가용영역 두 개를 생성했다.
그 후 각 가용영역마다 public subnet 하나와 private subnet 하나를 구성하고 public subnet은 10.0.0.0/24, 10.0.2.0/24로 구성하여 IGW를 두었고, private subnet은 10.0.1.0/24, 10.0.3.0/24로 구성하였다.
또한 public-subnet(10.0.0.0/24)에 배스쳔 호스트(Bastion host)를 하나 두어 Developer를 위한 ssh 접속 가능한 EC2를 하나 두고 private-subnet에 각각 EC2(백앤드 서버) 하나씩을 배치했다.
RDS는 백앤드 서버와 분리하기 위하여 rds-vpc를 따로 생성하여 northeast-2a, northeast-2c에 걸쳐 RDS를 생성하였고, 로컬 환경에서의 테스트가 가능하도록 하기 위해 IGW를 둔 public RDS로 구성하였다.
private-sub안의 EC2들은 외부 인터넷 망에 접근할 수 없기에 apt update 등을 위하여 nat-gateway를 두어 외부망과 소통할 수 있도록 하였고, RDS의 경우 public RDS로 구성하였기에 nat-gateway에 대한 접속을 허용해두어 EC2와 RDS가 통신할 수 있도록 하였다.
또한 private-subnet 두 개에 각각 EC2를 하나씩 둔 이유는 분산 서버를 구성하여 서버에의 요청이 분산되게 하기 위함이었으므로, ALB(Application Load Balancer)를 두어 IGW를 통해 들어오는 80번 포트에 대한 요청을 두 개의 EC2로 분산될 수 있도록 하였다.

이렇게 간략하게 설명해두면 구조와 구성 과정이 상당히 간단해보이지만 생각만큼 수월하게 진행되자만은 않았다. 아래에서는 서버 구조를 구성하고 배포를 하는 과정에서 만났던 문제들, 도움이 될 만한 정보들에 대해 작성하고자 한다.

Ubuntu에 Docker 설치

맨 처음 EC2를 구성하고 한 것은 Docker 설치였다. 서버를 Dockerfile을 통해 이미지로 빌드해 배포할 계획이었기 때문인데, Ubuntu EC2에의 설치는 매우 간단하게 끝낼 수 있었다.

sudo apt-get update
sudo apt-get install \
   ca-certificates \
   curl \
   gnupg \
   lsb-release
    
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

와 같이 간단하게 Ubuntu 인스턴스에 Docker를 설치할 수 있다. 또한 이 상태로 Docker를 사용하려 하면 sudo를 붙여 사용해야(ex. sudo docker version) 제대로 Docker를 사용할 수 있으므로 Docker 사용자 그룹에 현재 사용자를 추가하면 sudo 명령어 없이도 도커의 기능을 사용할 수 있다.

sudo usermod -aG docker $USER

과 같은 명령어를 통해 Docker 사용자 그룹을 정해줄 수 있다.

504 gateway time-out Error

위에서 설명한대로 VPC, EC2를 모두 구성하고 ALB를 달아 테스트를 해보니 504 gateway time-out 에러를 만날 수 있었다. 맨 처음에는 구글링을 통해 gunicorn의 타임아웃 기본값이 30초라서 이러한 문제를 겪을 수 있다는 글을 보고 timeout을 120초로 늘려보았다. 그러나 단순하게 생각해도 내가 구현한 내용들은 30초라는 타임아웃 시간 내에 완료하지 못할 기능이 존재하지 않았기에 다른 방향으로 생각해보기로 하였다.
그 후 확인해본 것은 Dockerfile을 통해 이미지를 빌드하는 과정에서의 my_settings.py 파일이었다. 파일을 확인해본 결과 host(mysql 주소) 값이 이전에 만들어두었던 테스트 서버의 호스트 주소로 되어있었다. 즉 EC2(백앤드 서버)와 피어링 되어있는 VPC 안에 존재하는 실 배포용으로 구성한 VPC 안에 들어있지 않는 이전에 만들어두었던 MySQL과 연결해 두었던 것이다.
그러나 my_settings.py의 host를 가장 최근에 생성한 실배포 서버용 MySQL로 변경하여도 타임아웃이 계속 나서 다른 해결책을 찾아보았다.

다음으로 시도했던 것은 back-server(백앤드 서버)와 back-rds(RDS 서버)의 라우트 테이블에 peering-connection을 추가하는 방법이었다. 두 VPC는 원래 다른 VPC로 서로 연결되어 있기 위해서는 peering-connection과 더불어 Route Table에 peering-connection에 대한 내용이 명시되어 있어야 된다는 글 때문이었다.

그러나 이 방법을 통해서도 타임아웃 에러를 해결할 수는 없었고, 그 다음엔 우선 RDS의 보안 그룹을 모두 풀어(All Traffic 0.0.0.0/0) 통신이 되나 확인해보는 것이었다. 놀랍게도 RDS의 보안그룹을 모든 ip주소에 대해 모든 트래픽을 허용해주는 것으로 변경하자 통신이 가능해졌다. 그러나 10.0.0.0/16과 같이 백앤드 서버의 private ip 주소를 inbound 규칙에 넣어주자 다시 통신이 먹통이 되었다.

사실 이 문제는 상당히 상당히 간단한 문제로, 맨 처음 RDS 인스턴스를 만들 때 public RDS로 구성한 것이 모든 일의 시작이었다. RDS를 public으로 구성하자 RDS의 엔드포인트는 RDS의 private ip를 가리키는 것이 아닌 RDS의 public ip를 가리키게 되었고, 그로 인해 private zone의 10.0.0.0/16에서의 접근이 불가능했던 것이다. 또한 nat gateway를 통해 private-subnet의 EC2들도 인터넷망을 통한 통신을 할 수 있었으므로 RDS에서 모든 소스에서의 모든 트래픽을 허용했을 때 EC2와 RDS의 통신이 가능했던 것이다.

결론적으로 private-subnet의 EC2들은 nat-gateway를 통해 외부와 통신하므로 RDS의 inbound 규칙으로 EC2들의 nat-gateway의 public-ip를 추가해주니 EC2와 RDS의 통신이 원활하게 될 수 있었다.

사실상 public RDS로 구성한 순간부터 당연한 것이었지만 전반적인 서버 구성에 대한 이해가 부족해서 발생했던 문제인 것 같다. gunicorn의 타임아웃 시간을 늘려본 것도 이러한 네트워크 망에 대한 이해가 전반적으로 부족했기에 시도할 수 있었던 방법이었던 것 같다.

정리

AWS는 공부를 하면 할수록 메타인지를 상당히 향상시켜주는 것 같다. 앞으로는 빠르게 달려나가는 것 보다는 전반적인 시스템/흐름에 대해 이해를 하면서 공부를 해야할 것 같다고 느꼈다. AWS 자격증 공부를 할지는 아직 모르겠지만 DevOps 쪽 공부도 상당히 흥미롭고 코드를 많이 치거나 그러진 않지만 진짜 개발 공부같다는 느낌을 많이 받을 수 있어서 좋았던 것 같다. 앞으로도 게으름 피우지 않고 공부해야겠다.

profile
Surfer surfing on the dynamic flow of the world

0개의 댓글