AWS를 이용한 간이 서버인프라(웹서버+WAS+DB) 구축

2019-07-08

.

Data_EngineeringTIL(20190706)

study program : https://www.fastcampus.co.kr/dev_camp_devb

[학습목표]

  • AWS를 이용한 간이 서버인프라(웹 서버 + WAS + DB서버) 구축 및 운영테스트

1) Nginx를 이용한 웹서버 구축

2) 웹서버 영역과 동일한 WAS 다중 서버환경 구축

3) AWS RDS(MySQL)를 이용한 DB 서버 구축

  • 구현목표 아키텍처

000

[학습기록]

1. 실습 전 간단한 기초개념 요약

1) 웹서버에서 nginx 서버는 뒷단의 WAS서버의 캐싱기능 및 프록시 서버 역할이 가능하여 매우 유용하다.

2) 간이 서버인프라의 요소 중 WAS 서버를 구성하는 ‘Node.js’

  • 단일쓰레드가 특징이다. 이말은 이 node.js가 열심히 일을 해도 쓰레드 하나밖에 못쓴다는 것이다. 우리가 was 영역을 구성 할 때 예를들어서 CPU가 몇개씩 있는 고성능 사양의 서버에다가 node.js 코드를 올린다고해도 이 WAS는 CPU 한개밖에 못쓴다는 것이다. 반면에 자바는 멀티쓰레드가 가능하다.

  • 그렇다면 CPU 하나밖에 못쓰는데 왜 node.js를 쓰는것인가. http io에 대해서는 이벤트루트를 기반으로 하고 있기 때문에 뛰어난 성능을 보여준다. 최근에는 버츄얼 머신에 대해서도 cpu 한개나 두개짜리로 상당히 라이트하게 쓸 수 있기 때문에 예전처럼 자바서버 하나를 구성하기 위해서 고성능의 서버를 여러대 배치하는 것보다 필요함에 따라서 cpu를 하나만 쓰고 있는 node.js라는 was를 vm단위로 유연하게 쓸 수 있는 장점이 있다.

  • 이말은 다시말해서 컴퓨팅에 대한 환경을 효율적으로 구성할 수 있다는 것이다. 또한 이렇게 라이트하게 만들 수 있다는 얘기는 마이크로서비스로 제공하기에도 적합하고, 도커 컨테이너에 올리기에도 적절하다는 것이다.

3) 우리는 그래서 이번실습에서 WAS영역에는 아래와 같이 네가지 툴을 설치할 것이다.

  • Node.js = Javascript runtime engine

  • Express = Node.js Web framework

  • NPM = Node.js package manager

  • PM2 = Node.js process manager

우리가 자바를 쓰든 파이썬을 쓰든 위와 같은 스텍들은 동일하게 들어갈 것이다.

2. 실습

step 1) Node.js(WAS) 환경이 구동될 EC2 인스턴스 생성

step 1-1) EC2 생성 시 주의사항 WAS는 8080포트로 통신하기 때문에 아래 그림과 같이 SSH 22번 포트 외에 8080 포트를 열어준 다음에 인스턴스를 생성해준다.

000-1

step 2) Node.js WAS 서버 내부 구축

step 2-1) 먼저 ssh와 터미널을 이용하여 인스턴스 접속

step 2-2) 아래와 같이 순서대로 명령어 입력

1) sudo su : root 유저로 변경

2) curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash - : curl 클라이언트를 통해 노드js(버전 8.x LTS), NPM 설치코드 가져오기

** 2)번이 중요한게 우리가 외부에서 노드js를 가져와서 설치하고 싶은데 우리가 지금 패키지 매니저 설치코드가 없는 상태이다. 그래서 curl로 외부에서 가져온것이다. 그리고 3)번에서 알 수 있듯이 yum이라는 패키지 매니저를 통해서 노드 js를 설치한 것이다. 우리가 구동하고자 하는 서버 운영체제에서 내가 설치하려고 하는 프로그램이나 코드가 없어서 가져오고 패키지 매니저를 설치하고 버전을 확인한 것이다. 대부분의 프로세스를 설치할때 거의 이런 과정을 거칠 것이다. 예를 들어서 특정 패키지 매니저로 무언가 가져오려고 하는데 그 패키지가 없다면 위와 같이 외부에서 가져와야 한다는 것이다. 정말 간단한 라이트한 버츄얼머신 컨테이너를 만들때도 그 컨테이너 안에 들어가는 내용들은 이런형태가 될 것이다.

3) yum install -y nodejs : yum 클라이언트로 노드js설치(npm도 같이 동봉되어 있어서 npm도 설치가 된다.)

4) node -v : 설치된 nodejs 버전 체크

5) npm -v : 설치된 NPM 버전 체크

1

step 2-3) Node.js 환경구축. 아래의 명령어들을 순차적으로 실행시킨다.

1) yum install -y git : git 클라이언트 설치

2) git clone -b v1 https://github.com/owen1025/Fastcampus-api-deploy.git : 미리 구현된 웹프로젝트 코드(Fastcampus-api-deploy 프로젝트 코드)를 git을 통해 clone으로 다운로드. 프로젝트는 브랜치 별로 코드 버전이 관리되어 현재단계에서는 v1 브랜치의 코드를 받아오기 위해 -b 옵션을 사용한다.

** 참고로 Fastcampus-api-deploy 프로젝트 내부에는 3가지 브랜치로 구성되어 있다. 그 세가지의 버전을 관리하기 위해서 v1, v2 라는 브랜치와 컨테이너 라는 브랜치가 있다. 현재 실습 간에는 v1에 브랜치에 있는 코드가 필요해서 관련 옵션 명령어로 해당 브랜치의 코드만 가져온 것이다. v1 코드는 우리가 아까 브라우저에서 url의 list로 접속하면 제이슨 형태로 리턴해줬다. 원래는 was의 db에 쿼리를 찌른다음에 가져와야 하는데 아직은 디비가 구축이 안되어 있기 때문에 코드상으로 그냥 정적인 형태로 리턴해주는 것으로 구현해 놓았다. 그래서 추후 디비서버까지 구축을 하면 v2 브랜치에 비로소 실제 이제 db에 직접 찔러보는 코드까지 구현이 되어있어서 실제 was 서버의 동작과정을 볼 수 있을 것이다.

3) ls -al : API 프로젝트 코드(Fastcampus-api-deploy 프로젝트 코드) 다운로드가 잘 되었는지 디렉토리 체크

4) cd Fastcampus-api-deploy/ : 다운받은 Fastcampus-api-deploy 디렉토리로 이동

[다운받은 Nodejs 프로젝트 구조]

  • pm2라는 프로세스 매니저로 구동되고 있는 노드js 프로젝트 환경

1-0

5) npm install -g pm2 : NPM을 통해 pm2(nodejs process manager)를 -g 옵션으로 글로벌 모드(전체 적용)로 설치

6) npm install : npm install 명령어를 입력했을 때 뒤에 패키지명이 없다면 프로젝트 내에 package.json 파일 안의 내용을 확인하여 관련 모듈들을 해당 프로젝트 내에 설치

7) pm2 start bin/www --name WAS : pm2를 통해 node.js로 작성된 API 프로젝트를 실행

** git으로 가져온 프로젝트 폴더 내에 bin/www 라는 파일이 있다. 이 파일이 was의 entry point이다. pm2라는 프로세스 매니저로 이 www 파일을 실행 할 것인데 이 시작점이 bin/www 파일이 될 것이고 이 프로세스의 이름을 WAS라고 명명할 것이다.

8) pm2 list : pm2로 관리되는 프로세스들을 확인

** 프로세스의 상태, 이름, 로그들이 어디에 찍히는지, 스크랩트 경로는 어디인지, 깃 브랜치 어떤걸로 관리되고 있는지 등을 아래 그림에서와 같이 알 수 있다.

9) pm2 show WAS : 방금 pm2로 실행한 WAS로 명시한 프로세스의 상세 정보를 확인

위의 명령어들을 실행하고 아래 그림과 같이 전시되면 정상적으로 진행이 된 것이다.

1-1

step 2-4) 웹브라우저를 열고 다음 같이 입력하고 접속했을때 아래 그림과 같이 제이슨 형태로 출력이 되는것을 확인

http://{WAS가 설치되어 있는 인스턴스 퍼블릭IP}:8080/list

