【ITニュース解説】Automating Deployment with Github Actions
2026年09月21日に「Dev.to」が公開したITニュース「Automating Deployment with Github Actions」について初心者にもわかりやすく解説しています。
ITニュース概要
GitHub Actionsで、インターネットから隔離されたAWSサーバーへ安全に自動デプロイする方法を解説。OIDCで一時認証情報を取得し、AWS SSM経由でサーバーにデプロイスクリプトを実行する。SSHキーや公開ポートなしで、コード変更からデプロイまでを効率的に自動化するCI/CDパイプラインを構築した。
ITニュース解説
ソフトウェア開発の現場では、コードの変更が頻繁に行われ、アプリケーションを最新の状態に保つ必要があります。しかし、以前のように手作業でサーバーにログインし、コードを更新してアプリケーションを再起動する手法では、時間がかかるだけでなく、ヒューマンエラーの原因にもなり、開発速度が低下するという問題がありました。そこで注目されるのが、CI/CDという概念です。
CI/CDとは、継続的インテグレーション(Continuous Integration)と継続的デリバリー(Continuous Delivery)または継続的デプロイメント(Continuous Deployment)を組み合わせた開発手法を指します。継続的インテグレーション(CI)は、開発者がコードを変更するたびに、その変更を自動的にテストし、共有のコードリポジトリに統合するプラクティスです。これにより、コードの不整合やバグを早期に発見できます。継続的デリバリー/デプロイメント(CD)は、CIで統合されたコードを自動的にテストし、配信するプロセスです。継続的デリバリーは自動デプロイの手前までを指し、継続的デプロイメントはコードの変更がリポジトリにプッシュされるたびに自動で本番環境にリリースするまでを指します。これにより、開発者はコードを書くことに集中でき、アプリケーションの品質とリリース速度が飛躍的に向上します。
今回のプロジェクトでは、CI/CDパイプラインを構築する上でいくつかの特別な課題がありました。まず、アプリケーションが動作するEC2インスタンス(Amazon Web Services上で稼働する仮想サーバー)が、インターネットから直接アクセスできない「プライベートサブネット」という安全なネットワーク領域に配置されていました。そのため、一般的なデプロイ方法であるSSH(セキュアシェル)を使って外部からサーバーに接続し、コードを操作することができませんでした。ポート22(SSHの標準ポート)も開いておらず、踏み台サーバーのような中間ゲートウェイも存在しない状況です。
二つ目の課題は、アプリケーションが単一のコンテナではなく、データベース(PostgreSQL)、バックエンド、フロントエンド、Webサーバー(Nginx)という四つのコンテナが複雑に依存し合うDocker Composeスタックとして動作している点でした。これらのコンテナは、特定の順序で起動し、かつ前のサービスが正常に動作していることを確認してから次のサービスが起動する必要があります。例えば、データベースが準備できていない状態でバックエンドが起動するとエラーになるため、単にコンテナを入れ替えるだけでなく、Docker Composeによる依存関係のオーケストレーション(調整・管理)が必要でした。
三つ目の課題は、セキュリティ上の問題でした。AWSのアクセスキーのような機密性の高い認証情報をGitHubの機密情報管理機能(GitHub Secrets)に保存したくありませんでした。アクセスキーは一度発行されると有効期限がなく、万が一漏洩した場合、悪意のある第三者によってAWSリソースが操作されるリスクが伴います。このプロジェクトでは、これらの問題を解決するために、「キーレス(認証情報を保存しない)」「到達可能(プライベートサブネットのサーバーに接続できる)」「構成可能(マルチコンテナスタックをオーケストレーションできる)」という三つの条件を満たす解決策が必要でした。
この課題への答えとして、IAM OIDC、Systems Manager(SSM)、そしてTerraformというAWSのサービスと、GitHub Actionsを組み合わせたパイプラインが構築されました。
まず、CIパイプラインでは、コードがサーバーにデプロイされる前に問題がないかを確認します。GitHubリポジトリのmainブランチへのプッシュやプルリクエストが行われるたびにこのワークフローが実行されます。主な処理は以下の三点です。一つ目はDocker Composeビルドの検証で、これは四つのコンテナイメージ全てを実際にビルドし、Dockerfileの記述ミスや依存関係の不備がないかを確認します。二つ目はフロントエンドのビルドで、npmコマンドを使ってTypeScriptのエラーや依存関係の問題がないかを検証します。三つ目はバックエンドのLinter実行で、Flake8というツールでコードの構文エラーや致命的な問題をチェックします。これにより、コードが壊れていないことを確認してから次のステップに進みます。
次に、デプロイに必要な認証の仕組みです。GitHub ActionsからAWSリソースにアクセスするために、通常であればAWSのアクセスキーを発行し、GitHub Secretsに保存する方法が考えられます。しかし、この方法ではキーの漏洩リスクが常に存在します。そこで採用されたのが、OIDC(OpenID Connect)という仕組みです。OIDCでは、アクセスキーを保存する代わりに、GitHubが発行する一時的なトークンをAWSに提示します。AWSは、このトークンが特定のGitHubリポジトリから発行されたものであることを確認し、そのリポジトリに対して一時的な認証情報(有効期限は一時間)を発行します。これにより、GitHubにアクセスキーを保存する必要がなくなり、たとえトークンが漏洩しても短時間で無効になるため、セキュリティが大幅に向上します。このOIDCの設定は、Infrastructure as CodeツールであるTerraformを用いて行われ、AWS上でOIDCプロバイダと、GitHub Actionsに付与されるIAMロール(権限の集合)がコードとして定義されます。
このIAMロールには、最小限の権限のみが付与されます。具体的には、特定のタグが付けられたEC2インスタンスに対してSSMコマンドを送信し、その実行結果を取得する権限のみです。リソースの作成や削除、機密情報の読み取り、IAM設定の変更といった危険な操作は一切許可されていません。これにより、万が一パイプラインが不正に利用されても、被害が限定されるように設計されています。
インターネットから到達できないプライベートサブネットのサーバーへのデプロイは、AWS Systems Manager(SSM)が解決します。EC2インスタンスにはSSM Agentというソフトウェアがインストールされており、これがAWSのSSMサービスと常に接続を維持しています。GitHub ActionsからAWS APIを通じてSSMにコマンドを送信すると、SSMサービスはそのコマンドをSSM Agent経由でサーバーに中継します。つまり、サーバー側からAWSサービスへの「アウトバウンド接続」が確立されているため、外部からサーバーへ「インバウンド接続」を試みる必要がないのです。これにより、SSHポートを開放したり、踏み台サーバーを構築したりすることなく、安全にサーバーを操作できます。
サーバー上で実際に実行されるデプロイスクリプトはシンプルです。まず、最新のコードをGitHubリポジトリから取得し(git reset --hard origin/mainコマンドでサーバー上のコードを完全にリポジトリと同期させます)、次にdocker compose buildでコンテナイメージを再構築し、docker compose up -dで依存関係を考慮しながらコンテナを起動します。さらに、docker image prune -fコマンドで不要になったDockerイメージを削除し、ディスク容量の枯渇を防ぎます。スクリプトはset -euo pipefailという設定により、途中で一つでもコマンドが失敗すると即座に終了し、デプロイの失敗をGitHub Actionsに通知します。
CDワークフローでは、OIDC認証で一時的なAWS認証情報を取得した後、AWS CLIコマンドを使って特定のタグ(Name=apartment-server)が付けられたEC2インスタンスのIDを動的に取得します。そのインスタンスに対して、SSM経由で先述のデプロイスクリプトを実行するコマンドを送信します。デプロイには時間がかかる可能性があるため、SSMコマンドの実行状況を定期的にポーリングし、完了を待ってから、その実行ログ(標準出力とエラー出力)を取得して、デプロイの成否を確認します。これにより、サーバーのIDをハードコードすることなく、インフラが再構築されても自動的に新しいサーバーを対象としてデプロイできる柔軟性を持っています。
構築を通じて得られた学びとして、サーバーは常にコードリポジトリの正確なミラーであるべきで、手動での変更を一切許さないという「サーバーの非特殊化」の重要性が挙げられます。また、OIDCやSSMのようなサービスを活用することで、セキュリティと利便性を両立できることも実感しました。認証情報の保存やSSHキーの管理といった煩雑な作業なしに、安全なデプロイパイプラインを構築できます。Docker Composeのヘルスチェック機能は、複数のサービスが依存し合うアプリケーションにおいて、安全な起動順序を保証するための「本当のデプロイロジック」として機能することも理解できました。そして、Dockerイメージはビルドごとに増え続けるため、定期的なクリーンアップはディスク容量枯渇を防ぐ上で不可欠です。
このパイプラインは、mainブランチへのプッシュで自動的にデプロイが行われる「継続的デプロイメント」を実現していますが、本番運用を考慮すると、さらに改善の余地があります。例えば、ステージング環境を設けて本番デプロイ前に詳細なテストを実行したり、手動承認ゲートを設けて人間がデプロイを承認するステップを挟んだりすることなどが考えられます。また、コンテナイメージをサーバー上でビルドするのではなく、事前にAWS ECR(Elastic Container Registry)のようなレジストリにプッシュしておき、サーバーはそれらをプルするだけにする「ビルド・ワン・デプロイ・メニー」戦略も有効です。さらに、環境変数をAWS Systems Manager Parameter Storeのような安全な場所に保管し、デプロイスクリプトが実行時に取得するように変更すれば、よりセキュアな運用が実現できます。
これらの取り組みにより、アプリケーションの迅速かつ安全なデプロイを実現する強力なCI/CDパイプラインが構築されました。