23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
AWS나 Azure 같은 Cloud 에서는 인프라스트럭쳐를 웹 콘솔 내에서 몇 번의 클릭만으로 구성할 수 있습니다.
그렇기에 내가 만들고자 하는 리소스를 자유롭게 구성할 수 있다는 장점이 있지만,
엔터프라이즈 레벨에서는 생성되는 리소스의 환경설정, 버전, 보안 등의 차이로 거버넌스에 어긋남에 따라 이슈가 발생할 수 있습니다.
때문에 IaC(Infrastructure as Code) 를 활용하여 Cloud 상의 인프라스트럭처를 템플릿화 하고, 보다 체계적으로 구성/관리하는 것이 좋습니다.
IaC의 가장 대표적인 툴에는 Terraform이 있는데요.
Terraform은 아래 세 가지 방식으로 모두 실행 시킬 수 있습니다.
CLI
GUI
API
CLI 방식은 흔히 많이들 알고 계시는 terraform init / terraform plan / terraform apply 명령어로 디렉토리 내에 있는 템플릿들을 동작 시키는 방식입니다. 실행 시킬 때 리소스 변수들을 입력해주어야 하기에, '운영자' 레벨의 실행 방식이라고 할 수 있습니다.
GUI 방식은 Terraform Cloud가 제공하는 웹콘솔 환경에서 VCS 저장소와 연동된 템플릿들을 동작 시키는 방식입니다. 이 또한 실행 시 Terraform Cloud 워크스페이스의 리소스 변수를 직접 관리해야 하기에, '운영자' 레벨과 가깝습니다. (User 권한을 분리하여 실행/승인 담당자를 나눌 수 있긴 합니다.)
API 방식은 어플리케이션 레벨에서 Terraform Cloud을 동작 시키는 방식입니다. REST API 형태로 JSON 포맷에 맞게 Terraform Cloud에 변수들을 전달하면 '사용자' 레벨에서 직접 프로비저닝을 요청할 수 있고, '운영자'는 승인 여부만 판단하면 되는 Self Provisioining을 구현할 수 있습니다.
이번 포스팅에서는 Terraform Cloud와 Terraform API를 활용하여, '사용자' 레벨의 Self Provisioning을 구현하는 방법을 공유 드리겠습니다.
좀 더 쉽게 이해를 돕기 위해, Terraform 템플릿으로 구성하는 인프라스트럭처는 간단하게 AWS의 VPC 구성부터 샘플 웹페이지가 띄워지는 EC2 인스턴스로 작성하였습니다.
Terraform이 실행시키고자 하는 표준 템플릿을 작성합니다.
AZ나 Inbound Rule 같은 표준 값들은 상수 값으로 넣어주고, VPC CIDR과 서비스 이름을 변수 값으로 받는 템플릿을 작성하였습니다.
### VPC ###
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr ### VPC CIDR은 변수로 받는다. ###
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "vpc-${var.service}" ### VPC 이름은 Service 명으로 받는다. ###
}
}
### Subnet ###
resource "aws_subnet" "public-subnet-a" {
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 4, 3)
### Subnet CIDR은 16개로 나눠진 VPC CIDR Array의 4번째로 받는다. ###
availability_zone = "ap-northeast-2a"
map_public_ip_on_launch = true
tags = {
Name = "sub-${var.service}-public-a"
}
}
### Internet Gateway ###
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "igw-${var.service}"
}
}
resource "aws_eip" "eip" {
vpc = true
depends_on = [aws_internet_gateway.igw]
}
### Route Table ###
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
tags = {
Name = "rt-${var.service}-public"
}
}
resource "aws_route_table_association" "publicrtasso-a" {
subnet_id = aws_subnet.public-subnet-a.id
route_table_id = aws_route_table.public.id
}
### Default Security Group ###
resource "aws_security_group_rule" "sgrprule-ec2" {
type = "ingress"
from_port = 80
to_port = 80
protocol = "TCP"
description = "sample web page"
cidr_blocks = [ "0.0.0.0/0" ]
security_group_id = aws_security_group.defaultsgrp.id
lifecycle {
create_before_destroy = true
}
}
### EC2 ###
resource "aws_instance" "web" {
ami = "ami-0cc9e73ac3bede711"
instance_type = "t2.micro"
associate_public_ip_address = "true"
vpc_security_group_ids = [
aws_security_group.defaultsgrp.id
]
user_data = << EOF
#!/bin/bash
service httpd start
EOF
subnet_id = aws_subnet.gwlb-subnet-a.id
tags = {
Name = "ec2-${var.service}"
}
}
output "instance_public_ip" {
value = aws_instance.web.public_ip ### Apply가 완료되면 EC2의 Public IP를 반환한다.
}Terraform Cloud란 Terraform의 운영 환경을 웹 콘솔로 제공하고, API 기능을 지원해주는 서비스입니다.
먼저 Organization과 Workspace를 생성해줍니다.
Organization은 Terraform Cloud에서 User와 권한을 구분하는 가장 큰 단위라고 생각하시면 되고,
Workspace는 한 번에 동작되는 Terraform Template들의 묶음이라고 생각하시면 됩니다. 일반적으로 Workspace는 공통 서비스 모듈들로 구성됩니다.
API를 구성하기 전에, 위 1번에서 작성한 Terraform HCL 템플릿을 Terraform Cloud에서 불러올 수 있도록 VCS 저장소와 연동해야 합니다.
저는 VCS 저장소로 GitHub를 사용했습니다.
연동에 대한 상세 가이드는 아래 링크를 참고해 주시기 바랍니다.
https://developer.hashicorp.com/terraform/enterprise/vcs
VCS 저장소 연동 후 그대로 Run 시키게 되면, 아무런 변수가 반영되지 않은 채 Template 그대로 Terraform이 실행됩니다.
우리는 '사용자' 레벨에서 변수를 입력받아 API 형태로 Terraform을 실행하기를 원하므로, Terraform API 호출 포맷을 작성하고 어플리케이션 내에 넣어보겠습니다.
Terraform은 수많은 기능들에 대해 API 형태로 제공합니다.
API 관련 상세 가이드는 아래 링크를 참고해 주시기 바랍니다.
https://developer.hashicorp.com/terraform/enterprise/api-docs
curl \
--header "Authorization: Bearer $TOKEN" \
--header "Content-Type: application/vnd.api+json" \
--request POST \
--data @payload.json \
https://app.terraform.io/api/v2/runs{
"data": {
"attributes": {
"message": "Custom message",
"variables": [
{"key": "service", "value": "test service"},
{"key": "vpc_cidr", "value": "10.0.0.0/24"}
]
},
"type":"runs",
"relationships": {
"workspace": {
"data": {
"type": "workspaces",
"id": "ws-abcdefghij"
}
},
"configuration-version": {
"data": {
"type": "configuration-versions",
"id": "cv-abcdefghij"
}
}
}
}
}저는 변수를 받아 apply 시키는 Run API를 사용했습니다.
function create() {
const data = {
"data": {
"attributes": {
"message": document.getElementById("create_service").value+" service create",
"variables": [
{ "key": "service", "value": "\""+document.getElementById("create_service").value+"\""},
{ "key": "vpc_cidr", "value": "\""+document.getElementById("create_vpc").value+"\""}
]
},
"type": "runs",
"relationships": {
"workspace": {
"data": {
"type": "workspaces",
"id": "ws-phAxaTqoLRVPrYSW"
}
}
}
}
}
const http = new XMLHttpRequest()
http.open('POST', 'https://app.terraform.io/api/v2/runs')
http.setRequestHeader('Content-type', 'application/vnd.api+json')
http.setRequestHeader('Authorization', 'Bearer $TOKEN')
http.send(JSON.stringify(data)) // Make sure to stringify
http. = function() {
alert(http.responseText)
}
}요건에 맞는 variables 포맷을 구성한 뒤 Terraform API를 호출하면 됩니다. 저는 간단하게 Ajax 방식으로 XMLHttpRequest를 사용했습니다.
사용자로부터 값을 입력받아 JSON 포맷 내에 넣어주었습니다.
어플리케이션 화면입니다. 서비스명은 ZERO, VPC CIDR은 10.10.10.0/24를 입력하고 생성을 눌러줍니다.
변수에 제가 입력한 값이 들어간 채로 API가 호출된 것을 볼 수 있습니다.
Terraform Cloud에서도 실시간으로 Apply 중인 내용을 볼 수 있습니다.
AWS 웹콘솔에서도 '사용자'가 입력한 서비스명과 CIDR로 리소스가 생성된 것을 볼 수 있습니다.
Terraform 템플릿에서 Output을 작성해 두었기에, Terraform Cloud 내에서 생성된 EC2의 Public IP를 확인할 수 있습니다. 이 또한 API로 화면 상에 뿌려줄 수 있습니다.
해당 Public IP를 호출하니 정상적으로 서비스가 런칭된 것으로 보입니다. ^^
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.