[t1013] Terraform 협업 & 워크플로

xgro·2023년 10월 6일
0

Terraform

목록 보기
10/10
post-thumbnail

📌 Notice

본 블로깅은 아래의 24단계 실습으로 정복하는 쿠버네티스 책을 기준하여 정리하였습니다.

출처 - 한빛출판네트워크

CloudNetaStudy 그룹에서 스터디한 내용입니다.
Hashicorp korea 유형욱님과 함께 스터디 하고 있습니다. 🙏
유형욱님과 윤서율님께 다시한번 🙇 감사드립니다.


📌 Summary

  • IaC와 테라폼을 이해하고 스터디에 필요한 실습 환경을 구성합니다.

  • 테라폼 기본 명령 사용법을 알아봅니다.

  • HCL을 이해하고 기본 활용 방법을 학습합니다.

  • 샘플코드 작성 및 배포를 실습합니다.



📌 Study

스터디에서 7.1~7.2 Git 관련 내용을 학습하였지만, Git을 사용한 개발환경에서는 기본적으로 숙지해야 하는 내용이므로 해당 블로그에서는 다루지 않습니다.

👉 Step 01. 7장 형상 관리

✅ 7.3 State 백엔드

State 백엔드 소개

구성 목적(3가지)

  • 관리 : 지속적인 State 백업을 위해서 local 이외의 저장소가 필요
  • 공유 : 다수의 작업자가 동일한 State로 접근해 프로비저닝하기 위한 공유 스토리지 필요
  • 격리 : 민감한 데이터가 State 파일에 저장될 가능성을 고려하여, 각각의 환경에 따라 접근 권한 제어 필요

7.3.1 Terraform Cloud (TFC) 백엔드

하시코프에서 프로비저닝 대상과 별개로 State를 관리할 수 있도록 SaaS 환경인 TFC를 제공하며 State 관리 기능은 무상을 제공 → 기존 Terraform CE 사용자가 가장 좋아하는 기능
HashiCorp Terraform: Enterprise Pricing, Packages & Features

  • 제공 기능 : 기본 기능 무료, State 히스토리 관리, State lock 기본 제공, State 변경에 대한 비교 기능
  • Free Plan 업데이트 : 사용자 5명 → 리소스 500개, 보안 기능(SSO, Sentinel/OPA로 Policy 사용) - 링크

테라폼 클라우드 가격정책 - [참고: Pricing, Feature]

  • Free : 리소스 500개 까지 무료 → 커뮤니티 버전
  • Standard : Free + 워크플로우 기능 추가 + 동시실행(Concurrency 개수 3개)
  • Plus : 정책, 보안, 신뢰성, 확장성 등 기업형 고객에게 적합(대규모 사용자를 위한 비용모델)
  • Enterprise : Plus와 대부분 유사하며 설치형 모델

👉 Step 01. 8장 워크플로

✅ 8.1 규모에 따른 워크플로

개인 워크플로
개인이 테라폼으로 일하는 방식의 예

  • Write : 프로비저닝하려는 목적에 따라 테라폼 코드를 작성
    • 개인 작업이더라도 반복적인 사용성을 고려하자.
    • 인수에 할당되는 값을 입력 변수화하고 반복적인 구조가 발생하는 경우 리소스 단위별로 반복문을 사용할지 다수의 리소스를 모듈화할지 결정한다.
  • Plan : 적용하기 위한 실행 계획을 통해 리뷰
    • 테라폼의 Plan뿐 아니라, terraform fmt를 통해 코드 형태를 포멧팅하고 변경되는 리소스를 리뷰한다.
    • 또한 테라폼과 함께 동작하는 tfsec이나 terrascan 같은 보안 취약성 점검 툴 등을 활용하는 것도 좋은 방안이다.
  • Apply : 코드로 실제 인프라를 프로비저닝
    • 실행 계획상으로는 정상이지만 실제 프로비저닝하는 단계에서 인수 값, 생성 순서, 종속성에 따라 오류가 발생할 수 있다.
    • 성공적인 완료를 위해 Write > Plan > Apply 단계를 반복하고 성공하는 경우 코드 관리를 위해 VCS에 코드를 병합한다.

