2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Github Actionsで実現するAzure App Serviceの自動デプロイ

2
Last updated at Posted at 2025-12-22

はじめに

開発環境でのアプリケーションの機能実装が完了すると、次に控えているのがステージング環境や本番環境へのデプロイ作業です。手順自体は決して複雑ではないものの、新しいイメージをプッシュして、アプリを再起動して、動作確認して……と、毎回手動で行うとなると地味に手間がかかります。

その“ちょっとした手間”を減らすために、GitHub Actions を使って デプロイ作業を自動化する CI/CD パイプラインを構築しました。こちらは今回の構築でやったことの備忘録です。

今回やったことはこちらの2つです。
①Azure Container Registry(ACR)へのイメージプッシュを自動化
②新イメージ適用のための Azure App Service の再起動を自動化

所属する開発チームのプロジェクトはリリース頻度が高いため、"ちりつも"ではありますが今回の改善で月あたり約4.5時間の時間削減につながりました。
この記事が日々業務改善を求められている人たちの参考になれば幸いです。

お知らせ

内容が少し長くなってしまったので先にお知らせです。
こちらの記事は ctc Advent Calendar 2025 の記事です。
12月も残りわずかになりました。これまでにも ctc(中部テレコミュニケーション株式会社)のメンバーが技術にまつわる知見を投稿していますので、ぜひご覧ください。

①でやったこと

Azure Container Registryの連携準備

ワークフローでAzure Container Registry(ACR)にアクセスできるようにするため、azure/docker-login@v1でログインをします。
これに必要なusernamepasswordを、GithubのSecretsに登録していきます。

  1. プッシュ先のACRの設定 > アクセスキーを開きます。
    使用するのはユーザー名passwordです。
    のちほどログインサーバーも使用するので、ここで控えておきましょう。
    画像1.png

2. Githubで対象リポジトリのSettings > Secrets and variables > Actionsを開き、
 「New repository secret」からSecretsを2つ登録します。
 ※一度登録すると登録した内容を確認できないので注意!

  • Name:REGISTRY_USERNAME、Secret:さきほど控えたユーザー名
  • Name:REGISTRY_PASSWORD、Secret:さきほど控えたpassword
    Secrets登録.png

「Github Enterprise」を利用している場合は、Organization secretsに登録するのがおすすめです。Organization secretsは複数のリポジトリで同じSecretsを使うことができるため、リポジトリごとの登録が不要になります!


GitHub Actions のワークフロー作成

今回は複数リポジトリに自動デプロイを適用させたかったので、リポジトリ共通で利用できるワークフローを独立したリポジトリに配置し、各リポジトリから共通ワークフローを呼び出すアプローチを取りました。
これによりワークフローのメンテナンスもしやすくなります。(実際に共通化をしておいたおかげで②の改修の手間も少なく済みました)

呼び出し元ワークフロー(各リポジトリに配置)

.github/workflows/call-deploy-to-acr.yml
name: Trigger ACR Deployment

on:
  push:
    branches:
      - main
      - develop
      - production

jobs:
  check-deployment:
    runs-on: ubuntu-latest
    outputs:
      dockerfile_exists: ${{ steps.check.outputs.dockerfile_exists }}
      repo_name: ${{ steps.check.outputs.repo_name }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        
      - name: Check Dockerfile and extract repository name
        id: check
        run: |
          if [ -f Dockerfile ]; then
            echo "dockerfile_exists=true" >> $GITHUB_OUTPUT
            echo "repo_name=${GITHUB_REPOSITORY##*/}" >> $GITHUB_OUTPUT
          else
            echo "dockerfile_exists=false" >> $GITHUB_OUTPUT
            echo "repo_name=" >> $GITHUB_OUTPUT
          fi

  deploy-to-acr:
    needs: check-deployment
    if: ${{ needs.check-deployment.outputs.dockerfile_exists == 'true' }}
    uses: [共通ワークフローのymlファイルを指定]
    with:
      image_name: xxxx
    secrets:
      REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
      REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}

