Azure FunctionsをGithub Actions経由でデプロイする
株式会社IVRyのエンジニア、町田です。
IVRyはMicrosoft Startupsに採択されており、R&D等でAzureを活用しています。 様々な用途でAzure Functionsを活用することがありますが、本番運用を考えるとCI/CDの利用は外せません。先日、Azure FunctionsをGithub Actions経由でデプロイしようとしたのですが、結構躓いてしまいました。中々情報が見つけられなかったこともあり、一つの参考として記事にいたします。
Azure Functionsの3種類のデプロイフロー
Azureの公式ドキュメントを見ると、Functionsのデプロイには3種類の方法が設定されています。
- VSCode, Visual Studio等のツールベース
- AzureのDeployment Centerを利用したマネージドなデプロイ
- Github Actions等の外部パイプライン
最も簡単な手法はVSCodeを利用したものかと思います。
流石にMicrosoft製ですからアドオン経由でシームレスにAzureのデプロイが可能です。
しかし、チームで開発をする場合や、本番運用を考えるとVSCode経由で誰かのローカルからデプロイするのはあまり望ましくありません。CI/CDの観点からは自動化したいところです。
自動化に当たり、Deployment Centerの利用かGithub Actionsの利用が考えられますが、今回はGithub Actionsでのデプロイをしてみたいと思います。
公式のやり方
早速ですが公式ドキュメントにGithub Actions経由のデプロイ方法が載っています。
ワークフローは以下の3段階です
- 認証
- ビルド
- デプロイ
※以降、デプロイに必要な関数アプリはすでに構築済みであることを仮定しています。
認証
デプロイ資格情報を利用する方法
デプロイ資格情報経由で認証を行うことができます。
これはドキュメント通りなので割愛しますが、Functionページから「デプロイ資格情報」をダウンロードして、ActionsのSecretにAZURE_FUNCTIONAPP_PUBLISH_PROFILE
として登録すればよいです。
そうすると、次のような形でworkflow.yml
のdeploy stepがかけるはずです。
(env.AZURE_FUNCTIONAPP_PACKAGE_PATH
は後で説明します。)
name: 'Run Azure Functions action'
uses: Azure/functions-action@v1
with:
app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }}
package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}
publish-profile: ${{ secrets.AZURE_FUNCTIONAPP_PUBLISH_PROFILE }}
実際、これでうまくいくと思いますが、実は別のやり方もあります。
Open ID Connectを利用する方法
GitHub Actions for deploying to Azureにある通り、Github Actions中でAzureにLoginすることでも認証が可能です。OpenID Connectに対応したサービスプリンシパルを作成することで認証を行っています。
公式ドキュメントにもちゃんと書かれてるのですが、Azure Functionのドキュメントにはリンクが貼られておらず、この手法の存在に気づきませんでした。
デプロイ資格情報はAzure Functionsへのアクセス権限があるユーザーであれば誰でもアクセスできるようです。一方、サービスプリンシパルを利用する方法は、設定は多少面倒ですが権限管理の面ではよりセキュアな手法になりそうです。
設定方法はドキュメントどおりですが、
- サービスプリンシパルを作成する
- フェデレーション資格情報の追加
- Secretの登録
となります。
躓いたところとして、Azure Portal経由だとフェデレーション資格情報が分かりづらいです。
Active Directory > アプリの登録 > (アプリケーション名)
からフェデレーション資格情報の設定にいけるのですが、これが分かりづらいです。キャプチャを貼りますが、そこがタブになっていると気づけませんでした。
ビルド
次にビルド部分の設定です。
ドキュメントには以下のように書かれています。
name: 'Resolve Project Dependencies Using Pip'
shell: bash
run: |
pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}'
python -m pip install --upgrade pip
pip install -r requirements.txt --target=".python_packages/lib/site-packages"
popd
ここで注意が必要なのは、Azure Functionを開発しているディレクトリの構造です。
自分はこういうディレクトリ構造で開発していたのでハマりました。
root
├── azure_function
│ ├── function
│ │ ├──__init__.py
│ │ └──function.json
│ ├── host.json
│ ├── proxies.json
│ └── requirements.txt
└── README.md
この構造の場合、AZURE_FUNCTIONAPP_PACKAGE_PATH
は./azure_function
とする必要があります。
ここを.
としたり./azure_function/function
と設定すると正しくデプロイできません。
ハマったのですが「正しくデプロイできない」だけで
Github Actionsは正常に終了することがあります。
もし正常に終了しているのに動かない!という状況が発生したら、ディレクトリ構造が怪しいかもしれません。
デプロイ
ここまで正しく設定できていればデプロイ自体で詰まることは無いと思います。
name: 'Run Azure Functions action'
uses: Azure/functions-action@v1
id: fa
with:
app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }}
package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}
workflow.yml全体
name: Deploy function app
on:
workflow_dispatch:
env:
AZURE_FUNCTIONAPP_NAME: 'YOUR FUNCTION APP NAME'
AZURE_FUNCTIONAPP_PACKAGE_PATH: 'path/to/your/package/root'
PYTHON_VERSION: '3.9'
permissions:
contents: read
pages: write
id-token: write
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: 'Checkout GitHub action'
uses: actions/checkout@v2
- name: Azure Login
uses: azure/login@v1
with:
client-id: ${{ secrets.ARM_CLIENT_ID }}
tenant-id: ${{ secrets.ARM_TENANT_ID }}
subscription-id: ${{ secrets.ARM_SUBSCRIPTION_ID }}
- name: Setup Python ${{ env.PYTHON_VERSION }} Environment
uses: actions/setup-python@v1
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: 'Resolve Project Dependencies Using Pip'
shell: bash
run: |
pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}'
python -m pip install --upgrade pip
pip install -r requirements.txt --target=.python_packages/lib/site-packages
popd
- name: 'Run Azure Functions action'
uses: Azure/functions-action@v1
id: fa
with:
app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }}
package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}
注意として、公式ドキュメントのPYTHON_VERSION
が3.7
になっていますが3.9
が推奨されているようでした。(2023/2/25現在)
まとめ
途中のディレクトリ構造で大分ハマってしまったので、相当時間がかかってしまったのですが、無事にGithub Actions経由でデプロイが出来ました。手間はかかったものの、結果的には開発速度の向上やデプロイ時の負担軽減の効果は大きいです。
実はAzure Functions自体もTerraformで作成してみたりしているのですが、ここでもかなり詰まりました。また後日その記事も書きたいと思います。
最後に、IVRyではインフラエンジニア・SREエンジニアを始め、エンジニアの絶賛採用中です。
電話という領域に最新の技術で挑む、やりがいのある仕事です。一緒に働いてくれる仲間を募集しています!
Discussion