1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

初めてのCI/CD。pushしただけで公開まで流れる理由を、図で理解した(GitHub Actions + Cloudflare Workers)

1
Last updated at Posted at 2026-11-03

1. はじめに

CI/CDという言葉は知っていましたが、なかなか勉強するまでには至りませんでした。それが仕事で使うことになり、とうとう勉強を始めることにしました。

とはいえ、どこから手をつければいいのか分かりません。調べると記事はたくさんあり、手順も丁寧に書かれています。ただ、どれも「こう書けば動く」が中心で、なぜpushしただけで最後まで流れるのかは、読んでもいまいち分かりませんでした。

幸い、今はAIという優秀なパートナーがいます。そこで今回は、AI(Claude Code)に助けてもらいながら、自分の環境で1つずつ検証していきました。

まず作ったのは、GitHubにpushすると、GitHub ActionsがCloudflare Workersへ自動で公開してくれるしくみです。画面で操作したのは3つ、書いたファイルも3つだけで、pushすると公開まで勝手に進んでいきます。実際に動かしてみても、やはり疑問は「何で流れるの?」、これだけでした。

この記事では、手順に加えて、なぜ最後まで自動で流れるのかを図で説明します。同じところでもやもやしている人の参考になればうれしいです。

なお、記事の内容はすべて自分の環境で動かして確かめていますが、CI/CDは初心者です。間違いなどがあれば、コメントで教えていただけるとうれしいです。

2. 作ったもの

GitHubのmainブランチにpushすると、約30秒で https://test.tobaru.net のページが更新されるしくみです。ページはHTMLファイル1つだけの、いちばん小さなものにしました。

ひとことで言うと、GitHubに置いたファイルを、GitHubのロボット(Actions)がCloudflareまで運んでくれます。運ぶときにCloudflareのドアを開けるので、ロボットに合鍵(APIトークン)を預けてあります。

04_overview.png

自分で用意したサーバーはありません。DNSのレコードとhttpsの証明書も、手では作っていません。

3. 環境

項目 内容
GitHub Freeプラン、Privateリポジトリ
Cloudflare Freeプラン
ドメイン Cloudflare Registrarで取得したtobaru.net(DNSもCloudflare)
デプロイの道具 cloudflare/wrangler-action@v4、wrangler 4
作業したPC Windows 11、VS Code、Git

自分のPCにNode.jsやwranglerは入れていません。wranglerはGitHub Actionsの中でだけ動きます。

ドメインのDNSがCloudflareにあることが、後で出てくる「1行でDNSと証明書ができる」の条件になります(5章の(5))。

4. 手順

画面で操作したのは(1)〜(3)の3つだけです。(4)はファイルを書くだけ、(5)はpushするだけです。

(1) GitHubにリポジトリを作る

  • 名前はtobaru-net-test、Privateにしました
  • README・.gitignore・ライセンスは付けず、空のリポジトリにします(ローカルで作ったファイルをそのままpushするため)

(2) CloudflareでAPIトークンを作る

  1. 右上の人のアイコン → プロフィール → APIトークン → トークンを作成する
  2. テンプレート「Cloudflare Workers を編集する」を使う
  3. 範囲を絞る
    • アカウントリソース: 自分のアカウントだけ
    • ゾーンリソース: 特定のゾーン → tobaru.netだけ
  4. 作成する。トークンは一度しか表示されないので、そのまま(3)に貼る

範囲を絞っておくと、万一トークンが漏れても、できることは「Workersの更新」と「tobaru.netの設定」だけです。

(3) GitHubのSecretsに登録する

リポジトリの Settings → Secrets and variables → Actions → New repository secret で、2つ登録します。

Name 値
CLOUDFLARE_API_TOKEN (2)で作ったトークン
CLOUDFLARE_ACCOUNT_ID CloudflareのアカウントID

(4) ファイルを3つ書く

tobaru-net-test/
├─ public/
│   └─ index.html            … 見せるページそのもの
├─ wrangler.jsonc            … Cloudflareへの注文書(何を・どこで出すか)
└─ .github/
    └─ workflows/
        └─ deploy.yml        … Actionsへの指示書(いつ・何をするか)

public/index.htmlは、ふつうのHTMLです(中身は省略)。

wrangler.jsoncです。ふつうのJSONはコメントが書けませんが、jsonc(JSON with Comments)は//で書けます。

{
  // Cloudflare側でのWorkerの名前(名札)。
  // この名前のWorkerがなければ新しく作り、あれば中身を置き換える
  "name": "tobaru-net-test",

  // Workersの動き方の基準日
  "compatibility_date": "2026-10-01",

  // 静的なファイル(HTML・画像など)の置き場所。この中身がそのままサイトに並ぶ
  "assets": {
    "directory": "./public"
  },

  // どのURLで出すか。custom_domain: true でDNSレコードと証明書も作ってくれる
  "routes": [
    { "pattern": "test.tobaru.net", "custom_domain": true }
  ],

  // xxx.workers.dev というCloudflareのURLでは公開しない
  "workers_dev": false
}

