normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

Azure DevOps の pipeline で自前マシンを使って Maven ビルドする方法

前回のポストで自前の端末を Azure DevOps のパイプラインへ登録する方法を記載しましたが、実はアレだけだと git がインストールされていないのでソースコードが端末から取得できず、当たり前ですが Java も Cento OS にインストールされていないのでビルド時にエラーが発生します。ハッキリ言って Azure DevOps pipeline にただ登録しただけの状態になっています。
normalian.hatenablog.com

今回は端末を Java のビルドで利用できるようにセットアップしていきます。Java のビルドには Ant や Gradle が有名ですが、今回は Maven を試したいと思います。実は Azure DevOps には以下の様に built-in の Maven タスクが存在します。
learn.microsoft.com

こちらを利用すれば Azure DevOps Pipeline でそのまま Maven ビルドを実行できるように思いますが、Azure DevOps エージェントをセットアップした自端末の CentOS マシンには Java がインストールされていないので、pipeline にて Maven タスクを実行すると以下というエラーメッセージが pipeline 内の結果に表示されます。こちらは読みやすいように改行しているのでご注意ください。

##[error]No agent found in pool "your agent pool name" which satisfies 
the following demand: agent.name. 
All demands: agent.name -equals "your specified machine name", maven,
Agent.Version -gtVersion 2.182.1

エラーメッセージを御覧になれば分かるように Maven がインストールされていないことに加え、Azure DevOps エージェントのバージョンも一定以上である必要が分かると思います。今回は前回のセットアップに加え、Maven のセットアップを追加しています。今回の記事でのスクリプトは、前回の記事で実施済のエージェントセットアップを含んでいるので、適宜読みかえて頂ければ幸いです。

Maven タスクを実行するためのスクリプトと Azure Pipeline 定義ファイル

まずは自分が Cent OS 内で実施したスクリプトを以下に記載します。

# CentOS で git v2 をインストールするためのパッケージをインストール& git と maven のインストール
sudo yum install -y https://packages.endpointdev.com/rhel/7/os/x86_64/endpoint-repo.x86_64.rpm
sudo yum install -y java maven git

# Azure DevOps エージェントのセットアップ
wget https://vstsagentpackage.azureedge.net/agent/2.210.1/vsts-agent-linux-x64-2.210.1.tar.gz
mkdir myagent
mv vsts-agent-linux-x64-2.210.1.tar.gz myagent/
cd myagent/
tar zxvf vsts-agent-linux-x64-2.210.1.tar.gz

sudo  ./bin/installdependencies.sh 
./config.sh 

# JDK の配置&Azure Pipeline がアクセスできるように権限制御
sudo mkdir /builds/
wget https://builds.openlogic.com/downloadJDK/openlogic-openjdk/8u342-b07/openlogic-openjdk-8u342-b07-linux-x64.tar.gz
mv openlogic-openjdk-8u342-b07-linux-x64.tar.gz /builds/

sudo mkdir -p /builds/binaries/externals
wget https://builds.openlogic.com/downloadJDK/openlogic-openjdk/8u342-b07/openlogic-openjdk-8u342-b07-linux-x64.tar.gz
sudo mv openlogic-openjdk-8u342-b07-linux-x64.tar.gz /builds/
sudo chown -R azureuser  /builds/

次に Azure DevOps のパイプライン定義もそのまま記載します。こちらは CentOS 側の配置した JDK パッケージのパスを参照していることに注意ください。

# Maven
# Build your Java project and run tests with Apache Maven.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/java

trigger:
- master

pool:
  name: JavaBuildVM-Agents
steps:
- script: |
    java -version
  env:
    JAVA_HOME: $(JAVA_HOME_8_X64)
    PATH: $(JAVA_HOME_8_X64)/bin:$(PATH)
- task: JavaToolInstaller@0
  inputs:
    versionSpec: "8"
    jdkArchitectureOption: x64
    jdkSourceOption: LocalDirectory
    jdkFile: "/builds/openlogic-openjdk-8u342-b07-linux-x64.tar.gz"
    jdkDestinationDirectory: "/builds/binaries/externals"
    cleanDestinationDirectory: true
- task: Maven@3
  inputs:
    mavenPomFile: 'pom.xml'
    mavenOptions: '-Xmx3072m'
    javaHomeOption: 'JDKVersion'
    jdkVersionOption: '1.8'
    jdkArchitectureOption: 'x64'
    publishJUnitResults: true
    testResultsFiles: '**/surefire-reports/TEST-*.xml'
    goals: 'package'

上記を踏襲すればすんなり動くと思いますが、如何にそれぞれのハマりどころの注意点を追記しています。

設定時の注意点① - git のバージョン

Cent OS で単に yum install git を実施した場合、v1 系の git がインストールされました。その場合、Azure DevOps pipeline 実行時に以下のエラーが発生します。

