TerraformステートをGitLab CI/CDに移行する方法

ソフトウェアプロフェッショナルとしてInfrastructure as Code (IaC)を扱っている場合、Terraformを頻繁に使用することが多いでしょう。新しいクライアントがIaCを使用するのを手助けする際、簡略化することが一般的ですが、Terraformの状態ファイルを管理することは最初の課題です。基本的に、Terraformの状態には機密情報が含まれており、ソース管理で保存すべきではないが、同時に複数のユーザーが同じTerraformの状態に取り組む場合、スケーリングが難しいです。その解決策は?バックエンドです。

状態ファイルをS3バケットに保存し、DynamoDBを使用してロック状態を管理することもできます。しかし、このアプローチは追加のリソースを作成する必要があり、特にクライアントがGitLabを使用している場合、複雑なオプションになります。最近、GitLabはTerraformを統合するためのハードルを下げ、Terraformの状態の保存と管理の方法、そしてCIの設定の簡単な方法を提供しました。

この記事では、Terraformの状態ファイルとは何か、それをGitLabに移行する方法、そしてCIパイプラインを設定する方法を説明します。リポジトリを訪れるにはこちらをご覧ください。

目次

  • Terraformの状態とは?
  • GitLabがTerraformの状態を管理するようにする方法
  • GitLabがIaCをCIパイプラインで実行するようにする方法
    • ボーナスヒント: Infracost
  • 結論

Terraformの状態とは?

Terraformは、コードで定義されたインフラストラクチャに関する情報を、stateファイルを介して記録します。JSON形式で書かれており、基本的にTerraformコードから作成された実際のリソースへのマッピングを記録します。以下は、terraform.tfstateの例です。主に、Terraformを実行するたびに、EC2インスタンスの最新の状態を取得し、Terraformの設定と比較して、どのような変更を適用する必要があるかを判断します:

 

{   
     "version": 4,    
     "terraform_version": "0.12.0",    
     "serial": 1,    
     "lineage": "1f2087f9-4b3c-1b66-65db-8b78faafc6fb",    
     "outputs": {},    
     "resources": [     
      {        
         "mode": "managed",        
         "type": "aws_instance",       
         "name": "example",       
         "provider": "provider.aws",       
         "instances": [         
           {           
             "schema_version": 1,           
             "attributes": {              
               "ami": "ami-0c55b159cbfafe1f0",             
               "availability_zone": "us-west-2a",             
               "id": "i-00a123a0accffffff",            
               "instance_state": "running",             
               "instance_type": "t2.micro",            
               "(...)": "(truncated)"           
            }         
          }       
        ]      
      }   
    ]  
 }

デフォルトでは、このterraform.tfstateは、Terraformファイル、計画、変更の適用を行っているローカルに保存されます。個人プロジェクトでテストを実行している場合は問題ありませんが、推奨される方法ではありません。以下が理由です:

  • 共有場所に保存: このstateファイルをローカルワークステーションにホストして他のエンジニアと協力する場合、状況は複雑になります。両方が最新のstateのバージョンを使用していることを確認する必要があり、同時にTerraform planやapplyを実行すると競合状態に陥る可能性があります。
  • 機密情報の保護: 生成されたstateファイルには暗号化キーやインフラストラクチャのパスワードが含まれることがあります。ただし、stateファイルはデフォルトでは暗号化されず、機密情報をプレーンテキストで保存するのは良くありません。
  • ロッキング: ほとんどのバージョン管理システムはロック機能をサポートしておらず、同じstateファイルに対して2人のチームメンバーが同時にTerraform applyを実行することを防げません。これが、stateファイルをソースコントロールで管理しない理由の一つです。

GitLabでTerraformステートを管理する方法

Terraformがクラウドインフラストラクチャのプロビジョニングの標準と見なされている中、GitLabは一年ほど前からTerraformステートの保存と管理方法を提供しています。そのため、最近GitLabを使用してIaCを管理し始めたことから、その移行プロセスを共有したいと思います。

この記事では、ローカルステートを使用しており、AWS S3バケットや他のバックエンドソリューションでステートを管理していることを前提とします。

まず、backend.tfをHTTPを使用するように変更する必要があります。

 

terraform {  
    backend "http" {} 
  }

次に、ターミナルで4つの変数を設定する必要があります。

1. PROJECT_ID: これは、リポジトリの「プロジェクト概要」ページに移動することで簡単に見つけることができます。

2. TF_USERNAME: リポジトリにアクセスできるGitLabのユーザー名。

3. TF_PASSWORD: GitLabユーザーから生成されたアクセストークン。

4. TF_ADDRESS: リモートステートバックエンドのURL。

 

PROJECT_ID="28450092"
TF_USERNAME="florianpialoux"
TF_PASSWORD="123456789"
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/aws-buckets"

これで、Terraformステートを以前の場所からGitLabに移動する移行コマンドを実行できます。以下のコマンドを使用してください。

 

  terraform init \  
    -migrate-state \  
    -backend-config=address=${TF_ADDRESS} \  
    -backend-config=lock_address=${TF_ADDRESS}/lock \ 
    -backend-config=unlock_address=${TF_ADDRESS}/lock \  
    -backend-config=username=${TF_USERNAME} \ 
    -backend-config=password=${TF_PASSWORD} \  
    -backend-config=lock_method=POST \ 
    -backend-config=unlock_method=DELETE \ 
    -backend-config=retry_wait_min=5

GitLabがステートファイルを管理を開始できるように、「はい」で確認を提供する必要があります。ローカルステートからGitLabへの例:


S3からGitLabへの例:

Now, you can navigate to Infrastructure > Terraform from the GitLab interface and see your state:

I noticed for some of the state files I had from S3 will be blank even after using the migrate-state command ran previously. In this case, you can run this:  

 
terraform state pull > aws-buckets.json

S3ステートからコンテンツをコピーしてプッシュを実行します。

 
terraform state push -lock=true aws-buckets.json

GitLabは、Terraform状態ファイルのバージョニングをサポートしていますが、WebUIを介して古いバージョンを表示/復元するには、GitLabプレミアムプランを使用している必要があります。そうでない場合、GraphQL API リクエストを行う必要があります。

GitLabでIaCをCIパイプライン経由で実行する方法

GitLabは、公式のTerraformバイナリの周りに薄いラッパースクリプトを提供するGitLab-Terraformを含むDockerイメージを提供しています。代わりに、Hashicorpの公式Dockerイメージを使用することもできます。GitLab Terraformイメージに関する詳細情報はこちらで入手できます。

Terraform applyジョブが実行されると、状態がいつ使用され、どのパイプラインで使用されたかを確認できます。

Learn more about what our gitlab-ci.yml looks like here. Below, are the variables that will need to be defined on the project level.

ボーナスチップ: Infracost

ご覧の通り、gitlab-ci.yamlにInfracostを追加しました。これにより、IaCに新しいリソースを定義するたびにコスト見積もりが表示され、クラウド請求に対するコントロールが強化されます。

結論

Terraformの状態とCIをGitLab上で実行することは、GitOpsのベストプラクティスに従う素晴らしい方法です。これらはIaC(Infrastructure as Code)の開発とデプロイに適した組み合わせです。ほとんどの方が既にGitLabをリポジトリに使用していることから、IaCを一つの場所にまとめ、GitLabが転送中および静止時の暗号化、バージョニング、状態のロックおよびアンロックをサポートすることでTerraformの状態を管理することがはるかに簡単になります。

Source:
https://dzone.com/articles/how-to-migrate-terraform-state-to-gitlab-cicd