TerraformでAzure Web Appsを構築してみた

またしてもTerraformです。5月入ってから隙間時間は業務含めてTerraformをいじっている感じです。前回まではAWSでテラってましたが今回はAzureです。しかもWeb AppsTable Storageサービスを利用して簡単なサンプルを作成し展開します。
こんなイメージです典型的なサーバレス?構成の一つですね。










サンプルアプリはこちらに保存しています。
まずはAzureCLIで試してみます。それができてからTerraform化します。
自分が後で見返すときにこっちの方が思い出しやすいのでこっちでまとめています。
*ほんといい加減Gitに上げたほうがいいのは分っている、、、

でうまくいけばカスタムドメインつけてSSL証明書をくっつけたいと思いましたが
そこは諸般の事情(お金がないので)挫折しました。

◆設定作業編

1.AzureCLI版

#リソースグループ作成
$ az group create --name sample_webapps_20200602 --location japaneast
#ストレージアカウントグループ作成
$ az storage account create \
    --name samplestorage20200602 \
    --resource-group sample_webapps_20200602 \
    --location japaneast \
    --sku Standard_GZRS

#テーブル作成
$ az storage table create --name tabletohonokai --account-name samplestorage20200602

#接続文字列取得
$ az storage account show-connection-string --name samplestorage20200602

#サンプルアプリコピー
$ git clone https://github.com/Otazoman/AzureWebappsSample.git
$ cd AzureWebappsSample

#サンプルアプリコンフィグファイル修正(接続文字列設定)
$ cp models/org_config.py models/config.py
$ vi models/config.py
--------------
STORAGE_CONNECTION_STRING = '"${connection_string}"'
--------------

#サービスプラン作成
$ az appservice plan create  --resource-group sample_webapps_20200602 --name sampleapps20200602 --location japaneast --sku FREE --is-linux

#WebAPPs立ち上げ
$ az webapp up --sku F1 -n tohonokaiwebsample -l japaneast -p sampleapps20200602 -g sample_webapps_20200602

#不要になったら、リソースグループごと削除
$ az group delete -n sample_webapps_20200602

そして本題のTerraformです。

2.Terraform版

2.1.事前準備作業

# サブスクリプションID取得
$ az account list --query "[].{name:name, subscriptionId:id, tenantId:tenantId}"
$ az account set --subscription="サブスクリプションID"

# appIdとパスワード取得
$ az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/サブスクリプションID"

# 環境変数設定
$ vi environment.sh
※新規作成
------------------------
#!/bin/sh
echo "Setting environment variables for Terraform"
export ARM_SUBSCRIPTION_ID="サブスクリプションID"
export ARM_CLIENT_ID="クライアントID"
export ARM_CLIENT_SECRET=クライアントシークレット"
export ARM_TENANT_ID="テナントID"
------------------------
$ chmod 755 environment.sh
$ ./environment.sh

# ディレクトリ作成
$ mkdir storage apps
$ cd apps
$ mkdir src
$ cd src
$ git clone https://github.com/Otazoman/AzureWebappsSample.git testappservice-20200524
$ cd ../

# デプロイ用シェルスクリプト作成
vi appsdeploy.sh
-----------------
#/bin/bash
cd /home/matarain/terraform/tohonokaiwebapps/${cur}

if [ -d .azure ]; then
   rm -Rf .azure
fi
/usr/bin/az webapp up --sku ${sku} \
                       -n ${name} \
                       -l ${location} \
                       -p ${plan} \
                       -g ${resource_group}

exit 0
-----------------
$ chmod 755 appsdeploy.sh

2.2.Terraformファイル群

(1)ルートに置くもの


# main.tf
-----------------
provider "azurerm" {
  features {}
}
resource "azurerm_resource_group" "rg" {
  name     = var.resource_group_name
  location = var.location
  tags = {
    environment = "prod"
  }
}

module "storage" {
  source              = "./storage"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
}

module "apps" {
  source              = "./apps"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  connection_string   = "${module.storage.connection_string}"
}

-----------------
# variables.tf
-----------------
variable "resource_group_name" {
  default = "sample_resourcegroup_20200602"
}

