初めてのAlibaba CloudリソースをTerraformで構築する


この記事で書くこと

先日AlibabaCloudにリソースを構築する機会があったのですが
普段はAlibabaCloudもTerraformもあまり使ったことがなかったため、リソース構築をするまでに行ったことについてまとめます。

Alibaba Cloudでリソースを構築する際に行ったこと

STEP1: 使うIaCツールを決める

社内的にIaCが推奨で、AWS上のリソースはCloudFormationを用いて管理・運用しているため
今回AlibabaCloudもリソースはコードで定義し、最終的には構築も自動化することを前提としました。

いくつか選択肢はあるようなのですが今回比較したのは2つです。
1つはチームで利用しているTerraform、もう1つはAlibaba CloudのサービスであるResource Orchestration Service(ROS)です。

▼Terraform
Alibaba Cloud Provider

▼ROS
Resource Orchestration Service

ROSはAWSのCloudFormationと同じような概念のサービスで、テンプレートを元にスタックを作成し、リソースを構築・管理することができます。

非常にざっくりですが、TerraformとROSを比較してみました。(2021/2時点)

判断軸にするか 項目 ROS Terraform
- ファイル言語 JSON、YAML HCL
WANT サポートしているリソースの数 64 64
MUST プログラムで操作可能か CLIで操作可能 CLIで操作可能
MUST 変更差分を確認できるか できる できる

変更差分の確認等、もう少し細かく見ていくと違いが出てくるかもしれないですが
おおよそはほぼ変わらない印象でした。

直近チームではTerraformを用いて業務で利用している各種ツール(ex.Datadog,PagerDuty)の設定コード化を進めているという背景があり、技術スタックを統一できるという点が魅力的だったため、今回はTerraformを採用することにしました。

STEP2: Terraformのファイル構成を考える

色々なやり方があると思うのですが、今回は以下のような形で試してみています。

$ tree
.
└── terraform
    └── alibaba
        ├── README.md
        ├── main.tf //AlibabaCloudのリソースを定義
        ├── staging
        │   ├── backend.tf //バックエンドを指定
        │   └── terraform.tfvars //variables.tfで定義した変数の値を指定
        └── variables.tf //利用する変数を定義

構築するリソースは多くないため、全てmain.tfに記述していくことを想定をしています。

STEP3: Terraform用のユーザ作成

AWSでCLIからスタック操作を行う際にIAMユーザを作成しクレデンシャル等を用意しますが、
この辺はAlibaba Cloudも同様でした。

https://registry.terraform.io/providers/aliyun/alicloud/latest/docs#testing)

Alibaba CloudではユーザIDの管理やそのアクセス制限を行うResource Access Management(RAM)というサービスがあるため、こちらを利用します。

RAM の概要

ユーザはRAMユーザ、権限付与はRAMポリシーをユーザに紐付けるといった形で提供されており、
その他にもRAMロールやユーザを束ねるグループも提供されているため、こちらもAWSのIAMとおおよそ同じような概念かと思います。

terraformを実行するのに必要なので、以下のような形でwebコンソールからユーザ(RAMユーザ)を作成しました。

プログラムによるアクセスでユーザを作成するとアクセスキーが発行されるため、控えておきます。

また、ユーザが作成された後にAdd Peremissionsから権限を追加します。

Add Permissionsから開くと以下のような画面が表示されるので
利用したいポリシー等を設定します。

ポリシーはAlibaba Cloudがマネージドで用意しているSystem Policyと自分で用意するCustom Policy、どちらも利用可能でした。

※(Terraformの話とはずれますが)今回エンジニア等開発者のAlibaba Cloudへのログイン環境はSSOで用意するため、それぞれのRAMユーザは作成していませんが、そうでない場合は個別にRAMユーザを作成し、ルートユーザは使わないのが良いかと思います。

STEP4: Terraform実行に必要な環境変数を設定する

先程作成したユーザの認証情報を環境変数に設定します。

ALICLOUD_ACCESS_KEY=STEP2で作成したアクセスキーを設定
ALICLOUD_SECRET_KEY=STEP2で作成したシークレットキーを設定
ALICLOUD_REGION=リソースを構築したいリージョンのID

STEP5: tfstateファイルを管理するリモートバックエンドを用意する

tfstateファイルはterraformが管理しているリソースの現在の状態を表すファイルです。
Terraform planを実行すると、Terraformはtfstateファイルと.tfファイルの内容を比較し、差分を出力します。

