8장 워크플로

김진원·2023년 8월 18일

IaC

목록 보기
10/10

"테라폼으로 시작하는 IaC"책을 기준으로 7주차 정리 내용입니다.


# 8.1 규모에 따른 워크플로

테라폼 워크플로는 Write > Plan > Apply 로 구성된다.
워크스페이스 별로 접근 권한을 관리하고 중앙에서 관리되는 실행 환경을 설계하여 규모에 맞는 워크플로 설계가 필요하다.


# 8.1.1 개인 워크플로

출처 - https://www.freecodecamp.org/news/terraform-workflow-working-individually-and-in-a-team/

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

# 8.1.2 다중 작업자 워크플로


출처 - https://www.freecodecamp.org/news/terraform-workflow-working-individually-and-in-a-team/

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

# 8.1.3 다수 팀의 워크플로

  • R&R이 분리된 다수 팀 또는 조직의 경우 테라폼의 프로비저닝 대상은 하나이지만 관리하는 리소스가 분리된다.
  • 단일 팀의 워크플로가 유지되고 그 결과에 대해 공유해야 하는 핵심 워크플로가 필요하다.

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



# 8.2 격리 구조

테라폼 수준의 격리는 State를 분리하는 데 목적이 있다.

  • 테라폼은 파일이나 하위 모듈로 구분하더라고 동작 기준은 실행하는 루트 모듈에서 코드를 통합하고 하나의 State로 관리한다.
  • 애플리케이션 구조가 모놀리식(+아키텍처)에서 MSA로 변화하는 과정은 테라폼의 IaC 특성과도 결부된다.

@ Monolithic Architecture

  1. 장점
  • 단일, 소수 인원으로 개발 편리
  • 통합된 시나리오 검증이 쉬운
  • 배포 간편
  1. 단점
  • 규모가 커지면 코드 추가, 수정, 삭제가 어려움
  • 신규 작업자가 전체를 리뷰해야 함
  • 부분적인 오류가 전체에 영향을

@ Micro Service Architecture

  1. 장점
  • 소규모 기능 단위로 배포와 테스트가 용이
  • 단위별 새로운 구성 적용이 수월
  • 서비스가 독립적으로 실행
  1. 단점
  • 다수의 배포를 위한 프로세스 구현 필요
  • 단위별 연계를 위한 로직 구현 필요
  • 나누는 기준 마련
  • 테라폼 또한 사용하는 리소스가 적고 구조가 단순하면 모놀리식 방식으로 구성하는 것이 인프라 프로비저닝 구축 속도는 빠를 수 있다.
  • 하지만 유지 보수, 인수인계, 운영의 관점에서는 프로비저닝 단위별로 분류하는, 마치 MSA와도 같은 분산된 설계가 매몰 비용과 기술 부채를 줄이는 데 효과적이다.
  • 규모가 큰 워크플로를 만들기 위해서는 간단하고 조합 가능한 부분들이 모여 집합을 이루어야 한다.
  • 이러한 집합에서 발생하는 정보는 다른 집합과 교환할 수 있지만, 각 집합은 독립적으로 실행되며 다른 집합에 영향을 받지 않는 격리된 구조가 필요하다.
  • 초기 테라폼 적용 단계에서 단일 또는 소수의 작업자는 단일 대상에 대해 IaC를 적용하고 하나의 루트 모듈에 많은 기능을 포함시킬 가능성이 높다.

# 8.2.1 루트 모듈 격리(파일/디렉토리)

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

# 8.2.2 환경 격리 - 깃 브랜치

  • 서비스의 테스트, 검증, 운영 배포를 위해 테라폼으로 관리하는 리소스가 환경별로 격리되어야 한다면 디렉터리 구조로 분리하는 방안을 고려할 수 있다.
  • 디렉터리별로 각 환경을 나누는 것은 개인의 관리 편의성은 높지만, 환경의 아키텍처를 고정시키고 코드 수준의 승인 체계를 만들기 위해서는 최종 형상에 대한 환경별 브랜치를 구성하기를 권장한다.
  • 디렉터리 구조만으로는 환경에 따라 사용자를 격리할 수 없다. 이때 깃의 브랜치 기능을 활용하면 환경별로 구별된 작업과 협업이 가능하다.