.github/workflows/deploy.ymlです。

name: Deploy

# いつ動くか(イベントの条件)
on:
  push:
    branches: [main]     # mainブランチにpushされたとき
  workflow_dispatch:     # Actionsタブの「Run workflow」ボタンで手動でも動かせる

jobs:
  deploy:
    runs-on: ubuntu-latest   # GitHubが数十秒だけ貸してくれるLinux
    permissions:
      contents: read
    steps:
      # 1. このcommitのファイル一式をランナーに取り出す
      - uses: actions/checkout@v5

      # 2. wranglerをインストールして動かす(commandを書かなければ wrangler deploy)
      - name: Deploy to Cloudflare Workers
        uses: cloudflare/wrangler-action@v4
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}    # 金庫の合鍵
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}  # どのアカウントに送るか
          wranglerVersion: "4"

(5) pushする

git init -b main
git add -A
git commit -m "最初のページとデプロイ設定"
git remote add origin https://github.com/<ユーザー名>/tobaru-net-test.git
git push -u origin main

pushしてから約30秒で、https://test.tobaru.netが開けるようになりました。10秒おきに確かめると、最初の3回はつながらず、4回目で200が返ってきました。

5. なぜ最後まで自動で流れるのか

答えを先に書くと、何かがずっと監視しているわけではありません。「イベントが起きたら、こう動く」という小さな決まりが、前の結果を受け取ってつながっているだけです。

pushしてから公開されるまでを、5つの段階に分けました。

05_sequence.png

画像をクリックすると、大きく表示されます。

ここからは、私が分からなかったところを順に説明します。

(1) GitHubはフォルダを監視しているの?

監視はしていません。pushやプルリクエストなどのイベントが起きたときにだけ、GitHubがそのcommitの.github/workflows/を開きます。中のYAMLを全部読んで、on:の条件に合うものだけを動かします。

それが分かる例です。

こんなとき デプロイは動く?
README.mdだけ変えてpush 動く。deploy.ymlは変わっていないが、「mainへのpush」というイベントが起きたから
deploy.ymlを書き換えたが、pushしていない 動かない。GitHubは自分のPCの中を見ていない
deploy.ymlを書き換えてpush 書き換えた後の内容で動く。そのcommitのファイルを読むから
別のブランチにpush 動かない。on:がbranches: [main]だから
プルリクエストをmainにマージ 動く。マージするとmainにcommitが入り、mainへのpushと同じになるから

「受付の人がマニュアルをずっと見張っている」のではありません。「呼び鈴が鳴ったらマニュアル棚を開いて、今回の用件に当てはまるページを探す」イメージです。マニュアル棚が.github/workflows/、ページの見出しがon:です。

(2) ファイルを指定していないのに、なぜwrangler.jsoncが使われるの?

deploy.ymlのデプロイの手順には、「どのファイルを送るか」を書いていません。それでも動くのは、書かなかったときの決まり(既定値)が2段階あるからです。

  1. wrangler-actionの決まり: commandを書かなければdeployを実行する(action.ymlに「Defaults to "deploy"」とあります)。workingDirectoryも書かなければ、リポジトリのいちばん上で実行する
  2. wranglerの決まり: wrangler deployは、実行したフォルダでwrangler.jsonc / wrangler.json / wrangler.tomlを探して読む

しかも、wrangler.jsoncそのものは送られません。「何を・どこに・どんな名前で」の指示として読まれ、送られるのはassets.directoryに書いたpublic/の中身です。

決まった名前・決まった場所に置けば何も書かなくても動き、変えたいときだけ書く。この考え方を「設定より規約(Convention over Configuration)」と呼ぶそうです。(1)の.github/workflows/も同じです。

(3) Cloudflareで何も作っていないのに、なぜWorkerができるの?

wrangler.jsoncの"name": "tobaru-net-test"で、「この名前のWorkerを、この中身にして」と頼んでいるからです。Cloudflareは、その名前のWorkerがなければ新しく作り、あれば中身を置き換えます。上の図のaltのところです。

どのアカウントに作るかはaccountId、入っていいかはapiTokenで伝えています。どちらもSecretsから渡しているので、deploy.ymlには値そのものを書いていません。

(4) Secretsは何のため?

Secretsは合鍵を入れておく金庫です。deploy.ymlには${{ secrets.CLOUDFLARE_API_TOKEN }}と、「金庫のこの引き出しを使って」とだけ書きます。合鍵そのものはどのファイルにも書かないので、コードを人に見せても漏れません。

(5) 1行でDNSと証明書までできるの?

できました。routesに"custom_domain": trueと書くと、「このホスト名をまるごとこのWorkerにする」意味になり、CloudflareがDNSのレコードとhttpsの証明書を作ってくれます。

