Cloud Tech

OpenTofu 와 Atlantis 연동하기

Hanhorang31 2024. 8. 3. 22:50
 

Overview

OpenTofu을 이해하고, Terraform Runner인 Atlantis와 연동하여 구성 동작을 확인하겠습니다.

OpenTofu ?

OpenTofu의 배경은 Terraform의 라이센스 변경과 관련이 있습니다. Terraform은 오랫동안 오픈 소스로 제공되었으나, 2023년 8월에 HashiCorp가 Terraform을 포함한 여러 제품의 라이센스를 변경하면서 더 제한적인 Business Source License(BSL)를 도입했습니다. BSL 도입에 따라 Terraform을 서비스 형태로 제공하거나, 상업적 목적으로 대규모로 사용하는 경우 라이센스 비용을 지불해야 합니다.

(출처: GeekNews)

 

이에 따라 오픈소스 진영에서는 Terraform을 포크하여 만든 도구로 OpenTofu를 출시했습니다.

사용 방법이나 특징들은 Terraform과 거의 비슷합니다. Graph를 통해 구성도를 확인하면 Terraform과 명령어만 다를 뿐 사용 동작은 똑같습니다.

OpenTofu 설치

Environment managers Tools 인 tenv를 통해 쉽게 설치가 가능합니다. (tfenv 아닙니다)

# Mac 기준 tfevn가 있으면 설치 에러로 삭제  
brew remove tfenv

# tenv 설치 
brew install tenv
tenv -h 

# 자동 완성 설정 
tenv completion zsh > ~/.tenv.completion.zsh
echo "source '~/.tenv.completion.zsh'" >> ~/.zshrc 

# OpenTofu 설치 
tenv tofu list-remote 
tenv tofu install 1.7.3
tenv tofu use 1.7.3

# tofu 사용
tofu -h 
  • Terraform과 사용 커맨드가 거의 비슷합니다.

Terraform to OpenTofu

이전 테라폼으로 구성한 EKS 환경을 OpenTofu를 통해 구성하겠습니다.

EKS 환경은 밑 프로젝트을 참고하여 구성하였습니다.

 

GitHub - Dhruvin4530/EKS-managed-node-group-Terraform: Upgrade the AWS EKS cluster with Zero Downtime using Terraform

Upgrade the AWS EKS cluster with Zero Downtime using Terraform - Dhruvin4530/EKS-managed-node-group-Terraform

github.com

 

# terraform version install 
tenv tf list-remote
tenv tf install 1.8.5
tenv tf use 1.8.5

terraform -h 

# 매개 변수 수정 
git clone https://github.com/Dhruvin4530/EKS-managed-node-group-Terraform.git
cd EKS-managed-node-group-Terraform

vi terraform.tfvars
----
cluster_name       = "prod-cluster"
instance_count     = 2
instance_size      = "t3.micro"
region             = "ap-northeast-2"
cluster_version    = "1.28"
ami_id             = "ami-085b4285663443932" # 1.27 x86 
vpc-cni-version    = "v1.14.0-eksbuild.3" # 1.27
kube-proxy-version = "v1.27.4-eksbuild.2" # 1.27


terraform init 
terraform apply -auto-approve 
  • tfenv를 제거하였기에 tenv를 통해 테라폼을 설치후 EKS 환경을 구성하겠습니다.

Terraform 으로 구성한 인프라를 OpenTofu로 마이그레이션하겠습니다.

마이그레이션 과정은 OpenTofu 공식문서를 참고하였습니다. 

  1. Terraform 버전 변환 : 1.8.2 이상의 테라폼 버전에서만 호환이 가능합니다. 그 아래의 경우 버전을 업그레이드해야 합니다.
  2. Terraform 상태 최신화 : Plan을 통해 변경사항이 있는 지 확인해주세요.
  3. OpenTofu 버전 확인 : Opentofu 버전이 1.7.1 이상인지 버전 확인이 필요합니다.
  4. Statefile 백업 : tofu로 변환 전 테라폼 Statefile 백업이 필요합니다.
  5. 코드 변경 : OpenTofu으로 변환은 아래의 코드 변경이 필요합니다.