** 8080포트는 와스를 구동할 때 WWW 파일의 내용을 보면 알 수 있듯이 HTTP 요청을 받는 웹서버를 하나 띄우게 되어 있다. 와스를 돌리는데 HTTP요청을 받고 응답을 주기 위해서 웹서버를 하나 띄우는 용도기 때문에 Nginx와 혼동하면 안된다. 와스를 돌리기 위해 띄우는 그 웹서버는 리슨포트를 8080을 쓰는 것이다. 8080포트에 /list라는 route가 들어오면 제이슨 데이터를 던져주게 설정을 미리 해둔것이다.

6

step 3) 로드밸런서(ELB) 새로 생성하여 2대의 WAS를 연결

step 3-1) 방금 위에서 만든 WAS 서버에 대한 AMI 이미지 생성

1) 방금 위에서 생성한 WAS 서버에서 pm2 startup 명령어 실행

** pm2 startup 명령어를 실행하면 pm2 start bin/www --name WAS 명령어와 systemctl enable pm2 명령어가 시스템 재부팅시에도 자동으로 실행되도록 등록된다. 그리고 아래 그림처럼 pm2 save를 하게 되면 pm2 startup의 정보를 저장하게 된다. 이말은 pm2로 띄운 프로세스에 대한 정보와 리눅스 호스트에서 실행되고 있는 백그라운드의 pm2에 대한 정보가 저장이되야 AMI를 생성하고 새로 인스턴스를 부팅을하면 pm2가 실행이 되고 노드js가 자동으로 실행되게 된다. 결론은 프로세스 매니저의 데몬을 호스트가 부팅이 되면 띄워야 하고, 프로세스 매니저를 관리하는 프로세스도 띄워줘야 한다.

7-3

위와 같이 자동으로 시스템 재시작 시 현재 구동되고 있는 PM2 프로세스들을 기록하여 스크립트가 작성된다.

2) 그리고 이를 저장하기 위해 위의 그림과 같이 pm2 save 명령어를 입력하고 실행한다.

명령어를 실행하면 아래와 같이 위에서 자동으로 작성된 스크립트가 저장된다.

7-4

step 3-2) 생성한 AMI이미지를 바탕으로 기존의 WAS 1대 외에 추가로 1대 생성

step 3-1)까지 진행한 WAS서버를 먼저 재부팅해주고 AMI를 만들어준다. 그 담에 생성한 AMI를 바탕으로 기존의 was와 동일한 WAS서버를 추가로 한대 만들어준다.

7-5

step 3-3) 로드밸런서를 생성하여 생성한 2대의 WAS와 연결

먼저 로드밸런서 탭에 가서 로드밸런서 생성을 클릭한다. 그리고 맨오른쪽 클래식 로드 밸런서 생성 버튼을 클릭한다.

그러면 아래와 같은 그림이 나오는데 로드밸런서 이름을 입력하고 로드밸런서 포트와 인스턴스 포트를 각각 8080으로 입력해준다.

7-9

위의 그림과 같이 설정을하고 단계 2 : 보안 그룹 할당으로 넘어가서 22번 포트와 8080 포트가 열려있는 보안그룹을 선택해준다.

그리고 아래 그림과 같이 ping경로를 /index.html 에서 /로 변경해준다. 그 다음에 ec2 인스턴스 추가 버튼을 클릭한다.

7-11

아래 그림처럼 우리가 생성했던 와스서버 2대를 선택해준다. 그리고 검토 탭까지 이동해서 생성 버튼을 클릭한다.

생성이 완료되면 로드밸런서에 와스서버 2대가 물려있는 것을 확인할 수 있다. 그리고 웹브라우저를 통해 http://{생성한 로드밸런서 퍼블릭 ip}:8080/list로 접속하면 아래 그림과 같이 전시가 되야 한다.

7-10

** 참고로 이렇게 구성하게 된 로드밸런스와 와스서버들은 네트워크 설정 시 디폴트로 하였기 때문에 퍼블릭 vpc 기반이라 외부에서도 접근이 가능한데 was 서버 인스턴스와 was 로드밸런서 생성 시 네트워크 설정을 프라이빗으로 하게되면 외부에서 접근을 막을 수 있게 된다. 그리고 이 프라이빗한 구역을 Nginx 서버 구역과 연결해주면 우리가 의도하는대로 외부와의 소통은 Nginx 로드밸런서가 하게 되고 Nginx에서 처리할 수 없는 부분을 was로 패싱해서 처리하는 시스템을 구축할 수 있게된다.

