Notice
Recent Posts
Recent Comments
Link
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Archives
04-25 14:27
관리 메뉴

ulismoon

IaC - MSA 와 AWS CDK: 코딩을 통한 직관적인 IaC 본문

Development

IaC - MSA 와 AWS CDK: 코딩을 통한 직관적인 IaC

ulismoon 2022. 4. 15. 02:37

태초에 Monolith 가 있었다

 어떤 서비스건 처음 만들 때는 한 곳에서 모든 걸 처리할 수 있도록 만드는 것이 편하다. 네트워크 구성을 하기도 편하고, 서비스 아키텍처도 단순하고, 개발도 한곳에서 모든걸 보면서 할 수 있다. 그렇기 때문에 관리 포인트도 적고 뭐가 어디 있는지, 이게 어디서 와서 어디에 영향을 주는지도 확인하기가 편하다. 지금도 많은 서비스가 이렇게 만들어져 운영되고 있고, 또 새로이 만들어지고 있을 것이다. 보통 이런 식으로 한곳에서 모든 기능을 다 담당하는 구조를 모노리식(Monolithic) 구조라고 한다. 예를 들어 PoC 를 하기 위해 간단히 만들어볼 서비스라면 굳이 리소스를 분리하지 않고 작은 서버 하나에 DB, 서버 로직, web proxy, cache 까지 모든 것을 다 집어넣어 만드는 쪽이 목표 달성에 유리하다. 빠르게 작동 여부와 사용자의 반응을 보는 것이 목표이기 때문에 고도화된 서비스 아키텍처를 구성하는 것은 비용적으로도 시간적으로도 별로 좋지 못하다. 실제로 나도 개인 프로젝트나 개발서버는 이런식으로 가능한 간단하게 구성해 싸고 편하게 서비스를 돌린다.

 

모노리스 덕에 인류는 발전했다(?) 2001 스페이스 오디세이에 나오는 monolith.

 하지만 서비스가 실제로 작동하기 시작하고 트래픽이 늘며 다른 서비스와의 접점이 늘고 심지어 서비스 자체가 확장되기 시작하면 이 구조는 큰 문제를 드러낸다. 바로 이 거대한 서비스 모든 곳이 서비스 전체의 SPOF(Single Point of Failure) 로 작동하기 때문이다. 예를 들어 광고 서비스와 웹서버와 디비를 한 서버에 올리고, 모든 로직을 하나의 코드베이스로 개발하는 상황을 가정하자. 이때는 광고 노출이 많아지면 덩달아 웹서비스가 느려지고, 웹에 요청이 많으면 디비가 부하를 받아 서버 전체 메모리가 부족해지는 상황을 만나기 쉽다. 누군가 광고 서비스의 로직을 건드리다 잘못해서 서버가 내려가면 같은 코드베이스에서 돌고 있던 웹서버는 한 것도 없는데 같이 누워야 한다. 광고 서비스의 버그를 열심히 고쳐 배포를 하자. 같이 누운 것도 억울한 웹 서비스는 단지 같은 코드베이스에 있다는 이유 하나만으로 같이 배포에 참가해야 한다. 여기에 관리자 기능이랑 CS 를 위한 고객관리 페이지 정도만 추가해본다면? Monolithic 구조에서 서비스가 발전할수록 하나의 작은 실수, 작은 변경이 만들어내는 서비스 전체의 영향은 갈수록 커질 것이다.

 

영 좋지 못한 설계를 가진 서비스는 이렇게 되기 십상이다.

 여기서 하고자 하는 이야기는 monolithic architecture 가 잘못된 구조라거나 SPOF 가 있는 구조가 잘못되었다는 것이 아니다. 일단 기본적으로 난 SPOF 가 아예 존재하지 않는 서비스를 만드는 것은 불가능하다고 생각한다. DB 를 생각해보라. Amazon Aurora 같은 서비스가 있기는 하지만 DB 는 대표적으로 떠올릴 수 있는 SPOF이다. 그것보다는 SPOF 의 개수를 어떻게 줄일 수 있는지, 그리고 어떤 사정으로 인해 하나의 서비스가 사용 불가한 상태가 되었을 때 다른 서비스에 주는 영향을 최소화하기 위해서는 어떻게 해야 하는지를 고민해보도록 하자.