EKS 환경에서는 위 내용에 대한 내용이 없으므로 생략합니다.

  1. OpenTofu 초기화
tofu init
  • Opentofu에 대한 프로바이더 확인하면 terraform과 동일한 provider를 사용함을 알 수 있습니다. terraform_aws_provider 는 MIT 라이센스로 opentofu에서도 그대로 사용이 가능합니다.


6. OpenTofu Plan을 통한 변경 사항 확인

tofu plan 
...

 

7. Opentofu apply

tofu apply

Apply를 진행하면 결과가 refresh가 되면서 statefile이 생성됩니다.

statefile은 테라폼과 같이 terraform.state 로 생성됩니다.

마이그레이션 과정 중 statefile이 덮어쓰기가 되며, 문제가 있을 시 롤백이 필요하기에 반드시 사전 백업이 필요합니다.

Atlantis 를 통한 CI 구성

OpenSource CI 툴인 Altantis에서 OpenTofu를 사용할 수 있도록 구성하겠습니다. Atlantis는 위 Opentofu로 구성한 EKS 환경에서 배포하겠습니다. 배포 구성은 아래 문서를 참고하였습니다.

 

Integrating Atlantis with OpenTofu.

Due to the Terraform license change, many companies are migrating their IAC processes to OpenTofu,...

dev.to

 

Atlantis Helm 배포 전 EKS 에 다음의 addon 구성이 필요합니다.

  • aws load balancer controller
  • external dns
  • ebs-csi driver
helm repo add runatlantis https://runatlantis.github.io/helm-charts

이전 필자의 블로그 글 스크립트에서 Opentofu를 사용하기 위한 플러그인을 추가해주세요.

vi values-atlantis.yaml
---------------

#  add atlantis public domain for :
atlantisUrl: http://horang.link

# Add your terraform repository:
##in my case I'm using the same repository
orgWhitelist: github.com/HanHoRang31/t101-cicd

# If using GitHub, specify like the following: 
github:
  user: t****66@gmail.com
  token: *******************
  secret: *******************

# -- Optionally specify an username and a password for basic authentication.
basicAuth:
  username: "admin"
  password: "1234"

ingress:
  annotations: 
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-2:*******
    alb.ingress.kubernetes.io/success-codes: 200-399
    alb.ingress.kubernetes.io/group.name: "atlantis"
  hosts:
    - host: atlantis.horang.link
      service: atlantis
      paths: ["/*"]


#Specify AWS credentials to be mapped to ~/.aws inside the atlantis container
# to allow atlantis container access AWS:
aws:
   credentials: |
              [default]
              aws_access_key_id = A***************K
              aws_secret_access_key = 0********************
              region = ap-northeast-2
   config: |
     [profile a_role_to_assume]
     role_arn = arn:aws:iam::**************:role/AmazonEKS_EBS_CSI_DriverRole
     source_profile = default
#defaultTFVersion set the default terraform version to be used in atlantis server
## it should be the same as your terraform version to overcome any terraform lock status
defaultTFVersion: 1.8.5

