CI/CD設計書 - GitHub Actionsによる自動デプロイ & AI投稿
GitHub Actionsを活用したCI/CDパイプラインの設計書。自動ビルドからCloudflare Pagesへのデプロイ、Pagefindインデックス生成、AI記事自動生成まで、ワークフロー設計の全体像を解説します。
はじめに
本記事は、ブログシステムのCI/CD設計書をブログ記事として公開するものです。GitHub Actionsを中心としたパイプライン設計、AI自動投稿ワークフロー、セキュリティ設計について解説します。
パイプライン概要
ワークフロー一覧
| ワークフロー | トリガー | 目的 |
|---|---|---|
deploy.yml(Deploy Blogs) | push (main, blog-modern/** 変更時) / schedule(毎日 03:00 JST) / workflow_dispatch | ビルド・検索インデックス生成・Cloudflare Pagesへのデプロイ(定期実行は予約記事の自動公開を兼ねる) |
ai-auto-post.yml(AI Auto Post) | schedule(毎月1日・15日 03:00 JST) / workflow_dispatch | AI記事の自動生成・校閲・コミット・デプロイ起動 |
パイプラインフロー
flowchart LR
A["push / schedule /<br/>workflow_dispatch"] --> B["Checkout<br/>+ Node.js 22"]
B --> C["npm ci"]
C --> D["Astro Build"]
D --> E["Pagefind<br/>インデックス生成"]
E --> F["_site/ へ配置<br/>(ルートは /blog-modern/<br/>へリダイレクト)"]
F --> G["wrangler pages deploy<br/>→ Cloudflare Pages"]
デプロイワークフロー詳細
トリガー設定
on:
push:
branches: [main]
paths:
- "blog-modern/**"
- "docs/basic-design.md"
- "docs/cicd-design.md"
schedule:
- cron: "0 18 * * *" # 毎日 03:00 JST
workflow_dispatch:
パスフィルターにより、blog-modern/ 配下または配布用の設計書に変更がある場合のみpushでワークフローが実行されます。毎日 03:00 JST の定期実行は、予約投稿の記事を公開日に自動公開するための再ビルドです(後述)。workflow_dispatch はAI自動投稿からの明示起動にも使用します(理由は後述)。
ジョブ構成
単一の build-deploy ジョブ(ubuntu-latest)で完結します:
actions/checkout@v4- リポジトリのチェックアウトactions/setup-node@v4- Node.js 22のセットアップnpm ci- 依存関係の厳密インストールnpm run build- Astroによる静的サイトビルド(出力先dist/)npx pagefind --site dist- 全文検索インデックスの生成_site/への配置 -dist/を_site/blog-modern/へコピーし、ルートには/blog-modern/へのリダイレクトHTMLを配置npx wrangler@4 pages deploy _site --project-name=dawneel-blog --branch=main- Cloudflare Pagesへデプロイ
環境設定
permissions:
contents: read
concurrency:
group: pages
cancel-in-progress: true
- permissions: デプロイはリポジトリへ書き込まないため
contents: readのみの最小権限 - concurrency: 新しいデプロイ開始時に進行中のデプロイをキャンセル(常に最新コミットを配信)
- 認証:
CLOUDFLARE_API_TOKEN(Pages編集権限のみ)とCLOUDFLARE_ACCOUNT_IDをGitHub Secretsから環境変数として注入
公開URL
| パス | 内容 |
|---|---|
/ | /blog-modern/ へリダイレクト |
/blog-modern/ | ブログ本体(https://dawneel.lacue.uk/blog-modern/) |
AI自動投稿ワークフロー
スケジュール設定
on:
schedule:
- cron: "0 18 14,28,29,30,31 * *" # UTC 18:00 = JST 翌日 03:00
workflow_dispatch:
GitHub Actionsのcronは UTC 基準で、JST 03:00 は前日の UTC 18:00 にあたります。cron式では「月末日」を表現できないため、15日の前日(14日)と1日の前日になりうる28〜31日のすべてで起動し、実行時に JST の日付を判定して1日・15日以外は即座にスキップします(JST日付ガード)。深夜 03:00 に実行するのは、サブスクリプションの利用枠を運営者が使わない時間帯に充てるためです。
手動実行(workflow_dispatch)では、トピック(省略時はtopics.jsonから自動選択)と、コミット・公開を行わない検証モード(dry_run)を指定できます。
生成プロセスフロー
flowchart TD
A["トリガー発火<br/>(cron / 手動)"] --> B["トピック選択<br/>(topics.json / 指定)"]
B --> C["記事生成<br/>(Claude Code CLI: claude -p)"]
C --> R{"自動校閲<br/>PASS / FAIL"}
R -->|PASS| D["Markdown出力<br/>(frontmatter + 本文)"]
R -->|FAIL| C2["指摘を添えて<br/>1回だけ再生成"]
C2 --> R2{"再校閲"}
R2 -->|PASS| D
R2 -->|FAIL| DR["draft: true で保存<br/>(公開されない)"]
DR --> E
D --> E["git commit & push"]
E --> F["deploy.yml を<br/>明示的に dispatch"]
トピック管理
scripts/topics.json でトピックのキューを管理:
{
"topics": [
{
"title": "トピック名",
"category": "AI入門",
"tags": ["AI", "入門"],
"audience": "IT未経験の新卒エンジニア",
"used": false
}
]
}
--auto フラグ指定時、used: false のトピックを先頭から順に選択し、生成後に used: true に更新します。あらかじめキューに積んだテーマを月2回のペースで消費していく設計です。
記事生成
記事の生成には、GitHub Actionsのランナー上で Claude Code CLI(claude -p によるヘッドレス実行)を使います。認証はサブスクリプションのOAuthトークン(CLAUDE_CODE_OAUTH_TOKEN)で行います。プロンプトには品質基準(概念→理由→操作の順序、分量、挨拶や常套句の禁止など)を明文化しています。
自動校閲ゲート
生成された記事は、コミット前にもう一度Claudeで校閲します。深夜の無人実行で、基準に達しない記事がそのまま公開されることを防ぐための仕組みです。
| 項目 | 内容 |
|---|---|
| 判定基準 | 文体(です・ます調)/ 書き出し / 概念先行の構成 / 用語定義 / 分量 / まとめの有無 |
| 出力形式 | 指摘を列挙したうえで、最終行で VERDICT: PASS / VERDICT: FAIL を判定 |
| FAIL 時 | 指摘内容をプロンプトに添えて1回だけ再生成し、再校閲する |
| 再 FAIL 時 | draft: true で保存する(サイトには出ず、人手レビュー待ちになる) |
デプロイ起動の設計判断
GitHub Actionsの仕様として、GITHUB_TOKEN によるpushは他ワークフローのpushトリガーを発火しません(ワークフローの無限連鎖を防ぐための制限)。このため、記事をpushしただけではデプロイが走らず、gh workflow run でデプロイワークフローを明示的にdispatchしています。
git commit -m "feat: auto-generated blog post [ai-post]"
git push
# Pushes made with GITHUB_TOKEN never fire the push trigger of
# other workflows, so dispatch the deploy workflow explicitly.
gh workflow run deploy.yml --ref main
これに伴い、ワークフローの権限には contents: write(コミット用)に加えて actions: write(dispatch用)を付与しています。
permissions:
contents: write
actions: write
生成失敗時の扱い
記事の生成に失敗した場合、ワークフローは失敗ステータスで終了し、その内容をGitHub Issueとして報告します。失敗に気づけない状態を作らないことを優先した設計です。
手動投稿(Claude Code連携)
手動枠の記事はClaude Codeとの対話で作成します。自動投稿と異なり、必ずユーザーレビューを通してから公開する運用です。
flowchart TD
A["ユーザー: 記事の作成を指示"] --> B["Claude Code: 記事生成<br/>→ src/content/blog/ に保存"]
B --> C["ユーザー: レビュー・修正指示 → 承認"]
C --> D["draft: false でコミット & push<br/>(pubDate = 公開予定日)"]
D --> E["deploy.yml が<br/>push トリガーで自動起動"]
運営者自身のpushは GITHUB_TOKEN ではないため、pushトリガーが通常どおり発火します。明示dispatchが必要なのはAI自動投稿ワークフローのみです。
予約投稿
レビューを通過した記事は、draft: false と公開予定日の pubDate を設定してすぐにコミットします。記事の一覧・RSS・記事ページの生成は共通の公開判定関数 isPublished(draft でなく、pubDate が JST の今日以前であること)を通すため、未来日付の記事はビルドされてもサイトには出ません。deploy.yml の毎日 03:00 JST の定期ビルドが、公開日の到来した記事を自動で公開します。公開日当日に人が作業する必要はありません。
手動投稿 vs 自動投稿
| 項目 | 手動(Claude Code) | 自動(GitHub Actions) |
|---|---|---|
| トリガー | ユーザーの指示 | cronスケジュール(毎月1日・15日) |
| トピック | ユーザー指定 | topics.jsonから自動選択 |
| レビュー | ユーザーレビュー必須 | AI自動校閲(再FAILは下書き保存) |
| デプロイ起動 | pushトリガー | gh workflow run による明示dispatch |
| 投稿頻度 | 随時 | 月2回 |
ブランチ戦略
個人ブログのため、main直接運用を採用:
flowchart LR
subgraph main["main ブランチ"]
direction LR
C1["手動投稿"] --> C2["AI自動投稿"] --> C3["手動投稿"] --> C4["AI自動投稿"] --> C5["CI修正"]
end
- 大きな変更時のみ
feature/xxxブランチを作成 - mainへのpush(blog-modern/** の変更)で自動デプロイが発火
シークレット管理
| シークレット名 | 用途 | 使用ワークフロー | 必須 |
|---|---|---|---|
CLOUDFLARE_API_TOKEN | Cloudflare Pagesデプロイ認証(Pages編集権限のみの最小権限トークン) | deploy.yml | ○ |
CLOUDFLARE_ACCOUNT_ID | Cloudflareアカウント識別子 | deploy.yml | ○ |
CLAUDE_CODE_OAUTH_TOKEN | Claude Code CLI認証(サブスクリプション) | ai-auto-post.yml | ○ |
- GitHub Secretsで管理(リポジトリ設定 → Secrets and variables → Actions)
- ワークフロー内で
${{ secrets.XXX }}として参照 - コードやログに露出しない設計(Actionsが自動マスク)
監視・通知
GitHub標準通知
- ワークフロー失敗時にメール通知(GitHub設定に準拠)
- Actionsタブでワークフロー実行履歴を確認可能
監視対象
| 項目 | 確認方法 |
|---|---|
| ビルド成功率 | Actions → ワークフロー実行履歴 |
| デプロイ状態 | Cloudflare Pagesダッシュボード(Deployments) |
| AI投稿成功率 | ai-auto-postワークフローログ |
| 生成失敗 | 自動で作成されるGitHub Issue |
| 校閲の結果 | ai-auto-postログ / draft: true で保存された記事 |
障害対応
ビルド失敗時
- Actionsログでエラー内容を確認
- ローカルで
npm run buildを実行し再現確認 - コード修正 → push → 自動リビルド
デプロイ失敗時
- wranglerのエラーログを確認(トークン無効・権限不足・プロジェクト名誤りが典型)
CLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_IDのSecrets設定を確認- 必要に応じてActionsから「Deploy Blogs」を
workflow_dispatchで手動再実行
AI投稿後にデプロイが走らないとき
- ai-auto-postのログで
gh workflow run deploy.ymlステップの成否を確認 - ワークフローの
permissions.actions: writeが設定されているか確認
AI記事生成の失敗時
- 作成されたGitHub Issueとai-auto-postのログでエラー内容を確認
CLAUDE_CODE_OAUTH_TOKENの有効性とサブスクリプションの利用枠を確認- 必要に応じて手動で
workflow_dispatchから再実行
校閲で下書き保存されたとき
- ログで校閲の指摘内容を確認
draft: trueで保存された記事を人手で修正し、draft: falseにしてコミット
まとめ
本CI/CD設計は、「push → 自動ビルド → Pagefindインデックス生成 → Cloudflare Pagesへ自動デプロイ」と「スケジュール → AI記事生成 → 自動校閲 → 自動コミット → デプロイの明示dispatch」の2つのパイプラインを実現します。毎日 03:00 JST の定期ビルドにより、予約投稿の記事も公開日に自動で公開されます。リポジトリを非公開に保ったまま、運用コストゼロで自動化されたブログ運用基盤を提供します。本記事はダイジェスト版で、完全版の設計書はダウンロードページからMarkdownファイルとして入手できます。
※ 本記事の内容は執筆時点の情報であり、正確性を保証するものではありません。ご利用の際は免責事項をご確認ください。
Related / 関連記事
関連記事
AI自動投稿パイプライン構築記 - 寝ている間にブログが更新される仕組み
毎月1日・15日の深夜3時、AIが記事を書いてこのブログに公開されるまでを人手ゼロで回す仕組みの構築記。ネタ切れ対策のキュー、Claude Codeのヘッドレス実行、cronの時差の罠、品質をプロンプトで縛る話まで。
基本設計書 - 社内ブログシステム
Astroで構築しCloudflare Pagesでホスティングする社内マイブログシステムの基本設計書。システム構成、技術スタック選定理由、機能仕様、データ設計、セキュリティ設計を網羅します。
Comments / コメント