Corca Medium 아카이브

클라우드 자원을 Pulumi로 편하게 배포해보세요!. 코드로 관리하는 클라우드 자원

2023-04-05오경택 (Back-end Engineer)

코르카에서는 IaC(Infrastructure as Code) 플랫폼으로 Pulumi를 사용하고 있습니다. IaC 개념이 몇몇 분들 란 인프라 구조를 등이 아니라 로 관리 에게는 생소할 수 있는데, IaC Console, CLI, SDK code 하는 것을 말하 주로 등의 클라우드 자원을 관리 며, AWS, Azure 할 수 있습니다.

그렇다면 과연 인프라를 코드로 관리하는 이유는 무엇일까요?!

일반적으로 생각하면 코드로 작성하는 게 귀찮기도 하고 새로 배워야 할 것도 많을 것 같은데 말이죠!

제가 생각하는 IaC 플랫폼으로 Pulumi를 활용하는 것의 장점은 3가지 정도 있는데요, 다음과 같습니다.

우선 플랫폼은 말 그대로 자원을 코드로 관리하기 위한 플랫폼입니다

클라우드 자원을 Pulumi로 편하게 배포해보세요!. 코드로 관리하는 클라우드 자원 본문 이미지

해당 플랫폼에서 제공하는 기능들은 정말 강력해요. AWS Console에서는 하나의 어플리케이션에 존재하는 자원들을 보기 위해서 ec2, s3, rds 등등 별도의 페이지에서 봐야 해서 너무나도 불편한 반면, IaC 플랫폼은 자 원을 한 눈에 볼 수 있도록 묶어줍니다!

그리고 배포를 한 번에 편리하게 해주거나 기존에 인프라를 관리하기 위해 사람이 일일이 하던 일을 컴퓨터 가 대신 해줍니다. 코딩의 본질이기도 하죠!

는 자원을 변수화 시켜서 다른 자원이 이를 참조할 수 있게 해줍니다

예를 들어 AWS의 security group을 변수화해서 ec2 인스턴스에 연결하거나, ecs container의 환경변수로 Database의 주소를 넣어줄 수 있습니다. 오늘은 이걸 코드로 작성해보는 시간을 갖도록 하겠습니다.

마지막으로 는 등의 형태로 지원을 합니다

따라서 경쟁자인 Terraform과 같이 새로운 언어를 배울 필요가 없습니다. 그나마 다행이네요!

2번 장점을 간단한 코드와 함께 살펴보겠습니다.

(이후에 나오는 코드는 Pulumi node SDK로 AWS 자원들을 관리하는 코드입니다.)

// index.js engine: 'postgres', instanceClass: 'db.t3.micro', ...

}); export { db }; @pulumi/pulumi 는 Pulumi의 기본 패키지입니다. 뒤에서 여기 있는 함수 중 하나인 all 함수를 어떻게 사용 하는지 보여드리겠습니다. @pulumi/aws 패키지는 Pulumi에서 제공하는 AWS 자원들을 관리하기 위해서 사 용하는 패키지입니다. AWS 자원들을 생성하는 작업은 전부 다 이 패키지를 사용합니다.

의 aws.rds.Instance 의 첫 번째 input은 Pulumi에서 자원마다 붙이는 urn suffix인데, Pulumi에서 보는 자원 의 이름이라고 생각하시면 됩니다. urn은 urn:pulumi:dev::rmp::aws:rds/instance:Instance::testDB 이런 식 으로 저장됩니다.

두 번째 input은 object 형태로, 자원을 구성하는 데 필요한 모든 설정값을 넣을 수 있습니다. 코드에서 보이 는 것처럼 aws.rds.Instance 의 engine, instanceClass, networkType 같은 것들을 설정할 수 있죠. AWS Console 에서 RDS instance를 만들 때 설정할 수 있는 값들이라고 보시면 됩니다. ( … 부분에 추가로 설정하고 싶은 설

정값을 넣으시면 됩니다!)

설 자 그럼, index.js로 저장하고 pulumi up 을 하게 되면 제일 먼저 Preview 작업을 진행합니다. 물론 Pulumi 치와 설정은 다 돼있어야 하겠죠

AWS credential ! [링크] Preview는 자원들이 어떻게 바뀔지 미리 보여주는 작업입니다. 여기서 yes를 하게 되면 클라우드 자원에 변 경사항을 적용하는 본격적인 작업을 진행합니다. 만약 자원을 만든 적이 없으면 Create를 하고, 자원이 이미 존재한다면 그대로 두고, input 값 중 자원의 설정값이 바뀐 것이 있다면 Update나 Replace를 합니다.

자원이 이미 만들어진 상태에서 해당 코드를 지우거나 첫 번째 input(urn의 suffix)을 바꾸고 pulumi up 하면 원래 있던 자원이 삭제되니까 조심하세요! [링크] 우리는 이 코드를 처음 실행하니까 RDS instance를 새로 만드는 Create를 합니다. 실행이 끝난 후 AWS Console로 들어가시면 RDS instance가 하나 만들어진 걸 확인할 수 있습니다.

안에서의 모든 는 기본적으로 에 저장 참고로 Pulumi metadata app.pulumi.com 되는데, index.js에서 자원 을 export 하면 app.pulumi.com 에서 Pulumi Console로 들어가시면 메인 화면에서 DB의 output을 확인할 수 있습니다! 물론, export 하지 않아도, Resources 탭에 들어가시면 확인할 수 있고, 여기에서는 DB의 모든 설정값들을 확인할 수 있습니다.

이제 DB의 주소를 ECS container의 환경변수로 넣어 볼건데요, 간단한 container를 띄우기 위해 ECS의 taskDefinition을 먼저 생성하고, 그 다음 fargate service를 생성해 보겠습니다!

