데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      Terraform Cloud와 Terraform API를 활용한 Self Provisioning 구현하기

      zero 22.11.30
      3,996 14 2

      IaC (Infrastructure as Code)

      AWS나 Azure 같은 Cloud 에서는 인프라스트럭쳐를 웹 콘솔 내에서 몇 번의 클릭만으로 구성할 수 있습니다.

      그렇기에 내가 만들고자 하는 리소스를 자유롭게 구성할 수 있다는 장점이 있지만,

      엔터프라이즈 레벨에서는 생성되는 리소스의 환경설정, 버전, 보안 등의 차이로 거버넌스에 어긋남에 따라 이슈가 발생할 수 있습니다.

      때문에 IaC(Infrastructure as Code) 를 활용하여 Cloud 상의 인프라스트럭처를 템플릿화 하고, 보다 체계적으로 구성/관리하는 것이 좋습니다.


      Terraform Cloud & Terraform API

      IaC의 가장 대표적인 툴에는 Terraform이 있는데요.

      Terraform은 아래 세 가지 방식으로 모두 실행 시킬 수 있습니다.

      1. CLI

      2. GUI

      3. 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 CloudTerraform API를 활용하여, '사용자' 레벨의 Self Provisioning을 구현하는 방법을 공유 드리겠습니다.

      좀 더 쉽게 이해를 돕기 위해, Terraform 템플릿으로 구성하는 인프라스트럭처는 간단하게 AWS의 VPC 구성부터 샘플 웹페이지가 띄워지는 EC2 인스턴스로 작성하였습니다.


      1. Terraform Template 코드 작성 (HCL)

      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를 반환한다.
      }


      2. Terraform Cloud 환경 구성

      Terraform Cloud

      Terraform Cloud란 Terraform의 운영 환경을 웹 콘솔로 제공하고, API 기능을 지원해주는 서비스입니다.

      image.png

      image.png

      먼저 Organization과 Workspace를 생성해줍니다.

      Organization은 Terraform Cloud에서 User와 권한을 구분하는 가장 큰 단위라고 생각하시면 되고,

      Workspace는 한 번에 동작되는 Terraform Template들의 묶음이라고 생각하시면 됩니다. 일반적으로 Workspace는 공통 서비스 모듈들로 구성됩니다.


      image.png

      API를 구성하기 전에, 위 1번에서 작성한 Terraform HCL 템플릿을 Terraform Cloud에서 불러올 수 있도록 VCS 저장소와 연동해야 합니다.

      저는 VCS 저장소로 GitHub를 사용했습니다.

      연동에 대한 상세 가이드는 아래 링크를 참고해 주시기 바랍니다.

      https://developer.hashicorp.com/terraform/enterprise/vcs

      VCS 저장소 연동 후 그대로 Run 시키게 되면, 아무런 변수가 반영되지 않은 채 Template 그대로 Terraform이 실행됩니다.

      우리는 '사용자' 레벨에서 변수를 입력받아 API 형태로 Terraform을 실행하기를 원하므로, Terraform API 호출 포맷을 작성하고 어플리케이션 내에 넣어보겠습니다.


      3. 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 포맷 내에 넣어주었습니다.


      4. 어플리케이션 테스트

      image.png

      어플리케이션 화면입니다. 서비스명은 ZERO, VPC CIDR은 10.10.10.0/24를 입력하고 생성을 눌러줍니다.


      image.png

      변수에 제가 입력한 값이 들어간 채로 API가 호출된 것을 볼 수 있습니다.


      image.png

      Terraform Cloud에서도 실시간으로 Apply 중인 내용을 볼 수 있습니다.


      image.png

      AWS 웹콘솔에서도 '사용자'가 입력한 서비스명과 CIDR로 리소스가 생성된 것을 볼 수 있습니다.


      image.png

      Terraform 템플릿에서 Output을 작성해 두었기에, Terraform Cloud 내에서 생성된 EC2의 Public IP를 확인할 수 있습니다. 이 또한 API로 화면 상에 뿌려줄 수 있습니다.


      image.png

      해당 Public IP를 호출하니 정상적으로 서비스가 런칭된 것으로 보입니다. ^^

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      zero 님의 최신 블로그

      더보기
      동영상 기고하기