이번 포스트에서는 AWS ELB application load balancer를 이용해 SSL을 적용 하는 방법을 정리한다. 

즉 이 포스트의 목적은 아래 Fig 1과 같은 architecture 로 서버 운영 구조를 완성하는 것이다. 

 

이 구조를 간단히 설명 하면 서버로 request 가 들어오면 load balancer는 요청이 https(port 443) 요청인지 확인한다. 만약 http(port 80) 요청이면 load balancer 가 이 요청을 https 로 redirection 한다. https 요청이면 load balancer 가 SSL session 의 종단점 역할을 대신해 요청을 decryption 해 target group 의 80 번 포트로 요청을 forwarding 한다. 이렇게 구성 하면 ec2 인스턴스에서 실행 중인 server가 ssl decryption 을 수행 하지 않아도 되니 조금더 가벼워 질수 있다. 

t2.micro 인스턴스인 내 서버의 짐을 줄여 주기 위한 시도이다. 

 

Fig 1. application load balancer를 이용한 SSL 적용 구조

aws ELB application load balancer 를 이용해 SSL을 적용하기 위한 순서는 아래와 같다. 

내 경우 django app 에 SSL 을 적용하기 위한 것으로 ec2 인스턴스는 이미 생성한 것을 이용한다. 


순서

1. ACM(amazon certificate manager) 에서 SSL 인증서 발급 및 호스팅 영역에 레코드 등록 

2. Target group 생성 