// index.js engine: 'postgres', instanceClass: 'db.t3.micro', ...
}); return JSON.stringify([ { name: 'app', image: '<container-image-uri>', environment: [ { name: 'DB_ADDRESS', value: dbAdress } ], ...

} ]);

클라우드 자원을 Pulumi로 편하게 배포해보세요!. 코드로 관리하는 클라우드 자원 본문 이미지

}); family: 'test-task-family', containerDefinitions: containerDefinitions, networkMode: 'awsvpc', requiresCompatibilities: ['FARGATE'], cpu: '512', memory: '1024', runtimePlatform: { operatingSystemFamily: 'LINUX', }, ...

}); cluster: '<cluster-name>', launchType: 'FARGATE', desiredCount: 1, platformVersion: 'LATEST', taskDefinition: testTask.arn, ...

}); 😆 갑자기 코드가 너무 길어졌는데, 전체적인 모양만 봐주세요!

우선 첫번째로 aws.ecs.TaskDefinition.containerDefinitions 에 들어갈 containerDefinitions 변수를 정의하 는데요, 모양이 좀 특이하죠? taskDefinition을 만드는 AWS ECS API의 특성상 containerDefinitions 속성은 JSON 문자열 형태로 들어가야 하는데, 문제는 JSON.stringify(db.address) 를 하게 되면 이상한 경고 메시지

를 출력한다는 것입니다.

$ pulumi up ...

Diagnostics:

pulumi:pulumi:Stack (test-stack): To get the value of an Output as a JSON value or JSON string consider either 1: o.apply(v => v.toJSON()) 2: o.apply(v => JSON.stringify(v)) This function may throw in a future version of @pulumi/pulumi."

...

자원들의 db.address 와 같이 Pulumi ouput은 대부분 일반 type이 아니라 pulumi.Output<T> type을 가집니 는 클라우드 자원을 관리하다 보니 코드를 비동기적으로 실행하여 당장 값을 받아올 다. 그 이유는, Pulumi 수가 없어서 과 같은 으로 정의할 수가 없습니다

string type . 따라서 db.address 는 pulumi.Output<string> type을 가집니다. javascript의 비동기 실행에 사용되는 Promise와 비슷한 개념이라고 생각하시면 돼요!

이어서 보시면 독특한 함수명이 있죠? apply 함수는 Promise의 Promise.prototype.then 함수와 비슷한데, db.address 의 값이 정해지면 apply 함수의 input으로 넣어준 함수를 실행합니다.

어느 자원의 output인 pulumi.Output<T> type을 가지는 변수를 다른 자원의 input으로 넣어주게 되면 알아서 Pulumi가 해당 값이 정해질 때까지 기다리고, 그 다음 코드를 실행해 줍니다. apply 함수의 return type 또한 pulumi.Output<T> 인데, 그래서 containerDefinitions 값이 정해지면 testTask 가 만들어지고, testTask.arn

값이 정해지면 testService 를 만들고… 이런 식으로 자원이 생성 됩니다!

을 해서 값이 정해지면 함수의 으로 들어간 정리하자면 다시 pulumi up db.address JSON.stringify input 를 문자열 형식으로 반환해서 변수에 할당 object JSON containerDefinitions 합니다. 이어서 testTasK , testService 자원이 생성되면서 결과적으로 RDS instance 주소를 ECS container 환경변수에 동적으로 할당

할 수가 있습니다!

그런데 만약 여러 개의 자원들이 전부 다 준비된 상태에서 실행하고 싶은 코드가 있는 경우는 어떻게 할까요?

container의 환경변수로 다른 자원들이 동시에 들어가는 경우가 빈번하게 있을 건데, 그럴 때에는 함수는 함수를 확장해서 쓸 수 있게 해주는 함수 pulumi.all 함수를 사용하면 됩니다. all apply 라고 보시면 되는데요, 다음과 같이 사용할 수 있습니다.

// index.js ...
return JSON.stringify([ { name: 'app', image: '<container-image-uri>', environment: [ { name: 'DB_ADDRESS', value: dbAdress }, { name: 'BUCKET_NAME', value: bucketName } ], logConfiguration: { logDriver: 'awslogs', options: {

'awslogs-group': logGroupName, 'awslogs-region': 'ap-northeast-2', 'awslogs-stream-prefix': 'ecs', }, }, ...

} ]); });

...

과 가 모두 준비되면 문자열을 반환해서 에 할당 containerDefinitions 합니다. 정말 편리한 기능이죠?

이렇게 Pulumi를 이용해서 간단한 AWS ECS container를 띄워봤는데요, 사실 Pulumi의 강력한 기능들을 블 로그 글 하나에 전부 담기엔 너무나 부족하다고 생각합니다. 기능이 강력한 만큼 배울 게 많아서 어려운 점도 많았던 것 같아요. 하지만 Dev Lead 충환님과 Tech Lead 태호님이 잘 도와주신 덕분에 Pulumi를 코르카에 안정적으로 도입할 수 있었던 것 같습니다!

다음에 또 기회가 된다면 더욱 더 퀄리티 있는 내용으로 돌아오도록 하겠습니다. 긴 글 읽어주셔서 감사합니 다!

우리가 살아가는 세상을 AI 기술로 변화시키는 팀 Corca는 고도화된 기술력과 기획력을 토대로 새로운 가치 를 창출하고 있습니다.

Corca의 여정에 함께하실 분들은 코르카 채용페이지를 확인해주세요!

기술 발전의 혜택을 모두가 누리게 하여 인류 문명의 발전에 기여하는 코르카