Azure CDNによるコンテンツ配信について

## 1. はじめに

Azure CDNとAzure Storageを利用してWebコンテンツを配信する方法を確認したので、備忘録として残しておきたいと思います。Azure DevOpsで最新コンテンツをAzure Storageへ格納する方法も確認してみましたが長くなるので別途備忘録を残したいと思います。

## 2. Azure CDNについて
[Azure CDN](https://docs.microsoft.com/ja-jp/azure/cdn/)は、Azure StorageやAzure AppService、Webサーバ上のコンテンツの高速配信を可能とするサービスです。
Azure Storage(Blob)にWebコンテンツ(HTML/JavaScript/CSS/他画像など)を格納しておき、そのコンテンツをAzure CDNのエッジサーバを経由してユーザに配信するという流れになります。

Azure Storage単体(ストレージアカウントの種類がStorageV2)でも[静的Webホスティングの機能](https://docs.microsoft.com/ja-jp/azure/storage/blobs/storage-blob-static-website-host)があるので、Azure CDNを使わなくてもAzure Storage上のWebコンテンツの配信は可能ですが、AzureCDNを使うとユーザの地域に近いエッジサーバからコンテンツを取得する(キャッシュもある)ため、各リージョンに展開されたAzure Storageからコンテンツを取得するより高速になります。(DirectoryIndex対応など、場合によってはAzure CDNの配信元をAzure Storageの静的Webサイトに指定するということもあると思います)

AWSでは[CloudFront](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/Introduction.html)が同種のサービスとして提供されています。

### Azure CDNのプロファイルとエンドポイント
Azure CDNにはプロファイルとエンドポイントという仕組みがあります。

#### エンドポイント
エンドポイント(CloudFrontで言うところのディストリビューション)は、コンテンツのアクセス先となるホスト名と配信元を紐づけたものとなります。配信元は実際にWebコンテンツが存在するオリジンサーバです(Azure Stroge,Azure AppSerivceや任意のWebサーバを配信元として設定可能のようです)。
エンドポイント単位で、カスタムドメインやキャッシュや最適化設定などの設定を行います(Premium Verizonを利用する場合はプロファイル単位での設定となる)。

１つのエンドポイントには１つの配信元のみの指定となるため、同一ドメイン名でこのパスの場合はWebコンテンツを取得しこのパスの場合には別のWebサーバ上のWebコンテンツ(またはWebAPI)を取得するという制御はできません。
(ここはCloudFrontとの違いであり、CloudFrontでは１つのディストリビューションに複数のオリジンを設定してBehaviorsによってパスに応じてアクセスさせるオリジンを切り替えるということができます。）

ユーザのアクセス先となるURLはこのエンドポイントのホスト名を指定したものになります。


#### プロファイル
Azure CDNでは、Microsoft標準のCDN/AkamaiのCDN/VerizonのCDNなど、複数のCDN製品を選択することが可能になっています(各種CDN製品の比較は[こちら](https://docs.microsoft.com/ja-jp/azure/cdn/cdn-features)を参照)。
Azure CDNのプロファイルでは、CDNとして上記どの製品を利用するかを選択します。またプロファイルはエンドポイントを集約したものになります(そのためエンドポイントで設定できる内容はエンドポイントが属するプロファイルのCDN製品に依存することになります)。

プロファイルとエンドポイントは1:Nの関係であり、エンドポイントを設定する前にプロファイルを作成しておく必要があります。

Azure CDNのプロファイルをデプロイしたリージョンとプロファイルで選択したCDN製品によって[料金](https://azure.microsoft.com/ja-jp/pricing/details/cdn/)が変動していきます(送信データ転送量による課金)。

## 3. Azure CDNのプロファイルとエンドポイントの作成
それでは、コンテンツ配信元となるAzure StorageとAzure CDNのプロファイルおよびエンドポイントを作成していきます。
今回AzurePortalで設定していきます。最終的にはARMテンプレートなどで展開できるようにした方が良いでしょう。

### 3.1. Azure Storageのストレージアカウント作成
Azure Portalからストレージアカウントを選択し、「追加」を選択します。
リソースグループやストレージアカウント名、リージョン名などを指定し作成を行います。
アカウントの種類は静的Webホスティングへ変更することも考慮しStorageV2にしました(Webホスティングを使わない場合はBlobStorage)。
![azurecdn01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280717/8fe8347e-48cf-639a-0fb8-abd87912648f.png)
![azurecdn02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280717/e0b3f644-50c3-d683-5a94-3ee3e55397e4.png)


ストレージアカウントが作成できたら、Blob ServiceからBlobを選択し、新規コンテナーを作成します。このコンテナーの中に配信するWebコンテンツを格納します(試しにindex.htmlなどを格納しておきます)。
![azurecdn03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280717/be6db3e9-84b2-2227-6fac-af65a426fd16.png)
![azurecdn04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280717/7e6e8a74-89e1-86c9-2e16-c635a94e29cf.png)

### 3.2. Azure CDNのプロファイル作成
Azure CDNのプロファイルを作成していきます。
Azure Portalから「CDNのプロファイル」を選択し、「追加」を選択します。
CDNプロファイル名と展開するリソースグループ、価格レベル(CDNの製品)を選択し作成を行います。
![azurecdn05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280717/94f651ac-cba6-6661-505c-0e824e800ad3.png)
Azure CDNが展開されるリージョンはリソースグループのリージョンと同一のようです。

### 3.3. Azure CDNのエンドポイント作成
Azure CDNのエンドポイントを作成していきます。
Azure Portalから先ほど作成したCDNのプロファイルを選択し、「＋エンドポイント」を選択します。
![azurecdn06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280717/3194bdb2-faaf-073a-b952-cfd7691744ec.png)

名前にはユーザがアクセスする際のホスト名を指定します。
配信元の種類ストレージ・配信元のホスト名を作成したストレージアカウントを指定します。また配信元のパスはストレージアカウントに作成したコンテナを指定します。
![azurecdn07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280717/c4d9011e-a9d3-9fb0-c06b-387d8a56b69a.png)


作成が完了し、エンドポイントの概要画面を開くと以下のようになります。
(作成が完了してからユーザがコンテンツを取得できるようになるまで数十分かかる場合があるようです)
エンドユーザは「エンドポイントのホスト名」に記載されているURLにてアクセスすることになります。カスタムドメインを設定して自分が所有するドメイン名でコンテンツを配信することも可能です。

```https://<ホスト名>.azureedge.net``` にアクセスすると、ストレージアカウントの配信元パスで指定したコンテナーからコンテンツを取得するという動きになります。

![azurecdn08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280717/9ee816b3-775b-b9b3-4fce-54579ee9adda.png)

### 3.4. サンプルのコンテンツ格納
Azure CDNによりコンテンツを取得できるか、Azure Storageのコンテナー上にサンプルコンテンツを格納し、ブラウザからアクセスできるか確認します。

サンプルは[こちら](https://docs.microsoft.com/ja-jp/azure/active-directory-b2c/active-directory-b2c-tutorials-spa)のAzureAD B2C確認用のサンプルシングルページアプリを配置してみます。
index.html内にHTMLとJavaScriptコードが記述されているので、このファイルのみをAzureStorageにアップロードし、ブラウザからアクセスしてみます。

![azurecdn09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280717/4f69f6fd-56c4-d704-4dab-9654a582e0d5.png)
コンテンツにアクセスでき、AzureAD B2Cの認証も正常にできました。
WebAPIアクセスはAPI側にCORSの設定をしていないのでエラーになっていますが、想定通りアクセスは可能なようです。

なおDirectoryIndexが効いていないので、パス名の記述も必要です。
これを解決するには、現時点ではAzureStorageの静的Webサイトを有効にしAzureCDNの配信元をAzureStorageの静的Webサイトに指定する対応を取ることになります。
(CloudFrontでもサブディレクトリのDirectoryIndexが有効にならないので、S3バケットに静的Webホスティングを有効にしてCloudFrontのオリジンに指定するという同様のやり方をする場合があります)
Azure CDNにはURLRewrite機能がありこれで実現できそうですが、URLRewriteはPremiumの機能のようでした。

Azure DevOps(Azure RepositoryとAzure Pipelines)を活用すれば、GitリポジトリにコンテンツをPUSHしたらAzureStorge上に最新コンテンツを配置するというやり方も可能ですね。

### カスタムドメインと証明書の設定について (修正/追記)
あとはAzure CDNにカスタムドメインを作成して、自分が所有するドメイン名でアクセスできるようにすれば、完成になるかなと思います。(カスタムドメイン設定時に検証が入るので、事前にCNAMEレコードを登録しておく必要があります)
またHTTPSを利用する場合はCDNマネージドな証明書かKeyVaultの証明書を設定が必要です。

CDNマネージドの証明書を使う場合、ドメインの検証が必要でCNAMEレコードの登録かWHOISに登録されたアドレスにメールが送信されるようです。(CDNマネージドの証明書を使う場合の設定については[こちら](https://docs.microsoft.com/ja-jp/azure/cdn/cdn-custom-ssl?tabs=option-1-default-enable-https-with-a-cdn-managed-certificate)を参照。)

CNAMEレコードはある程度間をもって登録しておく方が良さそうです。タイミングによっては(DNSレコードが伝搬しきれていなかったらしく)CNAMEの検証を迂回してメールの検証になってしまう場合もあるようです。ここでなかなか終わらないなとカスタムドメインごと削除してしまうと８時間は同じFQDNでCDNマネージド証明書を取得できないため、待機時間が増加します。
(DNSの伝搬が完了したかは```http://digwebinterface.com/```などでも確認できます。)

メールでの検証の場合は```validation@digicert.com```から以下のメールが届くようなのでリンクをクリックして検証を進めます。(admin@,administrator@,webmaster@,hostmaster@,postmaster@に届く。Route53など登録者情報のプライバシー設定が有効になっているドメインの場合でも届くようで、数時間後に検証メールが届きました。)

・件名

```
Please validate ownership of your domain ドメイン名 -- DigiCert order オーダー番号
```

・本文

```
Microsoft

DigiCert recently received a certificate request that requires approval prior to the certificate's issuance.

To review and approve this request, visit the following link:

https://www.digicert.com/link/approve.php?t=ID

Domain names requiring your approval: [ドメイン名]

The certificate was requested by:

Microsoft CDN
MicrosoftCDN@microsoft.com
1 (800) 642-7676

If you do not approve of this request, or if you have any questions or concerns please contact us directly.

Thanks!

The DigiCert Team

Phone: 1-801-701-9600
Email: support@digicert.com
Live Chat: www.digicert.com
```

手順や画像は[こちら](https://docs.microsoft.com/ja-jp/azure/cdn/cdn-custom-ssl?tabs=option-1-default-enable-https-with-a-cdn-managed-certificate#custom-domain-is-not-mapped-to-your-cdn-endpoint)に記載されている内容と同じものでした。



## 4. まとめ
Azure CDNを使いAzure Storage上のコンテンツを配信する方法を確認してみました。
Azure Storage上にシングルページアプリを配置し、アプリ内からAzure Functions上に構築したWebAPIを呼び出すという構成にすれば、サーバーレスなアプリケーションを構築することが可能と思います。
あとはAzure Storageに配置するコンテンツとAzure Functions用のコードをAzure DevOpsでデプロイできるようCICD環境を構築すれば業務でもうまく活用できると思います。


##参考情報
[Azure CDN のドキュメント](https://docs.microsoft.com/ja-jp/azure/cdn/)
[チュートリアル:Blob Storage で静的な Web サイトをホストする](https://docs.microsoft.com/ja-jp/azure/storage/blobs/storage-blob-static-website-host)
[Azure CDN 製品の機能を比較する](https://docs.microsoft.com/ja-jp/azure/cdn/cdn-features)
[Content Delivery Network の価格](https://azure.microsoft.com/ja-jp/pricing/details/cdn/)
[チュートリアル:Azure CDN カスタム ドメインで HTTPS を構成する](https://docs.microsoft.com/ja-jp/azure/cdn/cdn-custom-ssl?tabs=option-1-default-enable-https-with-a-cdn-managed-certificate)