variable "location" {
  default = "japaneast"
}
-----------------

(2)storageディレクトリ配下


# variables.tf
---------------------------
variable "resource_group_name" {}
variable "location" {}
variable "storage_name" {
  default = "testsampl20200523"
}
variable "type" {
  default = "GRS"
}
variable "table_name"{
  default = "tablesample"
}
---------------------------
# main.tf
---------------------------
resource "azurerm_storage_account" "asa_default" {
  name                     = var.storage_name
  resource_group_name      = var.resource_group_name
  location                 = var.location
  account_tier             = "Standard"
  account_replication_type = var.type
}

resource "azurerm_storage_table" "asa_table" {
  name                 = var.table_name
  storage_account_name = azurerm_storage_account.asa_default.name
}
---------------------------
# output.tf
---------------------------
output "connection_string" {
  value = azurerm_storage_account.asa_default.primary_connection_string
}
---------------------------

(3)appsディレクトリ配下

# main.tf
-----------------
data "template_file" "connectionstring" {
  template = file("${path.module}/src/${var.app_service_name}/models/org_config.py")
  vars = {
    connection_string = var.connection_string
  }
}

resource "local_file" "conection_string" {
  content  = data.template_file.connectionstring.rendered
  filename = "${path.module}/src/${var.app_service_name}/models/config.py"
}

data "template_file" "deployshell" {
  template = file("${path.module}/appsdeploy.sh")
  vars = {
    sku            = var.sku_size
    name           = var.app_service_name
    location       = var.location
    plan           = var.appservice_plan_name
    resource_group = var.resource_group_name
  }
}

resource "local_file" "deploy" {
  content  = data.template_file.deployshell.rendered
  filename = "${path.module}/src/${var.app_service_name}/appsdeploy.sh"
}

resource "azurerm_app_service_plan" "main" {
  name                = var.appservice_plan_name
  location            = var.location
  resource_group_name = var.resource_group_name
  kind                = var.os_type
  reserved            = var.os_param
  sku {
    tier = var.sku_tier
    size = var.sku_size
  }
}

data "external" "az_deploy" {
  program = ["bash", "${path.module}/src/${var.app_service_name}/appsdeploy.sh"]
}

resource "null_resource" "az_deploy" {
  provisioner "local-exec" {
    depends_on = [azurerm_app_service_plan.main]
    command = "${path.module}/src/${var.app_service_name}/appsdeploy.sh"
  }
}
-----------------
# variables.tf
-----------------
variable "resource_group_name" {}
variable "location" {}
variable "connection_string" {}
variable "appservice_plan_name" {
  default = "appsample-20200524"
}
variable "os_type" {
  default = "Linux"
}
variable "os_param" {
  default = true
}

variable "sku_tier" {
  default = "Free"
}

variable "sku_size" {
  default = "F1"
}
variable "app_service_name" {
  default = "testappservice-20200524"
}
-----------------

2.3.ディレクトリ構成

.
|-- apps
|   |-- appsdeploy.sh
|   |-- main.tf
|   |-- src
|   |   |
|   |   `-- testappservice-20200524
|   |       |-- README.md
|   |       |-- app
|   |       |   |-- __init__.py
|   |       |   |-- __pycache__
|   |       |   |   |-- __init__.cpython-37.pyc
|   |       |   |   |-- app.cpython-37.pyc
|   |       |   |   `-- config.cpython-37.pyc
|   |       |   |-- app.py
|   |       |   |-- static
|   |       |   |-- templates
|   |       |   |   |-- error.html
|   |       |   |   |-- index.html
|   |       |   |   |-- select.html
|   |       |   |   `-- upload.html
|   |       |   `-- uploads
|   |       |-- application.py
|   |       |-- appsdeploy.sh
|   |       |-- controllers
|   |       |   |-- __init__.py
|   |       |   |-- __pycache__
|   |       |   |   `-- viewrender.cpython-37.pyc
|   |       |   `-- viewrender.py
|   |       |-- models
|   |       |   |-- __init__.py
|   |       |   |-- __pycache__
|   |       |   |   |-- __init__.cpython-37.pyc
|   |       |   |   |-- config.cpython-37.pyc
|   |       |   |   |-- models.cpython-37.pyc
|   |       |   |   |-- table_crud.cpython-37.pyc
|   |       |   |   |-- tablestorage.cpython-37.pyc
|   |       |   |   `-- tablestorage_account.cpython-37.pyc
|   |       |   |-- config.py
|   |       |   |-- org_config.py
|   |       |   |-- table_crud.py
|   |       |   |-- tablestorage.py
|   |       |   `-- tablestorage_account.py
|   |       `-- requirements.txt
|   `-- variables.tf
|-- environment.sh
|-- main.tf
|-- storage
|   |-- main.tf
|   |-- outputs.tf
|   `-- variables.tf
|-- terraform.tfstate
|-- terraform.tfstate.backup
`-- variables.tf


