3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Azure Static Web AppsのバックエンドをContainer Appsにしてみる。ついでにAzure DevOpsでCI/CD環境も作る。

Posted at

1. Azure DevOpsでCI/CD環境を作る準備をしておく

⓪Azure DevOpsのサインアップ

以下リンクからサインアップします。

①Azure Reposでリポジトリの準備

プロジェクトをプライベートで作成します。
Azure Reposをフロントエンド、バックエンド用に2つ作ります

  • フロントエンド: Static Web Apps
  • バックエンド Container Apps

image.png

Github DesktopにCloneします。
Generate Git Credentialsをクリックし、パスワードを発行しておきます。

image.png

image.png

ユーザ名・パスワードを入力して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
api/app.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"
    )
api/modules/test_module.py
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を用意します。

api/requirements.txt
flask

②Dockerfileを作成する

Dockerfileを作成し、以下を定義します。

  • Python実行環境が整ったimageの指定
  • ソースのコピー
  • requirements.txtのコピー
  • python api/app.pyを実行するコマンド
api/Dockerfile
# 使用するイメージ
FROM python:3.10-alpine

# ソースの配置・パッケージインストール
COPY . .
RUN pip install -r requirements.txt

# コンテナ起動時のコマンド
CMD ["python", "app.py"]

フォルダ構成は以下のような形になります。

image.png

コンテナの起動確認を行い、先ほどの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にアップロードします。
まずは、コンテナレジストリーを作成します。

image.png

左側メニューからアクセスキーをクリックし、管理者ユーザーを有効化します。
また、ログインサーバ名をコピーしておきます。

image.png

続いて、上記手順で作成したレジストリにイメージをアップロードします。

az login
az account set --subscription <your-subscription>
# Dockerfileがあるディレクトリで実行
az acr build --image backend-for-openai-app:v1.0 --registry registryforopenai .

Container Appsを作成します。
まずは、コンテナアプリ名を付けます。

image.png

次に、コンテナを作成する際のイメージとタグを指定します。
先ほどアップロードしたものを入力します。

image.png

次に、インバウンド通信に関する設定を行います。
ポートフォワードの設定を行います。テスト環境のため、全てのインバウンドを許可します。
セキュリティで保護されていない接続を許可はチェックしていますが、外して大丈夫です。

image.png

以上の設定で作成します。
作成後、アプリケーションURLをコピーします。

image.png

この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の左側メニューの継続的デプロイをクリックします。

image.png

githubアカウントの情報を入力します。

image.png

mainブランチにpushが発生したタイミングでイメージがACRに格納され、ビルドされます。
イメージの格納先を入力します。

image.png

Azure ADへのアプリケーション登録とサービスプリンシパルの作成が必要です。

image.png


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ファイルを編集します。

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)
                console.log(res)

                this.response = res.data
            }
        }
    }
</script>
app/src/App.vue
<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

image.png

③Container Apps側でJavascriptからのリクエストを受け取れるようにする

Container AppsのCORSを有効化します。
※テストのため、配信元制限はかけていません。

image.png

以下のようにバックエンドのコンテナから返答があれば確認完了です。

image.png

④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 DevOpsだとエラーが出たので手動で設定しました、、)
    image.png

image.png

⑤Azure Pipelineの作成

frontendのリポジトリの画面から、set up buildをクリックし、
Node.js with Vueを選択します。

image.png

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の修正が必要です。

app/.gitignore
/dist
#/dist

distフォルダが差分として検出されるようになるので、mainブランチにpushしておきます。
staticwebapp.config.jsonで認証やルーティング設定を行う場合は、distフォルダに含める必要があることに注意します。

image.png

ここで一度AzureポータルからStatic Web Appsの画面に行き、デプロイトークンをコピーします。

image.png

Azure DevOps Pipelineに戻り、先ほど作成したパイプラインの変数にデプロイトークンを設定します。

image.png

image.png

規約変更により、無償利用枠の場合は申請をしなければなりません。
下記のようなエラーが出たため、こちらから利用申請を行います。

##[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

image.png

申請が通るとメールが来ます。
メールを確認したのち、pipelineを実行します。

image.png

Jobが終了したらStatic Web Appsの画面からURLをコピーし、ブラウザから開きます。
先ほど作成した画面と同じものが出力されればPipelineの構築は完了です。

image.png

まだバックエンドとのつなぎこみを行っていないため、ボタンを押しても返答がありません。

⑥Static Web AppsとContainer Appsを連携する

Static Web Appsの左側のメニューからAPIを選択します。

image.png

リンクをクリックします。

image.png

下記3項目を設定し、リンクをクリックします。

  • バックエンドリソースの種類:コンテナーアプリ
  • サブスクリプション:お使いのサブスクリプション
  • リソース名:Container Appsのリソース名

image.png

リンクに成功すると、以下のように運用に反映されます。

image.png

再度URLからアプリケーションを開き、ボタンを押すとContainer Appsへリクエストが流れていることを確認できます。

image.png

まとめ

Azure DevOpsはAzureポータルから作るものと思っていました、、。
あと、azure pipelineのドキュメント全然わからない。
パイプラインの勉強しないとですね。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?