Corca Medium 아카이브
클라우드 자원을 Pulumi로 편하게 배포해보세요!. 코드로 관리하는 클라우드 자원
코르카에서는 IaC(Infrastructure as Code) 플랫폼으로 Pulumi를 사용하고 있습니다. IaC 개념이 몇몇 분들 란 인프라 구조를 등이 아니라 로 관리 에게는 생소할 수 있는데, IaC Console, CLI, SDK code 하는 것을 말하 주로 등의 클라우드 자원을 관리 며, AWS, Azure 할 수 있습니다.
그렇다면 과연 인프라를 코드로 관리하는 이유는 무엇일까요?!
일반적으로 생각하면 코드로 작성하는 게 귀찮기도 하고 새로 배워야 할 것도 많을 것 같은데 말이죠!
제가 생각하는 IaC 플랫폼으로 Pulumi를 활용하는 것의 장점은 3가지 정도 있는데요, 다음과 같습니다.
우선 플랫폼은 말 그대로 자원을 코드로 관리하기 위한 플랫폼입니다
- IaC ‘ ’ .
해당 플랫폼에서 제공하는 기능들은 정말 강력해요. AWS Console에서는 하나의 어플리케이션에 존재하는 자원들을 보기 위해서 ec2, s3, rds 등등 별도의 페이지에서 봐야 해서 너무나도 불편한 반면, IaC 플랫폼은 자 원을 한 눈에 볼 수 있도록 묶어줍니다!
그리고 배포를 한 번에 편리하게 해주거나 기존에 인프라를 관리하기 위해 사람이 일일이 하던 일을 컴퓨터 가 대신 해줍니다. 코딩의 본질이기도 하죠!
는 자원을 변수화 시켜서 다른 자원이 이를 참조할 수 있게 해줍니다
- Pulumi .
예를 들어 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 } ], ...
} ]);
}); 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의 여정에 함께하실 분들은 코르카 채용페이지를 확인해주세요!
기술 발전의 혜택을 모두가 누리게 하여 인류 문명의 발전에 기여하는 코르카