Terraform で Market Place の Azure VM をデプロイするときにやること

Terraform 使い始めてしばらくになるのに知らなかったのでメモを残しておきます。

Terraform 定義

plan block がマストです。

resource "azurerm_virtual_machine" "main" {
  ...

  plan {
    name      = "{Name}"
    publisher = "{publisher}"
    product   = "{product}"
  }
}

storage_image_reference で記載する値と同じようなものを入れることになります。
詳細は Azure Provider のドキュメントを参照ください。

Azure Resource Manager: azurerm_virtual_machine - Terraform by HashiCorp

デプロイ前に実行すること

利用許諾に承諾する必要があります。
Azure ポータルでデプロイするときに画面に表示されるアレですね。

それぞれ以下のコマンドで実行します。

Azure CLI: az vm image | Microsoft Docs

PowerShell: AzureRM.MarketplaceOrdering Module | Microsoft Docs

もちろん該当のサブスクリプションに対して行う必要があるので、そこは注意ですね。

Cognitive Service を使った Jekyll 製の翻訳サイトを話題の Static Web Apps に載せ替えた

昨日書いた Azure CDN + Blob Static website のサイト、載せ替えたい欲求が高まったので載せ替えた。

今回の変更は Build 前だったのだが、今やるなら話題の Static Web Apps で実装するのがよさそう。というかもう載せ替えたい。

kheiakiyama.hateblo.jp

ホスティング

f:id:khei-fuji:20200525124958p:plain
hosting

これまで Azure CDN + Blob static website だったのが Static Web Apps に変わったので非常にシンプルになった。

デプロイ

f:id:khei-fuji:20200525125018p:plain
deployment

デプロイも構成要素が減った分シンプルになった。
Static Web Apps ではリソース作成時、GitHub Action が作成され、 GitHub の Secret にデプロイ用のキーが登録される仕様なので、それを使ってデプロイされる。

パイプラインは こちら

f:id:khei-fuji:20200525125855p:plain
GitHub - Secret

現在は Preview で課金されないことになっているが、個人サイトで使うには金額次第で元の構成に戻す可能性があるため、前の GitHub Action はファイルを残してある。
Disable にできない仕様のようなので、意味がない Trigger 設定にしておく。
参考: How can I disable a github action? - GitHub Community Forum

つまづいた点

Jekyll でデプロイできない

このサイトでは Jekyll を使っていて、Hugo のチュートリアル を見てデプロイ設定を推察して書いていたが、デプロイできずに Issue 投げて質問して解決した。

How do we use for jekyll? · Issue #27 · Azure/static-web-apps · GitHub

これだと NG(Hugo はこのパターン なのに・・)

        app_location: '/'
        app_artifact_location: '_site'

これで OK

        app_location: '_site'
        app_artifact_location: ''

一応回答の通りに対応したが、それだと app_artifact_location がなんのためにあるのかって気もしていて、たぶんそのうち解決するのだと思う。

感想

Static Site 部分、API 部分どちらも Consumption Plan になりますように。(個人でも払える範囲だといいなあ)

Effective DevOps ―4本柱による持続可能な組織文化の育て方

Effective DevOps ―4本柱による持続可能な組織文化の育て方

GitHub Actions を使って Azure CDN + Blob Static website を使った Cognitive Service の翻訳サイトをデプロイ

昔作った Cognitive Service による翻訳サイトのホスティングを普通の方法にアップデートした。

github.com

以前の課題

kheiakiyama.hateblo.jp

  • Azure Function Proxy で静的ホスティングは現代的ではないのと、Function のコストが微妙にかかるのでやめたい
  • Travis CI やめたい
  • 昔の記事まで保持するとコストかかる

ホスティング

f:id:khei-fuji:20200523230047p:plain
hosting

以前は Function Proxy + Blob Storage で配信していた。
当時は Blob Static website や Front Door がなく、CDN の設定もやりづらかった印象だったが、今はよくなっているので Azure CDN に置き換えた。
今回の変更は Build 前だったのだが、今やるなら話題の Static Web Apps で実装するのがよさそう。というかもう載せ替えたい。

デプロイ

f:id:khei-fuji:20200523230104p:plain
deployment

これまで Travis CI で処理していた部分を GitHub Actions で書き直した。
GitHub Actions での Blob へのデプロイは install-azcopy-action でインストールした azcopy が行う。
自分の cv サイトがほぼほぼ同じデプロイ方法 なので簡単に載せ替えできた。

