手動デプロイの恐怖から解放されたい。GitHub ActionsでCI/CDパイプラインを整えた話
「あ、テスト回し忘れてた……」
つい先日、リリース直前のタイミングでこんな冷や汗をかく思いをした。ローカル環境では問題なく動いていたし、ビルドも通ったはずだった。しかし、いざデプロイした後の画面を見ると、予期せぬランタイムエラーがログに並んでいる。結局、慌てて修正して再度デプロイという、最悪のループに陥ってしまった。
こうした「うっかり」は、プロジェクトが大きくなればなるほど致命的になる。個人開発であっても、自分の作業ミスをカバーしてくれる仕組みがないのは、精神衛生上あまり良くない。そこで、GitHub Actionsを使って、テストからビルド、デプロイまでを自動化するCI/CDパイプラインを構築することにした。
正直なところ、最初は「ワークフローの書き方がよくわからない」という悩みもあった。YAMLのインデント一つでエラーが出るし、環境変数の管理(Secrets)をどう設定すれば安全にデプロイできるのかも、調べて納得するまで時間がかかった。
まずは、一番シンプルかつ強力な構成を目指した。具体的には、`main`ブランチにPushされた際に、「Lintチェック」「ユニットテスト」「ビルド」を実行し、すべてパスしたら自動的にデプロイを行うという流れだ。
以下が、その際の実装例(`.github/workflows/ci-cd.yml`)である。
name: CI/CD Pipeline
on:
push:
branches: [ main ]
arg:
pull_request:
branches: [ main ]
jobs:
test-and-build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run Lint
run: npm run lint
- name: Run Tests
run: npm test
- name: Build project
run: npm run build
deploy:
needs: test-and-build
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Deploy to Server
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
run: |
echo "Deploying with token..."
# ここに実際のデプロイコマンド(AWS S3への同期や、SSH経由のコマンドなど)を記述する
この構成で導入して一番変わったのは、コードをPushした後の「安心感」だ。もしテストが失敗したり、ビルド時に型エラーが出たりすれば、GitHub上で即座に通知が来る。つまり、デプロイ前に「壊れたコード」を検知できるようになったわけだ。
特に`needs: test-and-build`という記述は重要で、これを入れることでテストやビルドが成功しない限り、後続のデプロイジョブが動かないように制御している。これがないと、たとえテストが落ちていてもデプロイが走ってしまうリスクがあるからだ。
また、デプロイに必要なAPIキーやSSH鍵などの機密情報は、GitHubのリポジトリ設定にある`Secrets`に逃がすようにした。ワークフローのファイル内に直接書くのは論外だし、環境変数として安全に注入する仕組みを整えることが、CI/CD構築におけるもう一つの大きな壁だったと感じている。
もちろん、最初は「ここまで作り込まなくてもいいかな」という誘惑もあった。しかし、一度この自動化の恩重に触れてしまうと、手動での作業に戻るのはかなり苦痛だ。ツールに任せられることはツールに任せて、エンジニアはもっと本質的なロジックの開発に集中すべきだと思う。
今後も、プロジェクトが複雑化していくにつれて、キャッシュ戦略の最適化や、コンテナイメージの作成といったステップを追加していく予定だ。少しずつ、より堅牢なパイプラインへと育てていきたい。