다중 작업자 워크플로

  • Write
    • 여러 작업자의 테라폼 코드가 충돌하지 않도록 VCS와 같은 형상관리 도구에 익숙해져야 한다.
    • 작업자는 작업 전에 미리 원격 저장소코드를 받고 깃에서는 브랜치를 활용해 개별적으로 작업한다.
    • 개인의 워크플로에서 고려한 변수화와 더불어 패스워드와 인증서 같은 민감 데이터가 포함되지 않도록 코드를 설계한다.
    • 또한 개인 작업 환경에서만 사용되는 변수는 공유하지 않는다.
    • 깃을 사용한다면 작업자 개인의 변수terraform.tfvars 에 선언하고 .gitignore에 추가해 개별적으로 테스트할 수 있는 환경을 구성할 수 있다
    • 이 단계에서 개별 작업자는 작은 단위의 개별 워크플로(Write > Plan > Apply)를 반복해야 한다.
    • 개별 작업 환경과 별개로 병합되는 코드가 실제 운영 중인 인프라에 즉시 반영되면 실행 후 발생할 오류 예측이 어려워 부담이 될 수 있다.
    • 이를 보완하기 위해 프로비저닝 대상의 환경을 검증운영, 또는 그 이상의 환경으로 구성 가능하도록 구조화한다.
    • 이때 사용하는 방식은 디렉터리 기반 격리깃 기반의 브랜치 격리다.
  • Plan
    • 둘 이상의 작업자는 프로비저닝 이전에 팀원 간 리뷰를 거쳐 변경된 내역을 확인하고 공통 저장소에 병합해야 한다.
    • 리뷰 단계에서는 추가, 삭제, 수정된 내역을 관련 작업자가 검증, 질의, 배움의 단계를 거쳐 복기함으로써 코드 상태를 개선 유지하고 작업자 간에 의도를 공유한다.
    • 코드 자체 외에도 테라폼의 Plan 결과를 풀 리퀘스트 단계에 같이 제공하면 영향을 받는 리소스와 서비스 중단에 대한 예측이 더 쉬워진다.
    • CI 툴과 연계하거나 Terraform Cloud/Enterprise의 VCS 통합 기능으로 자동화할 수 있다.
  • Apply
    • 코드가 최종 병합되면 인프라 변경이 수행됨을 알리고 변경되는 대상 환경의 중요도에 따라 승인이 필요할 수 있다.
    • 또한 변경하는 코드가 특정 기능, 버그 픽스, 최종 릴리즈를 위한 병합인가에 따라 이 단계에 추가로 코드 병합이 발생할 수 있다.
    • 관리하는 단위를 나누는 기준은 조직 R&R, 서비스, 인프라 종류 등으로 구분된다.