翻訳記事の生成

f:id:khei-fuji:20200523230021p:plain
translate

このサイトは RSS フィードを更新することが目的にあるため、コンテンツが追加されるごとにサイトが再度 Generate されないといけない。
以前は Travis CI のジョブを API で呼び出していたが、今回は GitHub Actions を呼び出す。
公式にあるように repository_dispatch を呼び出す必要がある。

参考:

ほか

ついでに Blob Storage のライフサイクル管理をいじって、90日前より前のコンテンツはすべて削除することにした。
RSS フィードを1週間読まないことはあっても 90日はさすがに不要なので。
経費削減。

Azure Storage のライフサイクルの管理 | Microsoft Docs

{
    "rules": [
        {
            "enabled": true,
            "name": "SaveCosts",
            "type": "Lifecycle",
            "definition": {
                "actions": {
                    "baseBlob": {
                        "tierToCool": {
                            "daysAfterModificationGreaterThan": 30
                        },
                        "delete": {
                            "daysAfterModificationGreaterThan": 90
                        }
                    }
                },
                "filters": {
                    "blobTypes": [
                        "blockBlob"
                    ],
                    "prefixMatch": [
                        "translated"
                    ]
                }
            }
        }
    ]
}

感想

GitHub Actions じわじわ詳しくなってきた。

Effective DevOps ―4本柱による持続可能な組織文化の育て方

Effective DevOps ―4本柱による持続可能な組織文化の育て方

Azure Resource Magement テンプレートを書くときにやっていること

大まかに以下の流れで行っている。

  1. 完成品を Azure Portal 上で実装
  2. Azure Portal 上でテンプレートを Export
  3. Visual Studio Code 上で編集
  4. Azure Portal 上でデプロイテスト、問題があれば一つ前に戻る

完成品を Azure Portal 上で実装

動作を確認する意味でも完成品がなければ何も進まない。
ありものをベースに書く。

Azure Portal 上でテンプレートを Export

以下のドキュメントの手順の通りにテンプレートを Export する。

docs.microsoft.com

自分で一から書くのは手間なので動いているものをそのまま落としてくるのが手っ取り早い。

Subscription Id や Resource Group Name などのパラメータがハードコードされているのがちょっと惜しい。
これについて Twitter に書いたところ PM っぽい人が反応してたので、返信したがその後返信がない。。。

Visual Studio Code 上で編集

以下のようにエディタの拡張機能もあるので、Visual Studio Code の生産性が高い。

marketplace.visualstudio.com

先に書いたパラメータの件などはここで書き換える。
テンプレートで使える関数は以下。concatresourceId あたりはほぼ必須だろう。

docs.microsoft.com

他にもリソースの種類によっては「こういうときにどうするのがいいんだろう?」という場面に出くわすことがある。
そういうときは以下の公式テンプレート集から同じシチューエーションを探して参考にする。
たとえばダウンロードしたテンプレートでは書かれている内容でもテンプレートとしては不要な記述が結構あるので、それをどこまで削るべきかといった判断に役立つ。

github.com

Azure Portal 上でデプロイテスト、問題があれば一つ前に戻る

完成したテンプレートを使ってデプロイし、思ったとおりデプロイされたリソースが動くか確認する。

テンプレートを使ったデプロイは以下のドキュメントの通り。

docs.microsoft.com

Azure で Nomad(Consul)のクラスターを作成する

Web サーバーとスケジュールジョブなら App Service と Logic App + Azure Container Instance が最初の選択肢だと考えていたが、他の選択肢を調べてみようと検証した。

Nomad 事情

Nomad は Hashicorp のプロダクト。
Nomad by HashiCorp

日本に馴染みがあるところでは Circle CI や trivago が使っている。
Who Uses Nomad - Nomad by HashiCorp

trivago の記事で KubernetesNomad の違いについて触れている。
"(意訳)Kubernetes は自動車だとしたら Nomad はスクーターで、場合に応じて使い分けます"
Maybe You Don't Need Kubernetes | Matthias Endler

公式でも Kubernetes との違いについて触れている。
"(意訳)Kubernetes は Docker にフォーカスしてますが Nomad は一般的な利用を想定しています"
Nomad vs. Kubernetes - Nomad by HashiCorp

