Azure Container Instancesで複数WebAPIを扱う
はじめに
Azure Container Instancesを使って
複数のWebAPIをコンテナグループで管理しようとしたときに
ポートを分ける方法でつまずいたので書いておきます。
目的
複数のWebAPI(コンテナ)をコンテナグループでまとめて、
IPアドレスやDNSnameは一つで、ポートを分けて各WebAPIにアクセスできるようにすることです。
<参考>
Azure Container Instances のコンテナー グループ | Microsoft Docs
使う環境
- Azureアカウント
- VisualStudio2019(WebAPI用)
- Docker for Windows(version 19.03.1)
全体の流れ
Container Registryの作成(Azureポータル)
↓
Dockerfileの作成(ローカル)
↓
Dockerイメージのpush(ローカル)
↓
Container Instancesの作成(Azureポータル)
手順
Container Registryの作成
Container Registryを作成します。
APIのDcokerイメージを置いておくところになります。
<詳細>
Azure Container Registry のドキュメント - チュートリアル | Microsoft Docs
Azureポータルにログインします。
新規リソース作成から[コンテナー]>[ContainerRegistry]をクリックします。
簡単にパラメータを設定します。
完成したら、アクセスキーを確認します。
後ほどDockerイメージをpushするのに使います。
Dockerfileの作成
今回WebAPIはVisualStudio2019で用意しました。
ローカルで起動させるとこんな感じです。
それぞれ別のポートでアクセスします。
詳しいコードのついては省略します。
このAPIそれぞれにDockerfileを作成します。
VSにてプロジェクトを右クリックし、[追加]>[Docker サポート...]をクリックします。
ターゲットOSは[Linux]で[OK]をクリックします。
Dockerfileが作成されます。
この中の「EXPOSE 80」の部分を今回使いたいポートに変更します。
今回はDeleteApiを5000、GetApiを5001にします。
これはローカルで実行したときとは異なるポートですが、問題ありません。
Dockerイメージをビルドします。
作成したDockerfileを右クリックし、[Dockerイメージのビルド]をクリックします。
これでDockerのイメージが作られます。
コマンドプロンプトで確認します。
ちゃんと作られてますね。
>docker images
Dockerイメージをレジストリにpushする
作成したイメージにタグをつけます。
Azure上のレジストリ内でバージョン管理するための認識です。
APIを編集更新するたびにDockerイメージをビルドしなおして
レジストリにあげる必要があるので、
タグを分けておくと、古いバージョンに戻すのも楽だと思います。
>docker tag <対象イメージのIMAGE ID> <接続先レジストリサーバー名>/<対象イメージ名>:tag
レジストリにpush
Azure上で作成したレジストリにpushします。
まずAzure上のレジストリにログインします。
>docker login <レジストリサーバー名> -u <ユーザ名> -p <パスワード>
その後にpushします。
>docker push <レジストリサーバー名>/<イメージ名>:tag
Azureポータル上で確認します。
ちゃんとpushされてますね。
Container Instancesの作成
いよいよ本題のContainer Instancesを作成します。
今回は複数のサービスがあるコンテナグループになりますので
下記手順を参考にしています。
チュートリアル - Azure Container Instances に複数コンテナー グループをデプロイする - テンプレート | Microsoft Docs
テンプレートの作成
Container Instances用のテンプレートを用意します。
参考サイトをもとにazuredeploy.jsonを作ります。
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "containerGroups_ContainerInstancesTest_name": { "defaultValue": "ContainerInstancesTest", "type": "String" } }, "variables": {}, "resources": [ { "type": "Microsoft.ContainerInstance/containerGroups", "apiVersion": "2018-04-01", "name": "[parameters('containerGroupsName')]", "location": "japaneast", "properties": { "containers": [ { "name": "deleteapi", "properties": { "image": "containerregistry0824.azurecr.io/deleteapi:1.0.0", "ports": [ { "protocol": "TCP", "port": 5000 } ],
"resources": { "requests": { "memoryInGB": 0.5, "cpu": 0.25 } } } }, { "name": "getapi", "properties": { "image": "containerregistry0824.azurecr.io/getapi:1.0.0", "ports": [ { "protocol": "TCP", "port": 5001 } ], "resources": { "requests": { "memoryInGB": 0.5, "cpu": 0.25 } } } } ], "imageRegistryCredentials": [ { "server": "レジストリサーバー名", "username": "レジストリユーザー名", "password": "パスワード" } ], "restartPolicy": "Always", "ipAddress": { "ports": [ { "protocol": "TCP", "port": 5000 }, { "protocol": "TCP", "port": 5001 }, ], "type": "Public", "dnsNameLabel": "ContainerInstancesTest" }, "osType": "Linux" } } ] }
編集する箇所としては各種名前、image、port、imageRegistryCredentials、各コンテナの設定あたりでしょうか。
各種名前:defaultValueがContainer Instancesの名前。dnsNameLabelがURLになるホスト名。nameが各コンテナの名前。
image:コンテナグループに入れるサービスのイメージ。
レジストリからコピーしてくると間違いないです。
port:VSで作成したDockerfileに記載したportを指定します。
imageRegistryCredentials:レジストリのアクセスキーの情報。
(補足)
リージョンによってCPU等の使用に制限があります。
最小値は1ではないので、動作に影響さえなければ0.5とかでも動きます。
Azure Container Instances リソースの可用性 | Microsoft Docs
テンプレートのデプロイ
AzureのCloudShellに接続し、作成したテンプレートをアップロードします。
アップロードしたファイルをコマンドでデプロイします。
>az group deployment create --resource-group <リソースグループ> --template-file <テンプレートファイル>
テンプレートに間違いがあればエラーが表示されます。
問題なく実行されればしばらく待った後にContainer Instancesの情報が表示されます。
デプロイが終わったらポータル上で確認します。
コンテナが二つできてますね。(でも一つ動いてない…?
接続してみます。
つながらない…なぜ…
よくよく設定を見てみます。
プロパティではちゃんとポートが指定されてます。
ログを見ると…むむむ。
なぜかポート80の表記が。
これはデフォルトが変わってないのでは?
と思い調べるとやはり環境変数を変える必要がありました。
asp.net - Why does aspnet core start on port 80 from within Docker? - Stack Overflow
ということで、テンプレートの"containers"配下に以下の部分を追記します。
"environmentVariables": [ { "name": "ASPNETCORE_URLS", "value": "http://+:5000" } ],
もし一つのコンテナに複数のポートを割り当てたい場合は;で仕切ります。
"environmentVariables": [ { "name": "ASPNETCORE_URLS", "value": "http://+:5000;http://+:5002" } ],
Container Instancesを再デプロイします。
確認します。
うんうん、ちゃんとポートが割り当たってますね。
接続します。
ちゃんと各ポートで接続されますね。めでたし。
おわりに
初めはDockerComposeを使いたかったのですが、
DockerOSがLinuxの場合、APIは一つまでしか対応していないようで断念…
API一つとDB等を組み合わせるには良いようです。
Preview版でなくなったときは複数APIも使えるようになってると嬉しいです。