다수 팀의 워크플로
R&R이 분리된 다수 팀 또는 조직의 경우

  • R&R이 분리된 다수 팀 또는 조직의 경우 테라폼의 프로비저닝 대상은 하나이지만 관리하는 리소스가 분리된다.
  • 단일 팀의 워크플로가 유지되고 그 결과에 대해 공유해야 하는 핵심 워크플로가 필요하다.
  • Write
    • 대상 리소스가 하나의 모듈에서 관리되지 않고 R&R에 의해 워크스페이스가 분리된다.
    • 서로 다른 워크스페이스에서 구성된 리소스 데이터를 권한이 다른 팀에게 공유하기 위해, 저장된 State 접근 권한을 제공하고 output을 통해 공유 대상 데이터를 노출한다.
    • 테라폼 코드 작성 시 다른 워크스페이스에서의 변경 사항을 데이터 소스로 받아 오는 terraform_remote_state 또는 별도 KV-store를 활용하는 코드 구성이 요구된다.
    • 또한 관리 주체가 다른 곳에서 생긴 변경 사항의 영향을 최소화하도록 리모트 데이터 소스의 기본값을 정의하거나 코드적인 보상 로직을 구현하는 작업이 필요하다.
  • Plan
    • 코드 기반으로 진행되는 리뷰는 반영되는 다른 팀의 인프라를 VCS상의 코드 리뷰만으로도 공유받고 영향도를 검토할 수 있다.
    • 병합을 승인하는 단계에 영향을 받는 다른 팀의 작업자도 참여해야 한다.
  • Apply
    • 프로비저닝 실행과 결과에 대한 안내가 관련 팀에 알려져야 하므로 파이프라인 구조에서 자동화하는 것을 추천한다.
    • 실행 후의 영향도가 여러 팀이 관리하는 리소스에 전파될 수 있으므로 코드 롤백 훈련이 필요하다.
    • 생성된 결과에 다른 워크스페이스에서 참조되는 output 값의 업데이트된 내용을 다른 팀이 확인하는 권한 관리가 필요하다

✅ 8.2 격리 구조

테라폼 수준의 격리 목표 : State를 분리

  • 테라폼은 파일이나 하위 모듈로 구분하더라고 동작 기준은 실행하는 루트 모듈에서 코드를 통합하고 하나의 State로 관리한다.

  • 애플리케이션 구조가 모놀리식(+아키텍처)에서 MSA로 변화하는 과정은 테라폼의 IaC 특성과도 결부된다.

  • 테라폼 또한 사용하는 리소스가 적고 구조가 단순하면 모놀리식 방식으로 구성하는 것이 인프라 프로비저닝 구축 속도는 빠를 수 있다.

  • 하지만 유지 보수, 인수인계, 운영의 관점에서는 프로비저닝 단위별로 분류하는, 마치 MSA와도 같은 분산된 설계가 매몰 비용과 기술 부채를 줄이는 데 효과적이다.

  • 규모가 큰 워크플로를 만들기 위해서는 간단하고 조합 가능한 부분들이 모여 집합을 이루어야 한다.

  • 이러한 집합에서 발생하는 정보는 다른 집합과 교환할 수 있지만, 각 집합은 독립적으로 실행되며 다른 집합에 영향을 받지 않는 격리된 구조가 필요하다.

  • 초기 테라폼 적용 단계에서 단일 또는 소수의 작업자는 단일 대상에 대해 IaC를 적용하고 하나의 루트 모듈에 많은 기능을 포함시킬 가능성이 높다.

루트 모듈 격리(파일/디렉터리)

  • 단일 작업자가 테라폼으로 프로비저닝을 하는 많은 경우에 관리 편의성 및 배포 단순화를 위해 하나의 루트 디렉터리에 파일로 리소스들을 구분하거나, 디렉터리를 생성하고 하위에 구성 파일 묶음을 위치시켜 루트 모듈에서 하위 디렉터리를 모듈로 읽는 구조를 사용한다.
  • 작업자가 관리하는 영역 또는 프로비저닝되는 리소스 묶음의 독립적인 실행을 위해 단일 루트 모듈 내의 리소스를 다수의 루트 모듈로 분리하고 각 모듈의 State를 참조하도록 격리한다.
  • 관리적인 측면으로는 작업자들의 관리 영역을 분리시키고 깃 기준의 리모트 저장소도 접근 권한을 관리할 수 있다.
  • 협업과 관련해 작업자별로 특정 루트 모듈을 선정해 구성 작업을 진행해 코드 충돌을 최소화하는 환경을 구성하고 인수인계 과정에서 리뷰하는 영역을 최소화할 수 있다.


🧩 Assignment

👉 과제

목표 - 아래 깃허브 저장소를 복제해 아래 조건에 만족하는 코드를 작성
https://github.com/terraform101/terraform-aws-collaboration

