【Terraform de Azure】 Azure Database for MySQL を Single構成で作成してみました

### 概要

「Infrastructure as Code」ということで、Terraform を用いて Azure Database for MySQL をシングル構成で作成し、mysqlコマンドで Database に接続してみます。


### ローカル環境

- macOS Monterey 12.3
- python 3.8.12
- Azure CLI 2.34.1
- terraform v1.0.11
- mysql Ver 8.0.28 for macos12.2 on x86_64 (Homebrew)

### 前提条件

1. Azure環境がすでに用意されていること（テナント/サブスクリプション）
2. ローカル環境に「azure cli」がインストールされていること
3. ローカル環境に「terraform」環境が構成されていること
4. ローカル環境に「mysql」がインストールされていること
5. TerraformでAzure上に環境構築するための[サービスプリンシパルが作成](https://qiita.com/turupon/items/5d024d43a60cd101be94)されており、Terraform のためのローカル環境変数が定義されていること

### 事前準備

ローカル環境からインターネットアクセス時に自動割当されているグローバルアドレスの取得

```
## 利用グローバルアドレスの取得（接続元アドレス）
$ curl inet-ip.info
155.123.22.111
```

---

## Azure Database for MySQL を  シングル構成で作成してみる

### terraform 定義ファイルの作成

プロバイダの定義

```main.tf
# プロバイダーの定義
terraform {
  required_providers {
    azurerm =  "~> 2.33"
  }
}

provider "azurerm" {
  features {}
  tenant_id     = var.ARM_TENANT_ID
  client_id     = var.ARM_CLIENT_ID
  client_secret = var.ARM_CLIENT_SECRET
}


# リソースグループ
resource "azurerm_resource_group" "this" {
  name     = var.resource_group_name
  location = var.region
  tags     = var.tags_def
}
```

パラメータ定義ファイル

```variables.tf
# 環境変数（Azureサービスプリンシパル）
variable ARM_TENANT_ID {}
variable ARM_CLIENT_ID {}
variable ARM_CLIENT_SECRET {}

# タグ情報
variable tags_def {
  default = {
    owner      = "ituru"
    period     = "2022-04-28"
    CostCenter = "PSG2"
    Environment = "Demo"
  }
}

# 各種パラメータ
variable region {}                  // 利用リージョン
variable resource_group_name {}     // リソースグループ名

variable mysql_name {}              // MySQLサーバ名
variable mysql_db_name {}           // MySQLデータベース名
variable mysql_admin {}             // MySQL管理者名
variable mysql_admin_pass {}        // MySQL管理者パスワード
variable mysql_fw_rule01 {}         // Firewallルール名_01
variable home_tokyo_ip {}           // 東京宅のIPアドレス

```

パラメータ値定義ファイル

```terraform.tfvars
# 環境変数の定義（Azureサービスプリンシパル）
ARM_TENANT_ID       = "zzzzzzzz-cccc-4645-5757-zzzzzzzzzzzz"
ARM_CLIENT_ID       = "xxxxxxxx-xxxx-4444-9922-xxxxxxxxxxxx"
ARM_CLIENT_SECRET   = "hogehogehogehogehogehogehogehogege"

# パラメータ値の定義
region                = "japaneast"           // 利用リージョン
resource_group_name   = "rg_ituru_mysql01"    // リソースグループ名
mysql_name            = "iturumysql01"        // MySQL名
mysql_db_name         = "iotdummydb"          // データベース名
mysql_admin           = "adminadmin"          // MySql管理者名
mysql_admin_pass      = "HogeHogeHoge!"       // MySql管理者パスワード
mysql_fw_rule01       = "Home_Tokyo"          // Firewallルール名_01
home_tokyo_ip         = "155.123.22.111"      // 東京宅のIPアドレス
```

MySQL 定義ファイル

```mysql.tf
# MySQL Server
resource "azurerm_mysql_server" "this" {
  name                = var.mysql_name
  location            = azurerm_resource_group.this.location
  resource_group_name = azurerm_resource_group.this.name
  tags                = var.tags_def

  administrator_login          = var.mysql_admin
  administrator_login_password = var.mysql_admin_pass

  sku_name   = "B_Gen5_2"
  storage_mb = 51200
  version    = "8.0"

  auto_grow_enabled                 = true
  backup_retention_days             = 7
  geo_redundant_backup_enabled      = false
  infrastructure_encryption_enabled = false
  public_network_access_enabled     = true
  ssl_enforcement_enabled           = true
  ssl_minimal_tls_version_enforced  = "TLSEnforcementDisabled"
}

# MySQL Database
resource "azurerm_mysql_database" "example" {
  name                = var.mysql_db_name
  resource_group_name = azurerm_resource_group.this.name
  server_name         = azurerm_mysql_server.this.name
  charset             = "utf8mb4"
  collation           = "utf8mb4_general_ci"
}

# Manages a Firewall Rule for a MySQL Server
resource "azurerm_mysql_firewall_rule" "this" {
  name                = var.mysql_fw_rule01
  resource_group_name = azurerm_resource_group.this.name
  server_name         = azurerm_mysql_server.this.name
  start_ip_address    = var.home_tokyo_ip
  end_ip_address      = var.home_tokyo_ip
}
```

### terraform の実行

```
## init
$ terraform init
    :
Terraform has been successfully initialized!

## plan
$ terraform plan
    :
Plan: 4 to add, 0 to change, 0 to destroy.

## apply
$ terraform apply
    :
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

```

### ローカルの作業ディレクトの状況

```
$ tree -a
.
├── .terraform
│   └── providers
│       └── registry.terraform.io
│           └── hashicorp
│               └── azurerm
│                   └── 2.99.0
│                       └── darwin_amd64
│                           └── terraform-provider-azurerm_v2.99.0_x5
├── .terraform.lock.hcl
├── main.tf
├── mysql.tf
├── terraform.tfstate
├── terraform.tfstate.backup
├── terraform.tfvars
└── variables.tf
```

---

## terraform 実行後の確認

### Azure CLI からの確認

```
## 作成先サブスクリプションへの接続
$ az account set --subscription '<Subscription_Name>'

## 作成したMySQLサーバの詳細表示
$ az mysql server show --resource-group rg_ituru_mysql01 --name iturumysql01 
{
  "administratorLogin": "adminadmin",
  "byokEnforcement": "Disabled",
  "earliestRestoreDate": "2022-03-30T14:31:28.173000+00:00",
  "fullyQualifiedDomainName": "iturumysql01.mysql.database.azure.com",
  "id": "/subscriptions/xxxxxxxx-1717-dada-9779-zzzzzzzzzzzz/resourceGroups/rg_ituru_mysql01/providers/Microsoft.DBforMySQL/servers/iturumysql01",
  "identity": null,
  "infrastructureEncryption": "Disabled",
  "location": "japaneast",
  "masterServerId": "",
  "minimalTlsVersion": "TLSEnforcementDisabled",
  "name": "iturumysql01",
  "privateEndpointConnections": [],
  "publicNetworkAccess": "Enabled",
  "replicaCapacity": 5,
  "replicationRole": "None",
  "resourceGroup": "rg_ituru_mysql01",
  "sku": {
    "capacity": 2,
    "family": "Gen5",
    "name": "B_Gen5_2",
    "size": null,
    "tier": "Basic"
  },
  "sslEnforcement": "Enabled",
  "storageProfile": {
    "backupRetentionDays": 7,
    "geoRedundantBackup": "Disabled",
    "storageAutogrow": "Enabled",
    "storageMb": 51200
  },
  "tags": {
    "CostCenter": "psg2",
    "Environment": "Demo",
    "owner": "ituru",
    "period": "2022-04-28"
  },
  "type": "Microsoft.DBforMySQL/servers",
  "userVisibleState": "Ready",
  "version": "8.0"
}

## Fireallルール一覧表示
$ az mysql server firewall-rule list --resource-group rg_ituru_mysql01 --server-name iturumysql01
[
  {
    "endIpAddress": "155.123.22.111",
    "id": "/subscriptions/xxxxxxxx-1717-dada-9779-zzzzzzzzzzzz/resourceGroups/rg_ituru_mysql01/providers/Microsoft.DBforMySQL/servers/iturumysql01/firewallRules/Home_Tokyo",
    "name": "Home_Tokyo",
    "resourceGroup": "rg_ituru_mysql01",
    "startIpAddress": "155.123.22.111",
    "type": "Microsoft.DBforMySQL/servers/firewallRules"
  }
]
```

### MySQLサーバへの接続

```
$ mysql --host=iturumysql01.mysql.database.azure.com --user=adminadmin@iturumysql01 -p
Enter password: [HogeHogeHoge!]
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 62991
Server version: 5.6.47.0 Source distribution

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```

#### データベースの確認

```
mysql> select SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME from INFORMATION_SCHEMA.SCHEMATA where SCHEMA_NAME = 'iotdummydb';
+-------------+----------------------------+------------------------+
| SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME |
+-------------+----------------------------+------------------------+
| iotdummydb  | utf8mb4                    | utf8mb4_general_ci     |
+-------------+----------------------------+------------------------+
1 row in set (0.03 sec)
```

#### データベースの利用とステータス確認

```
mysql> use iotdummydb;
Database changed

mysql> status
--------------
mysql  Ver 8.0.28 for macos12.2 on x86_64 (Homebrew)

Connection id:		63213
Current database:	iotdummydb
Current user:		adminadmin@155.123.22.111
SSL:			Cipher in use is ECDHE-RSA-AES256-GCM-SHA384
Current pager:		lv -c
Using outfile:		''
Using delimiter:	;
Server version:		5.6.47.0 Source distribution
Protocol version:	10
Connection:		iturumysql01.mysql.database.azure.com via TCP/IP
Server characterset:	latin1
Db     characterset:	utf8
Client characterset:	utf8mb4
Conn.  characterset:	utf8mb4
TCP port:		3306
Binary data as:		Hexadecimal
Uptime:			18 min 43 sec

Threads: 12  Questions: 503  Slow queries: 0  Opens: 198  Flush tables: 4  Open tables: 44  Queries per second avg: 0.447
--------------

## 切断
mysql> quit
Bye
```

### その他

#### MySQLサーバの制御

```
## 実行中のサーバーの停止
$ az mysql server stop --resource-group rg_ituru_mysql01 --name iturumysql01

## 停止中のサーバーの起動
$ az mysql server start --resource-group rg_ituru_mysql01 --name iturumysql01

## 実行中のサーバーの再起動
$ az mysql server restart --resource-group rg_ituru_mysql01 --name iturumysql01
```

#### 作成したリソースの削除

```
## destroy
$ terraform destroy
```

---

### まとめ

これで、Terraform でサクッと Azure環境上に Azure Database for MySQL をシングル構成で作成できました。 Azure Portal や Azure CLI で構築するのもいいですが、IaC化もいいですね。


### 参考記事

以下の記事を参考にさせていただきました。感謝申し上げます。
[Azure Database for MySQL での Azure AD 利用方法](https://qiita.com/Atsuki_Sumita/items/b4b06c745b92efd07bcb)
[MySQLをMacのターミナルで操作するときのメモ](https://qiita.com/nanatsu/items/33b57238b0e9ae0a1c78)