1
3

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.

GitHub Actionsを用いたCI/CDの基礎

1
Posted at

はじめに:CI/CDの必要性

「ローカルでは動いたけど、本番で動かない」
そんな状況に陥ったことはありませんか?

CI/CD(継続的インテグレーション/継続的デリバリー)は、開発・テスト・デプロイの自動化を通じて、開発品質の向上とチームの効率化を実現する仕組みです。

今回紹介するのは、GitHub Actions × Docker Compose を使った最小構成のCI/CDフローです。

今回のCI/CDフロー(図解)

今回は試しに以下のようなフローを構築しようと思います。

① ローカル開発(別ブランチ)
     ↓
② 開発ブランチにpush(例: feature/login)
     ↓
③ CI(自動):
   - Docker Composeでbuildできるか
   - pytestでテストが通るか
   - flake8でコード品質チェック
     ↓
④ Pull Request作成
     ↓
⑤ mainブランチにマージされたら自動でCD(デプロイ)
   - docker-compose.prod.yml を使って
   - 本番環境用イメージをBuild & 起動

この構成の特徴は、開発ブランチでCI、mainブランチでCDという明確な責任分離です。

実際に使用したコード

構成について

.
├── app/
│   └── main.py                # 本体アプリケーションのロジック(例:add関数)
├── tests/
│   └── test_main.py           # pytest によるユニットテスト
├── docker-compose.yml         # CI用の開発環境構成(ビルド&テスト実行)
├── docker-compose.prod.yml    # 本番用デプロイ構成(ポート公開・永続化など)
├── Dockerfile                 # アプリのビルド定義(pytest + flake8用)
├── requirements.txt           # Python依存ライブラリ定義
├── pytest.ini                 # カバレッジ表示用の設定ファイル
└── .github/
    └── workflows/
        ├── ci.yml             # CI処理:lint, testを自動化
        └── deploy.yml         # CD処理:mainマージ時に本番デプロイ

.github/workflows/ci.yml

.github/workflows/ci.yml
name: CI

on:
  push:
    branches: ["*", "!main"]
  pull_request:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: pip install flake8
      - run: flake8 app tests

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: docker compose up --abort-on-container-exit

詳細解説

name: CI
  • このワークフローの名前。GitHub Actions UIに表示される。
on:
  push:
    branches: ["*", "!main"]
  pull_request:
    branches: [main]
  • push: どのブランチでもpush時にCIを実行(ただし main は除外)
  • pull_request: main ブランチに対するPR作成時にもCIを実行

lintジョブ

jobs:
  lint:
    runs-on: ubuntu-latest
  • GitHubリポジトリのソースコードをチェックアウト
      - run: pip install flake8
  • 静的解析ツール flake8 をインストール
      - run: flake8 app tests
  • app/とtests/に対してPythonコードスタイルのチェックを実行
    • 例:関数定義前に2行空いていない、未使用importがあるなどのエラーを検出

testジョブ(例)

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: docker compose up --abort-on-container-exit
  • docker compose で docker-compose.yml に基づくテスト環境(app + db)を起動
  • pytest を実行し、テスト失敗時は exit code != 0 でワークフロー全体が失敗となる
  • --abort-on-container-exit によって、app コンテナが終了すると全体が止まる

.github/workflows/deploy.yml

github/workflows/deploy.yml
name: Deploy to Production

on:- 
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: docker compose -f docker-compose.prod.yml up -d --build

詳細解説

name: Deploy to Production
  • デプロイ用ワークフローのタイトル。GitHub UIに表示される。
on:
  push:
    branches: [main]
  • main ブランチに push されたときに発火
  • → PRをマージした後、自動で実行される

デプロイジョブの定義

jobs:
  deploy:
    runs-on: ubuntu-latest
  • deploy というジョブ名で、Ubuntu上で動作
    steps:
      - uses: actions/checkout@v3
  • ソースコード(mainブランチ)の最新状態を取得
      - run: docker compose -f docker-compose.prod.yml up -d --build
  • docker-compose.prod.yml に基づき 本番用イメージをビルド&バックグラウンド起動
  • -d:バックグラウンドで起動
  • --build:常に最新ソースコードからイメージを再構築

補足:なぜ ci.yml と deploy.yml を分けるのか?

理由 説明
責務の分離 CIはテスト品質保証、CDは本番反映。混ぜると保守性が下がる
再利用性 CIだけ複数ブランチで使えるが、CDはmainだけで良い
安全性 CDが条件付きで動作するようにすることで誤デプロイを防げる

個人的にハマったポイント

Docker Compose のバージョン違い

  • docker-compose(ハイフンあり)は GitHub Actionsでは非推奨
  • 正しくは docker compose(スペースあり)を使用

他のよくあるフロー構成パターン

GitHub Actions では、用途に応じてCI/CDの構成を柔軟に変えることができます。以下に、実務でよく使われる3つのパターンと、それに対応する設定・想定シナリオを紹介します。

パターン①:Staging環境を挟むCD構成

構成イメージ

feature/xxx ブランチ
   ↓ push
CI:lint / test(自動)

↓ PR → main
main ブランチにマージ
   ↓
CD:Stagingに自動デプロイ

↓ 手動承認
Productionブランチにマージ
   ↓
CD:本番に自動デプロイ

こんなときに使う

  • 本番に即反映させたくない(社内レビューや検証が必要)
  • ステージング環境でのQAやUATを挟みたいとき
  • 複数人チームで、リリース責任を明確にしたいとき

deploy.yml(Staging用)

on:
  push:
    branches: [main]  # mainマージでStagingにCD

# VPSやCloud RunなどにStagingデプロイ処理を書く

deploy-prod.yml(Production用)

on:
  push:
    branches: [release]

# 本番用環境に対してデプロイ処理を記述

パターン②:タグ付きリリースで本番CD(セマンティックバージョン)

構成イメージ

mainブランチが安定したタイミングで:

$ git tag v1.0.0
$ git push origin v1.0.0

   ↓
GitHub Actionsがタグ検知 → 本番デプロイ

こんなときに使う

  • リリースのたびに 手動で明示的に本番反映したい
  • バージョンを意識してデプロイ管理したい
  • OSS開発などで「タグ = リリース」の明示が必要なとき

deploy.yml(タグトリガー)

on:
  push:
    tags:
      - 'v*.*.*'  # セマンティックバージョン(例: v1.0.0)

# docker build & deploy 処理を書く

パターン③:Smokeテスト付きの自動ロールバック

構成イメージ

main push → 自動デプロイ → 自動テスト(Smoke Test)

成功 → 完了
失敗 → ロールバック処理を実行

こんなときに使う

  • リリース後すぐに 致命的なバグ検知を防ぎたい
  • 「壊れた本番環境」を最短で回避したい

deploy.yml(Smoke Test + ロールバック)

jobs:
  deploy:
    steps:
      - run: docker compose -f prod.yml up -d --build

  smoke-test:
    needs: deploy
    steps:
      - run: curl --fail http://localhost:8000/health || exit 1

  rollback:
    if: failure()
    needs: smoke-test
    steps:
      - run: docker compose -f prod.yml down && docker compose -f prev.yml up -d

終わりに

CI/CDは一見ハードルが高く見えますが、GitHub ActionsとDocker Composeだけでもここまでできるという実感を得ました。

今回紹介したようなシンプルな構成から始めて、将来的にはSlack通知や本番環境との連携まで広げることもできます。

1
3
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
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?