|
terraform { |
|
required_version = "~> 1.2.4" |
|
|
|
required_providers { |
|
azurerm = { |
|
source = "hashicorp/azurerm" |
|
version = "~> 3.12.0" |
|
} |
|
azapi = { |
|
source = "azure/azapi" |
|
version = "~> 0.4.0" |
|
} |
|
} |
|
} |
|
|
|
module "subnet_addrs" { |
|
source = "hashicorp/subnets/cidr" |
|
|
|
base_cidr_block = local.subnet_addrs.base_cidr_block |
|
networks = [ |
|
{ |
|
name = "default" |
|
new_bits = 8 |
|
}, |
|
{ |
|
name = "aca-cp" |
|
// must have a size of at least /23 |
|
new_bits = 7 |
|
}, |
|
{ |
|
name = "pe" |
|
new_bits = 8 |
|
}, |
|
] |
|
} |
|
|
|
provider "azurerm" { |
|
features { |
|
resource_group { |
|
prevent_deletion_if_contains_resources = false |
|
} |
|
} |
|
} |
|
|
|
provider "azapi" {} |
|
|
|
data "http" "my_public_ip" { |
|
url = "https://ipconfig.io" |
|
} |
|
|
|
resource "azurerm_resource_group" "aca_tf_sample" { |
|
name = local.rg.name |
|
location = local.rg.location |
|
} |
|
|
|
resource "azurerm_virtual_network" "default" { |
|
name = "vnet-default" |
|
resource_group_name = azurerm_resource_group.aca_tf_sample.name |
|
location = azurerm_resource_group.aca_tf_sample.location |
|
address_space = [module.subnet_addrs.base_cidr_block] |
|
} |
|
|
|
resource "azurerm_subnet" "default" { |
|
name = "snet-default" |
|
resource_group_name = azurerm_resource_group.aca_tf_sample.name |
|
virtual_network_name = azurerm_virtual_network.default.name |
|
address_prefixes = [module.subnet_addrs.network_cidr_blocks["default"]] |
|
} |
|
|
|
|
|
resource "azurerm_subnet" "aca_cp" { |
|
// workaround: operate subnets one after another |
|
// https://github.com/hashicorp/terraform-provider-azurerm/issues/3780 |
|
depends_on = [ |
|
azurerm_subnet.default |
|
] |
|
name = "snet-aca-cp" |
|
resource_group_name = azurerm_resource_group.aca_tf_sample.name |
|
virtual_network_name = azurerm_virtual_network.default.name |
|
address_prefixes = [module.subnet_addrs.network_cidr_blocks["aca-cp"]] |
|
} |
|
|
|
resource "azurerm_subnet" "pe" { |
|
// workaround: operate subnets one after another |
|
// https://github.com/hashicorp/terraform-provider-azurerm/issues/3780 |
|
depends_on = [ |
|
azurerm_subnet.aca_cp |
|
] |
|
name = "snet-pe" |
|
resource_group_name = azurerm_resource_group.aca_tf_sample.name |
|
virtual_network_name = azurerm_virtual_network.default.name |
|
address_prefixes = [module.subnet_addrs.network_cidr_blocks["pe"]] |
|
} |
|
|
|
resource "azurerm_private_dns_zone" "state_store" { |
|
name = "privatelink.blob.core.windows.net" |
|
resource_group_name = azurerm_resource_group.aca_tf_sample.name |
|
} |
|
|
|
resource "azurerm_private_dns_zone_virtual_network_link" "state_store" { |
|
name = "pdnsz-link-state-store" |
|
resource_group_name = azurerm_resource_group.aca_tf_sample.name |
|
private_dns_zone_name = azurerm_private_dns_zone.state_store.name |
|
virtual_network_id = azurerm_virtual_network.default.id |
|
} |
|
|
|
resource "azurerm_storage_account" "state_store" { |
|
name = "${var.prefix}acasampless" |
|
resource_group_name = azurerm_resource_group.aca_tf_sample.name |
|
location = azurerm_resource_group.aca_tf_sample.location |
|
account_tier = "Standard" |
|
account_replication_type = "LRS" |
|
|
|
network_rules { |
|
default_action = "Deny" |
|
// If you could run Terraform in network reachable private endpoint, you do not need the following rule |
|
ip_rules = ["${chomp(data.http.my_public_ip.body)}"] |
|
virtual_network_subnet_ids = [] |
|
} |
|
} |
|
|
|
resource "azurerm_storage_container" "state_store" { |
|
name = "state" |
|
storage_account_name = azurerm_storage_account.state_store.name |
|
container_access_type = "private" |
|
} |
|
|
|
resource "azurerm_private_endpoint" "state_store" { |
|
name = "pe-state-store" |
|
resource_group_name = azurerm_resource_group.aca_tf_sample.name |
|
location = azurerm_resource_group.aca_tf_sample.location |
|
subnet_id = azurerm_subnet.pe.id |
|
|
|
private_dns_zone_group { |
|
name = "pdnsz-group-state-store" |
|
private_dns_zone_ids = [azurerm_private_dns_zone.state_store.id] |
|
} |
|
|
|
private_service_connection { |
|
name = "pe-connection-state-store" |
|
is_manual_connection = false |
|
private_connection_resource_id = azurerm_storage_account.state_store.id |
|
subresource_names = ["blob"] |
|
} |
|
} |
|
|
|
// TODO: This will be replaced with AzureRM provider once it supports ACA |
|
resource "azapi_resource" "aca_env" { |
|
depends_on = [ |
|
azurerm_subnet.aca_cp |
|
] |
|
type = "Microsoft.App/managedEnvironments@2022-03-01" |
|
name = "ca-env-aca-tf-sample" |
|
parent_id = azurerm_resource_group.aca_tf_sample.id |
|
location = azurerm_resource_group.aca_tf_sample.location |
|
|
|
body = jsonencode({ |
|
properties = { |
|
zoneRedundant = true |
|
vnetConfiguration = { |
|
internal = true |
|
infrastructureSubnetId = azurerm_subnet.aca_cp.id |
|
} |
|
appLogsConfiguration = { |
|
destination = "log-analytics" |
|
logAnalyticsConfiguration = { |
|
customerId = var.log_analytics.workspace.id |
|
sharedKey = var.log_analytics.workspace.key |
|
} |
|
} |
|
daprAIConnectionString = var.app_insights.connection_string |
|
daprAIInstrumentationKey = var.app_insights.instrumentation_key |
|
} |
|
}) |
|
|
|
ignore_missing_property = true |
|
response_export_values = ["properties.defaultDomain", "properties.staticIp"] |
|
|
|
// Workaroud: delete operation complete immediatelly but it's actually running asynchronously, so occur "InUseSubnetCannotBeDeleted" error |
|
provisioner "local-exec" { |
|
when = destroy |
|
command = "sleep 1800" |
|
} |
|
} |
|
|
|
// TODO: This will be replaced with AzureRM provider once it supports ACA |
|
resource "azapi_resource" "aca_env_dapr_component_state_store" { |
|
depends_on = [ |
|
azapi_resource.aca_env |
|
] |
|
type = "Microsoft.App/managedEnvironments/daprComponents@2022-03-01" |
|
name = "statestore" |
|
parent_id = azapi_resource.aca_env.id |
|
|
|
body = jsonencode({ |
|
properties = { |
|
componentType = "state.azure.blobstorage" |
|
version = "v1" |
|
scopes = ["nodeapp"] |
|
secrets = [ |
|
{ |
|
name = "account-key" |
|
value = azurerm_storage_account.state_store.primary_access_key |
|
} |
|
] |
|
metadata = [ |
|
{ |
|
name = "accountName" |
|
value = azurerm_storage_account.state_store.name |
|
}, |
|
{ |
|
name = "accountKey" |
|
secretRef = "account-key" |
|
}, |
|
{ |
|
name = "containerName" |
|
value = azurerm_storage_container.state_store.name |
|
} |
|
] |
|
} |
|
}) |
|
|
|
ignore_missing_property = true |
|
} |
|
|
|
// TODO: This will be replaced with AzureRM provider once it supports ACA |
|
resource "azapi_resource" "aca_app_nodeapp" { |
|
depends_on = [ |
|
azapi_resource.aca_env, azapi_resource.aca_env_dapr_component_state_store |
|
] |
|
type = "Microsoft.App/containerApps@2022-03-01" |
|
name = "ca-app-aca-tf-sample-nodeapp" |
|
parent_id = azurerm_resource_group.aca_tf_sample.id |
|
location = azurerm_resource_group.aca_tf_sample.location |
|
identity { |
|
type = "SystemAssigned" |
|
} |
|
|
|
body = jsonencode({ |
|
properties = { |
|
managedEnvironmentId = azapi_resource.aca_env.id |
|
configuration = { |
|
ingress = { |
|
targetPort = 3000 |
|
external = false |
|
}, |
|
dapr = { |
|
enabled = true |
|
appId = "nodeapp" |
|
appPort = 3000 |
|
appProtocol = "http" |
|
} |
|
}, |
|
template = { |
|
containers = [ |
|
{ |
|
image = "dapriosamples/hello-k8s-node:latest" |
|
name = "nodeapp" |
|
} |
|
] |
|
scale = { |
|
minReplicas = 1 |
|
maxReplicas = 1 |
|
} |
|
} |
|
} |
|
}) |
|
|
|
ignore_missing_property = true |
|
} |
|
|
|
// TODO: This will be replaced with AzureRM provider once it supports ACA |
|
resource "azapi_resource" "aca_app_pythonapp" { |
|
depends_on = [ |
|
azapi_resource.aca_env, azapi_resource.aca_env_dapr_component_state_store |
|
] |
|
type = "Microsoft.App/containerApps@2022-03-01" |
|
name = "ca-app-aca-tf-sample-pythonapp" |
|
parent_id = azurerm_resource_group.aca_tf_sample.id |
|
location = azurerm_resource_group.aca_tf_sample.location |
|
identity { |
|
type = "SystemAssigned" |
|
} |
|
|
|
body = jsonencode({ |
|
properties = { |
|
managedEnvironmentId = azapi_resource.aca_env.id |
|
configuration = { |
|
dapr = { |
|
enabled = true |
|
appId = "pythonapp" |
|
appProtocol = "http" |
|
} |
|
}, |
|
template = { |
|
containers = [ |
|
{ |
|
image = "dapriosamples/hello-k8s-python:latest" |
|
name = "pythonapp" |
|
} |
|
] |
|
scale = { |
|
minReplicas = 1 |
|
maxReplicas = 1 |
|
} |
|
} |
|
} |
|
}) |
|
|
|
ignore_missing_property = true |
|
} |
|
|
|
resource "azurerm_private_dns_zone" "aca_env" { |
|
name = jsondecode(azapi_resource.aca_env.output).properties.defaultDomain |
|
resource_group_name = azurerm_resource_group.aca_tf_sample.name |
|
} |
|
|
|
resource "azurerm_private_dns_zone_virtual_network_link" "aca_env" { |
|
name = "pdnsz-link-aca-env" |
|
resource_group_name = azurerm_resource_group.aca_tf_sample.name |
|
private_dns_zone_name = azurerm_private_dns_zone.aca_env.name |
|
virtual_network_id = azurerm_virtual_network.default.id |
|
registration_enabled = true |
|
} |
|
|
|
resource "azurerm_private_dns_a_record" "aca_env" { |
|
name = "*" |
|
zone_name = azurerm_private_dns_zone.aca_env.name |
|
resource_group_name = azurerm_resource_group.aca_tf_sample.name |
|
ttl = 300 |
|
records = [jsondecode(azapi_resource.aca_env.output).properties.staticIp] |
|
} |