자 드가자 MSA 하러

 MSA는 Microservice Architecture 의 준말로, 말 그대로 서비스를 micro 하게 나누어 개발, 관리하는 구조를 말한다. 간단히 게시판을 예로 들면 회원, 게시판 보기, 글쓰기, 댓글, 관리자 기능을 다 잘게 나누어 개별 서비스로 만들고, 서비스 간의 통신을 통해 데이터를 주고받는 구조를 구축하면 MSA 게시판 서비스가 된다. 이런 구조에서는 댓글 기능에 문제가 생겨 댓글을 쓸 수 없게 되어도 다른 기능은 다른 곳에 분리되어 있기 때문에 사용자는 여전히 가입을 하고 글을 읽고 쓸 수 있다. Monolithic 구조에서는 회원, 게시판, 글쓰기, 댓글이 각각 서로의 SPOF 였다면, 지금은 일부 기능이 죽어도 다른 부분은 정상적으로 작동하면서 서비스 전체가 다운되는 상황을 최대한 방지할 수 있다.

 물론 다른 모든 것이 그렇듯 MSA 도 silver bullet은 아니다. 위의 구조를 따라 네트워크, 하드웨어 구성을 하려면 아마 개발하는 시간보다 인프라를 까는 데 더 많은 시간과 노력이 들 것이고 그게 다 어디에서 어떻게 돌아가고 있는지, 서로 어떤 관계를 가지고 있고 어떤 영향을 주는지도 관리해야 한다. 관리 포인트가 1개에서 2개가 되는 수준과는 차원이 다른 이야기가 MSA 를 도입하는 순간 펼쳐진다.

Amazon 과 Netflix 의 MSA 구조도. 어떻게 머리나 칠판에 그림 그려서 해볼만한 수준을 아득히 뛰어넘고 있다.

 게시판 만드는 데 서버가 5~6개 필요해진다는 시점에서 이미 MSA 를 포기하고 싶을 수도 있겠지만, 단 몇 초의 시간이 회사의 매출, 신뢰도와 직결되는 비즈니스 필드에서는 가능한 서버의 다운타임을 줄이고 SPOF 를 컨트롤하며 동시에 확장성도 가지는 구조를 만드는 것이 선택이 아닌 필수이기 때문에 결국 MSA 를 도입하는 것은 필연적인 수순이 될 것이다. 그려면 이 MSA 구조를 어떻게 하면 좀 더 잘 굴릴 수 있을까?

IaC: 코드가 인프라가 되는 세상이 있다?!

 개발자라면 뭘 보든 뭘 하든 이런 생각을 한번씩 하게 마련이다. "아 이거 스크립트 만들어서 돌리면 금방인데", "아 이거 코딩 간단하게 하면 두고두고 써먹을 수 있는데", "아 이거 저번에 만든거 재활용할 수 있는데". 서비스 구조와 인프라에 대해서도 같은 생각을 해볼 수 있을 것 같다. "아 이거 스크립트 만들어서 자동으로 인프라 깔리면 좋겠는데", "아 이거 인프라 코딩 간단하게 해서 두고두고 써먹으면 좋겠는데", "아 이거 저번에 만든 구조 재활용할 수 있으면 좋겠는데". 점점 커지는 서비스와 복잡해지는 인프라는 이러한 니즈를 점점 더 강화시켰고, 그 결과 서비스 인프라도 코드로 만들어 관리하는 지점에 도달했다. 이 결과물로 나온 것이 IaC, Infrastructure as Code 이다. 말 그대로 서비스 인프라를 코딩을 통해 구조화/문서화 하고 이를 자동으로 서비스에 반영시키며 고도의 재사용성도 갖출 수 있도록 하는 인프라 개발/관리 방법이다.

 나는 AWS 를 메인으로 사용하고 있으니 AWS 를 기준으로 살펴보자. AWS 에는 CloudFormation (이하 CFN)이라 불리는 서비스가 있다. CFN이 하는 일은 AWS 에 있는 모든 리소스를 일정한 포맷을 따르는 문서로 작성할 수 있도록 하는 규칙을 제공하고, 문서를 작성해 업로드하면 이를 해석해 실제 AWS 서비스에 반영시켜주는 것이다. 예를 들어 내가 t4g.small EC2 를 하나 만들어서 VPC 에 올리고 80 포트를 열고 싶다면 이것을 문서로 작성해 CFN 에 업로드만 하면 실제로 AWS 에서 EC2를 만들어 VPC 에 놓고 80 포트를 열어준다. 문서로 작성한 스펙에 따라 서비스를 그대로 구성할 수 있게 된 것이다. 하지만 이 CFN 에는 큰 단점이 있다. AWS 의 서비스가 많은 만큼 매우 많은 내용을 작성해야 하고 각각의 서비스가 가지는 수많은 속성과 가질 수 있는 값을 확인해야 하며, 심지어 요소 간에 의존성이 있는 경우 이 관계를 사람이 파악해서 작성해야 한다는 것이다. 우리가 할 것은 이런 게 아니니 예시만 슥 보고 진저리나 한번 치고 넘어가자.