initConfig:
  enabled: true
  image: alpine:latest
  imagePullPolicy: IfNotPresent
  # sharedDir is set as env var INIT_SHARED_DIR
  sharedDir: /plugins
  workDir: /tmp
  sizeLimit: 250Mi
  # example of how the script can be configured to install tools/providers required by the atlantis pod
  script: |
    #!/bin/sh
    set -eoux pipefail

    # terragrunt
    TG_VERSION="0.55.10"
    TG_SHA256_SUM="1ad609399352348a41bb5ea96fdff5c7a18ac223742f60603a557a54fc8c6cff"
    TG_FILE="${INIT_SHARED_DIR}/terragrunt"
    wget https://github.com/gruntwork-io/terragrunt/releases/download/v${TG_VERSION}/terragrunt_linux_amd64 -O "${TG_FILE}"
    echo "${TG_SHA256_SUM} ${TG_FILE}" | sha256sum -c
    chmod 755 "${TG_FILE}"
    terragrunt -v

    # OpenTofu
    TF_VERSION="1.6.2"
    TF_FILE="${INIT_SHARED_DIR}/tofu"
    wget https://github.com/opentofu/opentofu/releases/download/v${TF_VERSION}/tofu_${TF_VERSION}_linux_amd64.zip
    unzip tofu_${TF_VERSION}_linux_amd64.zip
    mv tofu ${INIT_SHARED_DIR}
    chmod 755 "${TF_FILE}"
    tofu -v
    
environment: 
  ATLANTIS_TF_DOWNLOAD: false
  TERRAGRUNT_TFPATH: /plugins/tofu
  
repoConfig: |
  ---
  repos:
  - id: /.*/
    apply_requirements: [approved, mergeable]
    allow_custom_workflows: true
    allowed_overrides: [workflow, apply_requirements, delete_source_branch_on_merge]
  
  • 아틀란티스를 사용하기 전 Github Repo 구성과 Webhook 설정이 필요합니다. 참고

위 스크립트를 기반으로 atlantis를 배포합니다.

kubectl create ns atlantis 
helm install atlantis runatlantis/atlantis -f values-atlantis.yaml -n atlantis

깃허브 웹 훅 연동도 확인해야합니다.

Alantis & OpenTofu 동작 확인

예제 파일을 배포하여 IaC CI 동작을 확인하겠습니다.

코드 관리 루트 디렉토리에 opentofu를 사용하기 위한 atlantis 정의 파일을 추가합니다.

vi atlantis.yaml 
---
version: 3
automerge: true
parallel_plan: true
parallel_apply: false
projects:
- name: terragrunt 
  dir: .
  workspace: terragrunt
  delete_source_branch_on_merge: true
  autoplan:
    enabled: true
    when_modified: ["*.hcl", "*.tf"]
  apply_requirements: [mergeable, approved]
  workflow: terragrunt
workflows:
  terragrunt:
    plan:
      steps:
      - env:
          name: TF_IN_AUTOMATION
          value: 'true'
      - run: find . -name '.terragrunt-cache' | xargs rm -rf
      - run: terragrunt init -reconfigure
      - run:
          command: terragrunt plan -input=false -out=$PLANFILE
          output: strip_refreshing
    apply:  
      steps:      
        - run: terragrunt apply $PLANFILE

위 스크립트에서 opentofu가 아닌 terragrunt를 통해 명령어가 수행됩니다.

이는 atlantis에서 opentofu를 아직 지원하지 않기 때문입니다.

terragrunt는 terraform과 opentofu를 둘 다 지원합니다.

Terragrunt만 있고 opentofu에 대한 명령어가 없다구요?

위 Atlantis helm 차트 배포 시 Terragrunt 내부 동작을 opentofu로 설정하였습니다.

environment: 
  ATLANTIS_TF_DOWNLOAD: false
  TERRAGRUNT_TFPATH: /plugins/tofu

Atlantis 설정이 끝났으면, 테스트를 위한 예제 파일을 생성하고 terragrunt 정의 파일을 다음과 같이 생성합니다.

echo 'resource "null_resource" "example" {}' > main.tf

vi terragrunt.hcl
--
terraform {
  source = "./"
}
~  

tree .   
.
├── README.md
├── atlantis.yaml
├── main.tf
└── terragrunt.hcl


git checkout -b opentofu 
git add . && git commit -m "test opentofu" && git push origin opentofu

이제 깃허브에서 main으로 PR을 요청하면 정상적으로 opentofu로 프로비저닝되는 것을 확인할 수 있습니다.