LoginSignup
2
0

Terraform & Azure AppServiceでSonarQubeをホストする

Last updated at Posted at 2024-03-05

この記事について

携わっているプロジェクトで、SonarQubeをホストしたい場面がありました。
Terraformを使ってデプロイをするのに少しハマったため、備忘録として記事にしておきます。

目次

  1. 利用するサービスについて
  2. リソースの作成
  3. 最後に

利用するサービスについて

AppService

  • SonarQubeをホストする基盤として使用します
  • P0v3を使用しましたが、スムーズに動きました

ストレージアカウント

  • SonarQubeの設定値などを格納するために使用するストレージアカウントです
  • 開発用途で速度や可用性を重視していないため、StandardV2LRSを選択しました

Azure Cosmos DB for PostgreSQL Cluster

  • バックエンド用のSQLデータベースとして利用します
  • コストが安いことを理由に選定し、Burstable 1 vCore 2GiB RAMを使用しています
  • 初めは組み込みH2データベースを使用していましたが、SonarQubeのアップデート時にマイグレーションが難しかったため、ちゃんとしたSQLデータベースを導入しました

リソースの作成

AppServiceを動かすために必要なリソース

AppServiceを構築するために必要なリソースの定義です。

//リソースグループ
resource "azurerm_resource_group" "sonarqube" {
  name     = "rg-sonarqube"
  location = "japaneast"
}

//AppServicePlan
resource "azurerm_service_plan" "sonarqube" {
  name                = "plan-sonarqube"
  location            = azurerm_resource_group.sonarqube.location
  resource_group_name = azurerm_resource_group.sonarqube.name
  os_type             = "Linux"
  sku_name            = "P0v3"
  worker_count        = 1
}
  • リソースグループは説明不要ですね
  • AppServicePlanではSKUをP0v3、Worker Countを1で指定しています

ストレージアカウントとファイル共有

SonarQubeの設定情報などを格納するためのストレージ共有を作成します。パスはこちらを参考にしました

locals {
  sonarqube_storage_share = toset([
    "data",
    "logs",
    "extensions"
  ])
}

resource "azurerm_storage_account" "sonarqube" {
  name                     = "stsonarqubemntb92f" //名前被り防止で乱数を追加
  resource_group_name      = azurerm_resource_group.sonarqube.name
  location                 = azurerm_resource_group.sonarqube.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

resource "azurerm_storage_share" "sonarqube" {
  for_each             = local.sonarqube_storage_share
  name                 = each.key
  storage_account_name = azurerm_storage_account.sonarqube.name
  quota                = 10
}
  • ストレージアカウントのnameはAzure上で一意に指定しないといけないので適当な乱数を追加しておきます
  • local値で必要なファイル共有を定義してfor_eachを使って3つ作っています

データベースの作成

次に、SonarQubeのデータベースとしてAzure Cosmos DB for PostgreSQL Clusterを設定します。

resource "random_password" "postgre" {
  length  = 20
  special = false
}

resource "azurerm_cosmosdb_postgresql_cluster" "sonarqube" {
  name                                 = "pg-sonarqube"
  resource_group_name                  = azurerm_resource_group.sonarqube.name
  location                             = azurerm_resource_group.sonarqube.location
  administrator_login_password         = random_password.postgre.result
  coordinator_storage_quota_in_mb      = 32768
  coordinator_vcore_count              = 1
  node_count                           = 0
  coordinator_public_ip_access_enabled = true
  sql_version                          = 15
  coordinator_server_edition           = "BurstableGeneralPurpose"
  node_server_edition                  = "BurstableGeneralPurpose"
}

data "azapi_resource" "cosmosdb_cl" {
  type                   = "Microsoft.DBforPostgreSQL/serverGroupsv2@2022-11-08"
  resource_id            = azurerm_cosmosdb_postgresql_cluster.sonarqube.id
  response_export_values = ["*"]
}
  • パスワードを考えたくないのでrandom_passwordを使用して、DB接続用のパスワード生成しています。
  • CosmosDB PostgreSQL Clusterは最小限の設定で構築しています。
  • ここで使用しているazurerm_cosmosdb_postgresql_clusterのAttributes ReferenceにはDBの接続用のエンドポイントが含まれていないんです。これで少しハマりました。
    • azapi_resourceのdataソースを使用して、エンドポイントを取得する方法を取りました
    • このdataソースを使用すると、リソースの情報がJSONで取得できるため、jsondecode関数を用いて、エンドポイントのFQDNを取り出せます
 ${jsondecode(data.azapi_resource.cosmosdb_cl.output).properties.serverNames[0].fullyQualifiedDomainName

AppServiceの作成

最後にSonarQubeを稼働させるAppServiceを作成します

resource "azurerm_linux_web_app" "sonarqube" {
 name                = "ase-sonarqube-b92f" //名前被り防止で乱数を追加
 location            = azurerm_resource_group.sonarqube.location
 resource_group_name = azurerm_resource_group.sonarqube.name
 service_plan_id     = azurerm_service_plan.sonarqube.id
 https_only          = true
 dynamic "storage_account" {
   for_each = local.sonarqube_storage_share
   content {
     name         = storage_account.key
     type         = "AzureFiles"
     account_name = azurerm_storage_account.sonarqube.name
     share_name   = storage_account.key
     access_key   = azurerm_storage_account.sonarqube.primary_access_key
     mount_path   = "/opt/sonarqube/${storage_account.key}"
   }
 }
 site_config {
   application_stack {
     docker_image_name   = "sonarqube:9.9-community"
     docker_registry_url = "https://index.docker.io"
   }
 }
 app_settings = merge({ for k in local.sonarqube_storage_share : "sonarqube_${k}" => "/opt/sonarqube/${k}" }, {
   SONAR_JDBC_URL                    = "jdbc:postgresql://${jsondecode(data.azapi_resource.cosmosdb_cl.output).properties.serverNames[0].fullyQualifiedDomainName}:5432/citus?user=citus&password=${random_password.DB.result}"
   SONAR_JDBC_USERNAME               = "citus"
   SONARQUBE_JDBC_PASSWORD           = random_password.DB.result
   SONAR_ES_BOOTSTRAP_CHECKS_DISABLE = true
 })
}
  • ストレージアカウントと同様、Azure上で一意にするためnameに乱数を含めています
  • ストレージ共有をマウントする箇所はdynamicブロックを使用してストレージ共有3つをマウントしています
  • site_configapplication_stackで適用したいコンテナイメージを指定できますhttps://hub.docker.com/_/sonarqubeで現在公開されているイメージが確認できます
  • app_settingsでは環境変数を設定します
    • ストレージ共有のパスはfor文で書きました。これは以下のように展開されます
      > { for k in local.sonarqube_storage_share : "sonarqube_${k}" => "/opt/sonarqube/${k}" }
      {
        "sonarqube_data"       = "/opt/sonarqube/data"
        "sonarqube_log"        = "/opt/sonarqube/log"
        "sonarqube_extensions" = "/opt/sonarqube/extensions"
      }
      
    • その他の値は事前に作成したPostgreSQLの設定値です
    • 上記の設定値をmerge関数を使用してTerraformに渡しています

最後に

これでデプロイが完了し、AppServiceのURLにアクセスするとSonarQubeが起動し、初期設定が可能です。SonarQubeの設定方法については公式ドキュメントや他の記事を参照することをお勧めします。適宜利用用途に合わせて設定値を見直していただければと思います。お役に立てれば幸いです。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0