Resources:
  SimpleVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.21.0.0/16

  SimpleVPCIpv6:
    Type: AWS::EC2::VPCCidrBlock
    Properties:
      VpcId: !Ref SimpleVPC
      AmazonProvidedIpv6CidrBlock: true

  SimpleIGW:
    Type: AWS::EC2::InternetGateway

  SimpleVPCIGWAssoc:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref SimpleVPC
      InternetGatewayId: !Ref SimpleIGW

 VPC 를 하나 만들고 Internet Gateway 를 하나 만들어 VPC 에 붙이는 설정이다. json 이 아닌 yaml 인 것은 그나마 다행인 것 같지만 (불행하게도 json 으로도 작성할 수 있다) 모든 리소스 하나하나를 만들 때마다 Resource Type 을 찾아야 하고, 어떤 Property 가 있는지도 찾아야 하고, AWS web console 에서도 본 적 없는 녀석을 알아내 코드로 만들어주어야 한다. 예를 들어 맨 아래에 있는 VPCGatewayAttachment 를 하지 않으면 기껏 만든 Internet Gateway 는 고아가 돼버린다. AWS console 에서는 저거 버튼 두번 클릭하면 붙는 과정이라 저걸 CFN 에 작성해야 한다는 것을 알기가 매우 어렵다. 물론 CFN 은 그 복잡하고 거대한 AWS 서비스를 결정적인 방법으로 만들 수 있도록 매우 잘 설계되어 있다. 공식 문서에 내용이 매우 상세하게 작성되어 있고, 구글링을 하면 예시도 꽤 찾을 수 있지만 지면이 아까우니 링크는 생략하도록 하겠다. 

이런 불편함을 개선해보겠다고 CFN visual editor 같은 것도 있는데, 더 어렵다. 그만 알아보자

 그럼 IaC 는 이쯤에서 절망해야 하는가? 댓츠노노. HashiCorp 라는 곳에서 만들어 IaC 계의 사실상 표준으로 여겨지는 Terraform 이라는 녀석이 있다. 이걸 이용하면 상대적으로 훨씬 간단하게, 그리고 조금 더 직관적으로 IaC 를 적용할 수 있다.

resource "aws_vpc" "SimpleVPC" {
  cidr_block       = "10.21.0.0/16"
  assign_generated_ipv6_cidr_block = true
}

