며칠간의 삽질을 하면서 느낀 점이 있다. 꼭 IaC로 모든 설정을 관리해야 할까? 라는 의문이었다. 당연히 IaC는 반복적이고 복잡한 인프라 설정을 코드로 대신할 수 있는 편리한 도구지만, 그 도구에 익숙하지 않아서 시간이 오래 걸린다면 처음에는 IaC로 할 수 있는 일부분만 구현해도 좋겠다는 생각이 들었다.
그래서 어제 언급한 블로그를 찾아서 VPC 선언까지는 IaC로 해 보고, 그 외에 다른 것들은 직접 선언해보기로 했다. 그게 더 빠르게 구현할 수 있는 방법이라고 생각했다.
사실 이렇게 마음먹은 이유가 또 있는데, 바로 ECS를 사용하게 되었을 때의 비용 문제였다. 소마에서 지원해주는 서버 비용을 봤을 때 AWS 인프라에서 돈이 가장 많이 들었던 두 개가 바로 ECS와 RDS였다. RDS의 경우는 구글 드라이브 동기화나, 프리 티어를 사용하는 등의 대체재가 있었다. 그러나 ECS의 경우는 이를 사용할 수 없다면 docker swarm 등의 다른 대체재를 생각해봐야 했다. 무궁무진한 방법들이 있다는 것을 알기에 GPT 질의를 통해 선택지를 좁혀 보기로 했다.
aws에서 제공하는 여러 서비스들 중 ECS를 잘 쓰고 있었어. 그런데 비용 문제로 이제는 ECS 말고 다른 서비스를 찾아봐야 할 것 같아. CI/CD 파이프라인 구축에서 ECS와 같은 역할을 하는 유사한 다른 서비스들을 추천해줘
그러면 [내가 이해한 것]을 바탕으로 '가장 저렴한 방법'과 '초보자가 가장 쉽게 따라할 수 있는 방법'의 순위를 각각 알려줘
[내가 이해한 것]
총 5개의 옵션이 있다.
1. aws fargate + app runner
2. google cloud run + github actions
3. aws lambda + serverless
4. docker swarm
5. kubernetes
GPT는 총 5개의 옵션을 제안해 주었고, 이 중에서 중요한 것이 '빠르게 구현 가능한지'와 '비용이 저렴한지'였다. 의외로 3번 옵션인 AWS lambda와 serverless 아키텍처를 결합한 옵션 모두가 저렴하면서도 초보자도 빠르게 구현할 수 있다고 했다.
저렴한 이유는 트래픽에 비례해서 비용이 증가하는 구조이므로 사용자가 적을 경우 비용이 많이 발생하지 않고, 서버리스이기 때문에 별도의 서버 관리 비용이 없다는 것이었다.
또한 초보자가 빠르게 구현할 수 있는 이유는 함수 단위로 실행되므로 구체적인 인프라 설정이 필요 없다고 했다. yaml 파일만으로도 설정이 가능한 것으로 보였다.
암튼 그렇게 해서 ECS는 AWS lambda로 대체하게 되었다. 아이러니하게도 AWS 생태계를 벗어나지 않았다..! 이러면 이제 aws lambda도 같은 aws provider 안에서 작성 및 apply가 가능하긴 한데... 일단 한 번에 너무 많은 걸 하려고 하지 말고 나에게 생소하고 복잡했던 vpc 설정만 terraform으로 대신해 보자.
💻 aws vpc, subnet, availability zone에 대해 알아보기
어제의 블로그처럼만 따라하면 vpc가 생성된다. 그러면 다 된 거 아닌가?라고 생각할 수 있는데, vpc만 선언하면 되는 게 아니라 그 안에 있는 public/private subnet 등의 추가 설정이 필요하므로 아직 다 된 것이 아니다.
그리고 해당 블로그를 따라하면서 의아했던 부분이 있다. 바로 private subnet이었다. 처음엔 이게 왜 필요한지 의문이었다. 보안 때문인 것이라고만 알고 있는데, 괜히 복잡할 것 같아서 선언하지 않아도 되는 게 아닌가 싶어서 질의해봤다.
aws vpc에서 subnet을 생성할 때 public, private subnet을 생성할 수 있잖아. 이때 private subnet을 설정해야 하는 이유가 있어?
private subnet은 보안 목적으로 생성하는 것이 맞았다. 우선 vpc 안에 subnet 개념이 있었다. 그리고 'vpc 내부 통신'이라는 개념이 있어서 vpc 내부 리소스들은 각자가 따로 통신할 수 있었다. 이 원리도 좀 궁금했는데, 일단은 private subnet의 역할을 먼저 알고 넘어가보자. private subnet 안에 있는 리소스들에 접근하려면, 같은 vpc 안에 있는 리소스들만 이 'vpc 내부 통신'을 통해서 접근할 수 있다. 그러므로 외부에서 vpc 안의 private subnet 안에 있는 리소스에 접근하는 것이 불가능하다. 이 사실 하나만으로도 보안을 증가시킬 수 있다.
그러면 private subnet 안에 있는 리소스들은 아예 외부와 단절된 게 아닌가? 라는 의문이 생길 수 있다. 정확히는 외부에서의 직접적인 호출과는 단절되어 있다. 그러나 결과적으로는 외부에서 private subnet 안에 있는 리소스들을 사용할 수 있고, private subnet 안에 있는 리소스들도 필요하다면 vpc 외부로 요청을 보낼 수 있다. 어떻게 이게 가능할까?
우선 인바운드 트래픽, 즉 private subnet 안의 리소스로 접근하는 경우를 보자. 이 경우는 같은 vpc 안의 다른 public subnet에 존재하는 리소스를 통해 가능하다. vpc 안에는 여러 private subnet들과 public subnet들이 존재할 수 있는데, 이 public subnet 안에 있는 리소스들이 일종의 연결다리 역할을 한다고 이해했다.
예시로는 간단하게 private subnet, public subnet을 사용한 아키텍처에서 유저의 요청이 들어왔을 때를 가정해 보자. 모든 subnet들은 하나의 vpc 안에 있다. vpc 안에는 public subnet이 있고(간단함을 위해서 하나의 리전, AZ만 있다고 가정해 보겠다), 이 안에는 로드밸런서(ALB)가 있다. vpc 안에는 private subnet도 있고, 이 안에는 웹 서버와 DB가 있다. 이 상태에서 유저의 요청이 alb로 들어온다. alb는 public subnet에 있기 때문에 외부의 요청을 받을 수 있다.
그러면 alb는 vpc 내부 통신을 통해서 같은 vpc 안의 다른 private subnet에 있는 웹 서버를 호출한다. 그리고 웹 서버에서도 마찬가지로 vpc 내부 통신을 통해 필요 시 같은(다른 private subnet일 수도 있는데 그건 상관없다) private subnet에 있는 DB를 호출한다. 이런 식으로 통신이 일어난다고 한다.
즉 중요한 자원인 서버와 DB를 public subnet에 두어 외부 접근을 가능하게 하지 않고도 로드밸런서를 두어서 이 리소스들에 대한 보안을 증가시킬 수 있겠다!
그렇다면 반대의 경우인 아웃바운드 트래픽(private subnet 안에 있는 리소스에서 외부로 요청을 보내는 경우)은 어떨까? 이 경우는 특별한 NAT Gateway라는 친구가 사용된다고 한다. NAT는 network address translation, 즉 네트워크 주소 변환을 의미한다.
컴과 수업에서 배운 기억이 희미하게 있는데, 외부와 분리된 private subnet에서 public한 웹 서버 등으로 요청을 보낼 때 거치는 과정이다. 이 과정이 필요한 이유는 private subnet에서 사용하는 주소를 public하게 사용될 수 있는 글로벌 ip주소로 바꿔줘야 하기 때문이다. 나도 여기까지만 생각이 나서 문서를 참고했다.
좀 더 구체적으로는 private subnet의 주소가 글로벌 ip주소로 변환되는 시점이 있다고 이해했다. 그 시점(경계)에 있는 라우터(경계 라우터)에서 이 NAT가 발생한다. private subnet에서 존재하는 요청자의 ip주소 대신, 글로벌 ip주소로 사용될 수 있는 주소를 송신자의 ip주소로 할당하고 패킷을 라우팅한다고 이해했다. 이것도 컴과 과목에서는 아예 하나의 챕터가 따로 있을 정도로 깊은 주제였던 기억이 있어서 일단은 여기까지만 알아보자.
아무튼 private subnet을 설정하고 그 안에 웹 서버와 DB를 두어야 하는 이유는 이것만으로도 설명할 수 있겠다. 그렇다면 또 다른 의문이 생긴다. private, public subnet은 한 쌍의 페어라고 가정한다면, 한 vpc 안에 몇 개의 subnet 페어가 필요할까? 이 역시 모호한 질문이었으므로 질의를 해 보았다.
aws vpc 안에 존재하는 private, public subnet은 한 쌍의 페어라고 가정한다면, 한 vpc 안에 몇 개의 subnet 페어가 필요할까?
GPT답게 하나의 정해진 답을 주지는 않았는데, 이전에 들어본 것처럼 이 페어의 개수는 '가용 영역(AZ)'의 개수에 영향을 받는다고 한다. 여기서 또 vpc와 subnet, 그리고 az(가용 영역)의 관계가 모호하게 느껴져서 추가 질의를 해 보았다.
vpc 안에 subnet이라는 개념이 존재한다고 이해했어. 그럼 available zone(AZ)은 어떤 개념이야? AZ는 vpc, subnet과 어떤 관계가 있는지 알려줘
정의를 살펴보자면 다음과 같다. AZ는 하나의 리전(region) 내에 존재하는 독립적인 물리적 데이터 센터라고 한다. 그리고 vpc는 하나의 리전에 걸쳐 존재한다. 반면 vpc 안의 subnet은 각 az별로 존재한다. 그러니까 하나의 vpc를 선언한 다음, 해당 vpc가 존재하는 리전에 총 몇 개의 az가 있는지에 따라서 private/public subnet 페어의 개수가 달라지겠다. 보통은 az의 개수만큼 페어를 선언하는 것이 일반적이라고 한다. 그 이유는 고가용성과 장애 대응을 위해서라고 한다.
어쨌든 결론은 나왔다. 특수한 상황이 아닌 이상 ALB 등에서도 모든 AZ에 걸쳐 리소스를 배포하도록 설정되어 있다고 한다. 그리고 나는 특수한 상황은 아니니, 일단은 모든 AZ(나의 경우에는 ap-northeast-2 리전의 2a, 2b, 2c, 2d AZ가 되겠다)에 리소스를 배포하도록 설정하자. 그러려면 총 4쌍의 private/public subnet 페어들이 필요할 것이다.
그런데 이렇게 보니 vpc를 만드는 것 외에도 private, public subnet을 만들고, 각 리소스를 subnet에 배치하고, 각 리소스끼리의 연결(가령 ALB가 웹 서버 리소스를 호출하도록 하기 등등)이 필요한 것 같다.... 아무래도 IaC는 다음으로 미루고, VPC를 직접 설정해보는 것부터 해 보면 좋겠다.
💻 aws vpc 설정하기
aws의 여러 서비스들 중 'vpc'를 누르고 'vpc 생성'을 누르면 다음과 같은 화면이 나온다. 여기서 vpc만 설정할지, 아니면 그 외에 관련된 리소스(서브넷과 인터넷 게이트웨이 등)까지 같이 생성할지를 선택할 수 있다. 원래는 관련 리소스도 같이 생성하는 것이 편하겠으나, 여기서는 az를 최대 4개가 아닌 3개까지밖에 기본 옵션으로 제공하지 않아서 직접 생성하기로 했다. 그러므로 'vpc 등'이 아니라 'vpc만'을 선택했다.
cidr도 사실 어떻게 등록해야 할지 감이 잘 오지 않았는데, 이전에 '10.0.0.0/16'으로 등록한 것이 기억나서 이 값을 그대로 따랐다. 이렇게 등록하면 약 60000개가 넘는 ip주소를 vpc에서 사용할 수 있다고 한다.
이렇게 설정을 해 주니 아래와 같이 새 vpc가 등록되었다.
이제는 서브넷을 생성할 차례이다. 방금 생성한 'onestep' 별칭을 가진 vpc를 대상으로 서브넷을 총 8개(public 4개, private 4개) 만들어주자.
우선 vpc 선택에서는 방금 만든 vpc를 선택해주고, 아래와 비슷하게 할당하면 된다.
이런 방식으로 총 가용 영역(az)의 수만큼 만들어주자. 나의 경우 리전이 ap-northeast-2라서 총 가용 영역이 4개인 관계로 4개 만들어줬다.
그리고 현재는 '퍼블릭 액세스 차단' 필드가 비활성 상태이다. 현재는 퍼블릭 서브넷을 만든 거라 이게 맞다. 이걸 활성 상태로 만들어준다면 private subnet의 기능을 할 수 있겠다. 나머지 private subnet들도 모두 만들고, 해당 서브넷들에 대해서는 퍼블릭 액세스를 차단해 줘야겠다. 관련 메뉴가 한 눈에 보이지는 않아서 GPT 질의를 사용해봤다.
aws vpc를 만들고 subnet들을 만들었어. 그런데 이 subnet들을 private subnet으로 만들고 싶어. 어떻게 하면 돼?
방법은 서브넷에 연결된 라우팅 테이블(routing table)에서 인터넷 게이트웨이(IGW)로의 연결을 제거하는 것이었다. 그러려면 우선 vpc 안에 있는 라우팅 테이블이 어떤 서브넷들에 연결되어 있는지를 확인하고, 만약 이 중에 private subnet이 포함된다면 그 연결을 제거해주면 되겠다.
'vpc 대시보드'에서 '라우팅 테이블' 메뉴를 눌러서 들어가봤다. 그런데 방금 만들어 준 8개의 서브넷들이 모두 라우팅 테이블들과 연결되어 있지 않았다. 이럴 경우 퍼블릭 액세스를 차단하고 있진 않지만, IGW와 연결된 라우팅 테이블과 연결되지 않았으므로 모두가 private subnet처럼 동작하고 있었다고 이해했다. 그래서 이들 중 public이 포함된 서브넷들만 해당 라우팅 테이블과 연결해 주었다.
원래는 '명시적 서브넷 연결'에 나온 서브넷이 한 개도 없었는데, 아래처럼 public 서브넷들만 추가해 주었다.
그런데 또 궁금한 게 생겼다. 그러면 private 서브넷들은 기본 라우팅 테이블과만 연결되어 있다고 했다. 그러면 public 서브넷에 있는 리소스에서 private 서브넷에 있는 리소스로 연결이 필요할 때 어떻게 연결할까? 즉 public 서브넷과 private 서브넷은 현재 같은 vpc에 있다는 것 말고는 라우팅 테이블 등과 일말의 연결고리도 없는 상황인데, 이 상황에서 어떻게 가령 public subnet 01이 private subnet 01을 찾을 수 있을까?즉 이 두 서브넷은 vpc와 az가 같지만, 그 외의 접점은 없다고 이해한 상황이다. 바로 질의해봤다.
결과는 vpc 내부 통신 메커니즘(이게 뭔지는 아직 모른다)을 통해 모든 vpc 내부의 리소스들은 서로 통신이 가능했다. 이 원리는 vpc 내 서브넷의 라우팅 테이블에 공통적으로 존재하는 'local'이라는 레코드 때문이란다. 찾아보니 정말 따로 명시해주지 않았음에도 기본적으로 이 하나의 레코드가 들어 있었다.
이쯤 되니 슬슬 복잡해진다. 그림을 한번 그려보자. 기본값으로 IGW를 통해 외부로 연결되지 않은 subnet들은 다음과 같은 모습일 것이다.
여기서 public 서브넷들은 vpc의 라우팅 테이블을 통해서 IGW(인터넷 게이트웨이)와 연결되어야 하겠다. 즉 아래의 그림과 같은 상황을 원한다.
그러려면 위에서 public 서브넷들만 연결한 라우팅 테이블이 IGW와 연결되어 있는지를 확인해봐야 하겠다. 그런데 해당 라우팅 테이블의 '라우팅' 섹션을 확인해보니 local 네트워크밖에 없어서, 어떻게 확인해야 할지 모르겠다.
하나의 vpc에서 사용되는 라우팅 테이블이 있다고 할 때, 이 라우팅 테이블을 인터넷 게이트웨이와 연결하고 싶어. 어떻게 하면 될까?
다음과 같은 단계를 거쳐야 했다.
- 인터넷 게이트웨이를 (없으면) 만든다.
- 1번에서 만든 IGW을 vpc와 연결한다.
- 라우팅 테이블과 IGW을 연결한다.
- 서브넷과 3번의 라우팅 테이블을 연결한다. (나는 이 부분을 위에서 했다.)
- 서브넷 설정에서 'ipv4 주소 자동할당' 옵션을 활성화한다. 왜냐하면 퍼블릭 서브넷 내의 리소스가 글로벌 ip를 가질 수 있어야 외부에서 접근할 수 있기 때문이다.
- 아웃바운드/인바운드 규칙 편집을 통해 퍼블릭 서브넷으로 접근이 가능하도록 수정한다.
하나씩 해 보자. 우선 1번을 확인하기 위해서 'vpc' 탭의 '인터넷 게이트웨이'를 눌러보았다. 그랬더니 이미 만들어진 IGW 리소스가 보였다. 이걸 사용해도 되는 건지, 아니면 내가 새 vpc를 만들었으니 IGW도 새로 만들어줘야 하는건지 싶어서 질의해봤다.
하나의 vpc당 하나의 인터넷 게이트웨이가 필요한 거야? 아니면 여러 vpc를 하나의 인터넷 게이트웨이에 연결할 수도 있는 거야?
GPT 피셜 vpc와 IGW는 1:1 관계라고 한다. 즉 vpc를 새로 만들었으면 igw도 새로 만들어야 하겠다. 만들어주고 vpc에 연결도 해 주었다. 원래 이 과정을 담아보려고 했는데 생각보다 너무 간단해서(30초컷) 캡처는 생략했다...
이제는 vpc 내의 라우팅 테이블과 IGW을 연결할 차례이다. '라우팅 테이블' 탭에 가서 연결할 라우팅 테이블을 선택한 뒤(없으면 만들어주자) '라우팅 편집' 메뉴를 눌러보자.
그러면 아래와 같은 화면(처음에는 local 레코드만 있다)이 나오는데, 여기서 대상을 '0.0.0.0/0' 즉 모든 ip주소로 설정해 주고, 연결 대상을 인터넷 게이트웨이로 설정해준다. 그러면 아까 만든 igw를 선택한 것인지를 옵션으로 확인할 수 있고, 여기서 클릭을 해주면 된다.
변경 사항을 저장하고 확인해보면, 기존엔 local만 있었던 라우팅 테이블 레코드에 인터넷 게이트웨이가 추가되었다.
그 다음엔 라우팅 테이블과 연결된 서브넷이 이 인터넷 게이트웨이를 사용할 수 있도록 연결해줘야 한다. 그런데 이 작업은 위에서 이미 서브넷과 라우팅 테이블을 연결해 주었으므로 건너뛰자.
이제는 퍼블릭 서브넷 설정에서 'ipv4 주소 자동할당' 옵션을 켜자. 그래야 퍼블릭 서브넷 안에 소속된 리소스들(가령 alb)이 ipv4 주소를 할당받을 수 있다. 아래와 같이 서브넷 편집 화면에서 체크박스를 눌러주면 된다.
마지막으로 서브넷에 연결된 보안 관련 리소스의 아웃바운드/인바운드 규칙을 확인해 주자. 신기한 것은 보안 관련 리소스래서 '보안 그룹'만 있는 줄 알았더니 '네트워크 ACL'이라는 친구가 있었다. 처음 보는 녀석이었다.
우선 익숙한 '보안 그룹'부터 설정해보자. 인바운드 규칙의 경우, 해당 개발 서버에서는 HTTP와 HTTPS 연결만 허용하려고 한다. 반면 아웃바운드 규칙의 경우 모든 연결을 허용해보겠다.
이제 '네트워크 ACL'을 설정해 보자. 이 친구와는 초면이었기에 우선 이 녀석이 뭔지부터 알아야 하겠다.
vpc 리소스의 '보안' 탭에 보안 그룹과 네트워크 ACL이라는 메뉴가 두 개 있는 것을 봤어. 보안 그룹과 네트워크 ACL이 각각 무엇이고 어떻게 다른지 설명해줘
보안 그룹과 ACL 모두가상 방화벽이라는 공통점이 있었다. 다만 세 가지의 차이점이 있었다.
- 보안 그룹의 경우는 개별 리소스별로 정의되는 방화벽이라면, ACL은 서브넷 단위로 정의되는 방화벽이었다.
- 보안 그룹은 stateful 하기 때문에 인바운드 규칙이 허용하는 트래픽은 아웃바운드 규칙에서도 허용된다. 반면 ACL은 stateless 하기 때문에 인바운드 규칙이 어떤 트래픽을 허용하더라도 아웃바운드 규칙에서 허용하려면 별도로 설정을 해 주어야 했다.
- 보안 그룹은 특정 트래픽을 '허용'하는 액션만 가능하지만, ACL은 특정 트래픽을 '제한'하는 액션도 가능했다.
왜 이게 필요한가 생각해 봤더니, 서브넷은 아무래도 여러 리소스들이 소속되어 있는 네트워크이다보니 개별적으로 보안그룹을 설정하는것도 물론 가능하겠지만 제어 수준을 전반적으로 관리하기 위해서는 네트워크 ACL이 훨씬 편리하겠다는 생각을 했다.
아무튼 네트워크 ACL은 이런 녀석이었다. 이제 여기서 인터넷의 모든 트래픽을 막고 있는지만 확인해보면 되겠다. '보안' 탭의 '네트워크 ACL'을 눌러 확인해보니 다행히 서브넷 단위에서는 모든 트래픽을 허용하고 있었다.
✅ 궁금한 점
- VPC와 IGW가 1:1 관계여야 하는 이유는 무엇일까?
- IGW의 정확한 정의는 무엇이고, IGW는 왜 필요할까?
- IGW로 연결한다는 게 구체적으로 무슨 의미일까?
- vpc 내부 통신의 원리가 궁금하다.
'개발 일기장 > SWM Onestep' 카테고리의 다른 글
20241219 TIL: zappa로 lambda에서 django 서버 배포하기 [진행중] (4) | 2024.12.19 |
---|---|
20241216 TIL: subnet 안에 lambda 배치하기 [진행중] (1) | 2024.12.16 |
20241214 TIL: terraform으로 AWS 설정 새로 세팅하기 [진행중] (0) | 2024.12.15 |
20241209 TIL: terraform으로 AWS 설정 새로 세팅하기 [진행중] (1) | 2024.12.09 |
20241208 TIL: terraform으로 AWS 설정 새로 세팅하기 [진행중] (0) | 2024.12.08 |