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

【実践】Docker × Azure × GitHub Actions で作る CI/CD 完全ガイド

0
Posted at

はじめに

本記事では、FastAPI (Backend)Next.js (Frontend) で構成されたWebアプリケーションを、Docker を使って Azure App Service へデプロイする手順を解説します。

今回使用するアプリケーションのソースコードはこちらです。
Githubリポジトリ:https://github.com/aripoyo14/practical_docker_deploy

デプロイするアプリの構成

通常、このアプリケーションをローカル(Dockerなし)で動かす場合は、Pythonの仮想環境を作って uvicorn を起動し、別途 Node.js で npm run dev を実行する必要があります。

本記事では、この Frontend と Backend が分離した構成 を Docker コンテナ化し、Azure 上で連携させて動かす「実践的なデプロイフロー」を構築します。

Dockerってそもそも何?という方はこちらの投稿から先にご覧ください。
Docker初心者によるDocker初心者のためのDocker解説

完成物のディレクトリ構造

本プロジェクトは モノレポ(Monorepo)構成 を採用しています。
1つのリポジトリの中に frontendbackend の両方のコードが含まれており、それぞれ個別に Docker コンテナとして動作します。

├── .github/workflows/          # CI/CD設定 (GitHub Actions)
│   ├── deploy-backend.yml
│   └── deploy-frontend.yml
├── backend/                    # FastAPI (Python) アプリケーション
│   ├── db_control/             # DB操作・モデル定義などのモジュール
│   ├── app.py                  # アプリケーションのエントリーポイント
│   ├── Dockerfile              # バックエンド用 Docker設定
│   ├── requirements.txt        # Python依存パッケージリスト
│   └── .dockerignore           # Dockerイメージに含めないファイルの設定
├── frontend/                   # Next.js (App Router) アプリケーション
│   ├── src/app/                # 画面・ページコンポーネント
│   ├── Dockerfile              # フロントエンド用 Docker設定
│   ├── package.json            # Node.js依存パッケージリスト
│   └── .dockerignore           # Dockerイメージに含めないファイルの設定
├── docker-compose.yml          # ローカル開発用構成 (Frontend + Backend + MySQL)
└── README.md

1. Dockerfile を作成する

まずは、アプリケーションをコンテナ化するための設計図である Dockerfile を作成します。

Backend の Dockerfile

backend/Dockerfile を作成します。

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

解説

  • FROM python:3.12-slim

    • ベースイメージの指定です。Python 3.12 がインストールされたLinux環境を土台に使います。
    • slim は必要最小限のツールだけを含んだ軽量版イメージです。イメージサイズを小さく抑えることで、デプロイ時間の短縮やセキュリティリスクの低減につながります。
  • WORKDIR /app

    • 作業ディレクトリの設定です。
    • コンテナ内部でのカレントディレクトリを /app に切り替えます。これ以降のコマンド(COPYやRUNなど)は、全てこの /app ディレクトリの中で実行されます。
  • COPY requirements.txt .

    • 依存定義ファイルのコピーです。
    • まず最初に requirements.txt だけをコンテナ内にコピーします。ソースコード全部をいきなりコピーしないのがポイントです。
  • RUN pip install --no-cache-dir -r requirements.txt

    • パッケージのインストールです。
    • pip install でライブラリをインストールします。
    • なぜソースコードのコピーより先にやるかというと、Dockerのキャッシュ機能を効かせるためです。ソースコードを変更しても、requirements.txt が変わっていなければ、この重いインストール処理はスキップ(キャッシュ利用)され、ビルドが爆速になります。
    • --no-cache-dir は pip 自体のキャッシュを残さないオプションで、イメージ容量を節約しています。
  • COPY . .

    • アプリケーションコードのコピーです。
    • ここで初めて、手元の backend ディレクトリの中身をすべてコンテナの /app にコピーします。
    • app.pydb_control フォルダなどがコンテナ内に配置されます。
  • EXPOSE 8000

    • ポート公開の宣言です。
    • このコンテナは「8000番ポートで通信を受け付けますよ」ということを明示しています(ドキュメント的な意味合いが強いです)。
  • CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

    • 起動コマンドです。コンテナが立ち上がった瞬間に実行されるコマンドです。
    • uvicorn: FastAPI を動かすための高速なサーバーです。
    • app:app: 「app.py ファイルの中にある app オブジェクト」を探して起動しなさい、という指示です。
    • --host 0.0.0.0: コンテナの外側からアクセスできるようにするための必須設定です。