◆参考サイト

・Terraform WebApps 

https://www.terraform.io/docs/providers/azurerm/r/app_service.html https://tech-blog.cloud-config.jp/2020-03-10-terraform-local-exec-app-service-ip-restriction/ https://www.terraform.io/docs/providers/azurerm/r/storage_table.html https://docs.microsoft.com/ja-jp/azure/developer/terraform/ https://www.terraform.io/docs/providers/azurerm/r/app_service_plan.html https://github.com/terraform-providers/terraform-provider-azurerm/issues/4144 https://tech-blog.cloud-config.jp/2019-12-30-terraform-application-insights/ https://github.com/innovationnorway/terraform-azurerm-web-app https://medium.com/@bappertdennis/deploy-azure-functions-with-terraform-83ab88c8373c https://medium.com/faun/starting-with-terraform-and-azure-d5a974bddfc2 https://github.com/terraform-providers/terraform-provider-azurerm/issues/3685 https://github.com/terraform-providers/terraform-provider-azurerm/issues/3696 https://cloudblogs.microsoft.com/opensource/2019/06/25/how-to-migrate-to-hashicorp-terraform-0-12-microsoft-azure/ https://medium.com/@jmarhee/using-external-data-sources-with-terraform-c3de27388192 https://github.com/rahulkhengare/terraform-azurerm-webapp

・Terraform TableStorege 

https://www.terraform.io/docs/providers/azurerm/r/storage_account.html https://iganari.hatenablog.com/entry/2019/10/28/051438

・ResourceGroup(terraform)


https://docs.microsoft.com/ja-jp/azure/developer/terraform/install-configure 

・Terraform 外部コマンド実行 

https://gist.github.com/tkuchiki/f0b804f2bae96e8676e5d86c0ee2bcb8 https://qiita.com/tmshn/items/64789684a6057131b8b6 https://stackoverflow.com/questions/52262234/how-to-use-external-data-source-in-terraform-with-bash-script https://dev.classmethod.jp/articles/terraform-v-0-8-0-rc3-introduces-external-functionality/ https://www.terraform.io/docs/provisioners/local-exec.html https://medium.com/@brad.simonin/learning-how-to-execute-a-bash-script-from-terraform-for-aws-b7fe513b6406

 ・WebApps

https://employment.en-japan.com/engineerhub/entry/2019/11/19/103000 https://onarimonstudio.hatenablog.com/entry/2019/01/10/190717 https://engineer-ninaritai.com/webapp-howto-make/ https://qiita.com/ume67026265/items/03b49f1531c6cd38a701 https://www.slideshare.net/hebikuzure/java-azure-web-apps https://www.slideshare.net/mihokurosawa96/azure-web-apps-63234477 https://blog.okazuki.jp/entry/2019/06/27/095152 https://eventmarketing.blob.core.windows.net/decode2019-after/decode19_PDF_MW01.pdf https://poke-dev.hatenablog.com/entry/2018/11/18/183235 https://qiita.com/colet/items/29195d1dd15ac066e3c3 https://blog.piyosi.com/entry/2019/12/30/201216 https://blog.piyosi.com/entry/2019/12/29/235549 https://pid123.blogspot.com/2019/06/azure-webappflask.html https://docs.microsoft.com/ja-jp/azure/app-service/deploy-staging-slots https://blog.shibayan.jp/entry/20200113/1578920798 https://blog.kokoni.jp/entry/2017/04/22/azure-web-apps%25e3%2581%25aeappsetting%25e3%2581%25ab%25e3%2581%25a4%25e3%2581%2584%25e3%2581%25a6%25e3%2581%25ae%25e8%2580%2583%25e5%25af%259f/ https://keyomura.hatenablog.com/entry/2018/02/12/174248 https://www.slideshare.net/kogesaka/azure-web-apps-ip-152603152