Nomad が Docker 特化ではないとはいえ k8s を使うべきシーンはそこまで多くないと考えていて、Nomad がそのときの代替案になるのではないかと考えている。

知るかぎり Nomad の as a Service はないため、下回りは自分で整える必要がある。

事前知識

  • Nomad 公式の Getting Started を完了している
  • Azure Virtual Machine やその周辺の知識を保持している
  • Terraform は利用している
  • Consul と Packer は触ったことがない

チュートリアル

Hashicorp が手順を用意してくれているので、それに沿って行う。

github.com

Nomad と Consul を同じクラスターにデプロイすることにし、"Deploy Nomad and Consul in the same cluster" の手順を追う。
手順の中で terraform-azurerm-nomad を見ていたと思ったらリンク先が terraform-azurerm-consul でいつの間にか違うリポジトリ、ということがあるのでそこは注意すること。

Consul と Nomad 入りの VM イメージ作成

Use the install-consul module from the Consul Azure Module and the install-nomad module from this Module in a Packer template to create an Azure Image with Consul and Nomad.

Packer 使って VM Image を作成してねということなので、リポジトリ内の以下を参考に作成する。
https://github.com/hashicorp/terraform-azurerm-nomad/tree/master/examples/nomad-consul-image

Packer 初めてだったのでよくわからずにそのまま packer build nomad-consul.json したが、できていた。
環境変数として与える Service Principal のスコープを制限しようとしたところ、packer-XXX というリソースグループを作成できる必要があり、そこだけハマった。

Consul と Nomad のサーバークラスター作成

Deploy a small number of server nodes (typically, 3) using the consul-cluster module. Execute the run-consul script and the run-nomad script on each node during boot, setting the --server flag in both scripts.

Terraform を使ってクラスターを作成する。
クラスターは Virtual Machine Scale Set で構成されている。
ドキュメントを読んで必要なパラメータを入れれば構成できる、はずなのだが Consul と Nomad が動いておらず、デプロイ後にミドルウェアのインストールを SSH で接続して行った。
ここは仮想マシンの起動スクリプトで完結できないと不便なので、実用するときはもう少し掘り下げる予定。

Consul と Nomad のクライアントクラスター作成

Deploy as many client nodes as you need using the nomad-cluster module. Execute the run-consul script and the run-nomad script on each node during boot, setting the --client flag in both scripts.

基本的にサーバークラスターと同じ要領で作業を進めるのみ。
自分の場合はサーバークラスターを作成した時点でコア数上限に引っかかり、別リージョンに作成した。
Consul と Nomaddatacenterregion の値は terraform テンプレートにリージョンとして書いてある値に準じるため接続できないエラーが出ていた。
デプロイ後に config を書き直すことで対応。

感想

Consul サーバークラスターのマネージドサービスが現在プライベートベータになっている。
Announcing HashiCorp Consul Service on Azure

Kubernetes も踏まえてこれを提供しているようだが、Nomad のマネージドサービスが欲しいなという印象。
そうはいっても現状はないので、Virtual Machine Scale Set をうまく使って仮想マシンを操作する必要がないように起動スクリプトを整備するのと、Consul と Nomad のアップデートなどの運用フローを整備できれば実用に耐えられるかなという印象。

Infrastructure as Code ―クラウドにおけるサーバ管理の原則とプラクティス

Infrastructure as Code ―クラウドにおけるサーバ管理の原則とプラクティス

App Service で KeyVault 参照する手順

この記事は Microsoft Azure Advent Calendar 2018 9日目の記事です。

Azure で好きなサービスは App Service です。
嬉しい機能追加のニュースが入ってきました。

Simplifying security for serverless and web apps with Azure Functions and App Service

Key Vault に保存した情報を App Service の環境変数から簡単に取り出せる仕組みができました。
動作や設定方法を簡単に確認します。

App Service の設定その1

App Service の Windows 版の場合は GUI で設定可能です。
ここでは App Service を Azure Active Directory にアプリケーション登録します。

App Service Register with Azure Active Directory
App Service Register with Azure Active Directory

Linux 版の場合も ドキュメント を読むと GUI で設定できそうでしたが、ポータルのUIが設定できなかったので Azure CLI で設定します。

Cloud Shell を開いてサクッと以下のコマンドを動かします。

az webapp identity assign --name myApp --resource-group myResourceGroup

Key Vault の設定

