QuestionAnswerPortalの API サーバーを構成する。
Azure リソース名 | 概要 |
---|---|
qatranslator-je-apim |
ユーザー/App Service からアクセスする API Management |
qatranslator-je-func |
API Management からアクセスする Functions |
qatranslator-je-funcplan |
Functions のプラン |
qatranslatorjesa |
Functions から参照するストレージアカウント |
qatranslator-je-cosmosdb |
Functions からアクセスする Cosmos DB |
qatranslator-je-vault |
シークレットを管理する Key Vault |
qatranslator-je-insights |
App Service/API Management/Functions を一括で監視する Application Insights |
(Your Own Translator) |
Functions からアクセスする事前に作成した Translator(枠を使い切った場合は代わりに DeepL へアクセスする) |
名称 | バージョン |
---|---|
Node.js | 20.10.0 |
Typescript | 5.3.2 |
上記以外のパッケージは、dependabot によってバージョン管理している。
Azure リソース/localhost に環境を構築する事前準備として、以下の順で初期構築を必ずすべて行う必要がある。
- Azure AD 認証認可用サービスプリンシパルの発行
- GitHub Actions 用サービスプリンシパルの発行
- リポジトリのシークレット・変数設定
- インポートデータファイルの作成
Microsoft ID Platform経由で Web アプリケーションに認証認可を実現するためのサービスプリンシパル QATranslator_MSAL を以下の手順で発行する。
- Azure Portal から Azure AD に遷移する。
- App Registrations > New registration の順で押下し、以下の項目を入力後、Register ボタンを押下してサービスプリンシパルを登録する。
- Name :
QATranslator_MSAL
- Supported account types :
Accounts in this organizational directory only
- Redirect URI :
Single-page application(SPA)
(左) とhttps://infhyroyage.github.io/QuestionAnswerPortal
(右)
- Name :
- 登録して自動遷移した「QATranslator_MSAL」の Overview にある「Application (client) ID」の値(=クライアント ID)を手元に控える。
- Expose an API > Application ID URI の右にある小さな文字「Add」を押下し、Application ID URI の入力欄に
api://{3で手元に控えたクライアントID}
が自動反映されていることを確認し、Save ボタンを押下する。 - Expose an API > Scopes defined by this API にある「Add a scope」を押下し、以下の項目を入力後、Save ボタンを押下する。
- Scope name :
access_as_user
- Who can consent? :
Admins and users
- Admin consent display name :
QATranslator
- Admin consent description :
Allow react app to access QATranslator backend as the signed-in user
- User consent display name :
QATranslator
- User consent description :
Allow react app to access QATranslator backend on your behalf
- State :
Enabled
- Scope name :
- API permissions > Configured permissions の API / Configured permissions にて、既定で Microsoft Graph API へのアクセス許可が与えられている「User.Read」の右側にある「...」を押下し、「Remove Permission」 > 「Yes, remove」を押下して、「User.Read」のアクセス許可を削除する。
- API permissions > Configured permissions の API / Configured permissions にて、「+ Add a permission」を押下後、以下の順で操作する。
- 「My APIs」タブの
QATranslator_MSAL
を選択。 - What type of permissions does your application require?にて「Delegated permissions」を選択。
QATranslator
のaccess_as_user
のチェックボックスを選択。- Add permissions ボタンを押下。
- 「My APIs」タブの
- Manifest から JSON 形式のマニフェストを表示し、
"accessTokenAcceptedVersion"
の値をnull
から2
に変更する。
GitHub Actions から Azure リソースを環境を構築するためのサービスプリンシパル QATranslator_Contributor を以下の手順で発行する。
- Azure CLI にてログイン後、以下のコマンドを実行し、サービスプリンシパル
QATranslator_Contributor
を発行する。az ad sp create-for-rbac --name QATranslator_Contributor --role Contributor --scope /subscriptions/{サブスクリプションID}
- 1 のコマンドを実行して得た以下の値を、それぞれ手元に控える。
appId
(=クライアント ID)password
(=クライアントシークレット)
- Azure Portal から Azure AD > App Registrations に遷移する。
- QATranslator_Contributor のリンク先にある Overview にある「Managed application in local directory」のリンク「QATranslator_Contributor」を押下し、QATranslator_Contributor のエンタープライズアプリケーションに遷移する。
- Overview の Properties にある「Object ID」の値(=エンタープライズアプリケーションのオブジェクト ID)を手元に控える。
QuestionAnswerTranslator リポジトリの Setting > Secrets And variables > Actions より、以下のシークレット・変数をすべて設定する。
Secrets タブから「New repository secret」ボタンを押下して、下記の通り変数をすべて設定する。
シークレット名 | シークレット値 |
---|---|
AZURE_APIM_PUBLISHER_EMAIL | API Management の発行者メールアドレス |
AZURE_AD_SP_CONTRIBUTOR_CLIENT_SECRET | 2.で発行した QATranslator_Contributor のクライアントシークレット |
DEEPL_AUTH_KEY | DeepL API の認証キー |
TRANSLATOR_KEY | 事前に作成した Translator のキー |
Variables タブから「New repository variable」ボタンを押下して、下記の通り変数をすべて設定する。
変数名 | 変数値 |
---|---|
AZURE_AD_EA_CONTRIBUTOR_OBJECT_ID | 2.で発行した QATranslator_Contributor のエンタープライズアプリケーションのオブジェクト ID |
AZURE_AD_SP_CONTRIBUTOR_CLIENT_ID | 2.で発行した QATranslator_Contributor のクライアント ID |
AZURE_AD_SP_MSAL_CLIENT_ID | 1.で発行した QATranslator_MSAL のクライアント ID |
AZURE_SUBSCRIPTION_ID | Azure サブスクリプション ID |
AZURE_TENANT_ID | Azure ディレクトリ ID |
qatranslator-je-cosmosdb
に格納するデータは、GitHub 上で管理せず、インポートデータファイルと呼ぶ特定のフォーマットで記述した Typescript のソースコードを、ローカル上で管理する運用としている。
インポートデータファイルは、ローカルで git clone した QuestionAnswerTranslator リポジトリ直下にdata/(コース名)/(テスト名).json
のパスでディレクトリ・json ファイルを作成する必要がある。
インポートデータファイルの json フォーマットを以下に示す。
[
{
"subjects": ["問題文1", "https://xxx.com/yyy/zzz.png", "問題文2", ... ],
"choices": ["選択肢1", "選択肢2", ... ],
"correctIdxes": [0],
"explanations": ["解説文1", "解説文2", ... ],
"incorrectChoicesExplanations": [null, ["選択肢2の解説文1", "選択肢2の解説文2", ... ], ... ],
"indicateImgIdxes": {
"subjects": [0, ... ],
"explanations": [2, ... ]
},
"escapeTranslatedIdxes": {
"subjects": [0, ... ],
"choices": [1, ... ],
"explanations": [2, ... ],
"incorrectChoicesExplanations": [null, [0, ... ], ... ]
},
"references": ["https://xxx.com/yyy/zzz.html", ... ]
},
{
"subjects": [ ... ],
:
},
]
json の各キーの説明を、以下に示す。
キー名 | 説明 | 必須指定 |
---|---|---|
subjects |
問題文/画像 URL | o |
choices |
選択肢 | o |
correctIdxes |
回答の選択肢のインデックス(複数回答の場合は複数指定) | o |
explanations |
解説文/画像 URL | |
incorrectChoicesExplanations |
不正解の選択肢の解説文(正解の選択肢/解説文無しはnull ) |
|
indicateImgIdxes |
subjects /explanations で指定した画像 URL のインデックス |
|
escapeTranslatedIdxes |
翻訳不要なsubjects /choices /explanations /incorrectChoicesExplanations のインデックス |
|
references |
リファレンス URL |
- QuestionAnswerTranslator リポジトリの各 workflow をすべて有効化する。
- QuestionAnswerTranslator リポジトリの Actions > 左側の Create Azure Resources > 最後の実行名 の順で押下し、右上の「Re-run jobs」から「Re-run all jobs」を押下し、確認ダイアログ内の「Re-run jobs」ボタンを押下する。
- ターミナルを起動して以下のコマンドを実行し、Azure にデプロイ済のストレージアカウントに対し、すべてのインポートデータファイルを 1 つずつ繰り返しアップロードする。
az storage blob directory upload --account-name qatranslatorjesa -c import-items -s "cosmosdb/data/*" -d . -r
- QuestionAnswerTranslator リポジトリの各 workflow をすべて無効化する。
- ターミナルを起動して以下のコマンドを実行し、リソースグループ
qatranslator-je
を削除する。az group delete -n qatranslator-je -y
- 2 のターミナルで以下のコマンドを実行し、論理的に削除した
qatranslator-je-vault
を物理的に削除する。az keyvault purge -n qatranslator-je-vault
- 3 のターミナルで以下のコマンドを実行し、論理的に削除した
qatranslator-je-apim
を物理的に削除する。az rest -m DELETE -u https://management.azure.com/subscriptions/(サブスクリプションID)/providers/Microsoft.ApiManagement/locations/japaneast/deletedservices/qatranslator-je-apim?api-version=2022-08-01
@azure/functions
のapp
を用いて、functions/src/index.ts に全エントリーポイントを記述する。
上記で生成した関数アプリが HTTP Trigger の場合、その関数アプリの API リファレンスである Swagger を apim/apis-functions-swagger.yaml に記述する。 API Management のデプロイは、この Swagger を使用する。
Azure にリソースを構築せず、localhost 上で以下のサーバーをそれぞれ起動することもできる。
サーバー名 | 使用するサービス名 | ポート番号 |
---|---|---|
Azure Functions(HTTP Trigger の関数アプリのみ) | Azure Functions Core Tools | 9229 |
Cosmos DB | Azure Cosmos DB Linux Emulator | 8081 |
Blob ストレージ | Azurite | 10000 |
Queue ストレージ | Azurite | 10001 |
Table ストレージ | Azurite | 10002 |
Tip
localhost 環境構築後、 Azure Cosmos DB Emulator の index.html にアクセスすると、Cosmos DB 内のデータを参照・更新することができる。
Caution
Azure Cosmos DB Emulator のリポジトリの Issueで議論されている通り、Apple シリコンの macOS は、Azure Cosmos DB Emulator がサポートされていないため、localhost 環境を構築することができない。
- 以下をすべてインストールする。
- Azure Functions Core Tools
- Docker
- Node.js 20.10.0
- 以下を記述したファイル
local.settings.json
を QuestionAnswerTranslator リポジトリの functions ディレクトリ配下に保存する。{ "IsEncrypted": false, "Values": { "AzureWebJobsStorage": "UseDevelopmentStorage=true", "COSMOSDB_KEY": "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==", "COSMOSDB_READONLY_KEY": "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==", "COSMOSDB_URI": "https://localhost:8081", "DEEPL_AUTH_KEY": "(Azureリソース環境構築時にGitHubへ登録したシークレットDEEPL_AUTH_KEYの値)", "TRANSLATOR_KEY": "(事前に作成したTranslatorのキー値)", "FUNCTIONS_WORKER_RUNTIME": "node", "NODE_TLS_REJECT_UNAUTHORIZED": "0" }, "Host": { "CORS": "*", "LocalHttpPort": 9229 }, "ConnectionStrings": {} }
- CORS は任意のオリジンを許可するように設定しているため、特定のオリジンのみ許可したい場合は
Host
>CORS
にそのオリジンを設定すること。
- CORS は任意のオリジンを許可するように設定しているため、特定のオリジンのみ許可したい場合は
- ターミナルを起動して以下のコマンドを実行し、Cosmos DB、Blob/Queue/Table ストレージをすべて起動する。実行したターミナルはそのまま放置する。
実行後、以下の標準出力が表示されるまで待機する。
docker compose up
localcosmosdb | Started
- 3 とは別のターミナルで以下のコマンドを実行し、Azure Functions を起動する。実行したターミナルはそのまま放置する。
cd functions npm run start
- 4 とは別のターミナルで以下のコマンドを実行し、起動した Cosmos DB サーバーに対し、インポートデータファイルからインポートする。
cd cosmosdb npm run import
- タイムアウトなどで失敗した場合、もう一度実行し直すこと。
- 構築手順の 4 で起動した Azure Functions のターミナルに対して Ctrl+C キーを入力し、起動した Azure Functions を停止する。
- ターミナルを起動して以下のコマンドを実行し、構築手順の 3 で起動した Cosmos DB、Blob/Queue/Table ストレージをすべて停止する。
docker compose down
初期構築以前の完全なクリーンな状態に戻すためには、初期構築で行ったサービスプリンシパル・シークレット・変数それぞれを以下の順で削除すれば良い。
- リポジトリの各シークレット・変数の削除
- GitHub Actions 用サービスプリンシパルの削除
- Azure AD 認証認可用サービスプリンシパルの削除
QuestionAnswerTranslator リポジトリの Setting > Secrets And variables > Actions より、Secrets・Variables タブから初期構築時に設定した各シークレット・変数に対し、ゴミ箱のボタンを押下する。
- Azure Portal から Azure AD > App Registrations に遷移する。
- QATranslator_Contributor のリンク先にある Delete ボタンを押下し、「I understand the implications of deleting this app registration.」のチェックを入れて Delete ボタンを押下する。
- Azure Portal から Azure AD > App Registrations に遷移する。
- QATranslator_MSAL のリンク先にある Delete ボタンを押下し、「I understand the implications of deleting this app registration.」のチェックを入れて Delete ボタンを押下する。