Frontend の Dockerfile

frontend/Dockerfile を作成します。

FROM node:22.13.0-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

RUN npm run build

EXPOSE 3000

CMD ["npm", "run", "dev"]

解説

  • FROM node:22.13.0-alpine

    • ベースイメージの指定です。Node.js 22.13.0 を使用します。
    • alpine は超軽量のLinuxディストリビューションです。一般的なLinuxイメージよりも圧倒的にサイズが小さいため、フロントエンドのコンテナ化では非常によく使われます。
  • WORKDIR /app

    • コンテナ内の作業場所を /app に設定します。
  • COPY package*.json ./

    • package.jsonpackage-lock.json をコピーします。
    • Pythonの時と同じく、依存関係のインストールを効率化するための手順です。
  • RUN npm install

    • 必要なライブラリ(node_modules)をインストールします。
  • COPY . .

    • Next.js のソースコード一式をコンテナ内にコピーします。
  • RUN npm run build

    • ビルドの実行です。
    • Next.js のアプリケーションを本番用に最適化(ビルド)します。これで .next フォルダなどが生成されます。
  • EXPOSE 3000

    • Next.js はデフォルトで 3000 番ポートを使うため、それを宣言しています。
  • CMD ["npm", "run", "dev"]

    • 起動コマンドです。
    • 開発サーバー (dev) を立ち上げています。
    • ※補足:本番運用(Production)を厳密に意識する場合は npm start を使うのが一般的ですが、今回は開発環境の設定をそのまま流用しやすくするため dev としています。

2. docker-compose.yml を作成する

複数のコンテナ(Frontend, Backend, Database)をまとめて管理・起動するための docker-compose.yml を作成します。

version: '3.8'

services:
  frontend:
    build: ./frontend
    ports:
      - "3000:3000"
    environment:
      - NEXT_PUBLIC_API_ENDPOINT=http://localhost:8000
      - API_ENDPOINT=http://backend:8000
    depends_on:
      - backend

  backend:
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      - DB_USER=root
      - DB_PASSWORD=${DB_PASSWORD}
      - DB_HOST=mysql
      - DB_PORT=3306
      - DB_NAME=crm
    depends_on:
      mysql:
        condition: service_healthy

  mysql:
    image: mysql:8.0
    ports:
      - "3307:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_DATABASE=crm
    volumes:
      - mydata:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  mydata:

解説

version: '3.8'

Docker Compose ファイルの記述バージョンです。新しい機能を使うために比較的新しいバージョンを指定しています。

Service: frontend

  • build: ./frontend: 先ほど作った frontend/Dockerfile を使ってイメージを作ります。
  • ports: "3000:3000": パソコンのブラウザで http://localhost:3000 にアクセスすると、コンテナの 3000番に繋がるようにします。
  • environment:
    • NEXT_PUBLIC_API_ENDPOINT: ブラウザ側からAPIを叩くためのURL。
    • API_ENDPOINT: Next.jsサーバー側からAPIを叩くためのURL(コンテナ間通信)。
  • depends_on: - backend: バックエンドが起動してからフロントエンドを起動するよう制御します。

Service: backend

  • build: ./backend: backend/Dockerfile を使ってイメージを作ります。
  • ports: "8000:8000": http://localhost:8000 でAPIにアクセスできるようにします。
  • environment: DB接続情報を渡します。
    • DB_HOST=mysql: ここが重要です。Docker Compose内ではサービス名(mysql)がそのままホスト名として使えます。
    • ${DB_PASSWORD}: パスワードをファイルに直接書くのは危険なので、.env ファイル等から読み込む変数にしています。
  • depends_on:
    • condition: service_healthy: 単に mysql コンテナが起動するだけでなく、「MySQLが準備完了(healthy)」になるまで待ってから起動します。これで「起動直後のDB接続エラー」を防げます。