Starting: Checkout SampleJavaProject@master to s
==============================================================================
Task         : Get sources
Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
Version      : 1.0.0
Author       : Microsoft
Help         : [More Information](https://go.microsoft.com/fwlink/?LinkId=798199)
==============================================================================
Syncing repository: SampleJavaProject (Git)
git version
git version 1.8.3.1
##[error]Min required git version is '2.0', your git ('/usr/bin/git') version is '1.8.3'
Finishing: Checkout SampleJavaProject@master to s

上記を見れば分かる通り、git v2 系をインストールする必要があります。

設定時の注意点② - JDK のセットアップ

自端末に対して JDK のセットアップから開始する必要がありますが、これには 以下の Java Tool Installer タスクを利用します。自分で展開されたファイルや tar.gz/zip 等で JDK パッケージをどこかに配置する必要があります。
Java Tool Installer task - Azure Pipelines | Microsoft Learn
実は手抜きをしようとタスクの jdkSourceOption の pre-installed を利用しようとしたのですが、こちらは Microsoft 側が標準で提供されているエージェントプールでのみ利用可能なようです。そのため、スクリプトで記載したような tar.gz ファイルを設置しています。
加えて、JDK パッケージを配置したフォルダの権限管理にも注意が必要です。Azure DevOps pipeline の実行時に権限が不足すると以下の様なエラーが発生します。こちらについても対応方法はスクリプトを参照ください。

Starting: JavaToolInstaller
==============================================================================
Task         : Java tool installer
Description  : Acquire a specific version of Java from a user-supplied Azure blob or the tool cache and sets JAVA_HOME
Version      : 0.209.0
Author       : Microsoft Corporation
Help         : https://docs.microsoft.com/azure/devops/pipelines/tasks/tool/java-tool-installer
==============================================================================
##[error]EACCES: permission denied, stat '/builds/binaries/externals'
##[error]EACCES: permission denied, stat '/builds/binaries/externals'
Finishing: JavaToolInstaller

Azure DevOps で自前マシンを pipeline で利用する方法

Azure DevOps でビルドやリリース時に pipeline と呼ばれる機能を利用しますが、その際に実際に pipeline を実行するコンピュートリソースには Microsoft 側があらかじめ提供する Microsoft-hosted agent と呼ばれるものと自身のマシンを利用できる Self-hosted Linux/macOS/Windows agent と呼ばれるものがあります。特に Microsoft-hosted agent については以下を参照頂ければと思いますが、Linux については Ubuntu のみが提供されています。
learn.microsoft.com

昨今では Ubuntu だけでも大きく困ることは無いと思いますが、CentOS 等の他のディスとリビューションを使いたい場合、自前のライブラリや特定の実行ファイル等と連携させたい場合、はたまたオンプレミス含めたシステム連携をしたい場合もあるでしょう。その場合には Self-hosted Linux/macOS/Windows agent を利用することでオンプレミスマシンを含めた自前の端末を Azure DevOps の pipeline を実行するコンピュートリソースとして活用することが可能です(以下の記事は Linux だけですが、macOSWindows の記事は左メニューより参照ください)。
learn.microsoft.com

Self-hosted Linux agents のセットアップ

これ自体は大して難しくありません。ステップとしては以下となります。

  1. 自身の Azure DevOps プロジェクトから Personal Access Token (PAT)
  2. エージェントプールを作成する
  3. 自端末でエージェントのセットアップ

まずは Personal Access Token (PAT) を取得してみましょう。以下の記事が参考になると思います。
learn.microsoft.com
初回セットアップ時、ちょっと分かりにくいのがポータル右上になる自分アイコンの左アイコンをクリックし、そのメニューから Personal Access Token のメニューを選びます。

画面が切り替わるので、以下の例に従って新規に Personal Access Token を作成してください。一度表示された PAT は再度表示されないのでメモ帳等に保存してください。

次にエージェントプールを作成します。自端末や Azure VM、もしくは EC2 等々の環境はこのエージェントプールを通して Azure DevOps の pipeline より選ぶことができます。以下の画面を参考に新規に作成できます。Agent Pool のタイプとして Self-Host と Virtual Machine Scale Set のどちらかを選ぶことができますが、Azure VM を登録する場合、Azure Kubernetes Service (AKS)を利用する場合ともに Self-Host を選択して問題ありません。

次に「自端末でエージェントのセットアップ」を行います。今回は Azure 上で CentOS 7.9 を選択した仮想マシンを利用しますが、これが AWS EC2 やオンプレミスの端末でももちろん問題ありません。ただしネットワークについては接続要件があるので、いくつかの FQDN へのアクセス追加等の確認が必要です。
learn.microsoft.com

CentOS 上で private エージェントの設定時に利用したコマンドは以下となる。tar.gz ファイルのリンクは Azure DevOps のポータルから取得できる。注意が必要なのは config.sh と svc.sh の実行時だ。

[azureuser@xxxxxxxx ]$ mkdir myagent && cd myagent
[azureuser@xxxxxxxx myagent]$ wget https://vstsagentpackage.azureedge.net/agent/2.210.1/vsts-agent-linux-x64-2.210.1.tar.gz
[azureuser@xxxxxxxx myagent]$ tar zxvf vsts-agent-linux-x64-2.210.1.tar.gz 
[azureuser@xxxxxxxx myagent]$ sudo ./bin/installdependencies.sh 
[azureuser@xxxxxxxx myagent]$ ./config.sh 
[azureuser@xxxxxxxx myagent]$ sudo ./svc.sh -h
[azureuser@xxxxxxxx myagent]$ sudo ./svc.sh install
[azureuser@xxxxxxxx myagent]$ sudo ./svc.sh start

config.sh の実行前、必要なライブラリが足りない場合はセットアップに失敗する。そのために installdependencies.sh を実施するケースが大抵となる。実際、ライブラリが足りない状態で config.sh を実行すると以下のエラーメッセージが表示される。

[azureuser@xxxxxxxx myagent]$ ./config.sh 
libicu's dependencies missing for .NET Core 3.1
Execute ./bin/installdependencies.sh to install any missing dependencies.

installdependencies.sh は管理者権限で実行する必要があるので sudo を利用して実行すると、環境に応じてライブラリを整備してくれる。

[azureuser@JavaBuildVM03 myagent]$ sudo ./bin/installdependencies.sh 
--------OS Information--------
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

------------------------------
The current OS is Fedora based
--------Redhat Version--------
CentOS Linux release 7.9.2009 (Core)
------------------------------

(中略)

config.sh 実行時に入力する必要のあるものは以下となる。ここで注意が必要なのは "server URL", "personal access token", "agent pool" だ。以下に私が実際に入力した例を示しているが、先述の 3 パラメーターは Azure DevOps における適切な登録先エージェントプールと仮想マシン紐づけの為に明示的な入力が必須となる。

  • Enter (Y/N) Accept the Team Explorer Everywhere license agreement now? (press enter for N) > Y
  • Enter server URL > https://dev.azure.com/normalian
  • Enter authentication type (press enter for PAT) >
  • Enter personal access token > ****************************************************
  • Enter agent pool (press enter for default) > JavaBuildVM-Agents
  • Enter agent name (press enter for JavaBuildVM03) >
  • Enter work folder (press enter for _work) >

デフォルトでは agent name にはコンピュータ名が指定されるが、特に問題なければこのまま指定して問題ない。work folder は pipeline 実行時に利用される作業ディレクトリとなる。こちらも特に変更しなくても問題ないと思うが、必要な場合は変更できる。

最後に svc.sh を利用してサービスとしての登録・実行を行っている。ポータル上の実行例では run.sh を利用しているが、この場合は実行セッションとプロセスが結びついてしまうので、ssh 等のログインが終了した時点で Azure DevOps のエージェントが終了してしまう。サービスとして登録するためには上記の様に svc.sh の利用が必要だ。以下に実行例を記載する。

[azureuser@JavaBuildVM03 myagent]$ sudo ./svc.sh install
Creating launch agent in /etc/systemd/system/vsts.agent.normalian.JavaBuildVM\x2dAgents.JavaBuildVM03.service
Run as user: azureuser
Run as uid: 1000
gid: 1000
/sbin/sestatus
SELinux status:                 enabled
Created symlink from /etc/systemd/system/multi-user.target.wants/vsts.agent.normalian.JavaBuildVM\x2dAgents.JavaBuildVM03.service to /etc/systemd/system/vsts.agent.norma
lian.JavaBuildVM\x2dAgents.JavaBuildVM03.service.
[azureuser@JavaBuildVM03 myagent]$ sudo ./svc.sh start

/etc/systemd/system/vsts.agent.normalian.JavaBuildVM\x2dAgents.JavaBuildVM03.service
● vsts.agent.normalian.JavaBuildVM\x2dAgents.JavaBuildVM03.service - Azure Pipelines Agent (normalian.JavaBuildVM-Agents.JavaBuildVM03)
   Loaded: loaded (/etc/systemd/system/vsts.agent.normalian.JavaBuildVM\x2dAgents.JavaBuildVM03.service; enabled; vendor preset: disabled)
   Active: active (running) since Fri 2022-10-14 20:10:09 UTC; 56ms ago
 Main PID: 6070 (runsvc.sh)
   CGroup: /system.slice/vsts.agent.normalian.JavaBuildVM\x2dAgents.JavaBuildVM03.service
           ├─6070 /bin/bash /home/azureuser/myagent/runsvc.sh
           ├─6072 ./externals/node16/bin/node ./bin/AgentService.js
           └─6081 /home/azureuser/myagent/bin/Agent.Listener run --startuptype service

Oct 14 20:10:09 JavaBuildVM03 systemd[1]: Started Azure Pipelines Agent (normalian.JavaBuildVM-Agents.JavaBuildVM03).
Oct 14 20:10:09 JavaBuildVM03 runsvc.sh[6070]: .path=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/azureuser/.local/bin:/home/azureuser/bin
Oct 14 20:10:09 JavaBuildVM03 runsvc.sh[6070]: Starting Agent listener with startup type: service
[azureuser@JavaBuildVM03 myagent]$ 

全てが正常に実行されていればエージェントプールに登録が完了される。以下の例では既に三個の仮想マシンを登録しているが、登録した agent name の下部に Online のメッセージが表示されているはずだ。

上記の場合、JavaBuildVM01 はメンテナンス中のため手動で disable にしており現在は利用不可、JavaBuildVM02 は offline のために利用できない状態ということが表示から理解できる。

pipeline で Self-hosted agents pool を指定する

最後に pipeline から作成した agent pool を指定する方法を紹介する。Azure DevOps の pipeline からは pool > name で agent pool name を指定することで利用できる。特定の agent name も指定可能だが、そちらは必要な場合は別途参照して欲しい。

trigger:
- master
pool:
 name: JavaBuildVM-Agents
teps:
- script: |
    java -version
  env:
    JAVA_HOME: $(JAVA_HOME_8_X64)
    PATH: $(JAVA_HOME_8_X64)/bin:$(PATH)

Azure Firewall の DNS Proxy 機能を利用して、Azure 外部の環境から Azure Private DNS を利用する

DNS サーバを利用した名前解決のうち、オンプレミス・パブリッククラウドを組み合わせた複数環境における閉域網での名前解決は特に複雑化することが多いです。Azure 環境の場合は Azure Public DNS や Azure Private DNS と呼ばれる機能がありますが、閉域網向けで利用される Azure Private DNS はオンプレミスや他プラットフォームからの名前解決ができないという課題があります。昨今では Azure DNS Private Resolver 機能もリリースされましたが、2022年7月時点ではプレビューなことに加え、現時点では Japan East/Japan West ともに利用できません。
docs.microsoft.com
Azure バックボーンネットワークを信じてアメリカ側のリージョンと日本側のリージョンをつなぎ、そちらで Azure DNS Private Resolver を使うという手もありますが、そもそも閉域網を非機能要件等で要求されている時点で高いレベルのコンプライアンスに沿う必要があり、日本国外のリージョンを使うということが厳しいことが多いというのが実態でしょう。

そんな以下の

  • 日本のリージョンだけで閉じたい
  • PaaS サービスだけで DNS を構築したい
  • オンプレや別の環境からでも名前解決をしたい

「ダイエットしたいけど甘いものが食べたい思春期さん」な要件を満たす場合、現時点では Azure FirewallDNS Proxy 機能が有効です(Azure DNS Private Resolver を待てというのは現時点では不問でお願いいたします)。
docs.microsoft.com

今回のアーキテクチャ図としては以下になります。外部環境としては GCP を想定していますが、これは別環境がオンプレミスや AWS であったとしても同様となります。こちらの Azure と GCP 間における VPN 接続は以前に記載した Azure と GCP を HA 構成の BGP VPN で接続する - normalian blog の記事を参照下さい。

上記のアーキテクチャで利用した Azure の各コンポーネント構成としては以下になります。

  • Application Gateway を配置した VNET を作成する
  • VPN で Azure と GCP 接続する
  • Azure Private DNS を VNET に接続する
  • Azure Private DNS に対し、Application Gateway の Private IP レコードを登録
  • 当該 VNET に Azure Firewall を配置し、DNS Proxy を有効化する

Azure FirewallDNS Proxy を利用する設定自体は非常に単純で、Azure Firewall 側の DNSメニューから DNS Proxy 設定を有効化するだけです。

上記に加えて参照する先の DNS サーバを「DNS Servers」のところで個別に IP 等で設定することも可能ですが、Default を指定することで Azure VNET が標準で参照する DNS 先、すなわち設定済の Azure Private DNS を見に行くことになります。

実際の動作例

では GCP 側の VM から Azure Private DNS に登録されている Application Gateway の Private IP を参照してみましょう。先述した通り、Azure Private DNS には既に Application Gateway の Private IP が登録済であり、VNET側に関連付けがなされているものとします。加えて、Azure Firewall 自体の Private IP は 172.19.100.4 として設定済です。

GCP 側の VM は特に DNS サーバの設定等はしていないまっさらな状態として構築し、そこで以下のコマンドを実行例しました。

特に何もせずに nslookup を実行しても Azure Firewall 側に名前解決をしに行かないので当然名前解決に失敗してますが、二回目は Azure Firewall の Private IP を DNS サーバとして指定することにより、無事に名前解決に成功しています。

Azure と GCP を HA 構成の BGP VPN で接続する

昨今のシステム構築時は複数のプラットフォームを活用することが多いと思います。最も多いケースは特定のパブリッククラウド(Azure 等)とオンプレミスとの組み合わせだと思いますが、異なるパブリッククラウドAWS, GCP 等)と接続して利用するケースも必要になると思います。コンプライアンス等によってはすべてをオンプレミス側のルータを起点・経由して異なるプラットフォームに接続することもあると思いますが、あるパブリッククラウドの特定機能を使いたいがために VPN で直接接続したいケースもあります。私が今回試したケースは「別プラットフォームから Azure にアクセスした場合の環境を作りたいな」と思い、出来心で試してみました。GCP から AWS や Azure に VPN 接続する記事としてはトップゲートさんが公開している記事が懇切丁寧に解説してくれているので、非常に参考になります。
www.topgate.co.jp
こちらをそのまま参考にしても良いと思うのですが、同記事は GCP 側で利用しているコンポーネントが Classic VPN となり、本番環境で利用したいであろう 高可用性(HA)VPN になっていないので、こちらを利用した際に Azure 側も含めてどの様に設定するかのポイントを記載したいと思います。
まず、アーキテクチャ図としては以下になります。太字でそれぞれ Azure/GCP でどの様なリソースを追加しなければならないかを明示しました。一点注意が必要なのが、Azure 側の BGP Routers は Virtual Network Gateway 設定の一部となっていますが、対比のためには明記した方が良いと思い記載しております。

