はじめに
「学生ひよこ界隈が送るGo/Javaで実現する「はじめてのバックエンド」Advent Calendar 2025」19日目の記事は、前回のコードにCI/CDパイプラインを構築します。
デプロイできたはいいけど、コードをちょっと修正するたびに、手動でテストして、手動でデプロイして...というのは、正直ちょっと面倒ですよね。
それに、人間がやるとミスも起こりがちです。
この記事では、前回の記事でのAPIにテストコードを追加して、GitHub Actionsと連携させることで、コードの変更からテスト、そしてデプロイまでを完全に自動化するCI/CDパイプラインの構築方法を解説します。
- RenderにGoアプリケーションをデプロイした経験がある方
- GitHub ActionsでCI/CDパイプラインを構築してみたい方
- テストからデプロイまでの完全自動化に挑戦したい方
この記事で、手軽に本格的なCI/CDパイプラインを完成させて、CI/CDへの難しさのハードルを下げていきましょう!
【実践】CI/CDパイプライン構築
今回構築するパイプラインの全体像は以下の通りです。
- 開発者が新機能(新しいAPIパス)を追加し、プルリクエストを作成します。
- GitHub Actionsが自動でテストを実行します (CI)。
- プルリクエストがレビューされ、
mainブランチにマージされます。 - マージをトリガーに、GitHub ActionsがRenderのDeploy Hookという特別なURLを叩きます。
- その信号を受け取ったRenderが、リポジトリの最新コードを取得し、自動でビルド&デプロイを開始します (CD)。
それでは早速実装していきます。
STEP1: APIにテストコードを追加する
まず、前回の記事で作成したAPIにテストコードを追加します。HTTPハンドラをテストするために、Goの標準ライブラリであるnet/http/httptestを使用します。
main.go (確認用)
package main
import (
"fmt"
"log"
"net/http"
"os"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) // ステータスコードを明示的に設定
fmt.Fprint(w, "Hello from Render!")
}
func main() {
http.HandleFunc("/", helloHandler)
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
log.Printf("Server starting on port %s", port)
if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatal(err)
}
}
main_test.go (新規作成)
package main
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestHelloHandler(t *testing.T) {
// 1. テスト用のリクエストを作成
req, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Fatal(err)
}
// 2. レスポンスを記録するためのRecorderを作成
rr := httptest.NewRecorder()
handler := http.HandlerFunc(helloHandler)
// 3. ハンドラーを直接呼び出し、リクエストとレコーダーを渡す
handler.ServeHTTP(rr, req)
// 4. レスポンスのステータスコードを検証
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusOK)
}
// 5. レスポンスのボディを検証
expected := "Hello from Render!"
if rr.Body.String() != expected {
t.Errorf("handler returned unexpected body: got %v want %v",
rr.Body.String(), expected)
}
}
このmain_test.goを追加し、リポジトリにプッシュしておきましょう。
STEP2: RenderでDeploy Hook URLを取得する
次に、GitHub ActionsからRenderのデプロイを開始させるための「合言葉」となるURLを取得します。
- Renderのダッシュボードにログインし、対象のWeb Serviceを選択します。
- サイドメニューから「Settings」ページに移動します。
- ページをスクロールし、「Deploy Hook」というセクションを見つけ、URLをコピーします。
STEP3: GitHubリポジトリにSecretを設定する
コピーしたDeploy HookのURLは、公開すべきではない重要な情報なので、GitHubのSecrets機能を使って安全に管理しましょう。
- GitHubリポジトリの「Settings」タブ > 「Secrets and variables」 > 「Actions」を選択します。
- 「New repository secret」ボタンをクリックします。
-
NameにRENDER_DEPLOY_HOOK_URLと入力し、Secretに先ほどコピーしたURLを貼り付け、「Add secret」ボタンを押します。
STEP4: GitHub ActionsでCI/CDパイプラインを構築する
いよいよ、CIとCDを繋ぐパイプラインを構築します。.github/workflows/ディレクトリにdeploy.ymlなどの名前でファイルを作成し、以下の内容を記述します。
.github/workflows/deploy.yml
name: Go CI/CD
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
# CI: テストを実行するジョブ
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: Run tests
run: go test -v ./...
# CD: Renderへのデプロイをトリガーするジョブ
deploy:
# このジョブは、mainブランチへのpushイベントの時だけ実行する
if: github.event_name == 'pull_request'
# 'test' ジョブが成功した後に実行する
needs: test
runs-on: ubuntu-latest
steps:
- name: Trigger Render Deploy
run: curl -X POST ${{ secrets.RENDER_DEPLOY_HOOK_URL }}
パイプラインのポイントは以下です。
-
testジョブ: プルリクエストやプッシュのたびに、go testコマンドを実行してコードの品質をチェックします (CI)。 -
deployジョブ:-
if: ...:mainブランチにマージ(プッシュ)された時だけ実行されるように条件を設定しています。 -
needs: test:testジョブが成功しない限り、デプロイは開始されません。 -
run: curl ...: GitHubのSecretに保存したURLを叩いて、Renderにデプロイを命令しています (CD)。
-
STEP5: 動作検証
すべての準備が整ったので実際にパイプラインが動く様子を体験してみましょう。
-
開発ブランチで変更:
ローカルで新しい開発ブランチを作成し、main.goのレスポンスを少し変更します。
fmt.Fprint(w, "Hello from CI/CD!") -
プルリクエストの作成:
変更をプッシュし、mainブランチへのプルリクエストを作成します。 -
CIの確認:
プルリクエストを作成すると、GitHub Actionsがトリガーされ、testジョブが自動実行されます。テストがパスすることを待ちましょう。 -
マージとCDの確認:
プルリクエストをマージします。この瞬間、CI/CDパイプラインが本領を発揮します。-
GitHub Actions: 「Actions」タブを見ると、マージをトリガーに
testジョブとdeployジョブが順に実行されるのが確認できます。 - Render: 「Events」タブを見ると、GitHub ActionsからのDeploy Hookによって新しいデプロイが開始されているのがわかります。
-
GitHub Actions: 「Actions」タブを見ると、マージをトリガーに
-
デプロイ完了の確認:
Renderのデプロイが完了したら、サービスのURLにアクセスしてみましょう。ブラウザにHello from CI/CD!と表示されれば、CI/CDパイプラインの構築は成功です!
RenderのイベントページでCDを回した時刻にデプロイが成功していたら完成です!
おわりに
この記事では、簡単なCI/CDの構築を行いながら、CI/CDについての基礎を学びました。
インフラの細かいことを気にせず、ひたすらコードで新しい価値を生み出すことに集中できるのが、CI/CDを実装する最大の醍醐味なので、さらに学んでいきたいと感じました。
最後までお読みいただき、ありがとうございました!
この「学生ひよこ界隈が送るGo/Javaで実現する「はじめてのバックエンド」Advent Calendar 2025」では、GoやJavaを使い、APIの作り方、データベースとの接続、テストやDockerといった気になったバックエンド技術の基本を振り返った学びを共有しています。
ぜひ他の記事もチェックして、筆者がこのひとりアドカレを完遂することができるか、確認してみてください(^^)
学生ひよこ界隈が送るGo/Javaで実現する「はじめてのバックエンド」Advent Calendar 2025
それでは、明日の「学生ひよこ界隈が送るGo/Javaで実現する「はじめてのバックエンド」Advent Calendar 2025」の記事もお楽しみに!