resource "aws_internet_gateway" "SimpleIGW" {
  vpc_id = "${aws_vpc.SimpleVPC.id}"
}

 위의 CFN 코드와 같은 작업을 하는 terraform 코드이다. 훨씬 더 직관적이고 짧은 코드로 같은 목표를 달성할 수 있다는 장점과 함께 하나의 terraform 파일로 여러 개의 cloud provider(AWS, Azure, GCP) 에 인프라를 구성할 수 있는 장점, 그리고 기존에 cloud 에 직접 만들어 사용하고 있던 리소스도 편리하게 가져와 사용할 수 있다는 강점이 있다. Terraform 을 이용하면 CFN 을 쓸 때에 비하면 매우 높은 생산성으로 인프라를 구축할 수 있다. 하지만 Terraform 도 만능은 아닌데, 사실 좀만 뜯어보면 이것도 결국 CFN 의 축약형에 불과하고, 유동적으로 리소스 일부만을 변경해 원하는 구조를 만드는 것이 매우 어렵다. 진정한 의미의 code 를 통한 인프라는 아니라고 볼 수 있는 것이다.

두둥등장, AWS CDK

 AWS CDK, 보통은 CDK 라고 부르는 이놈의 정식 명칭은 무려 Cloud Deveplopment Kit 이다. 클라우드를 개발 할 수 있도록 해주는 키트라는 말이다. AWS 에서 만들어 제공하고 있는, 원하는 프로그래밍 언어로 인프라를 코딩하면 이것을 AWS 에 그대로 구현해주는 개발도구이다. 현재 TypeScript, JavaScript, Python, C#, Go, Java 를 공식적으로 지원한다. 일단 예시 보고 가자. 동일하게 VPC 를 하나 만들어 Internet Gateway 를 만들어 달아주는 구성이다.

from aws_cdk import aws_ec2

vpc = aws_ec2.Vpc(
            self, "SimpleVPC", is_default=False,
            cidr="10.21.0.0/16",
        )

 끝이다. VPC 가 인터넷과 통신하기 위해서 Internet Gateway 는 필수이기 때문에 굳이 코딩하지 않아도 알아서 만들어 달아준다. 위의 두 개와 CDK 가 다른 것은 아예 모든 리소스가 class 화 되어 있다는 것이다. 사용하고자 하는 리소스 이름을 적고 괄호를 열면 이 서비스를 구성할 때 설정해야 하는, 설정할 수 있는 모든 선택지를 확인하고 골라서 사용할 수 있으며, IDE에서 내가 익숙한 언어로 type hinting 과 자동완성의 도움을 받아가며 인프라를 뚝딱뚝딱 만들어갈 수 있다. 그리고 cdk depoly 를 하면 알아서 CFN 파일을 빌드해 AWS 에 업로드하고 인프라를 구성해준다. 명령어 한 줄이면 되기 때문에 그냥 CI/CD 에 달아서 자동화도 할 수 있다. 여기까지 보면 Terraform 보다 좀 더 짧은 AWS 전용 무언가라고 생각할 수도 있겠지만, CDK가 다른 IaC 도구와 어떻게 다른지 몇 가지 예시를 통해 살펴보자.

인프라가 복사가 된다고?

 서비스를 개발하면 아마 거의 모든 경우 최소한 2개 이상의 환경을 구축하고 있을 것이다. 개발 환경과 프로덕션 환경. 개발 환경에서는 개발한 내용을 확인하고 테스트를 하며 잘 테스트된 결과는 프로덕션 환경에 배포되어 사용자들이 사용할 수 있게 된다. 그런데 MSA 를 잘 구성하면 할수록 이렇게 환경을 여러개 만드는 것이 불편하고 귀찮은 작업이 된다. 기본적으로 개발 환경은 프로덕션 환경과 동일하거나 유사하게 구성되어 있어야 인프라 구조의 차이에서 생기는 문제를 방지할 수 있으며, 디버그를 할 때에도 재현성을 높일 수 있다. 그런데 VPC 안에 여러 layer 의 subnet 을 두고 10단위의 트리거와 100단위의 람다가 움직이는 환경을 여러개 만들어 관리한다는 것은 상상만으로도 아찔하다. CFN 이나 Terraform 을 이용할 때에는 환경변수를 넣어서 처리해주거나 환경 별로 여러 벌의 stack 을 만들어야 하는데, 변경이 있을 때 관리를 한다는 것이 여간 불편한 일이 아니다. 이런 경우 CDK 는 매우 편리하게 동일한 구성을 가진 여러 개의 stack 을 생성할 수 있다.

 완전히 동일한 stack 을 두번 만들며 함수 인자로 stage 만 추가해주면 완전히 동일한 설정의 인프라를 간단히게 두 벌 얻을 수 있다. 설정하기에 따라 서로 다른 stage 를 다른 region 에 배포할 수도 있고, stage 별로 배포 시기를 다르게 할 수도 있다. 완전히 동일한 stack 을 기반으로 설정값만 추가해 복제된 stack 을 만들었기 때문에 인프라 구조에 변경이 생겼을 때 한 곳에서만 stack 을 변경하면 한번에 여러곳에 변경을 반영할 수 있다.