Service: mysql

  • image: mysql:8.0: Docker Hubにある公式の MySQL 8.0 イメージを使います。
  • ports: "3307:3306": ローカルPCの 3307番ポートを、コンテナの 3306番に繋ぎます(3306は自分のPCで既に使っていることが多いため、あえてずらしています)。
  • volumes: - mydata:/var/lib/mysql:
    • データの永続化です。コンテナを削除してもデータが消えないように、mydata という専用の保存領域にDBのデータを書き込みます。
  • healthcheck:
    • MySQLが本当にクエリを受け付けられる状態になったか、定期的に ping コマンドを打って確認する設定です。これのおかげで、Backend側が安心して接続開始できます。

3. Azureリソースグループを作成する

ここからはクラウド(Azure)側の設定です。まずはすべてのリソースを入れる「箱」を作ります。

  1. Azureポータルの検索窓で「リソースグループ」と検索し選択します。
  2. 「作成」ボタンをクリックします。
  3. サブスクリプション: 自分のものなどを選択。
  4. リソースグループ名: 任意の名前(例: rg-practical-docker)を入力。
  5. リージョン: 日本に近い Japan East (東日本) などを選択。
  6. 「確認と作成」→「作成」をクリックして完了です。

4. Azure Container Registry (ACR) を作成する

Dockerイメージを保存しておくための「倉庫」を作ります。

リソースグループの作成

参考資料:Azureのリソースグループとは?役割や作成方法・分け方

  1. Azureポータルの検索窓で「リソースグループ」と検索し選択します。
    6.png
  2. 必要事項を入力して、「作成」をクリック。
    7.png※既に存在するリソースグループ名のため、エラーが出ています。

ACRの作成

  1. Azureポータルの検索窓で「container」と検索し選択します。
    8.png

  2. 「作成」をクリック。

  3. リソースグループ: 先ほど作成したものを選択。

  4. レジストリ名: 世界で一意の名前(例: acrdeploytrial2024)を入力。※全て小文字である必要があります。

  5. SKU: 学習用なら「Basic」で十分です。

  6. 「確認と作成」→「作成」をクリック。
    9.png※既に存在するレジストリ名のため、エラーが出ています。

Adminユーザーの有効化(重要)

デプロイ時にユーザー名とパスワードでログインできるように設定を変更します。

  1. 作成された ACR のリソース画面に移動します。
  2. 左メニューの「設定」>「アクセス キー」を選択します。
  3. 「管理者ユーザー」 を「有効 (Enabled)」に切り替えます。
  4. 表示された ユーザー名パスワード をメモしておきます(後で使います)。
    10.png

5. ローカルのDockerイメージをACRに登録する

作成した ACR に、手元のパソコンで作ったDockerイメージをアップロード(Push)します。

Azure CLI でログイン

まず、コマンドラインツールで Azure にログインします。
参考資料:Azure CLI をインストールする方法

# Azureアカウントへのログイン(ブラウザが開きます)
az login

# ACRへのログイン
# ※ <ACR名> は先ほど作ったレジストリ名です
az acr login --name <ACR名>

「Login Succeeded」と表示されればOKです。

イメージにタグを付けてPushする

ACR にアップロードするためには、「これはどこのACRの、なんというイメージか」という名札(タグ)を付ける必要があります。

# === 1. タグ付け (Tagging) ===
# 形式: docker tag <元のイメージ名> <ACRログインサーバー>/<イメージ名>:<バージョン>

# フロントエンド
docker tag practical_docker_deploy-frontend <ACR名>.azurecr.io/frontend:v1

# バックエンド
docker tag practical_docker_deploy-backend <ACR名>.azurecr.io/backend:v1


# === 2. アップロード (Push) ===
# 作成したタグを指定してACRへ送信します

docker push <ACR名>.azurecr.io/frontend:v1
docker push <ACR名>.azurecr.io/backend:v1

これで、Azure上の倉庫(ACR)にイメージが格納されました。
成功しているとコンテナーレジストリにリポジトリが追加されます。
11.png

6. Azure App Service を作成する

いよいよアプリケーションを動かすサーバーを作ります。Frontend用とBackend用で2つ作成します。