ただし、次の2つがそろっているからできることです。

  • tobaru.netのDNSが、同じCloudflareアカウントにある(Cloudflareが自分でレコードを書き込める)
  • APIトークンにtobaru.netを触る権限がある(4章の(2)でゾーンを絞って許可した)

DNSが別の会社にあるドメインでは、この1行だけでは済みません。

custom_domainを付けずに"pattern": "test.tobaru.net/api/*"のように書くと、「このURLに来たアクセスだけWorkerが受け取る」という別の使い方になります。この場合、DNSのレコードは自分で作ります。

6. 警告が出たところ

最初は、他の記事と同じくcloudflare/wrangler-action@v3を使っていました。デプロイは成功しましたが、Actionsの結果のAnnotationsに、警告1件とお知らせ1件が出ました。

01_annotations.png

(1) Node.js 20 is deprecated(警告)

Node.js 20 is deprecated. The following actions target Node.js 20 but are being forced to run on Node.js 24: cloudflare/wrangler-action@v3.

wrangler-action@v3はNode.js 20向けに作られていて、GitHub側がNode.js 20を廃止していく途中なので、Node.js 24で動かしているという知らせです(GitHubのお知らせ)。今は動いていますが、将来動かなくなるおそれがあります。

調べるとv4が出ていて、action.ymlにusing: "node24"とありました。入力の項目(apiToken・accountIdなど)は同じなので、@v3を@v4に変えるだけで警告が消えました。

この修正もdeploy.ymlを1文字直してpushしただけです。しくみそのものの設定を変えた場合も、ページを変えた場合と同じ流れで反映されます(5章の(1)の表の3行目)。

(2) ubuntu-latestがUbuntu 26に移る(お知らせ)

The ubuntu-latest label will migrate to Ubuntu 26 beginning October 19, 2026.

runs-on: ubuntu-latestの中身が、順に新しいUbuntuに切り替わるという案内です(runner-imagesのIssue)。今回のワークフローはwranglerを動かすだけなので、そのままにしています。

(3) nameを変えるときの注意

つまずいたわけではありませんが、しくみから考えると注意が必要だと分かったところです。

nameを変えてpushすると、Cloudflareは名前が変わったとは受け取りません。「その名前のWorkerがないので新しく作る」と受け取ります(5章の(3))。古いWorkerは残ったままになるので、変えるときは古いほうの片付けも必要です。

7. Cloudflareの画面で確かめる

Cloudflareの画面では何も作っていませんが、pushしたあとに開くと、次の2つができていました。

(1) Workersの一覧

「Workers & Pages」を開くと、wrangler.jsoncのnameで付けたtobaru-net-testがあり、routesで頼んだtest.tobaru.netがつながっていました。

02_workers.png

「デプロイメントを表示」を開くと、pushした回数ぶんの履歴が並んでいます。GitHubのcommitと1回ずつ対応しています。

(2) DNSのレコード

tobaru.netのDNSのページには、自動で作られたtestのレコードがありました。自分では1つも作っていないのに、本当にレコードが出ていてびっくりしました。

03_dns.png

見えているもの 意味
左端の鍵のアイコン 自動で作られたレコードなので、ここからは編集できない
タイプ「Worker」 AやCNAMEではなく、「このWorkerに届けて」という特別なレコード
コンテンツ「tobaru-net-test」 wrangler.jsoncのname。名札でつながっている
「プロキシ済み」 アクセスはいったんCloudflareが受け取る

外のDNS(1.1.1.1)にtest.tobaru.netを聞いてみると、返ってくるのはCloudflareのIPアドレス(104.21.x.xなど)でした。「プロキシ済み」なので、サーバーの場所ではなくCloudflareのアドレスが返ります。応答のヘッダーにはServer: cloudflareとCF-RAY: …-NRTがあり、東京の拠点から返っていることも分かりました。

8. まとめ

最初は、なぜ自動で最後まで流れるのかが、いまいち理解できませんでした。でも、監視という大掛かりな仕組みではありませんでした。イベントが起きたときの動きが決まっていて、その決まりどおりに動くと、流れるように最後までつながる。それが分かったとき、美しいなーと思いました。DNSの画面に、自分では作っていないレコードが出ていたときも感動しました。

今回分かったことを並べると、次の3つです。

  • GitHubは監視していない。イベントが起きたときに.github/workflows/を読み、on:に合うものだけを動かす
  • 書いていないことは既定値で動く。wrangler-actionはdeployを実行し、wranglerは決まった名前のwrangler.jsoncを探す
  • CloudflareはnameでWorkerを見分け、なければ作り、あれば置き換える。custom_domain: trueならDNSと証明書も作る

次は、プルリクエストを作ったらチェックだけを動かし、mainにマージしたらデプロイする形(CIとCDの分離)を試す予定です。チェックも、pull_requestというイベントに決まりを足すだけで作れるはずです。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?