인프라를 서부웨이 주문하듯이 내맘대로 적당히 알아서 해주세요 엉엉

 CDK건 Terraform 이건 CFN 이건 결과물은 동일하다. 결정적으로(Deterministic) 구조화되어 AWS 가 해석할 수 있는 CloudFormation Stack 문서가 그것이다. 그런데 CDK 는 이 결정적인 문서를 아주 내 입맛대로 동적으로 생성할 수 있다. 다음 코드를 보자.

 이 코드는 route53에 custom domain 을 만들어 API Gateway 와 연결하고, 이곳을 통해 들어온 요청을 lambda 를 통해 처리하는 간단한 서버리스 웹 서비스를 구성하는 CDK stack 이다. 안을 보면 if 문도 있고, boto3 를 통해 값을 가져오는 것도 있고... 뭔가 결정적인 구조를 만들어내는 코드라고 보기에는 너무도 동적이고 자유롭다. CDK가 범용 프로그래밍 언어를 이용해 인프라를 코딩할 수 있게 해준 덕에 필요한 곳에 원하는만큼 로직을 추가해 stack을 구성할 수 있게 되었다. 앞에서 만든 값을 뒤에서 인자로 넘길 수도 있고, 조건에 따라 다른 값을 사용하도록 할 수도 있다. 인프라가 단순히 복사만 되는 것이 아니라 그 안에서 원하는 만큼의 변주도 줄 수 있다는 것은 상황에 따라 유사하거나 다른 환경을 한 곳에서 편리하게 구성하고 관리할 수 있는 CDK 만의 강력한 기능이다.

당연한 말씀이지만, 무적은 아닙니다. 킹치만 이것만한 게 없는걸

 CDK 도 당연히 완벽한 도구는 아니다. CDK 초기화를 위해선 꼭 빈 directory에 있어야 한다거나, cdk terminal 명령어 자체는 JS 로 작동하고 있어 다른 언어를 선택해도 npm을 하나 달고 다녀야 한다거나 하는 작은 블편함어서부터 AWS 에 더욱 강하게 종속되어 나중에 다른 cloud provider로 이동하는 것이 매우 어려워지는 큰 원인이 된다거나, 앞으로 인프라에 어떤 변경을 가하더라도 CDK 를 통하지 않으면 추후 stack 배포 시 에러가 날 수 있다거나, 그리고 최악의 경우 복구를 못하거나 CDK 를 버려야 하는 상황을 만나거나 하는 등의 critical 한 것까지 CDK 를 사용하는 데에도 감수해야 하는 어려움이 존재한다.
 꼭 CDK 가 정답이라고 생각하지는 않는다. 상황에 따라 적절한 도구를 사용하면 된다. 예를 들어 여러 개의 cloud provider 를 사용하는 경우 Terraform 을 사용하는 것이 가장 좋은 선택지가 될 수 있다. 어떤 도구를 사용하건 간에 인프라를 구성하고 다른 사람과 협업해 관리하고 다른 사람에게 관리를 이관해야 하는 업무 전반에 걸쳐 IaC 는 큰 장점으로 작용할 것은 명확하다고 생각한다. 서버 인프라를 구축하고 관리해야 하는 분들이 IaC를 통해 안정성과 가용성 높은 인프라를 조금이라도 편하게 관리할 수 있길 바란다.

Comments