詳細な解説は割愛しますが、呼び出し元ワークフローのポイントは以下の2点です。

  • 指定ブランチへの push をトリガーにワークフローを起動
  • Secretsは呼び出し元ワークフローから渡す(共通ワークフロー側での設定は不可)

共通ワークフロー(独立リポジトリに配置)

.github/workflows/deploy-to-acr.yml
name: Deploy to Azure Container Registry

on:
  workflow_call:
    inputs:
      image_name:
        description: 'リポジトリ名'
        required: true
        type: string
    secrets:
      REGISTRY_USERNAME:
        required: true
      REGISTRY_PASSWORD:
        required: true

jobs:
  deploy-and-restart:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Login to Azure Container Registry
        uses: azure/docker-login@v1
        with:
          login-server: <ログインサーバー>
          username: ${{ secrets.REGISTRY_USERNAME }}
          password: ${{ secrets.REGISTRY_PASSWORD }}

      - name: Build and push Docker image
        shell: bash
        run: |
          if [[ "${GITHUB_REF}" == "refs/heads/main" ]]; then
            echo "Building image for main branch..."
            docker build . -t <ログインサーバー>/${{ inputs.image_name }}:latest
            docker push <ログインサーバー>/${{ inputs.image_name }}:latest

          elif [[ "${GITHUB_REF}" == "refs/heads/develop" ]]; then
            echo "Building image for develop branch..."
            docker build . -t <ログインサーバー>/${{ inputs.image_name }}:develop
            docker push <ログインサーバー>/${{ inputs.image_name }}:develop

          elif [[ "${GITHUB_REF}" == "refs/heads/production" ]]; then
            echo "Building image for production branch..."
            DATE_TAG=$(date +'%Y%m%d')
            docker build . -t <ログインサーバー>/${{ inputs.image_name }}:production -t <ログインサーバー>/${{ inputs.image_name }}:${DATE_TAG}
            docker push <ログインサーバー>/${{ inputs.image_name }}:production
            docker push <ログインサーバー>/${{ inputs.image_name }}:${DATE_TAG}

          else
            echo "No matching branch found. Skipping build."
          fi

今回の共通ワークフローのざっくりとした流れは、

  • 呼び出し元ワークフローから受け取ったSecret情報でACRにアクセス
  • main / develop ブランチへのマージの場合:ACRに指定タグでプッシュ
  • production ブランチへのマージの場合:ACRに指定タグ&日付タグでプッシュ

になります。フロー内の<ログインサーバー>部分には、さきほど控えたxxx.azure.ioが入ります。

ここで重要な設定をします。
共通ワークフローを独立したリポジトリに配置したので、組織内の他リポジトリからのアクセスを許可する必要があります。
GithubでSettings > Actions > Generalを開き、「Accessible from repositories in the '[組織名]'」を選択します。(Saveをお忘れなく!)
ワークフローアクセス許可.png

②でやったこと

サービスプリンシパルの準備

Azure App ServiceをGithub Actionsから再起動をするには、再起動ができる権限でアクセスする必要があります。①ではACRにのみアクセスできる権限でログインをしていたので、ここで新たに設定をしていきます。
今回は同じリソースグループにある複数のAzure App Serviceが対象だったので、そのリソースグループの共同作成者権限をもつサービスプリンシパルを利用してazure/login@v1でログインをします。

必要情報は以下の4つです。①でもあったSecrets登録と同じ手順で登録します。

  • AZURE_CLIENT_ID(Azure上では「アプリケーションID」と表示)
  • AZURE_CLIENT_SECRET(サービスプリンシパル作成時のみ表示されるシークレット値)
  • AZURE_SUBSCRIPTION_ID(対象のサブスクリプションID)
  • AZURE_TENANT_ID(対象のテナントID)

ワークフローの追加

さきほど①で作成した2つのワークフローをそれぞれ編集します。
今回は develop ブランチへのマージがあったときのみ、ステージング環境を自動再起動するフローを追加しています。

