본문 바로가기

DevOps/Terraform

[T102 6주차] (16) 테라폼 협업 ( 깃Pull Request 통한 협업 )

cloudNet@ 팀의 가시다 님이 진행하는 테라폼 102 스터디 6주차 정리입니다.

 

 

인프라 규모가 커지고 관리 팀원이 늘어날 수록 코드 관리가 필요 → 서로 작성 코드 점검 및 협업 환경 구성 

구성 요소 : 코드를 다수의 작업자가 유지 보수 할 수 있도록 돕는 VCS Version Control System + 테라폼 State를 중앙화하는 중앙 저장소

 

 

✅ 유형 1 .  VCS, 중앙 저장소 없음

✅ 유형 2.  VCS(SVN, Git), 중앙 저장소 도입

✅ 유형 3 . VCS(Github), 중앙 저장소 도입 , State 백엔드 관리 

 

 

 

그림출처 : https://kschoi728.tistory.com/139

 

1. VCS  

  • 형상 관리 도구는 버전 관리 시스템을 지칭하는 도구이며, VCS 라고 불린다.
    • SVN : 중앙 저장소에서 코드와 히스토리를 관리하는 방식
    • Git : 분산형 관리 시스템으로 작업 환경에서도 별도로 코드 히스토리를 관리하고 중앙 저장소와 동기화
  • 과거에는 SVN을 많이 사용했는데, 최근에 가장 많이 사용하고 대중화 된 버전 관리 도구인 "git" 이 채택 되면서 소스 저장소를 서버에 두고 작업하는 SVN과 로컬 레포지토리와 Remote 레포지토리를 통해 종속성을 과감히 깨는 구조를 사용하는 "git"은 구조에 대한 차이점이 있습니다.
  • 커밋은 작업을 하던 로컬에만 저장 , 원격에 변경을 하려면 push 

1-1. git 

  • 분산형 관리 시스템
  • remote 저장소와 로컬 저장소를 동기화 시키는 방식
  • 브랜치? 
  • fork ? 

이미지 출처 : kschoi728.tistory.com/139

 


 

1-2. git  사용해보기

  • mac에 자동 설치된 git 
mzc01-kook@MZC01-KOOK terraform % git --version
git version 2.32.1 (Apple Git-133)
  • git 계정 만들기 
  • git token 만들기

token을 복사합니다.

  • github fork : 깃허브는 포크 fork 기능을 제공해 기존 리모트 저장소본인 소유의 저장소로 복사할 수 있다
  • 포크한 저장소는 원본 저장소와 연결이 되어 있으므로 이후 변경 사항을 원본 저장소에 적용하는 요청(Pull Request)이 가능하다.
  • https://github.com/terraform101/terraform-aws-collaboration

fork 할 레포지 토리를 들어가서 Fork 버튼을 누른다.
나의 Remote Repository로 포크 해온다.

  • github 클론 : 나의 Remote 레포지토리를 클론하여 로컬 레포지토리로 가져온다.
  • git clone 은 기존 리포지토리를 대상으로 하여 복제본 또는 대상 리포지토리의 복제본을 만드는 데 사용되는 명령어
$ git clone https://github.com/themapisto/terraform-aws-collaboration.git
  • test.txt를 변경한다.
# test.txt 
Koo Study 0808
  • add , commit , push
git add .
git commit -m 're'
git push

  • git ignore : 코드 파일 공유 시 깃 관리 대상 제외 -> .gitignore 정의 
    • .terraform 디렉터리 : init 실행 시 작성되므로 제외
    • .tfstate 파일 : 프로비저닝 결과 데이터 소스 정보, 민감 데이터가 포함, 다른 사용자가 같은 State 파일을 사용하는 경우 인프라 불합치 유발
    • tfvars 파일 : 프로비저닝 시 적용할 변수 값을 보관하는 파일로, 작업자 마다 별도 변수 사용
    • 시크릿 파일 : 인프라 구성에 필요한 시크릿 정보 파일
    • terraformrc 파일 : 작업자의 CLI 설정 파일


1-3 . Push / Pull 전략 

  • 커밋된 코드는 로컬 저장소에 기록되며 푸시를 하기 전까지는 리모트 저장소에 공유되지 않음 → 또한 작업 중 풀을 통해 리모트 저장소의 변경 사항을 로컬 저장소에 반영
  • 분기 되지 않은 리모트 저장소는 이러한 오류를 발생시킬수 있다.

  • 톰 디렉토리의 main.tf 파일 코드 내용 수정
...
provider "aws" {
  region = var.region
  default_tags {
    tags = {
      Project = "T101-Study-6week"
    }
  }
}
...
  • 수정된 코드를 커밋 후 리모트 저장소에 푸시
#
cd terraform-aws-collaboration-tom
git remote get-url origin
git add main.tf
git commit -m "add default tags & project name"
git push

  • jerry 디렉터리에서 작업 ( 다른 팀원이 작업하는것을 가정 )
#
cd ..
cd terraform-aws-collaboration-jerry
git remote get-url origin
git pull
cat main.tf |grep Project
  • 이번에는 양쪽 디렉터리의 tags에 Owner 항목을 추가하고 저장 시도
# jerry 디렉터리의 main.tf
...
provider "aws" {
  region = var.region
  default_tags {
    tags = {
      Project = "T101-Study-6week"
      Owner = "jerry"
    }
  }
}
...
  • git add / commit / push
#
cd terraform-aws-collaboration-jerry
git add main.tf
git commit -m "add default tags & Owner is jerry"
git push
  • tom 디렉터리도 똑같이 