step 4) WAS 로드밸런서(ELB) 작동테스트

우리가 기존에 생성해둔 Nginx 서버 인스턴스중에 아무거나 하나에 ssh로 접속하여

curl {앞서 생성한 ELB public DNS:8080}/list 명령어를 입력하여 아래 그림처럼 전시가 되는지 확인한다. 위에 웹브라우저에서 접근한것처럼 나올것이다.

** 우리가 이번 실습에서는 was elb를 디폴트 네트워크 설정으로 했기 때문에 퍼블릭 아이피로 접근해서 가져오는데 원래는 elb 및 was 인스턴스 네트워크를 private로 설정하고 nginx 서버에서 curl로 테스트할때도 was elb의 private dns로 접근해서 테스트해야한다.

** curl : 커맨드 라인용 데이터 전송 툴로 http, https 등 다양한 인터넷 프로토콜 지원, 리눅스나 맥os에 기본적으로 탑재되어 있음

8-1

** 참고로 실습사전에 Nginx 웹서버 2대와 nginx 서버들이 물려있는 로드밸런서를 생성했고 아래 그림과 같이 구동되고 있다.

00

step 5) Nginx 서버에 리버스 프록시 기능을 추가

  • step 5) 의도 : Nginx 서버에 접근한 사용자가 아래 그림처럼 요청했을때 동적데이터 처리부분은 was 서버로 넘겨서 처리할 수 있도록 한다. 다시말해서 클라이언트가 웹서버로 요청할때 구문중 api 가 포함되어 있다면 해당 url을 api 요청으로 인식해서 프록시 패스라는 기능을 통해 내부망의 was 영역(was 로드밸런서)으로 보낸다는 의도이다. 아래 그림중간에 클라이언트가 웹서버 로드밸런서로 http://elb-nginx-domain:80/api/list 로 요청하게되면 was 로드밸런서에 http://{was-lb-private-dns}:8080/list 로 요청하도록 유도한다. 여기서 헷갈리면 안되는게 서버의 웹브라우저로 접속했을때 앨범화면에서 리스트를 가져오는 버튼을 누르면 웹브라우저 로드밸런서에 나 지금 데이터 필요하니까 :80/api/list 에 요청을 보낼 것이다. 그런데 뒤에 물려있는 was 노드들은 api/list에 대한 라우트 룰을 처리하는 것이 아니라 그냥 list룰로 처리하게 된다. nginx가 요청을 받을때 요청내용 안에 api라는 문구가 있다면 api요청으로 인식하게 location을 바꿔서 was에 보낼때는 :8080/list로 보내주게 된다. nginx 설정하는 것은 api 문구가 들어가게 되면 nginx가 api 처리로 인식하여 본인은 해결할 수 없다고 인식하기 위함이다. 그리고 was에 보내줄때는 :80/api/list으로 이런식으로 보내주면 안되고 :8080/list로 보내줘야 한다. 즉 아래 마지막 그림처럼 GET/list로 바꿔서 보내주게 되는 것이다.

8-2

step 5-1) nginx가 설치된 EC2 인스턴스에 SSH로 접속해서 아래의 명령어를 순차적으로 입력하여 실행한다.

1) cd /usr/share/nginx/html/ : 기존 Fastcampus-web-deploy가 다운로드 된 디렉토리로 이동

2) ls -al : 디렉토리 내 파일 리스트 보기

3) rm -rf Fastcampus-web-deploy/ : 기존 프로젝트 삭제하기

4) git clone -b v1 https://github.com/owen1025/Fastcampus-web-deploy.git : 서버와 통신하는 Ajax 코드가 들어있는 v1 브랜치에 있는 웹 프로젝트 다운로드

5) vi Fastcampus-web-deploy/resources/js/common.js : 이 명령어를 실행하여 vim으로 아래 그림의 하단처럼 내용을 수정하고 저장한다.

  • BASE_URL = {nginx-lb-dns}/api/ 로 변경

