Terraformで既存のリソースを使ってデプロイする方法
今回の作業では、既存のリソースを基にして、新たなリソースをTerraformを使ってデプロイしていきます。
今回のソースはこちらで作成しました。
https://github.com/xiaotiantakumi/azure-terraform-templates/tree/azure-insights-to-functions
実際の運用でありそうな、リソースを既にあるApplication Insightを利用して新規作成するFunctionsのログを収集します。
既存のリソースは以下です。
- リソースグループ
- アプリケーションインサイト
- tfstateを保持するstorage
新規に作成されるリソースは以下です。
- Azure Function AppのLinuxバージョンを作成
- Azure App Serviceプランを作成
- Azure Storageアカウントを作成
tfstateの設定をAzure Storageに保持するように設定する
これまではtfstateファイルをローカルに出力していましたが、今後はAzure Storageのblobコンテナーに保存するよう変更します。
やり方については、下記に記載されています。
以下のように既にあるストレージアカウントにtfstate用のアカウントを作成しました。
私の設定は次のようになっています。
# Azure Provider source and version being used
terraform {
required_version = ">= 1.3.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.57.0"
}
azapi = {
source = "azure/azapi"
version = "~> 1.6.0"
}
random = {
source = "hashicorp/random"
version = "~>3.0"
}
tls = {
source = "hashicorp/tls"
version = "~>4.0"
}
}
backend "azurerm" {
resource_group_name = "tfstate"
storage_account_name = "saxiaotianprincipal"
container_name = "tfstate"
key = "terraform.tfstate"
}
}
provider "azurerm" {
features {}
}
provider "azapi" {
}
ストレージアカウントへ接続するための設定
Terraformの状態をAzure Storageに格納するためには、以下のスクリプトを実行する必要があります。このスクリプトは、必要なリソースグループ、ストレージアカウント、およびblobコンテナを作成し、その後、ストレージアカウントのアクセスキーを環境変数に設定します。
init.sh
#!/bin/bash
RESOURCE_GROUP_NAME=rg-sa-sample
STORAGE_ACCOUNT_NAME=saxiaotianprincipal
CONTAINER_NAME=tfstate
# Create resource group
# az group create --name $RESOURCE_GROUP_NAME --location eastus
# Create storage account
# az storage account create --resource-group $RESOURCE_GROUP_NAME --name $STORAGE_ACCOUNT_NAME --sku Standard_LRS --encryption-services blob
# Create blob container
# az storage container create --name $CONTAINER_NAME --account-name $STORAGE_ACCOUNT_NAME
# Retrieve and export the storage account key
ACCOUNT_KEY=$(az storage account keys list --resource-group $RESOURCE_GROUP_NAME --account-name $STORAGE_ACCOUNT_NAME --query '[0].value' -o tsv)
export ARM_ACCESS_KEY=$ACCOUNT_KEY
echo ARM_ACCESS_KEY=$ACCOUNT_KEY
terraform initする前に流してください。
source init.sh
設定にもかかわらずTerraformがストレージアカウントにアクセスできない場合、ストレージアカウントのネットワーク設定を確認することが重要です。特に、以下の設定が影響を与える可能性があります。
- パブリック ネットワーク アクセス: この設定を「すべてのネットワークから有効」にすると、どのネットワークからでもストレージアカウントへのアクセスが可能になります。セキュリティ上の理由から、制限が必要な場合は「選択した仮想ネットワークとIPアドレスから有効」を選択してください。完全に無効にすると、Terraformからのアクセスもできなくなるので注意が必要です。
- アクセス制御: ストレージアカウントに対するアクセス権を持つユーザーやサービスを確認し、Terraformが実行される環境からのアクセスが許可されている
ことを確認してください。アクセス権が不足していると、Terraformはストレージアカウントにアクセスできないため、適切な権限が与えられているかを検証することが重要です。
追加のチェックポイント
- ファイアウォールとネットワークルールの設定: ストレージアカウントにアクセスするためのファイアウォール設定とネットワークルールが正しく設定されているかを確認してください。不適切な設定は、Terraformからのアクセスを妨げる可能性があります。
- 接続のテスト: ストレージアカウントへの接続をテストすることで、ネットワーク問題が原因でないことを確認できます。これは、Terraformの問題とネットワークの問題を区別するのに役立ちます。
Application InsightsをPortalから作成
既存リソースを利用すると述べましたが、実はまだApplication Insightsを作成していなかったので、これを新たに作成します。
現状のリソースの状態
下記のように、既存リソースがあります。
既存リソースを利用するにはdataを利用する
今回、main.tfは以下のようになります。
locals {
tags = {
product = var.prefix
environment = var.environment
}
}
data "azurerm_resource_group" "rg" {
name = var.resource_group_name
}
data "azurerm_application_insights" "app_insights" {
name = var.app_insights_name
resource_group_name = var.resource_group_name
}
module "functions" {
source = "./modules/functions"
location = var.default_region
resource_group_name = var.resource_group_name
tags = local.tags
application_insights_connection_string = data.azurerm_application_insights.app_insights.connection_string
application_insights_key = data.azurerm_application_insights.app_insights.instrumentation_key
}
Terraformのdata
ブロックは、既存のインフラストラクチャリソースに関する情報を参照するために使用されます。これにより、既に作成されているリソースのデータを読み込み、その情報を他のTerraform構成の部分で使用することができます。data
ブロックは、新しいリソースを作成するのではなく、既存のリソースから情報を取得するために使用される点が重要です。
このケースでは、azurerm_resource_group
とazurerm_application_insights
の2つのデータソースが使用されています。これらのブロックは、特定のリソースグループとアプリケーションインサイトのリソースの詳細を取得するために使われています。例えば、azurerm_application_insights
データソースは、指定されたアプリケーションインサイトのconnection_stringとinstrumentation_key
のような情報に利用しています。
この機能を使用することで、既存のリソースに対するハードコーディングや不必要な重複を避けることができ、モジュラリティと再利用性を高めることができます。特に、複数の環境やモジュール間で共有されるリソースの情報を一元管理する場合に有効です。
Functionsの作成について
Azure Functionsは下記を参考にしました。
上記を見ていると、Insightに関連する設定について下記が必要ということがわかります。
application_insights_connection_string
– (Optional) The Connection String for linking the Linux Function App to Application Insights.application_insights_key
– (Optional) The Instrumentation Key for connecting the Linux Function App to Application Insights.
terraformのコードについて
このプロジェクトでは、Azure Function Appのデプロイに必要なリソースを以下のTerraformファイルで管理しています。
- /modules/functions/output.tf
- /modules/functions/main.tf
- /modules/functions/variables.tf
- output.tf: デプロイされたリソースの情報を出力する設定です。ここでは、Storage Account、App Service Plan、Function Appの各ID、名前、主要な接続文字列などの重要な情報を出力します。これにより、デプロイ後のリソース管理が容易になります。
- main.tf: Function App、Storage Account、およびService Planを定義しています。ここにはリソースの実際の定義が含まれています。
azurerm_storage_account
でStorage Accountを、azurerm_service_plan
でApp Service Planを、そしてazurerm_linux_function_app
でFunction App自体を作成します。これらは、リソースの名前、場所、および必要な設定で構成されています。 - variables.tf: リソースの構成に使用する変数を定義しています。デプロイするリソースの構成をカスタマイズするための変数が定義されています。これには、リソースの場所、名前、タグなどの情報が含まれます。これらの変数を使用することで、様々な環境や要件に応じたリソースのデプロイが可能になります。
azure-terraform-templates/terraform/modules/functions/output.tf
# storage account
output "storage_account_id" {
description = "The ID of the Storage Account."
value = azurerm_storage_account.az_storage.id
}
output "storage_account_name" {
description = "The name of the Storage Account."
value = azurerm_storage_account.az_storage.name
}
output "storage_account_primary_access_key" {
description = "The primary access key for the Storage Account."
value = azurerm_storage_account.az_storage.primary_access_key
}
output "storage_account_primary_connection_string" {
description = "The primary connection string for the Storage Account."
value = azurerm_storage_account.az_storage.primary_connection_string
}
# azurerm service plan
output "service_plan_id" {
description = "The ID of the App Service Plan."
value = azurerm_service_plan.az_service_plan.id
}
output "service_plan_name" {
description = "The name of the App Service Plan."
value = azurerm_service_plan.az_service_plan.name
}
# azurerm function app
output "function_app_id" {
description = "The ID of the Function App."
value = azurerm_linux_function_app.az_func.id
}
output "function_app_name" {
description = "The name of the Function App."
value = azurerm_linux_function_app.az_func.name
}
output "function_app_default_hostname" {
description = "The default hostname of the Function App."
value = azurerm_linux_function_app.az_func.default_hostname
}
azure-terraform-templates/terraform/modules/functions/main.tf
provider "azurerm" {
features {}
}
resource "azurerm_storage_account" "az_storage" {
name = var.storage_account_name
resource_group_name = var.resource_group_name
location = var.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_service_plan" "az_service_plan" {
name = "app-service-plan"
resource_group_name = var.resource_group_name
location = var.location
os_type = "Linux"
sku_name = "Y1"
}
resource "azurerm_linux_function_app" "az_func" {
name = var.storage_account_name
resource_group_name = var.resource_group_name
location = var.location
storage_account_name = azurerm_storage_account.az_storage.name
storage_account_access_key = azurerm_storage_account.az_storage.primary_access_key
service_plan_id = azurerm_service_plan.az_service_plan.id
# insight
# application_insights_connection_string = var.application_insights_connection_string
# application_insights_key = var.application_insights_key
app_settings = {
"APPINSIGHTS_INSTRUMENTATIONKEY" = var.application_insights_key
"APPINSIGHTS_CONNECTION_STRING" = var.application_insights_connection_string
}
site_config {}
}
azure-terraform-templates/terraform/modules/functions/variables.tf
variable "location" {
default = "japaneast"
description = "The Azure location to provision the resource in"
type = string
}
variable "resource_group_name" {
description = "The name for the resource group"
type = string
}
variable "tags" {
default = {}
description = "The tags to include for each of the provisioned resources"
type = map(string)
}
variable "function_name" {
description = "The name for the function app"
type = string
default = "func-xiaotian-dev-001"
}
variable "storage_account_name" {
description = "The name for the storage account"
type = string
default = "staxiaotiandev001"
}
variable "application_insights_connection_string" {
description = "The connection string for the application insights instance"
type = string
}
variable "application_insights_key" {
description = "The key for the application insights instance"
type = string
}
outputについての注意点
Terraformでは、モジュール内で定義された出力変数は、そのモジュールを使用している親のTerraform構成で明示的に出力されない限り、ルートレベルで直接表示されません。つまり、modules/functions/output.tf
で定義された出力変数をルートレベルで表示するには、それらを親のTerraform構成(通常はルートモジュール)で参照し、新たな出力変数として定義する必要があります。
modules/functions/output.tf
に定義された出力変数をルートレベルで表示するには、以下の手順を踏みます。
- モジュールの出力を参照する: モジュール内で定義された出力変数を、親Terraform構成で明示的に参照します。たとえば、
module.functions.storage_account_id
のようにしてモジュールの出力変数を指定します。 - 新たな出力変数として定義する: 参照したモジュールの出力変数を、親構成の新たな
output
ブロックで再定義します。これにより、その値はルートレベルの出力として利用可能になります。
下記のようになります。
output "storage_account_id" {
description = "The ID of the Storage Account."
value = module.functions.storage_account_id
}
sensitive
プロパティに注意
output
ブロックにsensitive
プロパティを指定することも重要です。これは、出力される情報が機密性の高いデータ(例えばアクセスキーなど)である場合に使用します。このプロパティがtrue
に設定されていると、その出力値はTerraformのUIやログに表示されなくなります。
output "storage_account_primary_access_key" {
description = "The primary access key for the Storage Account."
value = module.functions.storage_account_primary_access_key
sensitive = true
}
output "storage_account_primary_connection_string" {
description = "The primary connection string for the Storage Account."
value = module.functions.storage_account_primary_connection_string
sensitive = true
}
ディスカッション
コメント一覧
まだ、コメントがありません