AzureMysqlサーバのprimaryとreplicaを作ります。
また接続できる踏み台VMを一つ作ります。
main.tf
terraform {
required_version = ">= 1.6.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">=3.116.0"
}
random = {
source = "hashicorp/random"
version = ">=3.5.0"
}
}
}
provider "azurerm" {
features {
resource_group {
prevent_deletion_if_contains_resources = false
}
}
subscription_id = ""
}
# ランダム文字列で名前の衝突を防止
resource "random_string" "unique" {
length = 6
special = false
upper = false
}
#######################
# Resource Group
#######################
resource "azurerm_resource_group" "mysql_rg" {
name = "mysql-rg-${random_string.unique.result}"
location = "westus2"
}
#######################
# Virtual Network & Subnets
#######################
resource "azurerm_virtual_network" "vnet" {
name = "vnet-${random_string.unique.result}"
resource_group_name = azurerm_resource_group.mysql_rg.name
location = azurerm_resource_group.mysql_rg.location
address_space = ["10.0.0.0/16"]
}
resource "azurerm_subnet" "mysql_subnet" {
name = "mysql-subnet-${random_string.unique.result}"
resource_group_name = azurerm_resource_group.mysql_rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.1.0/24"]
delegation {
name = "mysqlDelegation"
service_delegation {
name = "Microsoft.DBforMySQL/flexibleServers"
actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"]
}
}
}
resource "azurerm_subnet" "vm_subnet" {
name = "vm-subnet-${random_string.unique.result}"
resource_group_name = azurerm_resource_group.mysql_rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.2.0/24"]
}
resource "azurerm_subnet" "bastion_subnet" {
name = "AzureBastionSubnet"
resource_group_name = azurerm_resource_group.mysql_rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.3.0/24"]
}
#######################
# NSG & Association
#######################
resource "azurerm_network_security_group" "mysql_nsg" {
name = "mysql-nsg-${random_string.unique.result}"
location = azurerm_resource_group.mysql_rg.location
resource_group_name = azurerm_resource_group.mysql_rg.name
security_rule {
name = "AllowMySQL"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "3306"
source_address_prefix = "10.0.2.0/24"
destination_address_prefix = "*"
}
}
resource "azurerm_subnet_network_security_group_association" "mysql_nsg_assoc" {
subnet_id = azurerm_subnet.mysql_subnet.id
network_security_group_id = azurerm_network_security_group.mysql_nsg.id
}
resource "azurerm_network_security_group" "vm_nsg" {
name = "vm-nsg-${random_string.unique.result}"
location = azurerm_resource_group.mysql_rg.location
resource_group_name = azurerm_resource_group.mysql_rg.name
security_rule {
name = "AllowSSH"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "10.0.3.0/24"
destination_address_prefix = "*"
}
}
resource "azurerm_subnet_network_security_group_association" "vm_nsg_assoc" {
subnet_id = azurerm_subnet.vm_subnet.id
network_security_group_id = azurerm_network_security_group.vm_nsg.id
}
#######################
# Private DNS
#######################
resource "azurerm_private_dns_zone" "mysql_dns" {
name = "privatelink.mysql.database.azure.com"
resource_group_name = azurerm_resource_group.mysql_rg.name
}
resource "azurerm_private_dns_zone_virtual_network_link" "mysql_dns_link" {
name = "mysql-link-${random_string.unique.result}"
resource_group_name = azurerm_resource_group.mysql_rg.name
private_dns_zone_name = azurerm_private_dns_zone.mysql_dns.name
virtual_network_id = azurerm_virtual_network.vnet.id
}
#######################
# Bastion
#######################
resource "azurerm_public_ip" "bastion_ip" {
name = "bastion-ip-${random_string.unique.result}"
location = azurerm_resource_group.mysql_rg.location
resource_group_name = azurerm_resource_group.mysql_rg.name
allocation_method = "Static"
sku = "Standard"
}
resource "azurerm_bastion_host" "bastion" {
name = "bastion-${random_string.unique.result}"
location = azurerm_resource_group.mysql_rg.location
resource_group_name = azurerm_resource_group.mysql_rg.name
ip_configuration {
name = "config"
subnet_id = azurerm_subnet.bastion_subnet.id
public_ip_address_id = azurerm_public_ip.bastion_ip.id
}
}
#######################
# VM
#######################
resource "azurerm_network_interface" "vm_nic" {
name = "vm-nic-${random_string.unique.result}"
location = azurerm_resource_group.mysql_rg.location
resource_group_name = azurerm_resource_group.mysql_rg.name
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.vm_subnet.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_linux_virtual_machine" "vm" {
name = "vm-${random_string.unique.result}"
location = azurerm_resource_group.mysql_rg.location
resource_group_name = azurerm_resource_group.mysql_rg.name
size = "Standard_B1s"
admin_username = "azureuser"
admin_password = "AzureVMpass123!"
disable_password_authentication = false
network_interface_ids = [azurerm_network_interface.vm_nic.id]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-focal"
sku = "20_04-lts"
version = "latest"
}
}
#######################
# MySQL - General Purpose SKUでレプリケーション対応
#######################
resource "azurerm_mysql_flexible_server" "primary" {
name = "mysql-primary-${random_string.unique.result}"
resource_group_name = azurerm_resource_group.mysql_rg.name
location = azurerm_resource_group.mysql_rg.location
# General Purpose SKU(レプリケーション対応)
sku_name = "GP_Standard_D2ds_v4"
administrator_login = "mysqladmin"
administrator_password = "MySQLadmin123!"
version = "8.0.21"
backup_retention_days = 7
# プライベートアクセスを有効化
delegated_subnet_id = azurerm_subnet.mysql_subnet.id
private_dns_zone_id = azurerm_private_dns_zone.mysql_dns.id
storage {
size_gb = 20
auto_grow_enabled = true
}
depends_on = [
azurerm_private_dns_zone_virtual_network_link.mysql_dns_link,
azurerm_subnet_network_security_group_association.mysql_nsg_assoc
]
}
# 読み取りレプリカ
resource "azurerm_mysql_flexible_server" "replica" {
name = "mysql-replica-${random_string.unique.result}"
resource_group_name = azurerm_resource_group.mysql_rg.name
location = azurerm_resource_group.mysql_rg.location
# レプリカモードを明示的に設定
create_mode = "Replica"
source_server_id = azurerm_mysql_flexible_server.primary.id
# レプリカも同じGeneral Purpose SKUを使用
sku_name = "GP_Standard_D2ds_v4"
# レプリカも同じサブネットとDNSゾーンを使用
delegated_subnet_id = azurerm_subnet.mysql_subnet.id
private_dns_zone_id = azurerm_private_dns_zone.mysql_dns.id
# ストレージ設定
storage {
auto_grow_enabled = true
}
depends_on = [
azurerm_mysql_flexible_server.primary
]
}
#######################
# Outputs
#######################
output "resource_group_name" {
value = azurerm_resource_group.mysql_rg.name
}
output "bastion_public_ip" {
value = azurerm_public_ip.bastion_ip.ip_address
}
output "vm_private_ip" {
value = azurerm_network_interface.vm_nic.private_ip_address
}
output "mysql_primary_fqdn" {
value = azurerm_mysql_flexible_server.primary.fqdn
}
output "mysql_replica_fqdn" {
value = azurerm_mysql_flexible_server.replica.fqdn
}
output "vm_ssh_command" {
value = "az network bastion ssh --name ${azurerm_bastion_host.bastion.name} --resource-group ${azurerm_resource_group.mysql_rg.name} --target-resource-id ${azurerm_linux_virtual_machine.vm.id} --auth-type password --username azureuser"
}
output "unique_suffix" {
value = random_string.unique.result
}
output "mysql_connection_commands" {
value = <<EOT
プライマリ接続:
mysql -h ${azurerm_mysql_flexible_server.primary.fqdn} -u mysqladmin -p
レプリカ接続:
mysql -h ${azurerm_mysql_flexible_server.replica.fqdn} -u mysqladmin -p
EOT
}
順番
terraform apply -target=azurerm_resource_group.mysql_rg
terraform apply -target=azurerm_virtual_network.vnet
terraform apply -target=azurerm_subnet.mysql_subnet -target=azurerm_subnet.vm_subnet -target=azurerm_subnet.bastion_subnet
terraform apply -target=azurerm_network_security_group.mysql_nsg -target=azurerm_network_security_group.vm_nsg
terraform apply -target=azurerm_subnet_network_security_group_association.mysql_nsg_assoc -target=azurerm_subnet_network_security_group_association.vm_nsg_assoc
terraform apply -target=azurerm_private_dns_zone.mysql_dns -target=azurerm_private_dns_zone_virtual_network_link.mysql_dns_link
terraform apply -target=azurerm_public_ip.bastion_ip -target=azurerm_bastion_host.bastion
terraform apply -target=azurerm_network_interface.vm_nic -target=azurerm_linux_virtual_machine.vm
terraform apply -target=azurerm_mysql_flexible_server.primary
terraform apply -target=azurerm_mysql_flexible_server.replica
terraform apply
-auto-approveを付けてshファイルにして実行可能。