Azureのコンテナサービス、どれ使えばいい？

仕事でMicrosoft Azureでサービスを用意する必要があり、IaaSは後々面倒だからコンテナベースのサービスにしようと考えたのですが……

> どれを使えばいいん？

と思い至ったわけです。
Azure上のコンテナサービスをあれこれ調べて、実際に使ってみて、 それぞれの向き不向きについて体感したものがるので、整理したいと思います。

## TL;DR

-   Azure上のコンテナサービスは3つ
    -   Azure Container Instance (ACI)
    -   Azure Kubernetes Service (AKS)
    -   Azure Container Apps (ACA)
-   アプリケーションの機能を提供するコンテナ(メインコンテナ)の数で考える
    -   メインコンテナが1つだけならACI
    -   メインコンテナが複数あるのであれば、あるいは今後増やす予定があればAKS / ACA
-   独自ドメインはどのサービスでも利用可能。ただし、設定方法はまちまち
    -   ACIではDNSにCNAMEレコードを設定
    -   ACAではサービス内の「カスタムドメイン」設定
    -   AKSではDNSにAレコードを設定
    -   Application Gatewayを使う場合はDNSとAレコード設定
-   証明書が自動でついてくるのはACAだけ
    -   ACI / AKSはACMEでの証明書の自動設定が可能
    -   AKSでカスタムドメインを使おうとするととたんに面倒くさくなる
-   とにかくドメインも証明書もAzureから提供されたものでいい！　のであればACA
-   ACMEによる証明書設定をするのであればACI / AKS
-   なんだかんだ融通がきくのはAKS
-   k8sのコマンドエコシステムを利用するならAKS

## Azureのコンテナサービスはなに？

Azureで提供されているコンテナサービスは3つあります。実際にはOpenshiftとかarc k8sなんてのもありますが、100%Azureという意味では3つかなと。

### Azure Container Instances

Azure Container Instances(ACI)は1つの仮想マシン上でコンテナを実行できるサービスです。
利用者は仮想マシンの管理をする必要はなく、仮想マシン上で実行するコンテナを管理するだけです。

イメージ的には、Azure Virtual Machine1台の上でコンテナを動かす形です。