このtfstateの保管先等はバックエンドと呼ばれるリソースで管理するのですが、別段設定をしないままだとバックエンドはローカルになり、tfstateもローカルに保存され、読み込まれます。

CIツールと連携させたり、複数人がTerraformの実行を行う場合はローカルだと不便なので
リモートバックエンドを用意して共有できる状態を作るのですが、今回はバックエンドにAlibaba CloudのObject Storage Service(OSS)を利用することにしました。

webコンソールから作成する場合は、必要事項を選択して作成するのですが
AWSのs3と同じような設定項目が設けられていることがわかります。

また、OSSの名前はs3同様にOSS全体でユニークである必要がありました。

STEP6. リソースを構築する

main.tfファイルに構築したいリソースを記述し

main.tf
terraform {
  required_version = "= 0.14.5"

  backend "oss" {
  }

  required_providers {
    alicloud = {
      source  = "aliyun/alicloud"
      version = "1.114.1"
    }
  }
}

resource "alicloud_ram_user" "hoge" {
  name         = "hoge"
  display_name = "hoge"
}

以下のコマンドで確認・反映を行いました。

# 実行内容を確認する
$ terraform plan -var-file='terraform/alibaba/staging/terraform.tfvars' terraform/alibaba

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # alicloud_ram_user.hoge will be created
  + resource "alicloud_ram_user" "hoge" {
      + display_name = "hoge"
      + force        = false
      + id           = (known after apply)
      + name         = "hoge"
    }

Plan: 1 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

# applyする
$ terraform plan -var-file='terraform/alibaba/staging/terraform.tfvars' terraform/alibaba

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:

Terraform will perform the following actions:

  # alicloud_ram_user.hoge will be created
  + resource "alicloud_ram_user" "hoge" {
      + display_name = "hoge"
      + force        = false
      + id           = (known after apply)
      + name         = "hoge"
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

alicloud_ram_user.hoge: Modifying... [id=xxxxxxxx]
alicloud_ram_user.hoge: Modifications complete after 4s [id=xxxxxxxx]

Q. リモートバックエンドのOSSをTerraformで管理できるか

先程webコンソールから作成したOSSですが、Terraformで作成した後にbackendに指定すれば
コード管理できるのではないか?と思ったので試してみました。

1. main.tfでOSSを作る

main.tf
terraform {
  required_version = "= 0.14.5"

  backend "oss" {
  }

  required_providers {
    alicloud = {
      source  = "aliyun/alicloud"
      version = "1.114.1"
    }
  }
}

resource "alicloud_oss_bucket" "infra" {
  bucket        = "infra"
  acl           = "private"
  storage_class = "Standard"
  versioning {
    status = "Enabled"
  }
}

backendがローカルな状態で先述のterraform plan&applyを実行し、
OSSが用意できたらローカルに作成されたtfstateファイルをOSSにアップロードします。

2. OSSが用意できたらbackendを再設定する

backend.tfファイルを用意し

staging/backend.tf
bucket = "infra"
region = "利用したいリージョンのID"
prefix = "terraform/alibaba/" #tfstateファイルをアップロードしたOSSのパス
key    = "terraform.tfstate"  

以下コマンドでbackendを再設定することで、今回作成したOSSがバックエンドとして設定されました。

$ terraform init -reconfigure -backend-config='terraform/alibaba/staging/backend.tf' terraform/alibaba

Initializing the backend...

Successfully configured the backend "oss"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Reusing previous version of aliyun/alicloud from the dependency lock file
- Installing aliyun/alicloud v1.114.1...
- Installed aliyun/alicloud v1.114.1 (signed by a HashiCorp partner, key ID xxxxxxxxxxxxxxx)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/plugins/signing.html

Terraform has been successfully initialized!

できるにはできるのですが、シンプルな手順ではないので
割り切ってWebコンソールから作る、というのも1つの手なのではないかと思いました。
(やってから気づいたのですが、Terraform Importを使う方が簡単だったかもしれません...)

まとめ

  • 困ったこと
    • RAMユーザやリモートバックエンドとしてのOSSの構成管理をどうするか
      • terraformの実行に必要で卵が先か鶏が先か状態になる
  • わかったこと
    • Alibaba Cloudでも構成管理を行うROSというサービスが提供されていた
    • terraform実行に利用するOSSやRAMユーザをコード管理したい場合はwebコンソールから作成後Terraform Importを使うのが良さそう