이번 프로젝트에서 인프라를 가장 신경쓰기로 목표했기 때문에 CI/CD부터 이중화, 보안 등 여러 분야를 신경써서 AWS 서비스를 개발해보고자 합니다.
이번 글의 목표는 Private Subnet에 Jenkins를 설치하고, Github Webhook을 통해 main 코드의 변경 발생 시 Lambda로 Request를 받아 Jenkins가 Public Subnet에 SpringBoot Server를 배포하도록 하는 것입니다.
키워드만 보면 무슨 말인지 잘 이해가 안되겠지만, 하나씩 차근차근 진행하도록 하겠습니다.
가장 처음 해야하는 일은 VPC를 생성하는 것입니다. VPC란 Virtual Private Cloud의 약자로, 퍼블릭 클라우드 환경인 AWS 내에서 VPC라는 독립적인 나만의 공간을 만드는 것입니다. 이를 통해 외부 인스턴스에서 내 인프라에 함부로 접속할 수 없도록 제한합니다.
CIDR이란?
네트워크 구분을 클래스(기존의 서브넷 A~E 클래스) 기반으로 작성하던 IP 주소 체계의 한계를 극복하고 주소 공간을 효율적으로 할당하기 위해 도입된 방식입니다.
ex) 192.168.1.0/24의 의미는 192.168.1.0 ~ 192.168.1.255까지를 사용하겠다는 의미입니다.
CIDR은 현대 IP 네트워킹에 많이 사용되는데, 라우팅이 쉽기 때문에 특히 BGP 프로토콜에서 핵심적인 역할을 합니다.
VPC에서 정한 네트워크의 범위 내에서 IP주소를 나누어야 합니다. 즉, 서브네팅을 통해 어떤 IP 주소들이 Private으로 지정될지, 어떤 IP주소들이 Public으로 지정될지 정해주어야 합니다.
왼쪽의 서브넷을 클릭합니다.
서브넷 생성을 클릭합니다.
VPC는 앞서 만들었던 VPC(태그를 지정했다면 태그명으로 확인할 수 있습니다.)를 선택합니다.
=> 이때 다른 VPC가 존재할텐데, 이는 기본적으로 계정에 배정된 VPC로 삭제가 불가능합니다.
서브넷 설정을 해줍니다.
어려울 수 있기 때문에 제가 생성한 서브넷을 표로 만들어보았습니다.
서브넷명 | 가용영역 | CIDR block |
---|---|---|
server-public-subnet-main | ap-northeast-2a | 10.100.0.0/28 |
server-public-subnet-backup | ap-northeast-2b | 10.100.0.16/28 |
server-private-subnet-main | ap-northeast-2a | 10.100.0.128/28 |
server-private-subnet-backup | ap-northeast-2b | 10.100.0.144/28 |
다음으로는 Routing Table을 생성해야합니다. Routing Table은 VPC 내부에서 네트워크 트래픽을 특정 네트워크 인터페이스로 전달하기 위한 규칙 집합을 담고 있습니다. 각 서브넷은 하나의 라우팅 테이블과 연결될 수 있습니다.
왼쪽에서 라우팅 테이블을 선택합니다.
라우팅 테이블 생성 버튼을 클릭합니다.
라우팅 테이블 이름과 VPC를 설정합니다.(이전에 만든 VPC 선택)
서브넷 연결 버튼을 클릭합니다.
2개의 public subnet을 라우팅 테이블에 연결합니다.
마찬가지로 라우팅 테이블을 1개 더 생성하여 private subnet 2개를 새로만든 라우팅 테이블에 연결합니다.
현재 단계까지 진행이 완료되었다면 4개의 서브넷과, 2개의 라우팅 테이블이 만들어졌을 것입니다. 한눈에 확인하려면 VPC 탭에서 생성한 VPC를 선택하고, 리소스맵을 보면 알 수 있습니다.
이름은 지정한대로 다를 수는 있겠지만, 어쨋든 라우팅 테이블에 Hover를 하면 서브넷과 2개씩 연결이 되어있어야 합니다.
VPC는 격리된 공간이기 때문에 외부 인터넷에 접속할수도, 접속을 받을수도 없습니다. Private Subnet에 생성할 EC2에게는 환영할만한 일이지만, Public Subnet도 접속할 수 없다면 무용지물일 것입니다. 따라서 IGW를 생성하여 Public Subnet에 접속할 수 있도록 연결해주겠습니다.
왼쪽에서 인터넷 게이트웨이를 클릭합니다.
이름을 설정하고 생성합니다.
작업 -> VPC에 연결을 클릭합니다.
이전에 생성했던 VPC를 연결합니다.
왼쪽에서 라우팅 테이블을 클릭합니다.
Public Subnet들과 연결된 라우팅 테이블을 클릭합니다.
아래 라우팅 -> 라우팅 편집을 클릭합니다.
라우팅 추가를 클릭하고, 왼쪽 대상엔 0.0.0.0/0
을, 오른쪽 대상엔 인터넷 게이트웨이
를 선택하면 자동으로 나오는 igw를 선택합니다. 이 IGW는 바로 전에 만들었던 인터넷 게이트웨이 이름입니다.
왜 대상과 대상이지?
이 부분은 AWS 한국어 버전을 이용하기 때문에 발생한 혼동입니다. 왼쪽의 대상은 Destination을 의미하는 대상이고, 오른쪽의 대상은 Target을 의미하는 대상입니다.
Destination: 트래픽의 목적지를 의미합니다. 라우팅 테이블과 연결된 서브넷에서 보내는 트래픽의 목적지입니다. 이는 좁은 범위부터 선택이 되므로, 0.0.0.0/0을 지정하더라도 10.100.0.0/24 -> local로 되어있는 Dest부터 선택됩니다.
Target: 해당 목적지를 가진 트래픽을 어디로 라우팅할지입니다. 0.0.0.0/0 -> igw로 함으로써 VPC 내부 트래픽을 제외하고는 모두 IGW를 통해 외부로 보내고, 외부에서 IGW를 통해 public subnet 내의 인스턴스에 접근을 가능하게 합니다.
변경사항을 저장합니다.
Private Subnet이 인터넷과 연결되어 있지 않다면 외부 라이브러리를 다운받기 매우 어려울 것입니다. 하지만 외부에서 인터넷 접속을 막으려고 분리했는데, 인터넷을 통해 올 수 있다면 여태 한 내용들이 무용지물입니다.
이를 해결하기 위해 NAT Gateway나 NAT Instance를 사용할 수 있습니다. 여기서는 NAT Gateway를 사용해보겠습니다.
왼쪽에서 NAT 게이트웨이 선택
NAT 게이트웨이 생성 버튼 클릭
이름과 서브넷, 탄력적 IP를 할당합니다.
왼쪽의 라우팅 테이블로 이동합니다.
private subnet에 연결된 라우팅 테이블을 선택합니다.
라우팅 편집을 클릭합니다.
대상 0.0.0.0/0 -> NAT 게이트웨이를 선택 시 자동으로 나오는 nat gateway를 선택합니다.
NAT 게이트웨이는 시간당 요금이 부과되는 나름 비싼 서비스이기 때문에 이후 과정에서 Jenkins 등을 설치할 때만 생성하고, 이후에는 삭제하는 것을 권장드립니다.