今回はシークレットを利用します。
Key Vault を開き、シークレット DbPassword を作成します。

keyvault-kv-secrets-list
Key Vault Secret List

シークレットを作成すると URI ができます。

keyvault-kv-uri
Key Vault Secret URI

この Secret Identifier URI は後で使うのでどこかにコピーしておきます。

次にアクセスポリシーを設定します。

Key Vault Add Policy1
Key Vault Add Policy1

Active Directory に登録した App Service をここで設定します。
アクセス権限については、今回はシークレットの読み込みだけなので、Get だけあれば動きます。

Key Vault Add Policy2
Key Vault Add Policy2

これで Key Vault の設定は終わりです。

App Service の設定その2

環境変数からの読み込みを App Settings で設定します。

App Service App Settings
App Service App Settings

以下のフォーマットを Value に設定します。

@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931)

SecretUri については Key Vault でコピーしておいた文字を入力しましょう。

設定は以上です。

設定がうまくいっていれば値が無事取得できます。

App Service Key Vault 参照成功
App Service Key Vault 参照成功

アクセス権が設定できていなかったり、取得に失敗した場合は以下のように、設定したとおりの値になります。

App Service Key Vault 参照失敗
App Service Key Vault 参照失敗

当然、みんな大好き Kudu でも読み出されたシークレットを確認できます。

App Service Kudu
App Service Kudu

あとがき

この機能は App Service 起動時に読み出し、環境変数に展開しているようです。
というのも、起動後に KeyVault 上のアクセスポリシーを削除してもアプリケーションが値を取得可能だったことからこれに至ります。
そのため、リクエスト毎取得するアプリケーション側の実装するよりもパフォーマンスへの影響を少なくできます。

また、アプリケーションの言語に依存せずに機能を利用できるのがありがたいですね。

参考記事

Azure Blob Storage を使った Static website の DevOps

kheiakiyama.hateblo.jp

以前から Static website 使ってポートフォリオサイト を動かしている。
Travic CI で AzCopy on Linux を使って適当なコンテナにデプロイし、そこから $web に手動コピーしてリリースするという手順を取っていた。

AzCopy がいつの間にか $web に対応していたので完全に自動化した。

Travic CI

サイトでは jekyll を使っているが、_site の部分を読み替えれば他のコンテンツ作成手段でも利用できるはず。

# Require Environment Variables
# - BLOB_CONTAINER_URL 
# - STORAGE_KEY
language: ruby
rvm:
  - 2.5
before_script:
  - chmod +x ./scripts/cibuild
script: ./scripts/cibuild
after_success:
  - sudo apt-get update
  - sudo apt-get install apt-transport-https -y
  - sudo add-apt-repository "deb http://security.ubuntu.com/ubuntu xenial-security main"
  - sudo add-apt-repository "deb http://cz.archive.ubuntu.com/ubuntu xenial main"
  - sudo apt-get update
  - sudo apt-get install libicu55 -y
  - sudo apt-get install libunwind-dev -y
  - wget -O azcopy.tar.gz https://aka.ms/downloadazcopylinux64
  - tar -xf azcopy.tar.gz
  - sudo ./install.sh
  - ls -la ./_site
  - azcopy --version
  - azcopy --source ./_site --destination "$BLOB_CONTAINER_URL" --dest-key $STORAGE_KEY --recursive --quiet --set-content-type
branches:
  only:
    - master
env:
  global:
    - NOKOGIRI_USE_SYSTEM_LIBRARIES=true # speeds up installation of html-proofer

環境変数

$BLOB_CONTAINER_URLhttps://xxx.blob.core.windows.net/$web のような指定になるが、Travis CI では特殊文字エスケープが必要なため、 https://xxx.blob.core.windows.net/\$web とする必要がある。

Environment Variables - Travis CI

デバッグ

最新の AzCopy on Linux を動かすために、Travis CI のデバッグで少し苦労した。

Travis CI で動くエージェントは Docker イメージが用意されているので下のリンクから該当イメージを探して手元で試すと早い。
ただし ruby のイメージは3GB超。。

Common Build Problems - Travis CI

Azure CDN への反映

コンテンツ更新するため、キャッシュを一旦削除した。

Azure CDN エンドポイントの消去 | Microsoft Docs

ドキュメントに載っていないが、Microsoft CDN のパージは3分くらいだったように感じる。