なぜ中小企業にも CI/CD が必要なのか
「CI/CD は大規模な開発チームが使うもの」と思っていませんか。実際には、少人数の開発チームこそ CI/CD の恩恵を受けやすいのです。なぜなら、限られた人数で開発・テスト・デプロイを行わなければならず、手作業による負担が大きいからです。
実際に、私が支援したシステム開発会社のA社(開発者3名)では、デプロイ作業に毎回2時間かかっており、しかもミスが頻発していました。CI/CD を導入した結果、デプロイ時間は10分に短縮され、ミスもゼロになりました。インフラ設計の基本方針については、少人数チームのインフラ設計も合わせてご覧ください。
Stack Overflow の調査によれば、CI/CD を導入している開発チームは、導入していないチームと比較して、以下のような違いがあります。
- デプロイ頻度が10倍以上
- デプロイ失敗率が5分の1以下
- 障害からの復旧時間が3分の1以下
- 開発者の生産性が約30%向上
本記事では、中小企業の開発チームが CI/CD を導入するための具体的な手順を、実例を交えながら解説します。難しい専門用語は避け、実務者の視点で分かりやすく説明していきます。
中小企業の開発チームが抱える課題
1. 手作業によるデプロイの負担とミス
多くの中小企業では、本番環境へのデプロイ(リリース)を手作業で行っています。典型的な手作業デプロイの流れは以下のようなものです。
- ローカル環境でコードを最新化
- FTPソフトでファイルをアップロード
- SSHでサーバーにログイン
- データベースのマイグレーション実行
- サービスの再起動
- 動作確認
この作業には30分〜2時間かかり、しかも手順を間違えるとサービスが停止してしまいます。
実際に、EC サイト運営会社のB社(開発者2名)では、デプロイ時にファイルのアップロード漏れが発生し、サイトが30分間エラー画面になってしまいました。この間に約20万円の売上損失が発生しました。
2. テストを後回しにしてしまう
開発スケジュールが逼迫すると、テストを十分に行わずにリリースしてしまうケースが多く見られます。「後でテストしよう」と思っても、次の開発タスクに追われて結局テストが疎かになります。
Webアプリ開発会社のC社(開発者4名)では、テストを手作業で行っていたため、毎回1-2時間かかっていました。そのため、「小さな変更だからテスト不要だろう」と判断してしまい、本番環境で不具合が発生することが度々ありました。
3. 本番環境と開発環境の差異
開発環境では動いていたのに、本番環境では動かないという問題も頻繁に発生します。これは、開発環境と本番環境で以下のような差異があるためです。
- ライブラリのバージョンが異なる
- 環境変数の設定が異なる
- データベースの状態が異なる
- OSやミドルウェアの設定が異なる
このような差異により、「開発環境では問題なかったのに、本番で動かない」という事態が発生します。
4. リリース頻度が低い
手作業でのデプロイは時間がかかり、しかもリスクが高いため、「まとめて一気にリリースしよう」となりがちです。その結果、リリース頻度が週1回、あるいは月1回といった低頻度になってしまいます。
リリース頻度が低いと、以下のような問題が生じます。
- 顧客へのフィードバックが遅れる
- 不具合の原因特定が難しくなる(大量の変更の中から原因を探す必要がある)
- 開発者のモチベーション低下(自分のコードがすぐに本番で動かない)
5. 属人化による継続性の問題
「デプロイは〇〇さんにしかできない」という状態になっているケースも多く見られます。この状態では、その人が休暇中や退職した場合に、デプロイができなくなってしまいます。
実際に、SaaS 開発会社のD社(開発者5名)では、デプロイを1人の開発者だけが担当していたため、その人が長期休暇を取ると、2週間デプロイができないという状況に陥りました。
CI/CD とは何か: 基本概念の理解
CI(Continuous Integration: 継続的インテグレーション)
CI は、開発者がコードを変更するたびに、自動的にビルドとテストを実行する仕組みです。
CI の流れ:
- 開発者がコードを変更し、Git にプッシュ
- CI ツールが自動的に変更を検知
- コードをビルド(コンパイル、依存関係の解決など)
- 自動テストを実行
- 結果を開発者に通知(成功/失敗)
CI により、コードの問題を早期に発見できます。変更直後にテストが実行されるため、何が原因で問題が起きたかすぐに分かります。
CD(Continuous Delivery/Deployment: 継続的デリバリー/デプロイメント)
CD には2つの意味があります。
Continuous Delivery(継続的デリバリー):
- ビルドとテストが成功したら、いつでもデプロイできる状態にする
- 実際のデプロイは手動で承認ボタンを押す
Continuous Deployment(継続的デプロイメント):
- ビルドとテストが成功したら、自動的に本番環境にデプロイする
- 人の承認なしで完全自動
中小企業の場合、まずは Continuous Delivery から始め、慣れてきたら Continuous Deployment に移行するのがおすすめです。
CI/CD のメリット
開発者のメリット:
- デプロイ作業から解放され、開発に集中できる
- テストを自動化でき、品質が向上する
- 変更が即座に本番環境に反映され、フィードバックが早い
企業のメリット:
- リリース頻度が上がり、競争力が向上する
- デプロイミスが減り、サービス停止のリスクが低下する
- 開発者の生産性が向上し、人件費効果が高まる
顧客のメリット:
- 新機能がすぐに利用できる
- バグ修正が素早く提供される
- サービスの品質が向上する
GitHub Actions を使った CI/CD 入門
なぜ GitHub Actions か
CI/CD ツールには、Jenkins、CircleCI、Travis CI、GitLab CI など様々な選択肢がありますが、中小企業には GitHub Actions をおすすめします。理由は以下の通りです。
- 無料枠が充実: 月間2,000分まで無料(中小企業には十分)
- 設定が簡単: YAML ファイルを1つ書くだけで始められる
- GitHub と統合: すでに GitHub を使っていれば、追加設定不要
- 豊富なテンプレート: 多くの言語・フレームワークのテンプレートが用意されている
GitHub Actions の基本構造
GitHub Actions は、.github/workflows/ ディレクトリに YAML ファイルを配置することで動作します。
基本的な構成要素:
- Workflow: 自動化の一連の流れ
- Job: Workflow 内の作業単位(複数のJobを並列実行可能)
- Step: Job 内の個別の処理(コードのチェックアウト、テスト実行など)
- Action: 再利用可能な処理のまとまり(公開されているものを利用できる)
実践例: Node.js アプリの CI 設定
Web アプリ開発会社のE社(開発者3名)の実例を紹介します。
要件:
- Node.js + Express のアプリケーション
- プルリクエストが作成されたら自動テスト実行
- main ブランチにマージされたら自動デプロイ
Step 1: テストの自動化
まず、プルリクエスト時に自動テストを実行する設定を作成します。
.github/workflows/test.yml を作成:
name: Test
# プルリクエストが作成されたときに実行
on:
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
# リポジトリのコードをチェックアウト
- uses: actions/checkout@v3
# Node.js のセットアップ
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
# 依存関係のインストール
- name: Install dependencies
run: npm ci
# テストの実行
- name: Run tests
run: npm test
# カバレッジレポートの生成
- name: Generate coverage report
run: npm run coverage
この設定により、プルリクエストが作成されると自動的にテストが実行され、結果がGitHub上に表示されます。
Step 2: デプロイの自動化
次に、main ブランチにマージされたら自動デプロイする設定を追加します。
.github/workflows/deploy.yml を作成:
name: Deploy
# main ブランチにプッシュされたときに実行
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
# テストを再度実行(念のため)
- name: Run tests
run: npm test
# 本番環境にデプロイ
- name: Deploy to production
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
HOST: ${{ secrets.HOST }}
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" | tee ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H $HOST | tee -a ~/.ssh/known_hosts
rsync -avz --delete ./dist/ user@$HOST:/var/www/app/
ssh user@$HOST 'cd /var/www/app && pm2 restart app'
Step 3: 秘密情報の設定
デプロイに必要な秘密情報(SSH鍵、サーバーアドレスなど)は、GitHub の Secrets 機能で管理します。
GitHub リポジトリの Settings → Secrets → Actions で以下を登録:
SSH_PRIVATE_KEY: サーバーにSSH接続するための秘密鍵HOST: デプロイ先サーバーのアドレス
導入結果
Before(手作業):
- デプロイ作業時間: 1回あたり約1時間
- デプロイ頻度: 週1回
- デプロイミス: 月2-3回
After(CI/CD導入後):
- デプロイ作業時間: 1回あたり約5分(自動化)
- デプロイ頻度: 1日3-5回
- デプロイミス: ほぼゼロ(過去3ヶ月で0回)
定量的な効果:
- デプロイ作業時間の削減: 月間約16時間(週1時間 × 4週)
- 開発者の時給を4,000円とすると、月間約64,000円の工数削減
- デプロイミスによる損失回避: 月間約50万円(推定)
段階的な CI/CD 導入ステップ
Phase 1: テストの自動化(1-2週間)
まずは CI から始めます。デプロイの自動化は後回しにして、テストの自動化に集中します。
実施内容:
- 既存のテストコードを整理(テストがない場合は最低限のテストを作成)
- GitHub Actions で自動テストを実行する設定を追加
- プルリクエスト時に自動テストが実行されることを確認
成功基準:
- プルリクエストを作成すると、自動的にテストが実行される
- テストが失敗すると、GitHub 上に赤いバツマークが表示される
- 全ての開発者が、テスト結果を確認してからマージする習慣がつく
Phase 2: ステージング環境への自動デプロイ(2-4週間)
次に、本番環境ではなく、ステージング環境(テスト用の環境)への自動デプロイを実装します。
実施内容:
- ステージング環境を用意(本番環境と同じ構成)
- develop ブランチにマージされたら、ステージング環境に自動デプロイ
- ステージング環境で動作確認
- 問題なければ、main ブランチにマージ(この時点では本番デプロイは手動)
成功基準:
- develop ブランチへのマージで、自動的にステージング環境が更新される
- ステージング環境で動作確認を行い、問題を早期発見できる
- デプロイの自動化に慣れ、不安が解消される
Phase 3: 本番環境への自動デプロイ(2-4週間)
最後に、本番環境への自動デプロイを実装します。ただし、最初は「承認フロー」を入れることをおすすめします。
実施内容:
- main ブランチにマージされたら、本番環境に自動デプロイ
- 最初は「承認ボタン」を押さないとデプロイされない設定
- 慣れてきたら、承認フローを外して完全自動化
成功基準:
- main ブランチへのマージで、承認後に自動デプロイされる
- デプロイ失敗時の自動ロールバック機能が動作する
- 開発者全員が、安心して頻繁にデプロイできるようになる
Phase 4: 継続的改善(ongoing)
CI/CD は一度導入すれば終わりではなく、継続的に改善していきます。
改善項目の例:
- テストカバレッジの向上(コードの何%がテストされているか)
- テスト実行時間の短縮(並列実行、キャッシュ活用など)
- デプロイ戦略の高度化(ブルーグリーンデプロイ、カナリアリリースなど)
- 監視・アラートの強化(デプロイ後の自動監視、詳細は監視・アラート設計を参照)
テストの自動化: 何をテストするか
テストの種類と優先順位
全てのコードをテストするのは現実的ではありません。まずは重要度の高い部分から段階的にテストを追加します。
優先度が高いテスト:
- 単体テスト(Unit Test): 個々の関数やクラスの動作確認
- 統合テスト(Integration Test): 複数のモジュールが連携して動作するか確認
- E2Eテスト(End-to-End Test): ユーザーの操作フローが正常に動作するか確認
中小企業の場合、最初は「単体テスト」と「重要な統合テスト」に絞ることをおすすめします。
実践例: テストカバレッジの段階的向上
SaaS 開発会社のF社(開発者4名)では、以下のようにテストを段階的に追加しました。
Phase 1: クリティカルパスのテスト(最初の1ヶ月)
- ユーザー登録・ログイン機能
- 決済処理
- データの保存・取得
これらは、不具合があると重大な問題になる部分なので、最優先でテストを追加しました。
Phase 2: ビジネスロジックのテスト(2-3ヶ月目)
- 料金計算ロジック
- 権限チェック
- データバリデーション
これらは、不具合があるとユーザーに迷惑をかける可能性がある部分です。
Phase 3: その他の機能のテスト(継続的に)
- UIコンポーネント
- ユーティリティ関数
- エッジケース
重要度は低いが、時間があるときに追加していきます。
結果:
- テストカバレッジ: 0% → 6ヶ月後に 65%
- 本番環境での不具合発生率: 月4-5件 → 月1件以下に減少
- 不具合修正にかかる時間: 平均4時間 → 平均1時間に短縮
テストが失敗したときのルール
テストが失敗した場合、以下のルールを徹底します。
- 失敗したテストを無視しない: 「後で直そう」は禁止
- 失敗の原因を特定する: コードの問題か、テストの問題か
- すぐに修正する: 他の作業より優先
- テストを削除しない: テストが間違っていれば、テストを修正する
このルールにより、テストの品質と信頼性が保たれます。
デプロイ戦略の選択
ローリングデプロイ
最も基本的なデプロイ方法です。複数のサーバーがある場合、1台ずつ順番に新しいバージョンに更新していきます。
メリット:
- シンプルで理解しやすい
- ダウンタイムがほぼゼロ
- 追加コストがかからない
デメリット:
- デプロイ中は、新旧バージョンが混在する
- 問題があった場合、ロールバックに時間がかかる
適用ケース:
- サーバーが複数台ある場合
- 新旧バージョンの混在が問題ない場合
ブルーグリーンデプロイ
現在稼働中の環境(ブルー)とは別に、新しい環境(グリーン)を用意し、切り替える方法です。
メリット:
- 切り替えが一瞬(DNSの切り替えだけ)
- 問題があればすぐにロールバック可能
- デプロイ前に本番環境で動作確認できる
デメリット:
- 2倍のリソースが必要(コスト増)
- データベースの移行が複雑になる場合がある
適用ケース:
- ダウンタイムが許されない重要なサービス
- ロールバックの容易さが重要な場合
カナリアリリース
新バージョンを一部のユーザーだけに提供し、問題がなければ全体に展開する方法です。
メリット:
- 問題があっても影響範囲が限定的
- 本番環境で少しずつ検証できる
- A/Bテストにも応用できる
デメリット:
- 実装が複雑
- トラフィック振り分けの仕組みが必要
適用ケース:
- ユーザー数が多いサービス
- 大きな変更をリスクを抑えてリリースしたい場合
中小企業におすすめの戦略
開発チームが3-5名の中小企業には、以下の組み合わせをおすすめします。
- ステージング環境: ブルーグリーンデプロイ(Cloud の機能で低コスト実装)
- 本番環境: ローリングデプロイ(シンプルに運用)
最初はローリングデプロイから始め、ビジネスが成長してきたらブルーグリーンやカナリアを検討します。
失敗しやすいポイントと対策
1. 完璧を目指しすぎる
失敗例: 全てのコードにテストを書き、完璧な CI/CD 環境を構築しようとして、いつまでも導入が完了しない。
対策:
- まずは最小限の構成で始める
- 重要な部分から段階的にテストを追加する
- 「80点の CI/CD を今すぐ始める」ことを優先する
- 完璧な100点を目指すのは後回し
2. テストのメンテナンスを怠る
失敗例: 最初はテストを書いていたが、次第にメンテナンスされなくなり、テストが失敗しても無視されるようになった。
対策:
- テストが失敗したら、必ず原因を調査して修正する
- テストを削除するのではなく、修正する
- テストの実行時間が長くなったら、最適化する
- 定期的にテストコードをレビューする
3. 本番環境との差異を考慮していない
失敗例: CI 環境では正常に動作するが、本番環境では動かないという問題が頻発する。
対策:
- CI 環境と本番環境を可能な限り同じ構成にする
- Docker などのコンテナ技術を活用する
- 環境変数の管理を徹底する
- 本番環境と同じバージョンのライブラリを CI でも使う
4. デプロイ失敗時の対応が不明確
失敗例: デプロイが失敗したが、ロールバックの手順が分からず、サービスが長時間停止した。
対策:
- 自動ロールバックの仕組みを実装する
- ロールバックの手順を明文化する
- デプロイ失敗時の対応をチーム全員で共有する
- 定期的にロールバック訓練を実施する
5. セキュリティを軽視する
失敗例: GitHub に秘密鍵やAPIキーをハードコードしてコミットしてしまい、外部に漏洩した。
対策:
- 秘密情報は必ず Secrets 機能で管理する
.gitignoreで環境変数ファイルを除外する- 秘密情報検出ツール(git-secrets など)を導入する
- 定期的にセキュリティ監査を実施する
導入事例: SaaS開発会社G社の CI/CD 導入
企業概要
- 業種: SaaS開発会社
- 開発者数: 5名
- 開発環境: Node.js + React + PostgreSQL
- 課題: デプロイが手作業で時間がかかる。テストが手動で、品質が安定しない。リリース頻度が低く、顧客へのフィードバックが遅い。
Before(CI/CD導入前の状況)
デプロイ方法:
- 手作業でFTPアップロード
- デプロイ担当者が1名(属人化)
- デプロイ時間: 1回あたり約2時間
- デプロイ頻度: 週1回(金曜日の夜)
テスト方法:
- 手動テスト(開発者が手元で確認)
- テストにかかる時間: 1回あたり約1時間
- テストカバレッジ: 測定していない(おそらく10%未満)
課題:
- デプロイが面倒なので、変更をまとめてリリースする習慣がついてしまった
- 手動テストは時間がかかるため、小さな変更ではテストをスキップしてしまう
- 本番環境で不具合が発見されることが多い(月3-4件)
- デプロイミスによりサービスが停止したことが過去1年で2回
導入プロセス(3ヶ月)
Phase 1: テストの自動化(1ヶ月目)
まず、既存のコードにテストを追加しました。
実施内容:
- 重要な機能(認証、決済、データ操作)の単体テストを作成
- GitHub Actions でプルリクエスト時に自動テスト実行
- テストカバレッジ測定ツール(Jest + coverage)を導入
初期テストカバレッジ: 0% → 35%
Phase 2: ステージング環境への自動デプロイ(2ヶ月目)
次に、ステージング環境を構築し、自動デプロイを実装しました。
実施内容:
- AWSにステージング環境を構築(本番の半分のスペック)
- develop ブランチへのマージで自動デプロイ
- デプロイ後の自動スモークテスト(基本機能の動作確認)
効果:
- 開発者がステージング環境で動作確認する習慣が定着
- 本番デプロイ前に問題を発見できるようになった
Phase 3: 本番環境への自動デプロイ(3ヶ月目)
最後に、本番環境への自動デプロイを実装しました。
実施内容:
- main ブランチへのマージで本番環境に自動デプロイ
- 最初は承認フローを設定(責任者が承認ボタンを押す)
- デプロイ後の自動監視(エラー率、応答時間)
- 自動ロールバック機能(エラー率が閾値を超えたら自動で前バージョンに戻す)
1ヶ月の慣らし期間後:
- 承認フローを外し、完全自動化に移行
After(CI/CD導入後の成果)
定量的な成果:
| 指標 | Before | After | 改善率 |
|---|---|---|---|
| デプロイ時間 | 2時間 | 5分 | 96%削減 |
| デプロイ頻度 | 週1回 | 1日3-5回 | 15-35倍 |
| デプロイミス | 月2-3回 | 月0-1回 | 70%減少 |
| 本番不具合 | 月3-4件 | 月1件以下 | 75%減少 |
| テストカバレッジ | 10%未満 | 70% | 7倍 |
工数削減効果:
- デプロイ作業時間: 月間約40時間削減(週1回2時間 → 毎日5分×20日 ≒ 1.5時間)
- テスト作業時間: 月間約60時間削減(手動テストが不要に)
- 不具合対応時間: 月間約20時間削減(不具合が減少)
- 合計: 月間約120時間の削減
- 金額換算: 月間約48万円(時給4,000円として)
定性的な成果:
- 開発者のストレス軽減(デプロイが怖くなくなった)
- リリース頻度が上がり、顧客からのフィードバックが早くなった
- 小さな変更でもすぐにリリースできるため、開発スピードが向上
- 新しい開発者が入っても、すぐにデプロイできるようになった
開発者の声:
- 「金曜日の夜にデプロイするストレスから解放された」(リードエンジニア)
- 「テストが自動化されたので、安心してリファクタリングできる」(開発者A)
- 「バグが本番で見つかっても、すぐに修正版をデプロイできる」(開発者B)
- 「CI/CD導入前は、デプロイが面倒で新機能の開発が遅れていた」(CTO)
顧客の声:
- 「以前は月1回のリリースだったが、今は毎日のように改善されている」
- 「不具合の修正が早くなった」
- 「要望した機能がすぐに実装されるようになった」
投資対効果
初期費用: 約80万円
- 外部コンサルティング: 50万円
- ステージング環境構築: 20万円
- 社内工数(テスト作成、設定作業など): 10万円相当
年間ランニングコスト: 約36万円
- ステージング環境の維持費: 月3万円 × 12ヶ月
年間削減効果: 約576万円
- 工数削減: 月48万円 × 12ヶ月
投資回収期間: 約1.7ヶ月
3年間の累計効果: 約1,648万円(初期費用を差し引いても1,568万円の削減)
まとめ: CI/CD 導入の第一歩
CI/CD は、中小企業の開発チームにこそ必要な仕組みです。限られた人数で高品質なソフトウェアを継続的に提供するには、自動化が不可欠です。
今日から始められる3つのアクション
Step 1: 現状を把握する(1週間)
- 現在のデプロイ方法を文書化する
- デプロイにかかる時間を測定する
- テストの実施状況を確認する
- 過去のデプロイミスや不具合を洗い出す
Step 2: テストの自動化から始める(2週間)
- 重要な機能のテストを1つ作成する
- GitHub Actions で自動テストを実行する設定を追加する
- プルリクエスト時にテストが実行されることを確認する
Step 3: 段階的にデプロイを自動化する(1-2ヶ月)
- ステージング環境を用意する
- ステージング環境への自動デプロイを実装する
- 慣れてきたら本番環境への自動デプロイを検討する
最後に
CI/CD の導入は、一度に完璧を目指す必要はありません。まずは小さく始めて、徐々に改善していくアプローチがおすすめです。重要なのは、「今日から一歩を踏み出す」ことです。
もし専門的なアドバイスが必要な場合は、GitHub、CircleCI、GitLab などのベンダーが提供している無料相談サービスを利用するのも良いでしょう。また、外部のコンサルタントに依頼することで、短期間で導入を完了させることも可能です。
CI/CD を導入することで、開発チームの生産性が向上し、顧客により良いサービスを提供できるようになります。本記事が、あなたの会社の CI/CD 導入の第一歩となれば幸いです。