이 base_url은 클라이언트에서 사용하는 코드이고 클라이언트가 우리가 셋팅해놓은 nginx에다 보낼건데 nginx에서 부하분산을 해주기 위해서 nginx 로드밸런서에게 보낸다고 명시적으로 설정한 것이다.

9

6) cd /etc/nginx/ : nginx.conf가 위치한 디렉토리로 이동

7) cp nginx.conf nginx-copy.conf : nginx.conf 수정 전 원본 설정파일 백업

8) vi nginx.conf : vi 편집기로 nginx.conf 열기

그리고 아래 그림과 같이 nginx.conf의 location 부분을 수정한다. proxy_pass 뒤 URL은 WAS(Node.js)가 운영 중인 인스턴스와 연결된 ELB의 DNS로 입력해준다.

그리고 저장하고 vim 에디터를 빠져나온다.

9-5

** 1) ~ 8) 단계의 내용을 나머지 nginx가 설치된 ec2에서도 똑같이 수행을 해준다.

** 참고로 위의 그림 nginx.conf 내용에서 location 블록은 상위에 있을수록 우선순위로 적용된다.

빨간색 박스 안에

rewrite /api/(.*) /$1 break;

부분은 api 뒤에 오는 모든 구문까지 선택해서 api 뒤의 모든문구는 달러1로 치환을 해준다. 그리고 이 달러1 변수는 프록시패스에서 설정한 url의 뒤에 붙게 된다.

예를 들어서 입력값으로 /api/list가 들어오게 되면 출력값으로 http://{was elb dns}:8080/list가 된다. 혹은 /api/login이 들어오게 되면 출력값으로 http://{was elb dns}:8080/login으로 만들어준다.

proxy_set_header값은 클라이언트의 운영체제 정보등을 고려해서 그 운영체제에 맞게 서비스를 해줘야 하기 때문에 필요한부분이다. 예를들어서 header 값에서 운영체제 정보를 뽑아온 다음에 proxy pass를 통해서 ios 백앤드를 담당하고 있는 서버로 리버스 프록시를 한다던지 아니면 안드로이드 백앤드를 담당하고 있는 서버로 리버스 프록시를 한다던지 이러기 위해 필요하다. 여기서는 그런거 따지지는 않아서 프록시패스 호스트에 관해 nginx에서 받은 헤더값 그대로를 뒷단으로 보내주기 위해 달러host로 설정했다.

또한 api/(.*) 이부분의 괄호 안의 부분을 if문을 넣을 수 있다. 이를 이용하면 여러가지 방안으로 응용할 수 있다 예를 들어서 contents라는 문구가 있을때 if문으로 명령어를 처리해주면 클라이언트가 contents라는 문구가 들어있는 요청을 보내주게 되면 이 nginx의 메모리에 캐싱된 데이터를 리턴해주고 따로 뒷단으로 프록시 패스 안해도 되는 경우를 만들 수도 있다. 요즘에는 인메모리 nosql엔진 중에 redis 서버를 두고 만약에 클라이언트가 해당 api contents라는 것을 보냈을때 redis서버에 프록시 패스한담에 물어봐서 키벨류로 관리하고 있는 캐싱된 데이터 중에 해당되는게 있는지 찾아서 리턴해 줄 수 있다. 다시말해서 contents 문구가 들어있는 url이 들어오면 뒷단 was에 보내지 말고 redis(캐싱서버)로 보내라 이런식으로 설정할 수 있다.

9) service nginx reload : nginx.conf 수정 내역을 적용하기 nginx를 재시작해준다.

10) 그리고 웹브라우저를 열고 http://{웹서버 영역의 로드벨런스 dns}/album으로 접속 후 main call to action을 클릭 시 아래 그림처럼 전시가 되면 정상적으로 수행이 완료된 것이다.

9-7

