2026年9月30日
2026年9月30日
Azure App Serviceにアプリをデプロイする手順|CLI・ZIPデプロイ・GitHub Actions・スロット
Azure App Service は、サーバーの OS やミドルウェアを自分で管理せずに Web アプリを動かせる Azure の PaaS です。この記事では、Azure CLI でリソースを作り、ZIP デプロイで最初の公開を行い、デプロイスロットと GitHub Actions で更新を安全に回すまでを、Linux 上の Python アプリを例に説明します。Node.js や PHP でも流れは同じで、ランタイムの指定と起動方法が変わるだけです。内容は2026年10月時点の Microsoft Learn のドキュメントに沿っています。
App Service の基本構成
App Service では、次の3つを順に作ります。
- リソースグループ: 関連するリソースをまとめる入れ物です。削除するときもグループ単位で片付けられます。
- App Service プラン: アプリを動かす計算資源(CPU・メモリ・インスタンス数)と、使える機能の範囲を決めます。
- Web アプリ: アプリ本体です。1つのプランに複数のアプリを載せることもできます。
この記事の後半で使うデプロイスロットは、Standard・Premium・Isolated の階層のプランでしか使えません。Free や Basic(B1 など)のプランではスロットを作れないので、スロットを使う予定があるなら最初から Standard(S1)以上か Premium v3(P0V3 など)で作ります。スロットの数も階層ごとに上限があり、Standard は5つまでです。各階層の料金は変わることがあるため、作成前に Azure の料金ページで確認してください。
WordPress を動かしたい場合は、Microsoft が用意している WordPress 向けの App Service 構成(Azure Database for MySQL と組み合わせるもの)を使うほうが手間が少なく済みます。この記事は、自作アプリや既存のアプリをデプロイしたい人向けの内容です。
Azure CLI でリソースを作る
ポータル画面でも作成できますが、手順を再現しやすく、画面の変更にも左右されにくい Azure CLI を使います。アプリ名は URL の一部になるため、Azure 全体で重複しない名前を付けます。
az login
az group create --name rg-myapp --location japaneast
# デプロイスロットを使うため Standard(S1)で作る。スロットが不要なら B1 でもよい
az appservice plan create \
--name plan-myapp \
--resource-group rg-myapp \
--sku S1 \
--is-linux
# 指定できるランタイムの一覧を確認してから選ぶ
az webapp list-runtimes --os linux
az webapp create \
--name myapp-example-001 \
--resource-group rg-myapp \
--plan plan-myapp \
--runtime "PYTHON:3.12"
ランタイムの書式(PYTHON:3.12 など)や選べるバージョンは、CLI とサービスの更新で変わります。az webapp list-runtimes の出力に表示された文字列をそのまま使うと、書式の間違いを避けられます。
作成したアプリには既定のホスト名が割り当てられます。新しく作るアプリでは、名前に加えてランダムな文字列や地域を含むホスト名になる場合があるため、次のコマンドで実際のホスト名を確認してください。
az webapp show \
--name myapp-example-001 \
--resource-group rg-myapp \
--query defaultHostName
すでに B1 などで作ったプランは、az appservice plan update --name plan-myapp --resource-group rg-myapp --sku S1 で階層を上げられます。
アプリ設定(環境変数)を入れる
データベースの接続情報や API キーは、コードに書かずに「アプリ設定」に入れます。App Service のアプリ設定は、アプリからは環境変数として読めます。
az webapp config appsettings set \
--name myapp-example-001 \
--resource-group rg-myapp \
--settings \
SCM_DO_BUILD_DURING_DEPLOYMENT=true \
DJANGO_SECRET_KEY="your-secret-key" \
DATABASE_URL="your-database-url"
SCM_DO_BUILD_DURING_DEPLOYMENT=true は、ZIP デプロイ時にサーバー側でビルド(Python なら requirements.txt からのパッケージのインストール)を行わせる設定です。これが無いと、パッケージが入らずに起動時エラーになることがあります。
秘密情報をさらに厳格に管理したい場合は、Azure Key Vault に保存してアプリ設定から参照する方法があります。少なくとも、秘密情報をリポジトリや ZIP ファイルに含めないようにしてください。
ZIP デプロイで最初の公開を行う
最初のデプロイは、ローカルで ZIP を作ってアップロードする方法がわかりやすいです。
cd myapp
zip -r ../app.zip . -x ".git/*" "venv/*" "__pycache__/*" ".env"
az webapp deploy \
--name myapp-example-001 \
--resource-group rg-myapp \
--src-path ../app.zip \
--type zip
仮想環境(venv)や .env を ZIP に含めないのがポイントです。ローカルの OS でビルドしたパッケージを持ち込むと、App Service の Linux 環境と合わずに動かないことがあります。
Python の場合、App Service は一般的な構成(Django の wsgi.py や Flask の app.py など)を自動検出して起動しようとします。検出できない構成では、起動コマンドを明示します。
az webapp config set \
--name myapp-example-001 \
--resource-group rg-myapp \
--startup-file "gunicorn --bind=0.0.0.0 --timeout 600 myproject.wsgi"
起動しないときはログを見る
デプロイ後にブラウザで「Application Error」などが出たら、まずログを確認します。
az webapp log config \
--name myapp-example-001 \
--resource-group rg-myapp \
--docker-container-logging filesystem
az webapp log tail \
--name myapp-example-001 \
--resource-group rg-myapp
ログで見るべき点は、よくある順に次のとおりです。
- モジュールが見つからない(ModuleNotFoundError など): ビルドが走っていません。
SCM_DO_BUILD_DURING_DEPLOYMENTの設定と、requirements.txtが ZIP の最上位にあるかを確認します。 - 起動コマンドのエラー: WSGI モジュールのパスが間違っています。
myproject.wsgiの部分を実際のディレクトリ構成に合わせます。 - 待ち受けアドレスの不一致: アプリが
127.0.0.1だけで待ち受けていると、App Service からの転送が届きません。0.0.0.0で待ち受けます。 - 環境変数の不足: アプリ設定の名前の綴りや、設定変更後にアプリが再起動されたかを確認します。
詳しく調べたいときは、Kudu(SCM サイト)からコンテナ内のファイルやデプロイ履歴を確認できます。
デプロイスロットを作る
デプロイスロットは、同じアプリの別環境です。自動デプロイの送り先にする前に、ここで staging スロットを作っておきます。
az webapp deployment slot create \
--name myapp-example-001 \
--resource-group rg-myapp \
--slot staging \
--configuration-source myapp-example-001
--configuration-source に本番のアプリ名を指定すると、本番スロットのアプリ設定・接続文字列・ランタイムのバージョンなどが複製されます。複製されるのは設定だけで、新しいスロットの中身(コード)は空です。スロットには myapp-example-001-staging を含む独自のホスト名が付き、そのまま公開状態になるので、外部に見せたくない場合はアクセス制限を設定します。
スワップで入れ替わらない設定を決める
スロットを入れ替える(スワップする)と、アプリ設定や接続文字列も既定ではコードと一緒に入れ替わります。本番用と検証用で値を分けたい設定(データベースの接続先など)は、「デプロイスロットの設定」としてスロットに固定します。
# 本番スロットの DATABASE_URL を本番に固定
az webapp config appsettings set \
--name myapp-example-001 \
--resource-group rg-myapp \
--slot-settings DATABASE_URL="production-database-url"
# staging スロットの DATABASE_URL を検証用に固定
az webapp config appsettings set \
--name myapp-example-001 \
--resource-group rg-myapp \
--slot staging \
--slot-settings DATABASE_URL="staging-database-url"
一方、独自ドメイン、TLS の設定、スケールの設定、マネージド ID などは、スワップしても入れ替わらずスロットに残ります。
GitHub Actions で staging に自動デプロイする
手動の ZIP デプロイに慣れたら、GitHub への push で staging スロットに自動デプロイされるようにします。認証には、長期間有効なパスワードを保存する発行プロファイルよりも、OpenID Connect(フェデレーション資格情報)を使う方法が推奨されています。Microsoft Entra ID 側でアプリ登録(またはユーザー割り当てマネージド ID)とフェデレーション資格情報を作成し、クライアント ID・テナント ID・サブスクリプション ID を GitHub のシークレットに登録しておきます。付与するロールは、対象のリソースグループやアプリに限定した最小限の範囲にします。
name: deploy-to-app-service
on:
push:
branches: [ main ]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- uses: azure/webapps-deploy@v3
with:
app-name: myapp-example-001
slot-name: staging
package: .
slot-name: staging は、前の節でスロットを作ってあることが前提です。スロットを使わない構成(Basic プランなど)では、slot-name の行を消すと本番に直接デプロイされます。アクションのメジャーバージョンは更新されることがあるため、各アクションのリポジトリで推奨バージョンを確認してから使ってください。
確認してから本番とスワップする
staging スロットの URL で動作を確認できたら、本番と入れ替えます。スワップでは、本番スロットの設定を staging 側のインスタンスに適用して再起動し、温まったことを確かめてから切り替えるため、切り替え時に本番が止まりません。問題があれば、同じスワップをもう一度実行すると元に戻せます。
az webapp deployment slot swap \
--name myapp-example-001 \
--resource-group rg-myapp \
--slot staging \
--target-slot production
本番の設定を当てた状態で一度確かめてから切り替えたい場合は、--action preview で第1段階だけを実行し、確認後に --action swap で完了、取り消すときは --action reset を使います。なお、デプロイのたびに自動でスワップする「自動スワップ」は、Linux の Web アプリでは使えません。
公開前の確認項目
- HTTPS のみを許可する設定(
az webapp update --name myapp-example-001 --resource-group rg-myapp --https-only true)を有効にする - 独自ドメインを使う場合は、DNS の検証レコードと証明書の設定を済ませる
- ヘルスチェックのパスを設定し、異常なインスタンスを切り離せるようにする
- ローカルディスクへの書き込みを前提にしない。スケールアウトや再起動で消える領域があるため、アップロードファイルは Blob Storage などに保存する
まとめ
- リソースグループ → App Service プラン → Web アプリの順に作る。スロットを使うならプランは Standard 以上にする
- ランタイム名は
az webapp list-runtimesの出力を使う - 秘密情報はアプリ設定や Key Vault に置き、ZIP やリポジトリに含めない
- 起動しないときは
az webapp log tailでログを見て、ビルド・起動コマンド・待ち受けアドレス・環境変数の順に確認する - スロットを作ってから GitHub Actions の送り先にし、環境ごとに違う設定は
--slot-settingsで固定してからスワップする
関連記事: