【ITニュース解説】A Simple CI/CD Pipeline That Actually Works
2026年08月25日に「Dev.to」が公開したITニュース「A Simple CI/CD Pipeline That Actually Works」について初心者にもわかりやすく解説しています。
ITニュース概要
CI/CDパイプラインの構築を初心者向けに解説。テスト、ビルド、デプロイの3段階をGitHub Actionsで実現する具体的な手順を示す。機密情報の管理、ロールバック、依存関係の解決といった実践的な課題にも触れ、シンプルで実際に機能するパイプラインの作り方を学ぶことができる。
ITニュース解説
システム開発では、アプリケーションのテスト、ビルド、デプロイといった一連の作業が頻繁に発生する。これらを開発者が手動で行うと、時間がかかり、人的ミスも発生しやすくなる。この課題を解決するのがCI/CDパイプラインという自動化の仕組みである。CI/CDとは、継続的インテグレーション(Continuous Integration)と継続的デリバリー(Continuous Delivery)の略で、コードの変更が自動的にテストされ、問題がなければ本番環境に近い場所へ自動でデプロイされる一連の流れを指す。多くの入門記事では簡単な例で説明されることが多いが、実際の開発現場ではシークレット情報の管理、問題発生時のロールバック、依存関係の変更によるパイプラインの破損など、より現実的で複雑な課題に直面する。この解説では、そのような現実的な課題に対応しつつ、理解しやすく、デバッグしやすく、そして拡張しやすいミニマルなCI/CDパイプラインの構築方法について具体的に解説する。
このパイプラインの核となるのは、三つの明確なステージである。一つ目は「テスト」ステージで、コードに誤りがないか自動化されたチェックを実行する。二つ目は「ビルド」ステージで、テストを通過したコードから実行可能なアプリケーションの成果物を作成する。三つ目は「デプロイ」ステージで、作成された成果物をサーバーに配置する。これらのステージを自動化するために、今回はGitHub Actionsというツールを利用する。GitHub Actionsは、GitHubのリポジトリに統合されたCI/CDサービスであり、パブリックリポジトリであれば無料で利用でき、さまざまなツールとの連携も容易である。GitLab CIやCircleCI、Jenkinsといった他のCI/CDツールでも、基本的な概念は共通しているため、ここで得られる知識は汎用的に活用できる。
具体的なパイプラインは、GitHubリポジトリ内の.github/workflows/deploy.ymlというファイルで定義される。このファイルはYAML形式で書かれ、パイプラインの名前をCI/CDと設定し、パイプラインが起動するトリガーを定義している。具体的には、mainブランチへのコードのプッシュ時と、mainブランチへのプルリクエスト作成・更新時にパイプラインが起動するよう設定されている。
次に、このパイプラインで実行されるジョブ(タスクのまとまり)が定義される。
最初のジョブはtestジョブである。このジョブはubuntu-latestという最新のUbuntu環境で実行される。実行されるステップは以下の通りだ。
まず、uses: actions/checkout@v4によって、GitHubリポジトリのコードがワークフロー実行環境にチェックアウト(取得)される。これはGitHub Actionsのほとんどのワークフローで最初に実行される基本的なステップである。
次に、uses: actions/setup-node@v4によって、Node.jsアプリケーションの場合、指定されたバージョンのNode.js環境がセットアップされる。ここではバージョン20が指定されている。
その後、run: npm ciというコマンドが実行され、プロジェクトの依存関係がインストールされる。npm ciコマンドは、package-lock.jsonファイルに記載された正確なバージョンで依存関係をインストールするため、環境による差異を防ぎ、「私の環境では動くのに、他の環境では動かない」という問題を解消するのに役立つ。
最後に、run: npm testというコマンドが実行され、定義されたテストスイートが実行される。このテストが失敗した場合、その後のジョブは実行されないようになっている。
二つ目のジョブはbuild-and-deployジョブである。このジョブはtestジョブの完了に依存しており(needs: test)、testジョブが成功した場合のみ実行される。また、実行条件としてif: github.ref == 'refs/heads/main' && github.event_name == 'push'が設定されている。これは「mainブランチへのプッシュイベントが発生した場合のみこのジョブを実行する」という意味である。つまり、プルリクエストの時点ではテストジョブのみが実行され、mainブランチにコードがマージされて初めてアプリケーションのビルドとデプロイが行われる仕組みだ。
このジョブもubuntu-latest環境で実行され、以下のステップが実行される。
ここでもuses: actions/checkout@v4によってリポジトリのコードがチェックアウトされる。
次にrun: npm ciで再度依存関係がインストールされる。
その後、run: npm run buildが実行され、アプリケーションがビルドされる。Node.jsアプリケーションの場合、Viteやwebpackのようなバンドラーを使ってソースコードを実行可能な形式に変換し、通常dist(distributionの略)フォルダに出力する。Pythonアプリケーションであればpython -m buildのようなコマンドに置き換わる。
そして、name: Deploy to serverという名前のステップで、実際にサーバーへのデプロイが行われる。
デプロイにはuses: appleboy/scp-action@v0.1.7というGitHub Actionを利用する。これはSCP(Secure Copy Protocol)を使ってビルドされたファイルをサーバーにコピーする。SCPはSSH(Secure Shell)を利用して安全にファイルを転送するプロトコルである。
このアクションでは、hostにデプロイ先のサーバーのIPアドレスまたはドメイン名、usernameにサーバーへの接続に使用するSSHユーザー名、keyにサーバーへのSSH接続に使う秘密鍵を指定する。これらの情報は直接ファイルに書き込まず、secrets.SERVER_HOSTのようにGitHub Actionsのシークレットとして登録された値を使用する。これにより、機密情報を安全に管理できる。
source: "dist/*"は、コピー元のファイルを指定し、ここではビルドによって生成されたdistフォルダ内のすべてのファイルを指定している。
target: "/var/www/myapp"は、コピー先のサーバー上のパスを指定し、このパスにビルドされたアプリケーションが配置される。
このように、パスワードや秘密鍵といったシークレット情報は、GitHub Actionsの「Settings > Secrets and Variables > Actions」から設定することが非常に重要である。SERVER_HOSTにはサーバーのIPアドレスやドメイン、SERVER_USERにはSSH接続用のユーザー名(例えばdeployやubuntuなど)、SSH_PRIVATE_KEYにはデプロイ専用ユーザーの秘密鍵を登録する。サーバー上には、セキュリティのために、rootユーザーではなく、限定された権限を持つ専用のデプロイユーザーを作成することが強く推奨される。
デプロイは通常、既存のファイルを上書きする形で行われるため、万が一デプロイによってアプリケーションに問題が発生した場合に備え、迅速なロールバック(以前の安定したバージョンに戻すこと)の仕組みが必要となる。このパイプラインでは、デプロイ前にサーバー上で現在のアプリケーションディレクトリをバックアップとして圧縮・保存する方法を推奨している。例えば、サーバー上でtar -czf /var/www/backups/$(date +%Y%m%d%H%M%S).tar.gz /var/www/myappというコマンドを実行することで、タイムスタンプ付きのバックアップファイルを作成できる。もし問題が発生した場合は、このバックアップファイルを展開するだけで、以前のバージョンに簡単に戻すことが可能だ。この作業は手動でも可能だが、スクリプトで自動化することも検討できる。
依存関係の厳密な管理も重要なポイントである。npm ciコマンドがpackage-lock.jsonを尊重するように、Pythonプロジェクトであればpip install -r requirements.txtでバージョンを固定し、開発環境と本番環境での差異をなくすことが重要だ。これにより、「私のPCでは動くのに、サーバーでは動かない」という問題を未然に防ぐことができる。
実際にパイプラインを使い始める前に、その動作を確認することが望ましい。ローカル環境でnpm testとnpm run buildを実行し、両方が成功することを確認してからmainブランチにコードをプッシュする。プッシュ後は、GitHubリポジトリの「Actions」タブでパイプラインの実行状況を確認できる。ここで、各ジョブやステップが問題なく実行されているか、ログを詳細に確認することが可能だ。
構築中に直面しやすい問題点もいくつかある。
一つ目はSSHキーのパーミッション問題だ。GitHub Actionsに提供する秘密鍵はOpenSSH形式である必要がある。例えば、ssh-keygen -t ed25519で生成された鍵は適切に動作する。PuTTY形式の鍵は変換が必要な場合がある。
二つ目はパスの問題だ。source: "dist/*"という設定は、ビルド成果物がdistフォルダに出力されることを前提としている。もしビルドが別のフォルダに出力される場合は、このパスをプロジェクトに合わせて調整する必要がある。
三つ目はサーバー側のパスのパーミッション問題だ。デプロイに使用するユーザーが、デプロイ先である/var/www/myappフォルダへの書き込み権限を持っている必要がある。これは、サーバー上でsudo chown -R deploy:deploy /var/www/myappのようなコマンドを一度実行して設定する。ここでdeploy:deployはユーザー名とグループ名を指す。
このシンプルなパイプラインが問題なく動作するようになれば、必要に応じて機能を拡張することもできる。例えば、テストの前にコードのスタイルや品質をチェックする「Lint」ジョブを追加したり、デプロイ後にデータベースのマイグレーション(データベースの構造変更)を実行するジョブを追加したり、パイプラインの失敗時にSlackなどに通知を送る仕組みを導入したりすることが可能だ。しかし、最初から多くの機能を追加するのではなく、まずは核となるシンプルさを保つことが重要である。複雑なシステムは構築もデバッグも難しくなるため、問題が発生した際にも、シンプルな構造であれば全体を素早く把握し、原因を特定しやすいという利点がある。
このパイプラインは、Kubernetesのような高度なコンテナオーケストレーションや、ブルーグリーンデプロイメントのような複雑なデプロイ戦略には対応していない。しかし、ほとんどのサイドプロジェクト、中小規模のビジネスアプリケーション、さらには一部の本番システムにとって、これだけで十分な機能を提供する。まずはシンプルに始め、動作することを確認し、その後で必要に応じて改善を加えていくというアプローチが、実際に機能するシステムを構築する上での最も効果的な方法だと言える。