step 6) Database 서버 (AWS RDS) 구축

  • 데이터베이스의 사용량이 많은 경우 하나의 데이터베이스로 모두 처리하는데 부담이 될 수 있다. 따라서 Master, Slave 등의 관계로 같은 데이터를 갖고 있는 데이터베이스를 여러 개 생성하여 요청을 분산 처리한다. 보통 Master는 write용, slave들은 read용으로 사용한다.

  • master, slave, replication 구조에서 가장 중요하게 고려해야 할 것은 데이터의 동기화이다. 예를들어서 마스터에다가 오늘 결제정보에 대한 쿼리를 날렸다. 그런데 마스터 서버가 슬레이브 서버랑 동기화가 안되어 있으면 치명적이다. 금융권에서는 치명적인 이슈가 될 것이다. 그래서 마스터와 슬레이브가 하나처럼 만들수 있는 클러스터라는 개념을 적용해야 한다.

  • 그래서 우리가 할 실습에서는 master, slave, replication 구조를 사용할 것이고, 데이터 동기화라는 이슈가 어쨌든 상당히 중요하다.

  • AWS RDS는 마스터, 슬레이브, 리플리케이션 구조를 원버튼으로 제공해준다.

step 6-1) Database server 생성

AWS RDS 콘솔로가서 데이터베이스 생성 버튼을 클릭한다. 그 다음에 아래 그림과 같이 설정하고 데이터 베이스를 생성해준다.

10

step 6-2) 데이터베이스 생성확인 및 Mysqlworkbench를 이용한 일부 디비내용 수정

[아래 그림설명]

1) 데이터베이스 콘솔에서 생성한 데이터베이스 확인

2) 또한 엔드포인트와 포트를 체크한다.

3) sqlworkbench를 실행하고 new connection을 생성하는데 아래 그림과 같이 입력하고 test conncetion까지 완료해준다.

4) ~ 5) 방금 new connection으로 생성한 connection으로 접속한다. 그리고 아래 그림과 같이 open sql을 클릭한다. 그리고 사전에 미리 작성하고 생성한 sql파일(devops.sql)을 선택해주면 해당 쿼리가 전시되는데 이를 실행해준다.

6) 아래 그림과 같이 LIST, USER 테이블이 생성되는지 확인

7) ~ 9) 데이터베이스 콘솔 중간에 보면 보안그룹 두개가 보일것이다. 여기서 인바운드라고 적혀있는 것을 클릭하면 거기에 물린 보안그룹이 나와 있는데 그 보안그룹을 우클릭하고 인바운드 규칙 편집을 클릭해서 아래 그림과 같은 창을 띄운다. WAS가 구동하는 EC2 인스턴스에서도 해당 RDS에 연결이 가능하게끔 was가 구동하는 ec2 인스턴스 보안그룹을 맞춰줘야 한다. 규칙편집에서 3306 포트 명시되어 있는 행의 소스부분에 was가 구동하는 ec2의 보안그룹이름을 추가하여 맞춰준다. 나는 이미 같은 보안그룹이라 따로 변경하지 않았다.

11

step 7) 웹서버 - WAS - DB 연결

  • step 7) 목표

WAS 내의 프로젝트를 v2로 변경한다. v2는 was와 db 간의 연결 관련 내용이 수록되어 있다.

12

아래 내용을 순차적으로 수행해준다.

1) SSH 클라이언트를 통해 WAS(Node.js)가 구동하는 EC2 인스턴스에 접속

2) ls -al

3) sudo su

4) rm -rf Fastcampus-api-deploy/ : 기존 API 프로젝트 제거

5) git clone -b v2 https://github.com/owen1025/Fastcampus-api-deploy.git : DB 서버와 통신하는 v2 프로젝트 코드 다운로드

6) cd Fastcampus-api-deploy/ : 새로 받은 v2 프로젝트 디렉토리로 이동

7) npm install : package.json에 명시된 모듈 의존성을 확인하여 관련 모듈 다운로드

8) vi package.json : vi 편집기로 package.json 수정

9) package.json가 vi로 열리면 아래 그림과 같이 database 부분에 host는 앞서 구축한 RDS의 엔드포인트(DNS)를 입력하고, 유저 부분은 아까 admin으로 만들었기 때문에 admin으로, 비번도 입력해준다.

10) vi 편집기에서 :wq로 package.json 저장하고 종료한다. 그리고 pm2 restart WAS로 수정내역을 적용하여 was 프로세스를 재기동한다.

** 1) ~ 10) 과정을 나머지 다른 하나의 WAS(Node.js)가 구동하는 EC2 에도 적용해준다.

13

11) 아래의 그림과 같이 RDS Read replica(읽기 전용 복제본)를 설정해준다.

14