3. application load balancer 생성 및 security 정책 설정(

4. route53의 domain A 레코드 변경

 

ACM(amazon certificate manager) 에서 SSL 인증서 발급 및 호스팅 영역에 레코드 등록

aws에는 amazon certificate manager 줄여서 ACM이 라는 서비스가 존재 한다. 

acm 콘솔로 이동하기 위해서는 'aws console -> 검색 창에서 certificate manager' 검색 -> cerificate manager 클릭 하면 된다. 

acm 은 ssl/tsl 인증서 발급이 가능 한데 나는 이중 ssl 인증서 발급을 요청했다. 

참고로 ssl 인증서를 발급받기 위해서는 DNS 검증이나 이메일 검증이 필요한데 여기서는 DNS 검증 방식을 사용 한다. 즉, 등록된 domain 이 있어야 한다는 의미이다. 

생성한 SSL 인증서는 ELB 인스턴스에 등록해 사용할 수 있다.

 

  1. SSL 인증서 생성을 위해 acm 콘솔에서 "인증서 요청"을 클릭하고 "퍼블릭 인증서"를 선택한다. 
  2. 다음과 같은 화면 이 나오는데 도메인 이름에는 ssl을 이용해 통신을 암호화 하고자 하는 domain 을 입력한다. 
    예를 들어 내 웹페이지의 주소가 askmeanything.com 이라 하면 이 주소를 입력하면 된다. 검증 방법은 DNS 와 이메일 검증이 있는데 DNS 검증을 추천한다. 다만 DNS 인증을 이용하기 위해서는 askmeanything.com 이 DNS 서버에 등록이 되어있어야 한다. DNS 서버에 domain 을 등록 하는 방법은 [aws]ec2 인스턴스 도메인 연결을 참조하자.
  3.  키 알고리즘은 원하는 걸 선택하면 된다.

Fig 2. 퍼블릭 인증서 요청

 

옵션을 다 선택하고 "요청"을 누르면 인증서가 생성된다. acm 콘솔에서 "인증서 나열" 에 들어가 방금 생성한 인증서를 클릭하면 다음과 같은 화면을 볼 수 있다. 

Fig 3. 인증서 상태

 

우측 위에 "상태"를 보면 "검증 대기 중" 이라고 나오는데 인증서 생성시 등록한 domain 에 대한 소유권 검증이 끝나지 않았기 때문에 다. 검증을 마치기 위해서는 Fig 3. 인증서 상태 페이지에서 아래 순서를 따라하자. 

 

4. "도메인 -> Route53에서 레코드 생성" 클릭

5. "Amazon Route 53에서 DNS 레코드 생성" 페이지 에서 SSL 인증서를 등록하고자 하는 domain 선택 및 레코드 생성 클릭.

이 과정에서 askmeanythin.com 호스팅 영역에는 CNAME 레코드가 추가 된다. CNAME 사용자가 도메인을 통제함을 증명하는 키-값 페어가 포함되어 있다. CNAME 레코드에 대한 자세한 설명은 이 페이지를 참조하자.

 

6. route53 에 5번에서 생선한 cname 레코드가 생성되고 시간이 좀 지나면 Fig2. 인증서 상태가 active 로 바뀐다. (얼마의 시간이 걸리는지는 정확하지 않은것 같다. 나의 경우 23:00 에 등록을 했고 20분이 지나도 상태가 바뀌지 않아 자고 일어났더니 바뀌어있었다.)

 

Target group 생성 

Fig 4. Load balancer 동작

Target group은 AWS ELB 로드벨런서가 요청을  route 하는 대상의 집합이다. 요청을 처리 할수 있는 lambda 나 ec2 instance등이  target group 에 속할 수 있다.  Fig 4. 을 보면 load balancer는 외부로 부터 들어 오는 요청을 target group 에 속한 ec2-2 로 route 한다. 

 

대상 그룹 생성을 위해서는 "ec2 콘솔 -> 로드벨런싱-> 대상 그룹" 페이지에서 우측 위에 있는 "create target group" 버튼을 누르면 된다. 버튼 클릭하면 Fig 5와 같은 페이지를 볼 수 있다. 나의 경우 ec2 인스턴스에 요청을 route 하는게 목적이므로 target type"instances" 로 선택했다.

Target group name에는 식별하기 쉬운 이름을 입력하자. 이 이름으로 load balancer 를 만들때 target group을 선택할 것이다. VPC 는 이 target group에 포함 시킬 ec2 인스턴스들이 할당된 VPC와 같은 것으로 선택한다. 이게 다르면 통신이 되지 않는다. 

 

Fig 5. target group 생성 페이지

생성을 클릭하고 나면 다음과 같은 페이지가 보인다. 이 과정이 실질적으로 방금 만든 target group에 요청을 처리할ec2 인스턴스를 추가하는 과정이다. 추가하고자 하는 ec2 인스턴스를 선택하고 해당 인스턴스의 어떤 port로 요청을 routing 할지 정하고 "Include as pending"을 클릭하면 된다.

아래 그림에서는 선택한 인스턴스의 80번 포트로 요청을 routing  하도록 설정했다.   

 

 

application load balancer 및 security 정책 설정

AWS ELB application load balancer 는 클라이언트에 단일 접속점을 제공하고 로드밸런싱을 수행한다. 무슨 말이냐면 같은 서비스를 제공하는 물리적인 서버가 여러개 있을때 이 서버들은 서로 다른 IP를 가지고 있을 수 있다. 클라이언트가 이 서버들 중 하나에 의해 서비스를 받기 위해서는 해당 IP에 접근을 해야 한다. 접근한 서버가 매우 바쁜고 다른 서버는 놀고 있다면 서비스의 가용성은 떨어지게 된다. 그렇다고 사용자가 어떤 서버가 놀고 있는지 일일이 모니터링 해서 덜 바쁜 서버에 접근 할 수도 없고 그렇게 한다고 해도 동일 한 서비스를 받기 위해 서로 다른 서버의 IP를 이용해 접근하는 것도 매우 불편하다. (극단적인 예로 설명 하다 보니 서버의 IP 로 접근한다고 표현했는데 domain을 사용하기 때문에 이렇게 되진 않는다)

 

application load balancer는 이런 상황에서 해법을 제공한다. 동일한 서비스를 제공하는 여러 물리 서버를 target group으로 묶고 이 target group으로 가는 모든 요청을 application load balancer가 받아서 target group 에 정해진 정책에 따라 업무를 배분한다. 사용자 입장에서는 서비스를 제공하는 각 서버의 IP 를 몰라도 되고 application load balancer의 IP 나 domain만 알면된다. 또한 load balancer 가 서버에 업무를 분배하므로 어떤 서버가 덜 바쁜지 모니텅링 할필요도 없다. 

 

또한 application load balancer를 이용 하면 이 포스트의 목적이었던 암호화된 통신 SSL 을 적용 할 수 있다. Fig 1 에서 처럼 암호화 되지 않은 요청이 application load balancer 로 도착하면 암호화 된 통신을 위해 이 요청을 https(port 443)으로 redirection 한다. 요청이 암호화된 요청이면 application load balancer 가 SSL 연결의 종단점 역할을 수행해 암호화된 요청을 해독하고 해도된 요청(request)를 target group의 80번 포트로 포워딩한다. 이렇게 되면 서비스를 제공하는 서버들은 요청을 해독하는데 자원을 할당하지 않아도 되는 장점(?)이 있다. 

 

이제 application load balancer 를 생서하는 방법을 알아 보자. "ec2 콘솔 -> 로드 밸런서" 페이지에 들어가 우측 상단의 "create load balancer"를 클릭한다. "Select load balancer type" 페이지에서 application load balancer 를 선택한다. 그럼 아래 Fig 7 과 같은 페이지를 볼 수 있다. 

Fig 7. Load balancer 설정 페이지

외부에서 들어오는 요청을 받아서 처리하는게 목적이므로 Basic configuration 의 scheme 에서 "internet-facing"을 선택한다. IP address type은 IP4 를 선택했다. 요즘은 IPv6가 많으니 실제 서비스를 위해서는 Dualtask 를 선택하는게 적절할거 같다. (나는 처음엔 IPv4 를 선택했다 나중에 dualstask으로 변경했다.)

 

Network mapping 에서는 target group 에 속한 ec2 인스턴스들이 속해 있는 VPC 와 같은 것을 선택하면 된다. Mappings 는 target group 에 속한 ec2 인스턴스의 가용영역(ec2 인스턴스 네트워크 페이지에서 확인가능)을 확인해 동일 한 것을 선택하면 된다. 최소 두개 선택하게 되어있는데 나의 경우 ec2 인스턴스의 가용영역인 ap-northeast-2a와 ap-northeast-2b (apne2-az2) 를 선택했다. 

 

 다음으로 Fig 8 처럼 security groups과 listener 정책을 설정한다. Security group(보안그룹)은 임의의 protocol과 port로의 요청을 어떻게 처리 할것인지 에 대한 규정을 담고 있다. ec2 인스턴스와 동일한 정책을 사용하기 위해서는 ec2 인스턴스에 할당한 보안그룹을 선택해도 된다. 나는 target group에 속한 ec2 인스턴스와는 다른 보안정책을 설정 하기 위해 default로 두었다. 

 

 listeners and routing은 생성중인 application load balancer 가 몇번 port로 들어오는 어떤 protocol의 요청을 어떻게 처리 할지 설정하는 것이다. Fig 8에서는 80번 포트로 들어오는 http 요청과 443 번 포트로 들어오는 https 요청에 대해 default action 으로 이전 섹션인 "Target group 생성"  단계에서 생성한 target group 으로 요청을 forwaring 하도록 설정 했다. 하지만 이렇게 설정해 놓으면 Fig 1에서 80번 포트로 들어오는 비암호화된 요청을 암호화된 요청으로 redirection 하고자 하는 계획과 다르므로 잠시 후 80번 포트로 들어오는 http 요청에 대한 routing 정책을 을 변경 할 것이다. 

Fig 8. 보안 그룹 및 리스너 세팅

 

application load balancer 의 생성단계는 거의 다 되었다. 443 번 포트로 들어오는 https 요청에 대한 listener를 등록 하면 아래와 같이 "Secure listener settings" 이라는 추가 설정 섹션이 생긴다. SSL 통신을 위한 certification 을 선택하라는 것인데 "ACM(amazon certificate manager) 에서 SSL 인증서 발급 및 호스팅 영역에 레코드 등록" 에서 생성한 인증서를 선택하면 된다. 이렇게 설정 하면 application load balancer 가 SSL 통신의 종단점 역할을 수행 할 수 있다. 인증서 선택 말고도 왼쪽에 "SEcurity policy"를 선택하는 란이 있는데 나는 이에 대한 지식이 부족해 일단 default 로 두었다. 

FIg 9. SSL 인증서 선택

 

 여기 까지 설정 하고 생성을 누르면 application load balancer 가 생성된다. "ec2 콘솔 -> 로드 밸런서" 페이지에 들어가면 생성한 application load balancer 를 볼 수 있다. 생성한 로드 밸런서의 "state" 가 Active라면 잘 생성되어 실행 중인 것이다. 하지만 몇번 만들어 본 결과 만들고 바로 확인 하면 "state" 가 "provisioning" 으로 나온 일종의 준비중 이라는 상태로 10분 정도 기다리면 Active 상태로 바뀐다. 

 

다음으로 80번 포트로 들어오는 http 요청을 어떻게 처리 할지에 대한 정책을 바꿔야 한다. 80번 포트는 http 요청으로 비보안이므로 이 요청을 https 요청으로 redirect 하도록 할 것이다. 위에서 application load balancer의 Listener 를 설정 할때 80 번 포트로 들어오는 요청에 대해 target group 으로 포워딩 하게 했기 때문에 이를 바꿔 주어야 한다. "ec2 콘솔 -> 로드 밸런서" 에서 생성한 로드 밸런서를 선택하고 아래 Fig 10처럼 Listener 상세 페이지에서 80번 포트 리스너의 Rules 값을 클릭한다.

Fig 10 로드 밸런서 상세

리스너 상세 페이지에서 우상단에 있는 manage ruls를 클릭한다. 아래 Fig 11 처럼 80번 포트에 대한 규칙을 리디렉션으로 바꾸고 대상을 HTTPS 로 하고 저장한다. 이렇게 설정 하면 80번 포트로 오는 요청을 443 번의 HTTPS 로 리디렉션 하게 된다. 

Fig 11. 리스너 규칙 변경 페이지

 

다음으로 할일은 load balancer에 할당된 보안 그룹에서 로드 밸런서의 리스너 포트를 오픈하는 것이다. 로드 밸런서 생성시 리스너를 등록 했다고 보안 그룹에서 해당 포트가 자동으로 오픈되지 않는다. 나는 이걸 몰라서 약 3시간을 디깅했다. 로드 밸런서에 할당된 보안 그룹 페이지로 들어가 아래 Fig 12 같이 인바운드 규칙을 바꾼다. 80, 443 번 이외의 포트를 허용 하고자 한다면 해당 포트도 추가 한다. 

Fig 12 로드 밸런서 보안 규칙

 

이제 target group에 속한 ec2 인스턴스는 로드 밸런서에서 오는 요청 만 받으면 되니 ec2 인스턴스의 보안 그룹 규칙도 변경해야 한다. application load balancer 가 SSL 종단점 역할을 해서 요청을 해독하고 ec2 인스턴스의 80 번 포트로 forwarding 해주므로 ec2 인스턴스의 보안그룹은 load balancer 의 보안 그룹에서 80 번 포트로 들어오는 요청만 받게 하면 된다. 아래 Fig 13 은 내 ec2 인스턴스 보안 그룹의 인바운드 규칙이다.

80번 포트의 소스가 위 Fig 12 에 나온 로드 밸런서 보안 규칙의 식별자임에 주의를 기울이자. 이렇게 설정하면 이 ec2 인스턴스는 로드밸런서를 통해서 80번 포트로 들어오는 요청만 받아서 처리하게된다. 아래 Fig 13에는 80 번 포트 외에 SSH접속을 위해 22 번 포트를 열어 놨는데 이건 어디서든 접근 할 수 있게 0.0.0.0/0 으로 소스를 설정했다.

Fig 13. target group 에 속한 ec2 인스턴스의 보안 규칙

 

이 단계 까지 끝났으면 application load balancer 가 정상 동작하는지 확인을 해보는게 좋다.

생성한 로드 밸런서의 상세 정보를 보면 ("ec2 콘솔 -> 로드 밸런서") DNS name 이라는 정보가있다. 이걸 카피 해서 웹 브라우저에 복사하자. Fig 13의 붉은 박스 부분이다. 

Fig 14. 로드 밸런서 상세 정보

target group에 속한 ec2 인스턴스에서 nginx 가 80번 포트로 요청을 리슨 하도록 설정되어있다면 로드 밸런서 주소로 접근 하면 nginx 의 "Welcome to nginx!" 페이지를 볼 수 있다. DNS name 통해 접속했는데 이 페이지를 볼수 없다면 무언가 잘못 설정했을 확률이 높으니 확인해 보자. 

 

 route53의 domain A 레코드 변경

이제 마지막 스탭이나 이 부분은 아주 쉽다. route53 서비스에서 호스팅 영역에 레코드 A의 값을 바꿔 주기만 하면된다. 

기존 레코드 A는 도메인 이름에 해당하는 ec2 인스턴스, 즉 서버의 IP를 가지고 있다. 서버가 실행 중인 ec2 앞에 로드 밸런서가 있고 모든 요청은 이 로드 밸런서를 통해서 서버로 포워딩 되도록 할것 이므로 도메인 이름 으로 접속을 하면 ec2 인스턴스가 아닌 로드 밸런서로 요청이 가도록 레코드 A를 변경하는 것이다. 

"route53 콘솔 -> 호스팅 영역 선택 -> 유형이 A인 레코드 선택 -> 레코드 편집 클릭" 

아래 Fig 15 처럼 "별칭"을 enable 하면 기존 값을 입력 하던 입력 폼이 "트래픽 라우팅 대상"을 선택하는 폼으로 바뀐다. 

이 라우팅 대상으로 이전 섹션에서 만들었던 application load balancer를 지정하면 된다. 

첫번 째 라우팅 대산의 type을 선택 옵션에서 "application/classic load balancer"를 선택한다. 다음으로 가용역영을 선택하는데 application load balancer를 생성할 때 Fig 7의 mapping 에서 지정한 지역 정보를 선택하면 된다. ec2 인스턴스의 가용영역과 같은 값이기도 하다.  마지막으로 라우팅 대상 application load balancer의 DNS를 선택하면 되는데 여기서 한가지 주의 할 점이 있다. 생성한 로드 밸런서를 선택 하려고 하는데 로드밸런서의 DNS name 앞에 "dualstack" 이라는 첨자가 붙는 경우가 있다. 내 경우가 이랬는데 로드 밸런서의 DNS name 이 "alb-app-lb-1790508963.ap-northeast-2.elb.amazonaws.com." 이라면 

"dualstack.alb-app-lb-1790508963.ap-northeast-2.elb.amazonaws.com." 와 같은 이름이 추천으로 뜨는 경우다. 

이런 경우 "dualstack" 이라는 첨자를 지우고 반드시 생성한 로드 밸런서의 DNS name 과 같은 값으로 입력해야 한다. 

나는 이 'dualstack' 이라는 첨자를 무시 했다가 또 2시간을 디버깅에 허비했다. 

Fig 15 레코드 편집 화면

 

 

 

- 끝 -

 

참조: 

아래 링크는 실제 서버 작업을 하면서 참고 했던 사이트 들입니다. 

1. https://docs.aws.amazon.com/ko_kr/elasticloadbalancing/latest/application/introduction.html

2. chatgpt(https://openai.com/blog/chatgpt/)

3. https://inpa.tistory.com/entry/AWS-%F0%9F%93%9A-ELB-Elastic-Load-Balancer-%EA%B0%9C%EB%85%90-%EC%9B%90%EB%A6%AC-%EA%B5%AC%EC%B6%95-%EC%84%B8%ED%8C%85-CLB-ALB-NLB-GLB

 

'AWS' 카테고리의 다른 글

[aws]ec2 인스턴스 도메인 연결  (0) 2023.01.26
[aws] ec2와 rds 연동  (0) 2023.01.22
[aws] ec2 상태검사 1/2개 통과  (2) 2023.01.21
[aws] 인바운드 규칙 변경  (2) 2023.01.18
[AWS] ec2 인스턴스 볼륨 추가 및 마운트  (0) 2023.01.15

이 포스트는 ec2 인스턴스에 운영 중인 웹사이트에 도메인을 연결하는 방법을 정리한다.

도메인 구매는 hosting.kr 에서 했으며 그 과정은 생략한다.

 

aws에서 ec2 와 도메인을 연결하기 위해선 route53 를 이용 해야한다.

route 53이란 DNS관리, 트래픽 관리, 가용성 모니터링, 도메인 등록 등을 제공하는 aws 서비스이다.

도메인을 ec2 인스턴스로 운영하는 서버에 할당하기 위해서는 크게 다음과 같은 절차를 따르게 된다.

1. 호스팅 영역 생성

2. 레코드 생성 (레코드란 특정 도메인의 트래픽을 어떻게 라우팅 할 것인지에 대한 정보를 담고 있는 객체이다)

3. 네임서버 주소 변경

 

이제 각 단계에 대해 자세히 정리 해보자.

 

호스팅 영역 생성

호스팅 영역이란 레코드의 컨테이너이고 레코드란 특정 도메인과 그 하위 도메인의 트래픽을 어떻게 라우팅 해야 하는지에 대한 정보를 담고 있다.

호스팅 영역을 생성 할때 설정해야 하는 값은 1. 도메인 이름, 2. 유형, 3. 태그 이다.

  • 도메인 이름은 내 서버에 할당한 url 값이다.
  • 유형은 퍼블릭과 프라이빗 두 가지가 있는데 아무나 접속할 수 있게 하기 위해선 퍼블릭을 선택한다.
  • 태그는 aws 리소스에 할당하는 레이블로 각 리소스를 관리하기 편하게 할당하는 이름 이라고 보면된다.

Fig 1. 호스팅 영역 생성 페이지

 

레코드 생성

호스팅 영역을 생성하고 나면 다음과 같은 레코드 정보를 볼 수 있다.

Fig 2. 레코드 정보

여기서 레코드 이름은 등록한 도메인에 해당한다. 이 도메인으로 오는 트래픽을 처리하는 규칙을 정의한 것이다.

유형은 보면 NS와 SOA 두 가지가 있다. 이는 호스팅 영역 생성시 자동으로 생성되는 레코드이다.

NS는  네임서버로 "호스팅 영역에 대한 신뢰할 수 있는 이름 서버 네 개를 나열한다."

네임서버의 역한은 도메인 이름과 IP의 상호변환을 가능하게 해주는 서버이다.

"SOA 레코드는 도메인에 대한 기본 DNS 정보를 식별한다" 라고 하는데 이건 이해가 잘 안간다. 더 이해가 되면 다시 정리 해야겠다.

 

ec2 인스턴스에 도메인을 연결하는게 목적이니 도메인 이름에 해당 하는 ip가 뭔지를 알려주기 위해 레코드를 생성해야 한다.

레코드 생성을 누르고 아래와 같은 화면이 나타나면 "값"을 입력하는 란에 이 도메인을 연결한 ec2 인스턴스의 ip를 입력하면 된다.

Fig 3. 레코드 생성 페이지

DNS 서버 설정

 레코드 생성 까지 했으면 이제 도메인을 구입했던 업체의 홈페이지로 접속해 네임서버를 변경해야 한다. 도메인을 구입하면 각 업체에서 해당 도메인으로 트래픽을 어떻게 처리 할지 쿼리할 네임버서를 자동으로 몇가지 설정하게 된다.

 나는 이렇게 자동으로 등록된 네임 서버가 아니라 aws route53의 DNS를 사용 할 것이므로

"pmanage.info(내 도메인)으로의 트래픽은 aws DNS 로 문의해 어떻게 routing할지 결정하세요"라고 지정하기 위해 이 과정이 필요하다.

 도메인 구입 업체의 웹페이지에 접속해 네임버서 관리 페이지에 접속한다.

나의 경우 hosting.kr 에 접속해 로그인을 하고 "도메인 관리->나의 도메인 -> 네임서버/DNS" 에서 바꿀 수 있다.

바로 위 "레코드 생성" 섹션의 Fig 2에서 NS 유형의 값에 있는 서버 주소를 아래와 같이 입력 한 후 저장하면 된다.

 

Fig 4. DNS 서버 변경 페이지

이렇게 등록 하고 나면 끝이다.

 

다만 바로 해당 도메인으로 접속하면 바로 접속은 안되는데 도메인 구입 후 2~3일이 지나야 한다고 한다.

나는 어제 구입했으니 2틀 뒤 다시 해당 도메인으로 접속해 보고 안되면 디버깅을 해야겠다.

- 끝 -

 

django app 공개 운영을 위해 [Django] 장고 앱 공개 운영 포스트 Fig 1의 nginx, mysql, django app을 하나의 ec2 인스턴스에 각각 도커 컨테이너로 실행 하려고 계획을 하고 서버를 실행했지만 이 방식에 큰 단점이 있어 아키텍쳐를 변경하기로 했다. 

 

이 포스팅은 aws RDS 인스턴스를 생성해 ec2 인스턴스와 연동하는 방법에 대해 정리한다.

 

목표

Fig 1. 아키텍쳐 변경 개요

Fig 1. (a)는 처음 계획한 운영 아키텍쳐로 ec2 instance 하나에 nginx, django app, mysql 3개를 각각 도커 컨테이너로 실행하는 방식이었고 Fig 1.(b)는 변경하고자 하는 아키텍쳐로 ec2 instance에는 nginx, django app만 운영하고 mysql은 aws RDS 인스턴스로 분리 운영 하는 방식이다. 

 

기존 아키텍쳐의 문제

Fig 1.(a) 처럼 아키텍쳐를 설계하는 것에는 다음과 같은 문제 점이 있었다. 

 

1. cpu 성능: 현재 테스트 운영에 사용하고자 하는 aws 프리티어 계정으로 만들수 있는 ec2 인스턴스는 vcpu 1개 , ram 1GB 가 한계 스펙이다. 이 성능으로 (a)와 같이 아키텍쳐를 구성한 결과 심심치 않게 cpu 사용률이 70% 이상으로 치솟는 경우가 발생했다. 

 

2. database backup: 나는 database 전문가가 아니라 EBS를 비휘발성으로 설정해 database backup 설정을 하고 실패 없이 관리한 자신이 없었다. 

 

위와 같은 문제를 해결하기 위해 mysql을 ec2에 설치해 운영 하지 않고 Fig 1. (b) 처럼 별도 RDS인스턴스로 분리하기로 결정했다.

 

Fig 1. (a) 처럼 운영하는 것도 장점은 있다. RDS는 비용이 생각 보다 비싼데 database를 잘알고 백업 보안 schema를 잘 설정 할 수 있다면 ec2 를 이용하는 게 비용적인 측명에서 더 좋다고한다.

 

RDS 인스턴스 생성

RDS 인스턴스 생성을 위해서는 aws console 검색 창에 RDS 를 검색 한후 'rds console -> 데이터베이스 -> 데이터베이스 생성' 을 클릭하면 된다. 

나의 경우 mysql rds 인스턴스를 생성했다. mysql의 경우  라이선스가 GNU v2.0 으로 별도 라이선스 비용이 들어가지 않는다. 아래 그림 처럼 표준 생성에서 '엔진 옵션->Mysql' 을 선택하고 버전을 기존 사용 하던 8.0.31 로 설정했다.

다음으로 아래 그림의 제일 위는 템플릿을 선택하는 과정인데 나는 당연히 월 750시간 사용이 무료인 계정이니 '프리 티어'를 선택했다. '프리 티어' 템플릿을 선택하면 '가용성 및 내구성'은 자동으로 '단일 DB 인스턴스'로 설정된다. 

그 아래에서는 'DB 인스턴스 식별자'를 입력하는데 여기서 입력하는 이름이 'rds console -> 데이터베이스'에 들어가면 나오는 db 인스턴스 식별자이다. 자신의 용도에 맞게 직관적인 이름을 넣으면 된다.

자격증명은 mysql 서버에 접속 할때 사용하는 user id 와 password 이다. 

인스턴스 클래스는 정보는 link에 매우 상세하게 나와있으니 정확한 정보는 링크를 통해 확인하고 여기선 간단히만 정리하자. 

 

  • 스탠다드 클래스 : 컴퓨팅, 메모리 및 네트워크 리소스의 균형을 제공하며 많은 데이터베이스 워크로드에 좋은 선택. 스탠다드 클래스는 대부분의 일반적인 데이터베이스 요구사항을 충족 할수 있는 사양이다.
  • 메모리 최적화 클래스: 메모리에서 대용량 데이터 집합을 처리하는 워크로드의 성능을 가속화합니다. 높은 처리 성능이 요구되는 경우에 적합하다. 메모리를 더 많이 확보하면 더 많은 데이터를 메모리에 저장하고 이는 쿼리 시간 단축으로 이어질 확률이 높으므로..
  • 버스터블 클래스: 기준 수준의 CPU 성능과 함께 기준 수준 이상으로 버스트할 수 있는 기능을 제공합니다. 여기서 버스트란 순간 확장으로 순간적으로 더많은 리소스를 필요로 하는 경우 이를 가능하게 한다는 의미 이다. 

'프리 티어' 계정의 소유자인 나에게 허락된건 버스터블 클래스 이므로 이걸 선택한다. (사실 이거면 나에겐 충분하기도 하다)

스토리지는 범용 ssd로 세팅하고 프리티어에 주어진 20gb 를 할당한다. 스토리지 자동 조정은 할당한 크기 이상의 용량을 어플리케이션이 사용하고자 할때 자동으로 할당량을 조정해 주는 것이다. 즉 비용 증가로 이어질 수 있다.

이제 생성한 rds 인스턴스와 연결할 ec2 리소를 선택한다. ec2 인스턴스 에서 자신이 원하는 어플리케이션이 서버가 동작하는 ec2 인스턴스를 선택하면 된다.  ec2 인스턴스를 선택하면 VPC 는 자동 할당 된다. 

'퍼블릭 엑세스' 에서 '예'

를 선택하면 외부(같은 VPC에 속하지 않은 host)에서 생성할 mysql 서버에 접속할수 있다. "아니오"를 선택하면 이 DB 인스턴스와 같은 VPC 에 속한 ec2 인스턴스에서만 접속 가능하다. 

이 후로도 '데이터베이스 인증' 설정이 있는데 mysql 접속시 사용할 사용자 인증 방식에 대한 설정이다.

RDS와 ec2 인스턴스 연동

RDS 인스턴스 생성시 '퍼블릭 액세스 가능' 을 선택했거나 연동 하고자 하는 ec2 instance와 같은 VPC에 속하도록 세팅 했다면 연동자체는 매우 쉽다. 

 

퍼블릭 액세스 가능 한지 아닌지는 RDS console-> 데이터베이스 -> 인스턴스 상세 정보의 '연결 & 보안' 탭을 보면 알 수 있다. 

아래 그림의 가장 오른 쪽 보안 섹션을 보면 '퍼블릭 액세스 가능' 항목에 '예' 라고 되어 있으면 localhost(본인의 workstation이나 laptop)에서 도 접속이 가능 한 상태 이다. 

 

 

1. 퍼블릭 액세스 가능 선택한 경우

로컬에서 terminal을 열고 접속을 위해 사용했던 ip 대신 위 그림의 '앤드포인트' 밑의 주소를 이용 하면 된다. 

위 그림의 예를 들자면 mysql -h 옵션의 값으로 '앤드포인트' 값을 사용 하고 -P 옵션으로 '포트'를 지정한다. 

-u 옵션로 데이터베이스 생성시 지정한 사용자 id를 입력하면 된다. 

mysql -h product.cie6ndifnblb.ap-northeast-2.rds.amazonaws.com -P 3306 -u admin -p

product.cie6ndifnblb.ap-northeast-2.rds.amazonaws.com

 

2. 퍼블릭 액세스 가능 의 값이 '아니오' 인 경우

퍼블릭 액세스가 불가능한 경우 접속하고자 하는 데이터베이스와 같은  vpc(vitual private cloud)에 속한 ec2 인스턴스에 연결해  

'퍼블릭 액세스 가능' 한경우와 똑같이 '앤드포인트' 정보를 이용해 접속할 수 있다. 

mysql -h product.cie6ndifnblb.ap-northeast-2.rds.amazonaws.com -P 3306 -u admin -p

 

추가 작업

나의 경우 docker-compose 로 서버를 실행 하므로 위의 rds database instance 앤드포인트 정보로 docker-compose.yml 정보를 업데이트 해줘야한다. 환경변수를 선언하는 environment의 DB_HOST_ADDRESS 값에 database 앤드포인트를 할당한다.

(django app 실행 전에 새로 만든 mysql 서버에 django app에서 사용 하는 database를 생성하고 django app에서 database 를 migrate 하는 절차를 반드시 실행해야 한다.)

version: "3.7"
services:
  nginx:
    container_name: web_server
    restart: on-failure
    image: nginx:stable
    volumes:
      - ${PWD}/etc/jnbdrive_nginx:/etc/nginx/sites-enabled/default
      - ${PWD}/etc/nginx.conf:/etc/nginx/nginx.conf:ro
      - ${PWD}/staticfiles:/home/nginx/www/static
    ports:
      - 80:80
    environment:
      DJANGO_HOST: django_app

  django_app:
     container_name: django_app
     build: .
     image: django_app:latest
     ports:
       - 8000:8000
     restart: always
     environment:
       DB_PORT: 3306
       DB_HOST_ADDRESS: product.cie6ndifnblb.ap-northeast-2.rds.amazonaws.com # rds instance endpoint 
     tty: true
     networks:
       - backend
     volumes: 
       - ${PWD}:/home/docker/workspace/django_app
     command: ./start_server.sh

networks:
  backend:
    # Use a custom driver
    driver: bridge

 

- 끝 -

EC2 인스턴스에서 실행 중이던 앱에 접속이 안되어 인스턴스 상태 확인을 해보니 상태검사 1/2개 통과 라는 메시지를 발견해 이를 해결하기 위한 과정을 정리해본다.

-> 시스템 로그의 정확한 분석에 실패해 나의 경우 해결은 아직 못했다.(2023.01.21)

Fig 1.상태 검사 실패 화면

상태 검사

Amazon ec2는 아래 두 가지 상태 확인을 통해 각 ec2 인스턴스 상태를 모니터링한다.

1. 시스템 상태 확인

시스템 상태 확인은 인스턴스가 실행되는 기본 호스트에서의 문제를 탐지합니다. 네트워크, 하드웨어 또는 소프트웨어 문제로 인해 기본 호스트가 응답하지 않거나 이에 연결할 수 없는 경우 이 상태 확인에 실패합니다.

 

2. 인스턴스 상태 확인

인스턴스 상태 확인 실패는 인스턴스의 연결 가능성에 문제가 있음을 나타냅니다. 이 문제는 다음과 같은 운영 체제 수준 오류로 인해 발생합니다.
1. 운영 체제 부팅 실패
2. 올바른 볼륨 탑재 실패
3. CPU 및 메모리 소진
4. 커널 패닉
5. 네트워크가 작동하지 않음

 

위 두 가지중 어떤것이 문제인지 파악하기 위해서는 'ec2 콘솔 -> 인스턴스 -> 상태  검사' 탭을 참조하면 알 수 있다.

아래는 문제가 생긴 내 인스턴스의 상태 검사 탭인데 나의 경우  시스템 상태 검사 : 통과, 인스턴스 상태 검사: 인스턴스 연결성 검사 실패 였다.

Fig 2. 상태 검사 세부정보

 

원인 분석

인스턴스 상태 검사를 통과 하지 못한 경우 원인 분석을 위해 시스템 로그를 확인하고 시스템 로그에 있는 데이터에 따라 그에 맞는 해결 방법을 적용해야 한다.

 

1. 인스턴스 리부트: ec2 console -> 인스턴스 ->인스턴스 상태 -> 인스턴스 재시작

2. 시스템 로그 확인: 재시작 후 인스턴스 상태가 '실행중' 이면 -> 작업 -> 모니터링 및 문제해결 -> 시스템 로그 가져오기

 

Fig 3. 시스템 로그 가져오기 화면

누르면 다음과 같이 로그를 볼 수 있고 다운로드 할 수 도 있다.

Fig 4. system log

 

분석 결과

aws 에서는 친절하게도 위 로그에서 발견 할수 있는 대표적인 error 들을 정리해  분석시 참조 할 수 있게 제공한다.

link: Troubleshoot system log errors for Linux-based instances 

 

하지만 아쉽게도 내 시스템 로그에는 위에 해당 하는 에러는 없었다. 의심 가는 로그는

'GRUB failed boot detection' 라는 문구 인데 직접적인 관련이 있는지는 아직 모르겠다.

더 분석해 봐야겠다.

 

 

참고 자료: https://aws.amazon.com/ko/premiumsupport/knowledge-center/ec2-linux-status-check-failure/

 

연결할 수 없는 EC2 Linux 인스턴스의 상태 확인 실패 문제 해결

닫기 Gurkamal 씨의 동영상을 보고 자세히 알아보기(9:28)

aws.amazon.com

 

이 포스트는 aws ec2 인바운드 규칙 변경 방법을 정리한다. 

 

상황:

ec2 인스턴스에 nginx 서버를 띄우고 'wget my.ip.address' 로 통신 확인을 하니 응답이 오지 않고 timeout 이 발생해서 해결방법을 알아 보다 aws ec2 보안 그룹이 80번 포트를 오픈 하지 않아서 라는 이유를 발견하고 이에 대한 해결책으로 본 포스팅을 작성한다.

 

인바운드 규칙 변경:

aws ec2 는 보안그룹 설정이 있다. 'ec2 -> 인스턴스->보안 텝'에 가면 아래와 같은 정보를 볼수 있다. 이때 인바운드 규칙을 보면 22, 443 번 포트만 open되어 있는 것을 확인 할 수 있다.

Fig 1. ec2 인스턴스 보안 그룹 정보

아래 처럼 입력 하면 기본 http 서버 즉 80 번 포트로 접속을 시도 하기 때문에 허용되지 않은 포트라 페이지를 가져 오지 못한것이다. (내가 참고한 블로그에서는 aws 가 기본적으로 80번 포트를 오픈 해놨다고 했는데 잘못된 정보 였나 보다. )

wget 192.168.0.5

테스트를 위해 보안 그룹 인바운드 규칙에 80번 포트 허용을 추가 하자.

인바운드 규칙 추가를 위해 Fig 1. 에서 '보안 그룹' 밑에 있는 파란 글자 'sg-01c149~~~~'를 클릭하면 아래와 같은 화면이 나온다. 이 화면에서 우측하단에 보면 '인바운드 규칙 편집' 이라는 버튼이 있다.

클릭 하자.

Fig 2. 보안 그룹 정보

그럼 아래와 같은 화면이 나온다.

Fig 3. 인바운드 규칙 편집 창

좌측 하단에 규칙 추가를 클릭해서 '유형' Http를 검색해 추가 한 후 '소스' 에 0.0.0.0/0 을 추가 하면 아래와 같이 된다.

규칙 저장을 클릭 하면 변경 사항이 적용 된다.

Fig 4. 인바운드 규칙에 http 를 추가한 화면

저장 하고 보안 그룹의 인바운드 규칙을 보면 아래 그림과 같이 80번 포트를 허용이 추가된 것을 볼 수 있다.

Fig 5. 80 번 포트가 추가된 인바운드 규칙

 

wget 을 이용해 다시 테스트 해보니 이번엔 아래와 같이 응답을 받았다. 다만 gateway 에러가 났다.

일단 timeout이 아니라 응답을 받긴 했으니 이제 nginx 설정을 디버깅 해야겠다.

 - 끝 -

 

문제

django app 운영을 위해 aws ec2 인스턴스를 생성시 2개의 볼륨을 생성 후 인스턴스에 접속해 df -h 를 입력해 보니 아래와 같이 생성한 EBS 볼륨이 마운트 되지 않는 것을 발견했다.

Fig 1.

해결

ec2-> 볼륨 정보에 들어가서 생성한 볼륨 정보를 보니 아래와 같이 '/dev/sdb' 라는 볼륨이 있는 것을 확인 할수 있다.

Fig 2.

ec2 인스턴스에서 'ls /dev/sd?' 라고 검색해도 아무 것도 안나오는데

위의 볼륨 /dev/sdb 는 ec2 인스턴스내에서 /dev/xvdb 라는 dev 이름을 가지고 있기 때문이다.

aws 를 처음 접하는 나로서는 볼륨 정보 탭에 나온 정보와 인스턴스 내부의 이름이 달라 당황스럽지만 어쨋든 찾았다.

/dev/xvdb 에 대한 정보를 위해 fdisk 를 이용해 아래와 같이 8GB 가 할당된 볼륨임을 확인했다.

Fig 3.

lsblk 라는 명령으로도 볼륨 정보를 확인 할수 있다.  결과는 아래 처럼 나온다. (아래 결과는 내가 /xvda, /xvdb 봄륨의 용량을 각각 15GB, 10GB 로 수정 한 후의 결과이다.)

Fig 4.

파일 시스템 생성 및 마운트

위 정보를 보면 /xvdb 볼륨은 아직 파일시스템도 없고 접근가능한 마운트 위치도 없기 떄문에 사용이 불가능 하다.  이제 파일시스템을 생성하고 마운트 시켜 보자.

 

1. 파일 시스템 생성

나는 ext4 파일시스템을 생성 하기 위해 아래와 같은 명령을 사용했다. '/dev/xvdb'는 파일시스템을 생성하기 위한 타겟 볼륨명이다.

lsblk 나 fdisk 로 확인 가능 하다.

sudo mkfs -t ext4 /dev/xvdb

2. 마운트 위치 생성.

데이터 백업용으로 위 볼륨을 사용할 것이기 때문에 /mnt 아래 backup_storage 라는 폴더를 만들었다.

sudo mkdir /mnt/backup_storage

3. 마운트

sudo mount /dev/xvdb /mnt/backup_storage/

파일시스템과 마운트 위치가 위 설정 대로 되었는지 확인 하기 위해 아래 명령을 입력 한다. 

옵션  -T 는 파일시스템을 확인 하기 위해, H 는 사람이 읽기 편한 볼륨 크기를 표시하기 위해 사용했다.

df -TH

Fig 5.

위 결과를 보면 Fig 1 과 다르게 /dev/xvdb 가 ext4 라는 파일시스템을 가지고 있고 /mnt/backup_storage 에 마운트 된것을 확인 할 수 있다.

 

- 끝 -

+ Recent posts