【Azure】AI SearchをTerraformで構築する

2024/06/08に公開

AI SearchをTerraformで構築する

今回はAI SearchをTerraformで構築します。
AI SearchにServiceを作成するまでを本記事で行います。

前提

  • Azureへのアカウント作成済み
  • サブスクリプション作成済み

Azureでサービスプリンシパルを作成する

サービスプリンシパルを作成

Terraform実行用のサービスプリンシパルを作成します。
azure-cliを使ったCLIでの作成でも良いが、今回はAzureのGUIから作成。

サービスプリンシパルは[Microsoft Enta ID]の[アプリの登録]から作成するとのことです。(名前が違ってややこしい)
[Microsoft Enta ID] > 左メニュー[管理] > [アプリの登録]を選択
今回は以下の登録内容で既定のディレクトリのみとして登録します。

サービスプリンシパルのシークレットを作成

azure-cliからサービスプリンシパルを使用したリソース操作を行うためにシークレットを作成します。

[Microsoft Enta ID] > 左メニュー[管理] > [アプリの登録] > [すべてのアプリケーション]から作成したアプリケーションを選択
左側メニュー[証明書とシークレット] > [新しいクライアントシークレット]を選択し、有効期限を設定して作成します。(有効期限は無期限にはできないみたい)

ここで作成したシークレットの値はTerraform実行する際に使用します。

サービスプリンシパルへロールの割り当て

作成したサービスプリンシパルにはリソース作成用の権限が無いのでロールを割り当てます。
[サブスクリプション] > [アクセス制御(IAM)] > [ロールの割り当てを追加]を選択

共同作成者を割り当て

特権管理者ロールの共同作成者を選択し次へ
※ 共同作成者は権限が大きすぎるため実際に使用する際はカスタムロールを作成してください。

先ほど作成したサービスプリンシパルを選択し次へ

レビューと割り当てを選択し、共同管理者の割り当ては完了です。

閲覧者を割り当て

共同作成者の手順と同様に職務ロールの閲覧者を割り当てしてください。

Terraform

事前準備

azure-cliをインストールしていないならインストール

brew install azure-cli

環境変数をexport

azure-cliを使う際のアクセス制御はいくつかあるみたいだが、今回は環境変数にシークレットをexportします。

export ARM_SUBSCRIPTION_ID=XXXX
export ARM_TENANT_ID=XXXX
export ARM_CLIENT_ID=XXXX
export ARM_CLIENT_SECRET=XXXX

各値はazureサービスから以下を確認してください。
ARM_SUBSCRIPTION_ID: [サブスクリプション]のサブスクリプションIDを設定
ARM_TENANT_ID: [Microsoft Enta ID]の使用するディレクトリのテナントIDを設定
ARM_CLIENT_ID: [Microsoft Enta ID]で作成したサービスプリンシパルのクライアントIDを設定
ARM_CLIENT_SECRET: [Microsoft Enta ID]で作成したサービスプリンシパルの値を設定(シークレットIDでは無いので注意)

main.tf

実際には環境毎のmain.tfから使用されると思うのでvariableを定義しています。
今回はvariableのdefaultの値を使用していますが、環境に合わせてvariableに値を設定して使用してください。
※ 以下をそのままapplyした場合は

terraform {
  required_version = ">= 1.8.5"

  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">=3.107.0" # 執筆時点の最新バージョン
    }
  }
}

provider "azurerm" {
  features {}
}

variable "name" {
  type        = string
  description = "The name of the search service."
  default     = "azure-ai-search"
}

variable "location" {
  type        = string
  description = "Location for all resources."
  default     = "japaneast"
}

variable "sku" {
  type        = string
  description = "The pricing tier of the search service you want to create (for example, basic or standard)."
  default     = "free"
  validation {
    condition = contains([
      "free", "basic", "standard", "standard2", "standard3", "storage_optimized_l1", "storage_optimized_l2"
    ], var.sku)
    error_message = "The sku must be one of the following values: free, basic, standard, standard2, standard3, storage_optimized_l1, storage_optimized_l2."
  }
}

variable "replica_count" {
  type        = number
  description = "Replicas distribute search workloads across the service. You need at least two replicas to support high availability of query workloads (not applicable to the free tier)."
  default     = 1
  validation {
    condition     = var.replica_count >= 1 && var.replica_count <= 12
    error_message = "The replica_count must be between 1 and 12."
  }
}

variable "partition_count" {
  type        = number
  description = "Partitions allow for scaling of document count as well as faster indexing by sharding your index over multiple search units."
  default     = 1
  validation {
    condition     = contains([1, 2, 3, 4, 6, 12], var.partition_count)
    error_message = "The partition_count must be one of the following values: 1, 2, 3, 4, 6, 12."
  }
}

variable "semantics_search_sku" {
  type        = string
  description = "The pricing tier of the semantic search feature."
  default     = "free"
  validation {
    condition     = contains(["free", "standard"], var.semantics_search_sku)
    error_message = "The semantics_search_sku must be one of the following values: free, standard."
  }
}

resource "azurerm_resource_group" "rg" {
  name     = "${var.name}-resource-group"
  location = var.location
}

resource "azurerm_search_service" "search" {
  name                          = "${var.name}-search"
  resource_group_name           = azurerm_resource_group.rg.name
  location                      = azurerm_resource_group.rg.location
  sku                           = var.sku
  replica_count                 = var.replica_count
  partition_count               = var.partition_count
  public_network_access_enabled = true # 公開設定、プライベートネットワークで使用する場合はfalse
  # freeの場合はnullとしないとエラーになるため、条件分岐を追加
  semantic_search_sku           = var.sku != "free" ? var.semantics_search_sku : null
}

実行

  • init
terraform init
  • plan
terraform plan
  • apply
terraform apply

apply実行後にAI Searchが作成されていればOKです。

後片付け

terraformで作成したリソースは以下で削除

terraform destroy

サービスプリンシパルは手動で削除してください。

リポジトリ

https://github.com/i-shinya/azure_ai_search_terraform

参考

Discussion