출처 - https://betterprogramming.pub/a-simple-git-repository-strategy-93a0c7450f23

  • main : 운영 코드가 관리되며 이곳에는 직접적으로 구성 변경을 수행하지 않음
  • QA : 검증 대상 인프라를 구성하는 코드로, 메인 브랜치와 같이 직접적인 구성 변경을 수행하지 않음
  • DEV : QA 전 단계로 메인 코드 구성과 기능 브랜치의 병합을 담당
  • feature : 새로운 리소스를 추가하고 구현하며 여러 개가 될 수 있음
  1. 관리의 편의성을 고려해 Hot-fix와 Release 브랜치를 추가할 수도 있지만 인프라의 특성상 개발, 검증, 운영으로 나눈다.
  2. 환경 간에 프로비저닝이 되는 리소스를 갖추고 있다면 운영을 위한 프로비저닝 환경을 안정적으로 유지할 수 있다는 장점이 있다.
  3. 디렉터리 구조로 관리하는 환경별 디렉터리 구성 방식에서는 개발할 때 작성한 구성을 다시 복사해 검증 또는 운영에 반영하므로 환경별로 구성이 다른 상황이 발생할 여지가 높고, 모든 디렉터리에 접근 가능할 경우 검증과 운영을 위한 구성을 직접 수정하는 일이 발생할 가능성이 높다.
  4. 따라서 작업자가 다수의 환경을 동시에 관리한다면 디렉터리로 구분하더라도 각 디렉터리마다 동일한 깃 저장소의 브랜치별 리모트 구성을 하는 것이 바람직하다.

# 디렉터리 격리에 깃 브랜치 연결

이 방식은 동일한 브랜치를 변경해가면 작업해 발생하는 실수를 줄일 수 있고, 각 브랜치가 연결되어 있으므로 단일 작업자가 다수의 환경을 관리하는 이점과 각 환경별로 리소스 구성이 동일하게 유지되는 장점이 있다.



# 8.3 프로비저닝 파이프라인 설계 - 깃허브

실제 서비스가 실행되는 대상을 프로비저닝하면 테라폼의 Plan과 Apply 과정상에 추가로 코드 검증, 실행 계획 검증, 실행 후 결과 확인과 같은 추가 동작을 자동화해 연계할 필요성이 생긴다.

  • 도구 : 젠킨스, Github Action, TFC/TFE
  • Github Action : 깃허브 환경에서 제공하는 CI/CD 자동화 도구 - 워크플로를 설계하고 다양한 라이브러리들을 이용해 다양한 작업 구성이 가능
  • 저장소 포크 : https://github.com/terraform101/terraform-aws-github-action
  • Github Action은 별도의 State 저장소를 제공하지 않기 때문에 테라폼 실행으로 생성되는 State가 항상 초기화되어 프로비저닝 결과를 유지할 수 없다.

백엔드 활성화를 진행하자

  1. Remote Repo를 Local 환경에 복제
MyGit=skwwnl
git clone https://github.com/$MyGit/terraform-aws-github-action

# 확인
tree terraform-aws-github-action
cd terraform-aws-github-action
git remote get-url origin

  1. main.tf의 terraform 블록에서 사용자의 TFC 설정 organization으로 변경
# terraform login 설정 토큰 확인
cat ~/.terraform.d/credentials.tfrc.json | jq

  • main.tf 내용 수정