呼び出し元ワークフローの編集

.github/workflows/call-deploy-to-acr.yml(追記部分のみ抜粋)
 deploy-to-acr:
    needs: check-deployment
    if: ${{ needs.check-deployment.outputs.dockerfile_exists == 'true' }}
    uses: xxx
    with:
      image_name: xxx
      app_service_name: xxx #ステージング環境を指定
      resource_group: xxx
    secrets:
      REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
      REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
      AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
      AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
      AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
      AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

呼び出し元ワークフローには、ステージング環境を指定するための変数app_service_nameresource_group、そしてさきほど登録したSecretsを渡すように追記しました。

共通ワークフローの編集

.github/workflows/deploy-to-acr.yml(一部省略)
name: Deploy to Azure Container Registry

on:
  workflow_call:
    inputs:
      image_name:
        description: 'リポジトリ名'
        required: true
        type: string
      app_service_name:
        description: 'Azure App Service名'
        required: false
        type: string
      resource_group:
        description: 'リソースグループ名'
        required: false
        type: string
    secrets:
      REGISTRY_USERNAME:
        required: true
      REGISTRY_PASSWORD:
        required: true
      AZURE_CLIENT_ID:
        required: false
      AZURE_CLIENT_SECRET:
        required: false
      AZURE_TENANT_ID:
        required: false
      AZURE_SUBSCRIPTION_ID:
        required: false

jobs:
  deploy-and-restart:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

#<中略>

 # App Service再起動(stagingのみ)
      - name: Azure Login
        if: github.ref == 'refs/heads/develop' && inputs.app_service_name != ''
        uses: azure/login@v1
        with:
          creds: '{"clientId":"${{ secrets.AZURE_CLIENT_ID }}","clientSecret":"${{ secrets.AZURE_CLIENT_SECRET }}","subscriptionId":"${{ secrets.AZURE_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZURE_TENANT_ID }}"}'

      - name: Wait for image propagation
        if: github.ref == 'refs/heads/develop' && inputs.app_service_name != ''
        shell: bash
        run: |
          echo "⏳ イメージの更新を待機中... (60秒)"
          sleep 60
          echo "✅ 待機完了"

      - name: Restart App Service
        if: github.ref == 'refs/heads/develop' && inputs.app_service_name != ''
        shell: bash
        run: |
          echo "🔄 App Service再起動開始"
          echo "対象リソースグループ: ${{ inputs.resource_group }}"
          echo "対象App Service名: ${{ inputs.app_service_name }}"
          
          # App Serviceの存在確認
          echo "📋 対象App Serviceの確認中..."
          az webapp show --name ${{ inputs.app_service_name }} --resource-group ${{ inputs.resource_group }} --query "name" -o tsv
          
          # 再起動実行
          echo "🔄 再起動を実行します..."
          az webapp restart \
            --name ${{ inputs.app_service_name }} \
            --resource-group ${{ inputs.resource_group }}
          
          echo "✅ App Service再起動完了"

共通ワークフローには、develop ブランチにプッシュされている、かつ、ステージング環境のアプリ名が渡されている場合に指定されたAzure App Serviceを再起動するフローを追加しました。
また、ACRに新イメージがプッシュされてすぐに再起動を実施するとビルドが間に合ってないことがあったため、再起動前に60秒の待機時間を設けています。

ワークフローのテスト

ワークフローの動作はGithubの「Actions」から確認できます。
共通ワークフローの呼び出しからアプリの再起動まで、ブランチのマージをトリガーに自動で完了しました(達成感)。

ワークフロー呼出部分.png

ワークフローログ.png


まとめ

ここまでお読みいただきありがとうございます。
今回は、GitHub Actions を使って ACR へのプッシュと App Service の再起動を自動化したことで、デプロイ作業の手間を減らすことができました。
それだけでなく、手作業によるヒューマンエラーのリスクを減らすことができたのも自動化してよかったポイントですね。

今後もできるところから改善をして、より快適な開発環境を整えていければと思います。

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?