ルーティングとして BGP を利用するので、クラウド間で互いに AS 番号を指定して BGP ルータの設定をしています。こちらに加えて VPN Gateway の Public IP や BGP Router の IP を Azure/GCP で互いに設定します。先述した通り「高可用性(HA)VPN 」を実現するためにコンポーネントの数が増えており、混乱しやすいのではと思うので本記事が理解の手助けになれば幸いです。

Azure/GCP で作成するコンポーネント

今回のケースでは以下のコンポーネントを作成する必要があります。設定次第で前後はあると思いますが、作成の流れとしてはおおよそ以下になると思います。

  1. Azure, GCP で Virtual Network, VPC Network を作成、NSG, ファイヤウォール等を設定
  2. Azure 側で Virtual Network Gateway x 1 を作成
  3. GCP 側で Peer VPN Gateway x 1 を作成
  4. GCP 側で Cloud VPN Gateway x 1 を作成
  5. GCP 側で Cloud Router x 1 を作成
  6. GCP 側で VPN Tunnel x 2 を作成
  7. GCP 側で BGP Session x 2 を作成
  8. Azure 側で Local Network Gateways x 2
  9. Azure 側で Connections x 2

流石に 一つ目の項目は説明は不要だと思うので、Azure の Virtual Network Gateway の作成から行きましょう。

Azure 側で Virtual Network Gateway x 1 を作成

以下の例を参考にして頂ければと思います。

特に以下の設定項目は必須です。Second Public IP を新規で作成するので、リソース名等は適宜設定してください。作成時には Configure BGP はいったん off のままで後で設定します。

設定名 設定値
Gateway Type VPN
VPN Type Route-based
Enable active-active mode enabled
SECOND PUBLIC IP ADDRESS Create new

次に Virtual Network Gateway の Configuration メニューを選択し、Configure BGP を有効化します。ここで設定する主な項目は ASN と Custom Azure APIPA BGP IP address の二つです。今回の設定値としては以下にしました。

設定名 設定値
ASN 65510
Custom Azure APIPA BGP IP address 169.254.21.14
Second Custom Azure APIPA BGP IP address 169.254.22.50

ASN は GCP 側(別プラットフォーム側)でも設定し、異なる番号を入力します。ASN に関してはプライベートレンジの範囲で任意に入力して問題ありません。(Second)Custom Azure APIPA BGP IP address については、Azure のサポートする BGP IP のレンジが 169.254.21.* ~ 169.254.22.* である点、後述しますが GCP 側が Peer BGP IP(この場合は Azure BGP IP を指します)が "/30 subnet" 以内に居ないといけない制約がある点に注意が必要ですが、この範囲で有れば任意で問題ありません。