作成手順

  1. Azureポータルで「App Services」を検索し選択。
    12.png

  2. 「作成」>「Web アプリ」を選択。

  3. 基本タブ:

    • リソースグループ: 作成したものを選択。
    • 名前: アプリのURLになります(例: app-frontend-trial)。
    • 公開: 「Docker コンテナー」を選択(重要!)。
    • オペレーティングシステム: 「Linux」を選択。
    • プラン: テスト用なら B1F1 (Free) を探して選択。
  4. コンテナータブ:

    • オプション: 「単一コンテナー」
    • イメージソース: 「Azure Container Registry
    • レジストリ: 作成したACRを選択。
    • イメージ: frontend (または backend) を選択。
    • タグ: v1 を選択。
  5. 「確認と作成」→「作成」をクリック。
    ※これを「フロントエンド用」と「バックエンド用」で2回繰り返してください。

13.png

7. GitHub Actions で自動デプロイを構築する

ここまでの手順だと、コードを修正するたびに手動でビルド・プッシュするのは大変です。
GitHub にコードをプッシュしたら、勝手に Azure までデプロイしてくれる仕組み(CI/CD)を作ります。

ワークフローファイルの作成

リポジトリの .github/workflows/ フォルダの中にYAMLファイルを作成します。

deploy-frontend.yml (フロントエンド用)

name: Deploy Frontend to Azure App Service

on:
  push:
    branches:
      - main
    paths:
      - 'frontend/**'  # frontendフォルダに変更があった時だけ動く

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest  # GitHub側のサーバー(Ubuntu)で実行

    steps:
      # 1. リポジトリのコードを取得
      - name: Checkout repository
        uses: actions/checkout@v3

      # 2. Azureにログイン
      - name: Log in to Azure
        uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}

      # 3. ACRにログイン
      - name: Log in to ACR
        run: az acr login --name <あなたのACR名>

      # 4. ビルドしてACRにPush
      - name: Build and Push Docker image
        run: |
          # コミットハッシュ(github.sha)をタグに使ってユニークにする
          docker build -t <あなたのACR名>.azurecr.io/frontend:${{ github.sha }} ./frontend
          docker push <あなたのACR名>.azurecr.io/frontend:${{ github.sha }}

      # 5. App Serviceへデプロイ
      - name: Deploy to App Service
        uses: azure/webapps-deploy@v2
        with:
          app-name: ${{ secrets.APP_SERVICE_FRONTEND }}
          images: <あなたのACR名>.azurecr.io/frontend:${{ github.sha }}

解説

  1. paths: - 'frontend/**':
    • これが重要です。「frontendフォルダの中身が変わった時だけ」この処理を走らせます。backendの修正時は無視することで、無駄なデプロイを防ぎます。
  2. docker build ... ${{ github.sha }}:
    • タグに v1 などの固定値ではなく、${{ github.sha }}(その時点のコミットID)を使っています。これにより、「どのコミットのコードで動いているか」が明確になり、バージョン管理が確実になります。
  3. secrets.AZURE_CREDENTIALS:
    • ログイン情報などの機密情報はコードに直書きせず、GitHubの「Secrets」機能を使って隠蔽します。

※ バックエンド用の deploy-backend.yml も、パスを backend/** に、アプリ名をバックエンド用に変えて同様に作成します。

最後の仕上げ:GitHub Secrets の設定

GitHubリポジトリの「Settings」→「Secrets and variables」→「Actions」に、以下の変数を登録します。

Secret名 設定する値
AZURE_CREDENTIALS サービスプリンシパルのJSON情報(後述のコマンドで取得)
APP_SERVICE_FRONTEND 作成したフロントエンド用App Serviceの名前
APP_SERVICE_BACKEND 作成したバックエンド用App Serviceの名前

AZURE_CREDENTIALS 取得用コマンド:
Azure CLIで以下を実行し、出力されたJSON全体をコピーして登録してください。

az ad sp create-for-rbac --name "myAppDeploy" --role contributor \
    --scopes /subscriptions/<サブスクリプションID>/resourceGroups/<リソースグループ名> \
    --sdk-auth

デプロイ完了!

お疲れ様でした!これで以下のフローが完成しました。

  1. ローカルでコードを修正して git push
  2. GitHub Actions が変更を検知
  3. Dockerイメージを自動ビルドして ACR に保存
  4. Azure App Service が新しいイメージに更新される

これで、開発に集中できるモダンな開発環境の出来上がりです。

15.png
16.png
17.png

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