・TableStorage

https://qiita.com/dojyorin/items/be5b231992f187a93a5a https://docs.microsoft.com/ja-jp/azure/cosmos-db/table-storage-how-to-use-python https://maku.blog/p/xyzwod2/ https://docs.microsoft.com/ja-jp/azure/storage/tables/table-storage-overview https://docs.microsoft.com/en-us/cli/azure/storage?view=azure-cli-latest https://qiita.com/saiyuki1919/items/6ffc9a66aa70bb9cda5a https://maku.blog/p/o8ufwct/ https://buildersbox.corp-sansan.com/entry/2019/01/21/110000 https://www.atmarkit.co.jp/ait/articles/1707/24/news039.html https://docs.microsoft.com/ja-jp/azure/storage/common/storage-samples-python https://maku.blog/p/hquhjki/ https://docs.microsoft.com/en-us/cli/azure/storage/entity?view=azure-cli-latest

 ・ローカルテスト

https://docs.microsoft.com/ja-jp/azure/storage/common/storage-use-emulator https://docs.microsoft.com/ja-jp/azure/storage/common/storage-use-azurite https://qiita.com/blue32a/items/b0f117f44a481317b68a https://awesomeopensource.com/project/arafato/azurite https://github.com/Azure/Azurite/blob/master/README.md

・VSCode

https://docs.microsoft.com/ja-jp/azure/javascript/tutorial-vscode-azure-app-service-node-01?tabs=bash https://qiita.com/nlog2n2/items/1d1358f6913249f3e186 https://qiita.com/dearmarie/items/4e8c7bb5d71d4f626b74 https://docs.microsoft.com/ja-jp/learn/modules/prepare-your-dev-environment-for-azure-development/3-exercise-set-up-dev-environment?pivots=vscode 

・flaskアプリ作成

https://qiita.com/kiyokiyo_kzsby/items/0184973e9de0ea9011ed https://qiita.com/5zm/items/ac8c9d1d74d012e682b4 https://www.it-swarm.dev/ja/python/flask%E3%81%AB%E4%BF%9D%E5%AD%98%E3%81%9B%E3%81%9A%E3%81%AB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E8%AA%AD%E3%81%BF%E5%8F%96%E3%82%8A%E3%81%BE%E3%81%99/1043208366/ https://tanuhack.com/flask-client2server/ https://qiita.com/bowtin/items/194c1f3b1211d7892ab8

・Azureカスタムドメイン+SSL(未検証)

https://onarimonstudio.hatenablog.com/entry/2019/01/10/190717
https://docs.microsoft.com/ja-jp/azure/app-service/app-service-web-tutorial-custom-domain
https://qiita.com/dev-kuri734/items/03b6879794804d764859
https://architect.slowcat.net/wordpress/domain-ssl/
https://www.ether-zone.com/managed-app-service-cert/


ほんとはカスタムドメインつけてhttps化したかったんですが、ドメインのところと証明書発行で有料の証明書しかないみたいだったのと新しく出てきた無料証明書がどうやらベータまでなので今回はパス、最新の機能で色々とあるらしいですが、まだまだ様子見です。

結果的にやりたかったPaaS+カスタムドメイン+SSL証明書構成はAzureでもできるんですが金銭的なハードルが高いのでどこかでGAEのカスタムドメイン+SSLを試してみたいと思っています。

コメント

このブログの人気の投稿

証券外務員1種勉強(計算式暗記用メモ)

GASでGoogleDriveのサブフォルダとファイル一覧を出力する

マクロ経済学(IS-LM分析)