GCP 側で Peer VPN Gateway x 1 を作成

GCP 側に移動して Peer VPN Gateway を作成します(Azure 側でいう Local Network Gateway)。今回は高可用性のオプションを設定しているので、two interfaces のオプションを選択し、以下の様に Azure 側の VPN Gateway の Public IP アドレス x 2を指定します。

GCP 側で Cloud VPN Gateway x 1 を作成

Peer VPN Gateway では「Azure 側の VPN Gateway ってこのアドレスだよ」というガワを作成しているだけなので、GCP 側でも本体である Cloud VPN Gateway を作成する必要があります。VPN Gateway の所属する Network と Region を指定して Cloud VPN Gateway を作成します。作成後、以下の様に Public IP が二つ割り当てられるので、Azure 側で Local Network Gateways を作成する際にはこちらを利用します。

GCP 側で Cloud Router x 1 を作成

GCP 上では Cloud Router を作成します。こちらは BGP の動的ルーティングを行うために必要なコンポーネントになります。この辺り Azure は VPN Gateway 側のリソースに統合されてみえるので、見た目上の違いとして表れている点だと思います。

ここで GCP 側の ASN を指定します。この値はプライベートレンジかつ Azure 側の ASN と異なる必要があります。今回は 65509 を指定しました。

GCP 側で VPN Tunnel x 2 を作成