조건

  1. Terraform Cloud를 State 백엔드로 구성
Workspace 이름 : terraform-edu-part1-assessment
실행 모드는 local
  1. AWS 공통 Tag : Project = “workshop”

  2. aws_instance는 반복문을 사용해 3개 구성

  3. EIP를 제거하고 EC2에서 public ip를 자체 사용하도록 구성

  4. placeholder 변수는 아래 3가지가 각각의 aws_instance에 적용되도록 구성

placekitten.com
placebear.com
placedog.net

1. TFC State 벡엔드 구성

별도의 워크스페이스를 생성하여 백엔드를 위한 리소스를 별도 생성합니다.

워크 스페이스 생성시 프로젝트에 반영할 수 있도록 가이드가 표시됩니다.

테라폼 작업을 Local에서 할 수 있도록 환경설정을 완료합니다.

2. AWS 공통 Tag : Project = "workshop"

프로바이더 항목에서 공통 태그를 선언하여 전체 리소스에 할당 할 수 있습니다.

provider "aws" {
  region = var.region
  default_tags {
    tags = {
      Project = "workshop"
    }
  }
}

3. aws_instance 반복문 사용해 3개 구성

변수 placeholder의 개수만큼 ec2가 생성하고자 하므로 for_each 구문을 통해 변수(배열)에 할당된 값 만큼 반복하도록 하는 소스코드를 작성합니다.

resource "aws_instance" "hashicat" {
  for_each = toset(var.placeholder)
  ami                         = data.aws_ami.ubuntu.id
  instance_type               = var.instance_type
  key_name                    = aws_key_pair.hashicat.key_name
  associate_public_ip_address = true
  subnet_id                   = aws_subnet.hashicat.id
  vpc_security_group_ids      = [aws_security_group.hashicat.id]

  tags = {
    Name = "${var.prefix}-hashicat-instance"
  }
}

4. EIP를 제거하고 EC2에서 public ip를 자체 사용하도록 구성

기존 소스코드에서 선언된 EIP 관련 소스코드를 삭제하여 EC2의 자체 Public ip를 사용하도록 구성합니다.

resource "aws_eip" "hashicat" {
  instance = aws_instance.hashicat.id
  vpc      = true
}

resource "aws_eip_association" "hashicat" {
  instance_id   = aws_instance.hashicat.id
  allocation_id = aws_eip.hashicat.id
}

5. placeholder 변수 각각 적용 구성

variables.tf
인덱스에 따라 다른 변수가 선언 되어야 하므로 배열을 사용하여 변수를 선언합니다.

variable "placeholder" {
  default     = [
    "placekitten.com",
    "placebear.com",
    "placedog.net"
  ]
}

main.tf
선언된 변수를 사용하여 ec2의 count에 따라 다른 변수가 선언될 수 있도록 설정합니다.

  provisioner "remote-exec" {
    inline = [
      "sudo apt -y update",
      "sleep 15",
      "sudo apt -y update",
      "sudo apt -y install apache2",
      "sudo systemctl start apache2",
      "sudo chown -R ubuntu:ubuntu /var/www/html",
      "chmod +x *.sh",
      "PLACEHOLDER=${var.placeholder[count.index]} WIDTH=${var.width} HEIGHT=${var.height} PREFIX=${var.prefix} ./deploy_app.sh",
      "sudo apt -y install cowsay",
      "cowsay Mooooooooooo!",
    ]
profile
안녕하세요! DevOps 엔지니어 이재찬입니다. 블로그에 대한 피드백은 언제나 환영합니다! 기술, 개발, 운영에 관한 다양한 주제로 함께 나누며, 더 나은 협업과 효율적인 개발 환경을 만드는 과정에 대해 인사이트를 나누고 싶습니다. 함께 여행하는 기분으로, 즐겁게 읽어주시면 감사하겠습니다! 🚀

0개의 댓글