...
provider "aws" {
  region = var.region
  default_tags {
    tags = {
      Project = "T101-Study-6week"
      Owner = "tom"
    }
  }
}
...
  • git add / commit / push
#
cd ..
cd terraform-aws-collaboration-tom
git add main.tf
git commit -m "add default tags & Owner is tom"

# tom의 루트 모듈 변경 코드를 리모트 저장소에 보낼 때 실패
git push

❌  push 실패

mzc01-kook@MZC01-KOOK terraform-aws-collaboration-tom % git push
To https://github.com/themapisto/terraform-aws-collaboration.git
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'https://github.com/themapisto/terraform-aws-collaboration.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
  • 푸시 전 풀을 먼저 수행해 리모트의 변경 사항을 로컬과 비교한 후 필요할 때 수정해 푸시하는 습관이 필요하다
  • 변경 사항에 충돌이 없는 경우 자동으로 커밋 지점이 병합된다
  • 풀 동작에 충돌이 있을 것으로 가정해 옵션을 붙여 수행 : git rebase
#
git pull --no-rebase

현재 변경 사항 ( 로컬 )

수신 변경 사항 ( remote )

 

 


1-4 .  Pull  Request 전략 

 

  • Push / Pull 전략으로도 코드 협업이 가능하지만, 다른 사람의 커밋을 확인 하기 어렵고, 리모트 저장소에 푸시할 때가 되어야 충돌 상황을 확인하게 된다는 단점이 있음
  • 작업된 테라폼 코드에 대한 코드 리뷰와 메인스트림 (main branch) 의 원할한 관리를 위해 병합 방식을 통한 코드 변경을 권장함
  • 깃으로 코드를 관리할때 주로 사용되는 브랜치를 이용하는 방안으로, 작업자가 코드 수정을 위해 메인에서 별개의 브랜치를 생성하고,
  • 작업후에 본인의 브랜치를 병합할때 코드 관리자에게 코드를 검토 후 병합을 요청하는 방식이다.


✅ 시나리오 1단계 

  • 코드 충돌을 유발 하기 위해서 tom이 메인 브랜치에 푸시한 상황에서 jerry가 Owner 항목을 jerry & tom으로 변경하려 한다.
  • 메인 브랜치에 바로 푸시하지 않고 작업을 위한 브랜치를 생성한 뒤 작업을 수행한다.
#
cd ..
cd terraform-aws-collaboration-jerry

# 최신 코드 pull 해두기
git pull

# 현재 브렌치 확인
git branch
<q로 빠져나옴>

# 새로 만든 jerry-owner-task 브랜치로 전환
git checkout -b jerry-owner-task
git branch
  • jerry 디렉터리의 main.tf 코드 수정
...
provider "aws" {
  region = var.region
  default_tags {
    tags = {
      Project = "T101-Study-6week"
      Owner = "jerry & tom"
    }
  }
}
...
  • jerry에서 작업중인 브랜치로 코드를 푸시 ( git push 시 메인에 바로 직접 코드를 푸시하는 것은 오류가 발생할 것 )
mzc01-kook@MZC01-KOOK terraform-aws-collaboration-jerry % git push
fatal: The current branch jerry-owner-task has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin jerry-owner-task
    
    
# branch 전략 

git add main.tf
git commit -m "add default tags & Owner is jerrh & tom"
git push origin jerry-owner-task

# 결과 

Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 320 bytes | 320.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
remote: 
remote: Create a pull request for 'jerry-owner-task' on GitHub by visiting:
remote:      https://github.com/themapisto/terraform-aws-collaboration/pull/new/jerry-owner-task
remote: 
To https://github.com/themapisto/terraform-aws-collaboration.git
 * [new branch]      jerry-owner-task -> jerry-owner-task

 

  • Pull Request 신청 시 유의 사항 ( Fork 한 레포지토리에서 자기 자신의 Remote Repository로 변경 )

  • Merge 완료

 

깃 ( PR ) 을 통한 State 관리는 여러 단점이 있다.

✅ 팀 단위로 테라폼을 관리할 경우 상태 파일을 관리하는 방안이 필요
- 깃을 이용해서 사용하는것은 너무 복잡함
✅ 상태 파일 잠금 ?
- 잠금 기능 없이 두 팀원이 동시에 테라폼을 실행 한다면 상태 파일을 동시 업데이트 하기 때문에 충돌 가능 합니다. ( race condition )
✅ 상태 파일 격리 ? 
- dev 와 검증 stage 과 상용 prodction 각 환경에 대한 격리가 필요

🔔  Git 같은 SCM  쓰면 테라폼 State 관리가 어려운 이유 !  

❌ 수동 오류 Manual error

  • 테라폼을 실행하기 전에 최신 변경 사항을 가져오거나 ( pull ) 실행 하고 나서 push 하는 것을 잊기 쉽습니다(?).
  • 팀의 누군가가 이전 버전의 상태 파일로 테라폼을 실행하고, 그 결과 실수로 이전 버전으로 롤백하거나 이전에 배포된 인프라를 복제하는 문제가 발생 할 수 있음.

❌ 잠금 Locking

  • 대부분의 버전 관리 시스템은 여러 명의 팀 구성원이 동시에 하나의 상태 파일에 terraform apply 명령을 실행하지 못하게 하는 잠금 기능이 제공되지 않음.

❌ 시크릿 Secrets

  • 테라폼 상태 파일의 모든 데이터는 평문으로 저장됨. 민감 정보가 노출될 위험.