GCP 側では Cloud VPN Gateway, Peer VPN Gateway, Cloud Router と一通りの登場人物が作成できたので、漸く VPN Tunnel x 2 を作成します。Cloud VPN Gateway の画面から VPN Tunnel を作成できますが、原則は既に作成済のリソースを選ぶだけだと思います。IKE-pre-shaed key をここで pick up し、後で Azure 側で Connection を作成する際に利用する点、VPN Tunnel は二つ作る点に注意してください。

GCP 側で BGP Session x 2 を作成

Configure BGP sessions は後で設定する様に選択し、いったん設定を完了します。その後、VPN Tunnels 一覧から BGP の設定をします。以下に設定例を記載していますが、ここで Azure 側で設定した ASN 番号と Custom Azure APIPA BGP IP address を利用します。

設定名 設定値
Peer ASN 65510(Azure 側で設定した値)
Cloud Router BGP IPv4 address 169.254.21.13
BGP Peer IPv4 address 169.254.21.14(Azure 側で設定した値)

本記事では片方の VPN Tunnel のみ設定を記載していますが、高可用性のために用意したもう一つの VPN Tunnel 側も同様に設定してください。

Azure 側で Local Network Gateways x 2

これで漸く GCP 側は一通りの設定が完了したので、Azure 側に戻り、Local Network Gateway を二つ作成します。以下を参考にリソースを作成して下さい。