[Azure Container Instances とは - Microsoft Azure](https://learn.microsoft.com/ja-jp/azure/container-instances/container-instances-overview)

### Azure Kubernetes Service

Azure Kubernetes Service(AKS)はAzure上でのフルマネージドK8sサービスです。
Azure Virtual Machine Scale Set(VMSS)を基盤として、Azure Load BalancerやパブリックIPアドレス、Azure Application Gatewayなど複数のサービスの組み合わせで構築されています。機能もりもりです。
VMSSを利用したk8sクラスタの自動水平スケーリングや、KEDAを利用したデプロイメントの水平スケーリングも可能です。

当然ながら、K8sエコシステムのコマンド、`kubectl` `helm` などを使用することが可能です。

[Azure Kubernetes Service (AKS) とは - Microsoft Azure](https://learn.microsoft.com/ja-jp/azure/aks/what-is-aks)

### Azure Container Apps

Azure Container Apps(ACA)はサーバレスk8sプラットフォームです。
k8sなのにサーバレス？　というのは疑問かもしれませんが、こちらはAKSを基盤として、しかしk8s管理のあれこれはすべてAzure任せ(`helm`や`kubectl`が利用できない)となっています。

k8s特有の大量のマニフェスト投入をする必要もなく、GUI / CLIで実行するコンテナ設定やKEDAの条件設定をすることでk8sで動くようなアプリケーションを実行できます。

[Azure Container Apps の概要 - Microsoft Azure](https://learn.microsoft.com/ja-jp/azure/container-apps/overview)

## まず考えるべきは中核となるコンテナの数

さて、3つあるサービスのどれを選ぼうか、という話ですが。
まずは **何を動かしたいのか？** というのがポイントです。

この手のコンテナでは、動作の性質によって、3種類のコンテナがあると思います。

-   initコンテナ
-   サイドカーコンテナ
-   コンテナ(本稿では「メインコンテナ」)

コンテナは動かしたいものの本体に当たるものです。他のコンテナとの対比としてメインコンテナと表現します。
initコンテナはメインコンテナ実行の前に初期化処理を行うコンテナで、メインコンテナ実行前に終了するものです。DBの稼働確認とか、ファイルシステムの権限確認とか。
サイドカーコンテナはinitコンテナの亜種となりますが、メインコンテナと並行して動作し、メインコンテナの補助を行うものです。ログ転送エージェントとか、もろもろ監視エージェントとか。

ACI / AKS / ACAいずれでもinitコンテナ、サイドカーコンテナは対応しています。メインコンテは言わずもがな。

となると、分岐点はメインコンテナにあります。
コンテナで実行するアプリケーションの場合、メインコンテナが1つだけとは限りません。コンポーネント別にコンテナが別れていて、それぞれを配備して連携して動作させる必要性があります。APIコンテナとWeb GUIコンテナみたいな区別が分かりやすいでしょうか。

実のところ、3つのコンテナサービスはすべて複数のメインコンテナを実行する機能があります。しかし、コンテナ間の接続方法について大きな違いがあります。

| サービス | 接続方法                                                         |
| :------: | :--------------------------------------------------------------- |
|   ACI    | localhost:<公開ポート>で接続。<br />コンテナでポートの重複は不可 |
|   AKS    | k8sの仕様(サービスなら<サービス名>.<名前空間>.svc.cluster.local) |
|   ACA    | コンテナアプリ名(アプリ名がsome-appであればsome-appで接続)       |

特にACIの接続方法が独特です。docker composeのようなイメージで触ると戸惑うこと間違いなしです。localhostでつなぎに行くし、コンテナが公開するポートはそれぞれユニークである必要がある、と。
これはあれですね、複数のメインコンテナを動かす前提にないやつです。

ということで、メインコンテナが1つならACI、複数ならAKSかACAが良いかと思います。

## ドメインと証明書

パブリッククラウドのコンテナで動かしたいものといえば、多くはWebアプリケーションになるかと思います。
となると切っても切り離せないのがドメインと証明書です。証明書についても購入した証明書を使用したり、ACME対応のサービス(Let's Enctyptとか)で動的に証明書を取得するでしょう。
このあたりにも色々と考え方の違いが垣間見えます。

### ACI

ACIの場合、インスタンス1つにFQDNが割り当てられます。
IPアドレスについては隠蔽されているため、`nslookup`などで見ない限りわかりません。
仮想ネットワークにデプロイしない場合はパブリックIPアドレス、仮想ネットワークにデプロイする場合はサブネット内のプライベートIPアドレスが割り当てられます。

FQDNは以下の形式で提供されます。

```
dns-name-label.region.azurecontainer.io
```

dns-name-labelは作成時に設定できる識別子になります。regionは配置するロケーションですね。東日本ならjapaneast、みたいな塩梅。

#### カスタムドメイン

ACIでは直接自前のドメインを設定する方法はありません。
そのため、保有するDNSにおいて、CNAMEレコードで上記FQDNを設定することでカスタムドメインでの通信を実現します。

また、仮想ネットワーク内に配置されている場合、FQDNは内部ネットワーク内でしか機能しないため、Azure Application Gateway経由でのアクセスとなります。この場合、Azure Application Gatewayに設定するフロントエンドIPアドレスと自前ドメインをAレコードまたはAAAAレコードで紐づける必要があります。

#### 証明書の扱い

このFQDNに対して証明書は設定されません。
証明書の設定にはサイドカーコンテナを利用します。公式ドキュメントではサイドカーコンテナとしてCaddyを使用したACMEによる証明書利用が解説されています。

[サイドカー コンテナー内で Caddy を使用して自動 HTTPS を有効にする - Microsoft Azure](https://learn.microsoft.com/ja-jp/azure/container-instances/container-instances-container-group-automatic-ssl)

### AKS

AKSの場合、コントロールプレーンに対するFQDNは設定されますが、webアプリケーションに対してはIPアドレスが割り振られるだけ（Ingressリソースの適用後に初めて分かる）であり、FQDNの割当はありません。

IPアドレスについては、マネージドNGINXイングレスコントローラであるアプリケーションルーティングの場合はパブリックIP、Azure Application Gatewayを使用するApplication Gateway Ingress Controller(AGIC)の場合はプライベートIPが割り当てられます。

どちらにせよ、FQDNによるアクセスをするためには自前のドメインを保有している必要があります。

#### 証明書

FQDNが割り当てられない以上、証明書の割当もありません。AKSでは証明書の扱いには2種類が利用可能です。

-   Azure Key Vault
-   cert-manager(helm)

購入した証明書を利用するならAzure Key Vault, ACMEを利用するならcert-managerの利用が好適かなと。

[アプリケーション ルーティング アドオンを使用してカスタム ドメイン名と SSL 証明書を設定する - Microsoft Azure](https://learn.microsoft.com/ja-jp/azure/aks/app-routing-dns-ssl) [AKS クラスター用の Application Gateway で Let's Encrypt 証明書を使用する - Microsoft Azure](https://learn.microsoft.com/ja-jp/azure/application-gateway/ingress-controller-letsencrypt-certificate-application-gateway)

### ACA

ACAの場合、公開設定としたアプリの場合FQDNが割り当てられます。IPアドレスについては隠蔽されていますが、仮想ネットワーク内に配置する場合はサブネット範囲のプライベートIPアドレス、microsoftマネージドネットワーク(==仮想ネットワーク内に配置しない)に配置する場合はパブリックIPとなります。

FQDNは以下の形式で提供されます。

```
app_name.unique.region.azurecontainerapps.io
```

app_nameはアプリケーション名、uniqueはランダムな識別子で、作成後に初めて分かるものです。regionは配置するロケーション。

#### カスタムドメイン

自前ドメインの利用については、microsoftマネージドネットワーク上にある場合、カスタムドメインの設定を行うことができます。
仮想ネットワーク内の場合、ACA自体は外部公開されていないため、Azure Application Gatewayを利用する必要があります。この場合、Azure Application Gatewayに設定するフロントエンドIPアドレスと自前ドメインをAレコードまたはAAAAレコードで紐づける必要があります。

#### 証明書

公開IPが割り当てられているFQDNの場合、Microsoftより証明書の割当がされています。
カスタムドメインでmicrosoftマネージドネットワーク上にある場合は試していないのでどうなるのか分からないです……(Microsoftから証明書割当がありそうな気がしますが……)

カスタムドメインでAzure Application Gatewayを使用する場合はAzure Key Vaultとの連携が必要です。

サイドカーとしてcaddyを使って簡単証明書設定、cert-managerで簡単証明書設定なんてふうにはいかなさそうなんですよね……

一応 [Key Vault Acmebot](https://github.com/shibayan/keyvault-acmebot)というshibayan氏による実装があるので、ACME対応自体は可能です。

## ネットワーク監視性

ACI / AKS / ACA のネットワーク監視を行ったり、仮想ネットワーク内のリソースを公開するには、Azure Application Gatewayを利用することになります。
このとき、Microsoft割当のFQDNを直接使用できなくなるので、カスタムドメインまたはAzureパブリックIPアドレスのドメインネームラベルを使用したドメイン`domain-name-label.region.cloudapp.azure.com`を使用する必要があります。

証明書についてはACIはサイドカーコンテナ、AKSはcert-managerで処理ができるのでそこまで不都合があるとは思えませんが、ACAの場合は結構大変です。

もともとのFQDNに設定された証明書は当然使用できません。また、ACMEを使用するためにKey Vault Acmebotを使用する場合、このツールはDNS01方式でドメイン検証を行うため、TXTレコードを作成できるDNSゾーンが必要です。
つまり自前ドメインが必須、`domainnamelabel.region.cloudapp.azure.com`は使用できません。

Azure Application Gatewayを使用してあれこれしたい場合(仮想ネットワーク内からのサービス公開、L7ロードバランシング、WAF)、コンテナサービスをACAで構築するとACAのいいところが結構潰されてしまうんですよね……

## マインドと使い分け

いろいろとまとめてみましたが、これら踏まえて自分なりの考え方・使い方を整理したいなと。

-   メインコンテナは？　→1つならACI、複数ならAKS / ACA
-   ACMEを使いたい？ →ACI / AKS
-   とにかくコンテナを動かしたい！　監視？　WAF？　そんなの知らん！　→ ACA
-   Azureから払い出されたドメインを使うので十分！　→ ACI / ACA
-   自前のドメインを使う！ → AKS + アプリケーションルーティング / Azure Application Gateway + ACI or AKS
-   アプリケーションリソースは内部ネットワークに置いて安全にしたい！　→ Azure Application Gateway + ACI or AKS

## まとめ

Azureいいぞ。