1. Azure DevOpsでCI/CD環境を作る準備をしておく
⓪Azure DevOpsのサインアップ
以下リンクからサインアップします。
①Azure Reposでリポジトリの準備
プロジェクトをプライベートで作成します。
Azure Reposをフロントエンド、バックエンド用に2つ作ります
- フロントエンド: Static Web Apps
- バックエンド Container Apps
Github DesktopにCloneします。
Generate Git Credentials
をクリックし、パスワードを発行しておきます。
ユーザ名・パスワードを入力してCloneします。
これでGithub Desktopで管理できるようになります。
2. バックエンド用のContainer Appsを作成する
先ほど作成したbackendリポジトリをローカルにcloneしました。
ローカルのフォルダ内での作業です。ブランチはmainです。
①ソースを用意する
FlaskでHTTPリクエストに応答するソースコードを書き、簡易的なWebサーバを作ります。
- リクエストパス:
/api/test
- HTTPメソッド:
POST
上記リクエストに応答するために2ファイル作成します。
- api/app.py
- api/modules/test_module.py
from flask import Flask, request
from modules.test_module import TestModule
app = Flask(__name__)
@app.route("/api/test", methods=["POST"])
def post_test():
data = request.json['test_data']
response = TestModule().test_func(data)
print(response)
return response
if __name__ == "__main__":
app.run(
host="0.0.0.0",
port="5000"
)
class TestModule:
def __init__(self):
pass
def test_func(self, data):
return data
app.pyを実行後、curlでPOSTリクエストを投げてみます。
python api/app.py
curl -X POST localhost:5000
# POSTリクエスト
curl -X POST -H "Content-Type: application/json" -d '{"test_data": "Hello!"}' http://localhost:5000/api/test
This is test.
うまく動作しています。requirements.txtを用意します。
flask
②Dockerfileを作成する
Dockerfileを作成し、以下を定義します。
- Python実行環境が整ったimageの指定
- ソースのコピー
- requirements.txtのコピー
- python api/app.pyを実行するコマンド
# 使用するイメージ
FROM python:3.10-alpine
# ソースの配置・パッケージインストール
COPY . .
RUN pip install -r requirements.txt
# コンテナ起動時のコマンド
CMD ["python", "app.py"]
フォルダ構成は以下のような形になります。
コンテナの起動確認を行い、先ほどのcurlコマンドを打ちます。
ポートだけ8000に変更します。
cd api
# イメージのビルドとコンテナ起動
docker build -t myapp .
docker run -d -p 8000:5000 myapp # 8000に来たリクエストを5000にポートフォワード
# curl
curl -X POST -H "Content-Type: application/json" -d '{"test_data": "Hello!"}' http://localhost:8000/api/test
This is test.
これでイメージの準備は整いました。
コミットし、pushしておきます。
③Container Appsの作成
Container Appsを作成する前に、先ほど作成したイメージをAzure Container Registoryにアップロードします。
まずは、コンテナレジストリーを作成します。
左側メニューからアクセスキーをクリックし、管理者ユーザーを有効化します。
また、ログインサーバ名をコピーしておきます。
続いて、上記手順で作成したレジストリにイメージをアップロードします。
az login
az account set --subscription <your-subscription>
# Dockerfileがあるディレクトリで実行
az acr build --image backend-for-openai-app:v1.0 --registry registryforopenai .
Container Appsを作成します。
まずは、コンテナアプリ名を付けます。
次に、コンテナを作成する際のイメージとタグを指定します。
先ほどアップロードしたものを入力します。
次に、インバウンド通信に関する設定を行います。
ポートフォワードの設定を行います。テスト環境のため、全てのインバウンドを許可します。
セキュリティで保護されていない接続を許可はチェックしていますが、外して大丈夫です。
以上の設定で作成します。
作成後、アプリケーションURLをコピーします。
このURL+/api/testに対して、POSTリクエストを送って動作確認を行います。
curl -X POST -H "Content-Type: application/json" -d '{"test_data": "Hello!"}' https://backend-container-for-openai-app.wittybay-28470bf8.eastus.azurecontainerapps.io/api/test
# 出力
This is test.
先ほどと同じ出力が得らればバックエンドのコンテナ化は完了です。
④CI/CD環境の設定
2023年5月25日現在は、Azure DevOpsには対応していません。
今回は設定項目だけ紹介します。
Containers Appsの左側メニューの継続的デプロイをクリックします。
githubアカウントの情報を入力します。
mainブランチにpushが発生したタイミングでイメージがACRに格納され、ビルドされます。
イメージの格納先を入力します。
Azure ADへのアプリケーション登録とサービスプリンシパルの作成が必要です。
3. Static Web Appsを作成し、Container Appsと繋ぐ
①雛形プロジェクト作成
手順2で作成したリポジトリをCloneし、そのフォルダ内での作業です。
まずは、雛形プロジェクトを作成します。
# インストール
npm install -g @vue/cli
vue --version
# 雛形作成
vue create app
# 起動確認
cd app
npm run serve
# HTTPリクエスト用のモジュールを追加
npm install axios
②POSTリクエストを投げれるようにする
続いて、ボタンを押したらバックエンドにPOSTリクエストを投げる部分を実装します。
以下の2ファイルを編集します。
<template>
<div>
<button @click="post_test()">POSTテスト</button>
<h2>{{ response }}</h2>
</div>
</template>
<script>
const axios = require('axios').create()
export default{
name: "PostTest",
data: () => ({
post_body:{
test_data:"Hello!"
},
response: ""
}),
methods:{
post_test: async function (){
console.log(this.post_body.test_data)
const container_url = "https://test-cotainer-app.calmcoast-b2bb2cd5.eastus.azurecontainerapps.io"
const api_path = "/api/test"
const res = await axios.post(container_url+api_path, this.post_body)
console.log(res)
this.response = res.data
}
}
}
</script>
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
<PostTest/>
</div>
</template>
<script>
// import HelloWorld from './components/HelloWorld.vue'
import PostTest from './components/PostTest.vue';
export default {
name: 'App',
components: {
// HelloWorld,
PostTest
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
編集が完了したら起動確認を行います。
npm run serve
③Container Apps側でJavascriptからのリクエストを受け取れるようにする
Container AppsのCORSを有効化します。
※テストのため、配信元制限はかけていません。
以下のようにバックエンドのコンテナから返答があれば確認完了です。
④Static Web Appsを作成する
上記手順で作成したコードを用いてStatic Web Appsを作成します。
APIエンドポイントを編集した後、手順1で作成したリポジトリのmainブランチにpushしておきます。
Static Web Apps × Container Appsの場合、
/api/*のリクエストをContainer Appsに流してくれます。
そのため、先ほどはContainer AppsのURLを指定していましたが修正します
- app/src/components/PostTest.vue
<template>
<div>
<button @click="post_test()">POSTテスト</button>
<h2>{{ response }}</h2>
</div>
</template>
<script>
const axios = require('axios').create()
export default{
name: "PostTest",
data: () => ({
post_body:{
test_data:"Hello!"
},
response: ""
}),
methods:{
post_test: async function (){
console.log(this.post_body.test_data)
// const container_url = "https://test-cotainer-app.calmcoast-b2bb2cd5.eastus.azurecontainerapps.io"
// const api_path = "/api/test"
// const res = await axios.post(container_url+api_path, this.post_body)
const endpoint = "/api/test"
const res = await axios.post(endpoint, this.post_body)
console.log(res)
this.response = res.data
}
}
}
</script>
編集後、mainブランチへpushしておきます。
Azureポータルに移り、Static Web Appsを作成していきます。
デプロイの詳細という項目に注意します。
⑤Azure Pipelineの作成
frontendのリポジトリの画面から、set up buildをクリックし、
Node.js with Vueを選択します。
yamlが生成されます。以下のように書き換えます。
trigger:
- main
pool:
vmImage: ubuntu-latest
steps:
- checkout: self
submodules: true
- task: AzureStaticWebApp@0
inputs:
app_location: 'app/dist'
api_location: ''
output_location: ''
skip_app_build: true
env:
azure_static_web_apps_api_token: $(deployment_token)
npm installをする際のディレクトリの指定方法が分からなかったです。
そのため、build済みのフォルダを使ってAzure Static Web Appsにデプロイするyamlに書き換えています。
↑により、app/.gitignoreの修正が必要です。
/dist
#/dist
distフォルダが差分として検出されるようになるので、mainブランチにpushしておきます。
staticwebapp.config.jsonで認証やルーティング設定を行う場合は、distフォルダに含める必要があることに注意します。
ここで一度AzureポータルからStatic Web Appsの画面に行き、デプロイトークンをコピーします。
Azure DevOps Pipelineに戻り、先ほど作成したパイプラインの変数にデプロイトークンを設定します。
規約変更により、無償利用枠の場合は申請をしなければなりません。
下記のようなエラーが出たため、こちらから利用申請を行います。
##[error]No hosted parallelism has been purchased or granted. To request a free parallelism grant, please fill out the following form https://aka.ms/azpipelines-parallelism-request
申請が通るとメールが来ます。
メールを確認したのち、pipelineを実行します。
Jobが終了したらStatic Web Appsの画面からURLをコピーし、ブラウザから開きます。
先ほど作成した画面と同じものが出力されればPipelineの構築は完了です。
まだバックエンドとのつなぎこみを行っていないため、ボタンを押しても返答がありません。
⑥Static Web AppsとContainer Appsを連携する
Static Web Appsの左側のメニューからAPIを選択します。
リンクをクリックします。
下記3項目を設定し、リンクをクリックします。
- バックエンドリソースの種類:コンテナーアプリ
- サブスクリプション:お使いのサブスクリプション
- リソース名:Container Appsのリソース名
リンクに成功すると、以下のように運用に反映されます。
再度URLからアプリケーションを開き、ボタンを押すとContainer Appsへリクエストが流れていることを確認できます。
まとめ
Azure DevOpsはAzureポータルから作るものと思っていました、、。
あと、azure pipelineのドキュメント全然わからない。
パイプラインの勉強しないとですね。