設定名 設定値
IP Address 35.242.112.236(GCP 側の Cloud VPN Gateway の Public IP #1)
Address Space(s) 10.101.0.0/16(GCP 側の VPC Network のアドレス )

繰り返しとなりますが、こちらの操作も高可用性のために GCP 側の Cloud VPN Gateway 二つ目にあたる Local Network Gateway も作成を忘れない様にして下さい。

Azure 側で Connections x 2

最後に Azure の Virtual Network Gateway から Connections を二つ作成します。これで設定は完了するはずです。

設定名 設定値
Connection Type Site-tosite(IPSec)
Local network gateway GCP 側の Public IP を指定した上記で作成のリソース
Shared key (PSK) GCP 側で pick up した値
Enable BGP 有効化
Enable Custom BGP Addresses 有効化
Custom BGP Addresses GCP 側で設定した BGP peer IPv4 address を設定

設定が上手くいかない場合

Azure 側では Virtual Network Gateway の Connections メニューで接続状態が確認できます。以下の様に Status が Unknown の場合は VPN の接続自体でこけています。この場合は shared key や各 IP アドレスの設定を見直してください。

VPN 接続が上手くいった場合でも以下の様に BGP sessions status が waiting for peer のままで BGP のルーティングが始まらない場合があります。

当然 BGP ルータの IP アドレス等の設定を再確認が必要ですが、何度も設定を見直しているせいで反映がどうなっているかの把握が難しい状態で BGP の設定が完了しない場合、以下の Azure の Virtual Network Gateway 側で Reset を試すと上手く接続が完了する場合があります。Reset 配下にある VPN troubleshoot も VPN 接続時のトラブルシューティングには参考になります。

Azure Front Door のログ情報を Kusto クエリで眺めてみる

前回は Azure Front Door に対してカスタムドメイン設定とBring Your Own Certificate (BYOC) 設定を行った場合のハマりどころについて紹介しました。今回は Azure Front Door のログデータを Log Analytics に送付し、Kusto Query をいくつか発行してデータを確認してみようと思います。

Azure Front Door 側のログ設定

まずは Azure Front Door 側で Diagnostic setting を有効化します。ここでは FrontDoorAccessLog, FrontDoorHealthProbeLog, FrontDoorWebApplicationFirewallLog のカテゴリがありますが、当然すべて選択して作成済の Log Analytics ワークスペースにデータを転送します。

Azure Front Door に関わらず Log Analytics のログ転送はいちど有効化して安定した後の場合、体感的には遅くとも数分以内に Log Analytics ワークスペース側にログが転送されています。しかし、初回設定時には8時間?程度の時間がかかる場合があるので注意ください。

Azure Front Door の基本的なログ情報

以下に何のひねりもない Kusto Query を発行した結果を張り付けたのでご賞味ください。

AzureDiagnostics テーブルでは通信プロトコル(HTTP/HTTPS)、ステータスコード、ホスト名、Azure Front Door の Origin URI、アクセス元の国等々が取得できるのが確認できると思います。Usage テーブルは Log Analytics ワークスペースに流れ込むデータ量がログとして蓄積されていますが、今回は割愛します。

何カ国かからのアクセスが来ているかは以下の様なクエリで抽出が可能です。私は現在米国におり、テスト用に頻繁にアクセスしたのでデータに表れています。

AzureDiagnostics |
where Category == "FrontDoorAccessLog" |
summarize access_by_country = count() by clientCountry_s

次にどの URI に一番アクセスされたかを以下の Kusto Query で取得してみましょう。

AzureDiagnostics |
where Category == "FrontDoorAccessLog" |
summarize requests_of_each_uri = count() by requestUri_s |
order by requests_of_each_uri 

さらに 404 のステータスコードを返した URI が何かの一覧は以下で取得できます。

AzureDiagnostics |
where  Category == "FrontDoorAccessLog" |
where httpStatusCode_s == 404 |
summarize by requestUri_s

ここまでで FrontDoorAccessLog カテゴリの基本的な情報を操作する方法は理解で来たと思いますので、次は FrontDoorWebApplicationFirewallLog 側を見てみます。

Azure Front Door の WAF 機能のログを確認してみる

FrontDoorWebApplicationFirewallLog は WAF 機能でのマッチングしたリクエストの情報が出力されます。試しに以下のカスタムルールを作成し、当該 Azure Front Door に付与します。

本ルールはアクセス元の地域が米国だった場合に Log Analytics ワークスペース側に情報を転送するものです。実際に Kusto Query を発行して情報を確認します。

AzureDiagnostics |
where Category == "FrontDoorWebApplicationFirewallLog"


ご覧の通り、どの URI にアクセス時、ルールにマッチングしたか、どの様なアクションが取られたか等がログの情報から分かります。スクリーンショットでは action_s は Logであり、ログ情報が出力されるだけの設定です。

感の良い方なら気づいたかもしれませんが、ルール名にある通り最初はアクセスをブロックしようとしました。ログとしては以下です。action_s は Block として出力されているのですが、ブラウザからは普通にアクセスできてしまいました。こちらは私の設定ミスかもしれませんので、何か気づきが有ればまた更新したいと思います。これは policyMode_s に記載があるとおり detection モードで動作していることが原因です。こちらを prevention モードに変更すればブロックされます。

カスタムドメイン&BYOC で Azure Front Door を試した際のハマりどころ

その昔から Azure には Traffic Manager と呼ばれるリージョンレベルで負荷分散が行える機能がありましたが、同機能の位置づけはグローバル DNS 的なものであり、WAF 的な機能、URL の書き換え、SSL オフロードといった機能を利用したい場合、リクエストをリージョンレベルに振り分けた後、リージョン単位でのサービス(Azure 組み込み機能だと Application Gateway が一般的)で制御をおこなうのが一般的でした。Azure Front Door はリージョンを跨いでのリクエスト振り分けが可能なことに加え、上記で記載した機能も同リソースを用いることで実現可能です。
https://docs.microsoft.com/en-us/azure/frontdoor/front-door-overview

Azure Front Door には Standard と Premium と呼ばれる二つの SKU がありますが、特に Premium SKU を利用する場合は Private Link の利用が可能になります。Standard SKU でも機能的に十分なことが多いとは思いますが、いわゆるエンプラ的なお客様のコンプライアンスに沿うために閉域的な通信が必要な場合には必須な機能といえます。
https://azure.microsoft.com/en-us/pricing/details/frontdoor/

生まれも社畜、育ちも社畜、今は外資社畜としてコテコテのエンプラ道を歩んできた身からすれば、上記の Private Link に加えて「カスタムドメイン」と「Bring Your Own Certificate (BYOC) 」を試さざるを得ないと思い色々と試しました。結果的には以下の構成になっております。今回は Azure Front Door で SSL オフロードをしていますが、こちらは要件に合わせて調整下さい。

これに関しては色々とハマりどころがあり、ハマりどころときれいな設定手順を混ぜるとこんがらがりそうだったので、今回はハマりどころに注力して記載しております。

Azure Front Door に証明書を登録する際には Azure AD の Global Administrator 権限が必要になる場合がある

Azure Front Door は Azure Key Vault 経由でしか証明書が読み込めません。そのため Azure Front Door 向けの Service Principal を作成・登録して操作する必要があるのですが、こちらの処理時に当該 Azure AD の Global Administrator 権限が必要になります。

Note

This action requires you to have Global Administrator permissions in Azure AD.
 The registration only needs to be performed once per Azure AD tenant.

https://docs.microsoft.com/en-us/azure/frontdoor/front-door-custom-domain-https

ただこちらは Azure AD テナント毎に一度操作を実行すればよいので、Global Administrator に処理を頼むことができれば問題ありません。つまり Azure Front Door のリソースを何個作ろうと同じサービスプリンシパルを使いまわすことになります。この辺りはヘイシャーにお勤めの方とかは Microsoft.AzureFrontDoor-Cdn とかの名前で Service Principal を探せば見つかると思います(以下参照。
Register Azure Front Door CDN with Key Vault - Azure Tech Guy

Azure Front Door はオレオレ証明書をサポートしない

こちらに関しては良く言えば「セキュリティ的に厳密さが高いのがデフォルト設定になっている」ともいえますが、開発時には中々大変です。以下にはっきりと記載がありますが、自己証明書を利用する場合はアクセスがブロックされます。

When you create your TLS/SSL certificate, you must create a complete certificate chain with
an allowed Certificate Authority (CA) that is part of the Microsoft Trusted CA List. If you use 
a non-allowed CA, your request will be rejected.

Certificates from internal CAs or self-signed certificates aren't allowed.

End-to-end TLS with Azure Front Door | Microsoft Docs

トラステッド認証局 (CA) からの署名済み証明書を取得する必要がありますが、ここは Azure Front Door をお試しで試す場合に大きなハードルの一つ目です。こちらに対しては App Service Certificate を利用しました。ご存じない方も居るかも知れませんが、同機能は App Service 専用ではありません。
Add and manage TLS/SSL certificates - Azure App Service | Microsoft Docs

Azure Front Door は HTTPS 通信時に CN がマッチングしないと通信をはじく

開発環境と似たような設定で本番リリースした結果で痛い目を見ることを避けらるようになっているとも言えますが、やはり開発時にはハードルが高いです。節のタイトルに加えて Azure Front Door 自体には「apex/root ドメインは未サポート(normalian.work とかはダメで、www.normalian.work とかならOK」という制約もあります。

Enabling HTTPS via Front Door managed certificate is not supported for 
apex/root domains (example: contoso.com). You can use your own
certificate for this scenario. Please continue with Option 2 for further details.

Tutorial - Configure HTTPS on a custom domain for Azure Front Door | Microsoft Docs

ここで注意が必要なのが、当然ながら App Service Certificate は apex/root ドメイン(normalian.work 等)で作成する必要があるということです。何が問題かというと、Azure Front Door 自身は apex/root ドメインは未サポート( www.normalian.work とかならOK )の点とでドメイン名に不整合が発生します。私は

  • App Service Certificate で normalian.work ドメイン向けの Standard SKU の証明書作成
  • Azure Front Door で www.normalian.work のカスタムドメイン登録

を行い、一通りの設定をしましたが、当然疎通は通らず、Log Analytics のログを確認したところ CertificateNameCheckFailed のエラーが発生していました。

こちらに関しての回避方法は比較的容易で App Service Certificate 側でワイルドカード証明書として作成する方法です。

App Service Certificate 上でワイルドカード証明書として作成した場合、www.normalian.work といったドメインでも対応が可能になります。Azure Front Door には Azure Key Vault 経由で登録されるので以下の様になります。

CNAME レコードの登録、TXT レコードの登録が必要

こちらに関しては大して問題ならないかもしれませんが、Azure Front Door でカスタムドメインを登録する場合はタイトルで記載した二つの処理が必要になります(以下は設定済の環境。

How to add a custom domain - Azure Front Door | Microsoft Docs

私は未だにメールの多さでちょっと辛いお名前ドットコムを使っており、以下が同サイトでの設定画面になっています。一つ目の CNAMEと三つ目の TXT レコードが Azure Front Door 向け、二つ目の TXT レコードが App Service Certificate 向けと言ったところです。

今回はほぼ証明書とカスタムドメインでのハマりどころを記載しましたが、誰かの手助けになれば幸いです。

Tips to attach Ultra disk to Azure VMs

I believe Ultra disks are essential for mission critical workloads - SAP, Oracle DB or other high IOPS workloads. Here are some tips to attach Ultra disks for your existing VMs.

Confirm availability and zone for Ultra disk

Ultra disk is not available in all Azure regions. You should confirm availability for Ultra disk in your regions.
Select a disk type for Azure IaaS VMs - managed disks - Azure Virtual Machines | Microsoft Docs
But I can attach Ultra disk to my "Standard B4ms (4 vcpus, 16 GiB memory)" VM in West US 2 region as of 17th Jan 2022. The availability might be expanded.
f:id:waritohutsu:20220118065937p:plain
f:id:waritohutsu:20220118065852p:plain

In addition to regional perspective, you need to note that you should put your Ultra disks on same zones with your VMs, otherwise you can't attach your Ultra disks to your VMs.
f:id:waritohutsu:20220118065319p:plain

Adjust IOPS and disk size for your env

As default, it's only 1024 IOPS even if you will choose Ultra disk. You should change the disk size and Disk IOPS to retrieve Ultra disk performance completely. This screenshot shows maximum IOPS per disk as of Jan 2022.
f:id:waritohutsu:20220118064101p:plain

Enable additionalCapabilities.ultraSSDEnabled property for your VMs

You would get error below if you will try to attach Ultra disks to your VMs. It's required to enable additionalCapabilities.ultraSSDEnabled property on your VMs.
f:id:waritohutsu:20220118065457p:plain

Keep in mind that you have to make your VMs deallocated when you will enable additionalCapabilities.ultraSSDEnabled property by running commands below or other ways.

az account set --subscription "your subscription"
az vm update -n "your vm name" -g "your resource group name" --ultra-ssd-enabled true