terraform {
  cloud {
    organization = "<MY_ORG_NAME>"         # 생성한 ORG 이름 지정
    hostname     = "app.terraform.io"      # default

    workspaces {
      name = "terraform-aws-github-action"
    }
  }

  • .github/workflow/action.yml 내용 수정
env:
  MY_PREFIX: DEV
  TF_VERSION: 1.2.6 # 1.2.5에서 변경
  • push
git add main.tf
git add .github/workflow/action.yml
git commit -m "init"
git push

push 하는 도중 에러 발생!!

해결은 아래와 같이 토큰의 권한 설정에서 workflow를 체크해준다.

해결 !!

  1. 지정된 Terraform Cloud 백엔드 활성화를 위해 terraform init을 수행
terraform init
tree .terraform

워크스페이스가 생성된다.

  1. 생성된 TFC 워크스페이스의 실행 모드 Execution mode를 Local로 수정
    • terraform-aws-github-action 워크스페이스(State 백엔드 역할만 수행) 확인 → 선택 후 좌측에 Settings 클릭 → General
    • 실행 모드 변경 : Execution Mode 에서 Local 선택 → 하단의 Save settings 클릭하여 변경 적용

  • Secrets 정보 등록

# 연습 문제1 (실패)

  • 브랜치 생성 : add-env-variable
git branch
**git branch -M add-env-variable**
  • main.tf 수정
resource "aws_vpc" "hashicat" {
  cidr_block           = var.address_space
  enable_dns_hostnames = true

  tags = {
    name        = "${var.prefix}-vpc-${var.region}"
    environment = var.environment  # 원래 값 Production
  }
}
  • variable.tf 내용 추가
variable "environment" {
  type        = string
  description = "Define infrastructure’s environment"
  default     = "dev"

  validation {
    condition     = contains(["dev", "qa", "prod"], var.environment)
    error_message = "The environment value must be dev, qa, or prod."
  }
}
  • Push
terraform fmt
git add .
git commit -m "add env variable"
git push origin HEAD

  • PR 날리기


실패가 뜬다..

해결 : 레포지토리 Settings -> Actions -> General -> 최하단 Workflow permissions을 read and write permissions로 변경

성공!!

EC2까지 잘 생성되었다.


# 8.4 Terraform Cloud (TFC)

워크플로 구성 환경 제공, Github Action 보다 자유도는 낮지만 VCS연동, 변수 구성, RBAC, 원격 실행 환경 등의 기능 활용

저장소 포크 : https://github.com/terraform101/terraform-aws-tfc-workflow

MyGit=<>
MyGit=skwwnl
git clone https://github.com/$MyGit/terraform-aws-tfc-workflow
cd terraform-aws-tfc-workflow

MyTfcOrg=<각자 자신의 TFC 조직명>
MyTfcOrg=t102test
sed -i -e "s/<MY-ORG>/$MyTfcOrg/g" main.tf

#
git add main.tf
git commit -m "init"
git push

#
terraform init
  • TFC 생성 워크스페이스에 Execution Mode를 Remote로 유지하여 앞선 실습과 차이를 둔다.

  • plan을 입력!

원격에서 plan을 진행하고 있으며, 보고 싶으면 아래 주소에 방문해서 볼 수 있다.

prefix의 기본 값도 없어서 에러가 발생.


  • 입력 변수 : TFC에서는 실행 후 인라인으로 넣을 수 없기 때문이며, 기존 terraform.tfvars 를 대체하는 역할을 수행함.
    • 따라서 기존 terraform.tfvars 파일은 동작하지 않는다

직접 prefix와 내 닉네임을 넣어서 변수를 생성한다.

추가로 AWS ID와 Secret을 추가하고, sensitive를 체크하여 Value를 숨길 수 있다.

다시 Plan하면 정상적으로 나온다.

TFC에서 apply를 직접 진행한다.

최종적으로 EC2 Instance가 생성됨을 볼 수 있습니다.

마무리는 모든 리소스를 지우는 Destroy를 진행합니다.

1개의 댓글

comment-user-thumbnail
2023년 8월 18일

좋은 글 감사합니다. 자주 올게요 :)

답글 달기