EC2 + GitHub Actions で WebアプリをCI/CDデプロイする【GitHub Packages + CodeDeploy 体験】

AWS Basic
スポンサーリンク
スポンサーリンク

はじめに

「インフラは AWS でいいけど、デプロイは GitHub Actions でやりたい」——クラウドと Git を組み合わせたハイブリッドな CI/CD 構成は、多くの現場で採用されています。このハンズオンでは、EC2(Tomcat)への自動デプロイを GitHub Actions + AWS CodeDeploy で実現します。

さらに実務でよく見かける「社内共通ライブラリを GitHub Packages で管理・共有する」仕組みも体験できます。Spring Boot WAR をビルドする際に共通ライブラリを GitHub Packages からフェッチし、CodeDeploy で EC2 にデプロイするまでの一連のフローです。

[GitHub リポジトリ]
  ├── common-lib/ → push → GitHub Actions → GitHub Packages に publish
  └── app/        → push → GitHub Actions
                               ├── GitHub Packages から common-utils を取得
                               ├── mvn package → webapp.war
                               ├── zip → S3 にアップロード
                               └── CodeDeploy を呼び出す
                                        ↓
                          [EC2: Tomcat + Spring Boot WAR]  my-ec2app
                                        ↓
                          [ALB: my-ec2app-alb] ← インターネット
                                        ↓
                          [RDS MySQL: my-ec2app-rds]

このハンズオンで体験できること:

  • GitHub Packages を使った共通ライブラリの管理・共有
  • GitHub Actions(OIDC 認証)で AWS にキーレスアクセス
  • CodeDeploy + appspec.yml を使った EC2 へのデプロイ自動化
  • SSM Parameter Store でデータベースパスワードを安全に管理
  • CloudFormation によるインフラ一括構築(VPC / EC2 / ALB / RDS / CodeDeploy)

コード詳細は GitHub を参照してください。


-->

スポンサーリンク

キーワード解説

用語意味
GitHub PackagesGitHub リポジトリ内で Maven/npm などのパッケージを管理・共有するレジストリ。社内共通ライブラリの配布に使える
GitHub Actions OIDCアクセスキーをリポジトリに保存せず、JWT トークンで AWS を操作するキーレス認証方式
CodeDeployEC2 への WAR 配置・サービス停止/起動・ヘルスチェックを自動化する AWS のデプロイサービス
appspec.ymlCodeDeploy がデプロイ時に実行するファイル配置先とフックスクリプト(BeforeInstall / AfterInstall / ValidateService)を定義するファイル
SSM Parameter StoreDB パスワードなどの設定値を暗号化して管理し、EC2 から安全に取得できる AWS のサービス
CloudFormationAWS リソースをコード(YAML/JSON)で定義・一括管理する IaC サービス
ALB(Application Load Balancer)HTTP/HTTPS をリスンして EC2 にリクエストを振り分けるロードバランサー

スポンサーリンク

① 全体構成を理解する

このハンズオンの主役は 2 つのワークフローです。

①-1 common-lib のパブリッシュ(ec2-publish-lib.yml

common-lib/ が変更されると起動し、Maven ライブラリを GitHub Packages に publish します。actions/setup-javasettings.xml を自動生成するため、認証設定は不要です。

①-2 アプリのデプロイ(ec2-app-deploy.yml

app/ が変更されると起動します。処理の流れは次の通りです:

① OIDC で AWS に認証
② GitHub Packages から common-utils を取得しながら mvn package で WAR をビルド
③ zip 化して S3 にアップロード(webapp.war + appspec.yml + scripts/)
④ CodeDeploy でローリングデプロイ(〜1〜2 分)

デプロイパッケージの構造:

deploy.zip
├── webapp.war         ← Tomcat の webapps/ に配置
├── appspec.yml        ← CodeDeploy の設定
└── scripts/
    ├── stop_server.sh      ← Tomcat を停止・古い WAR を削除
    ├── start_server.sh     ← SSM から DB 情報を取得・Tomcat 起動
    └── validate_service.sh ← /api/health を最大 60 秒リトライ確認

② OIDC 認証と IAM ロールを設定する

GitHub Actions が AWS に安全にアクセスするための OIDC(OpenID Connect)認証 を設定します。アクセスキーをリポジトリに保存せずに AWS を操作できる現代的な方式です。

②-1 OIDC プロバイダーを登録する(初回のみ)

AWS コンソール → IAM → 「IDプロバイダー」→「プロバイダーを追加」

項目
プロバイダータイプOpenID Connect
プロバイダー URLhttps://token.actions.githubusercontent.com
対象者(Audience)sts.amazonaws.com

ECS ハンズオン(cdk-ecs-webapp)完了済みの場合はスキップ可。

②-2 IAM ロールを作成する

AWS CloudShell で以下を実行します(GITHUB_OWNERREPO は自分のリポジトリに合わせて変更):

ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
GITHUB_OWNER="your-github-username"   # ← 自分の GitHub ユーザー名
REPO="your-github-repo"               # ← 自分の GitHub リポジトリ名
EMPLOYEE_ID="my"                      # ← 好きなプレフィックス(例: 123456)
ROLE_NAME="${EMPLOYEE_ID}-github-actions-role"

cat > /tmp/trust-policy.json << EOF
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/token.actions.githubusercontent.com"
    },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringEquals": {
        "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
      },
      "StringLike": {
        "token.actions.githubusercontent.com:sub": "repo:${GITHUB_OWNER}/${REPO}:ref:refs/heads/main"
      }
    }
  }]
}
EOF

aws iam create-role \
  --role-name $ROLE_NAME \
  --assume-role-policy-document file:///tmp/trust-policy.json

# 権限ポリシーを付与(S3 + CodeDeploy)
cat > /tmp/permissions.json << EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:GetObject"],
      "Resource": "arn:aws:s3:::${EMPLOYEE_ID}-ec2app-deploy-*/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "codedeploy:CreateDeployment",
        "codedeploy:GetDeployment",
        "codedeploy:GetDeploymentConfig",
        "codedeploy:RegisterApplicationRevision"
      ],
      "Resource": "*"
    }
  ]
}
EOF

aws iam put-role-policy \
  --role-name $ROLE_NAME \
  --policy-name "${ROLE_NAME}-policy" \
  --policy-document file:///tmp/permissions.json

# ロール ARN を表示
aws iam get-role --role-name $ROLE_NAME --query Role.Arn --output text

出力された ロール ARNarn:aws:iam::...)をコピーしておきます。


③ GitHub Variables を設定する

GitHub リポジトリ → SettingsSecrets and variablesActions「Variables」タブ

「New repository variable」で以下を追加します:

Name説明
EMPLOYEE_IDmyリソース名プレフィックス
AWS_ROLE_ARNarn:aws:iam::...②-2 で表示されたロール ARN
AWS_ACCOUNT_ID123456789012AWS アカウント ID(S3 バケット名に使用)

Variables vs Secrets:ARN や ID は機密情報ではないため Variables に保存します(パスワード類は Secrets を使う)。


④ CloudFormation スタックを作成する

自分の IP アドレスを確認し(curl https://checkip.amazonaws.com)、CloudFormation でインフラを一括作成します:

aws cloudformation deploy ^
  --template-file ec2-github-actions/infra/template.yaml ^
  --stack-name my-ec2app ^
  --parameter-overrides EmployeeId=my DBPassword=Handson1234! MyIP=123.456.78.901/32 ^
  --capabilities CAPABILITY_NAMED_IAM ^
  --region ap-northeast-1

所要時間:約 10〜15 分(RDS の作成に時間がかかります)

CloudFormation スタックが作成するリソース:

リソース名前
VPC / サブネット / IGWmy-ec2app-vpc
EC2(Amazon Linux 2023 + Tomcat 10.1)my-ec2app
ALBmy-ec2app-alb
RDS MySQL 8.0my-ec2app-rds
S3(デプロイアーティファクト保管)my-ec2app-deploy-{アカウントID}
CodeDeploy Application + Deployment Groupmy-ec2app
SSM Parameter Store(DB 接続情報)/my/ec2app/db-host, /my/ec2app/db-password


⑤ スタックの Outputs を確認する

aws cloudformation describe-stacks ^
  --stack-name my-ec2app ^
  --region ap-northeast-1 ^
  --query "Stacks[0].Outputs" ^
  --output table
キー内容
ALBEndpointアプリ URL(後で使用)
DeploymentBucketNameS3 バケット名
CodeDeployApplicationNameCodeDeploy アプリ名
EC2InstanceIdEC2 インスタンス ID(SSM 接続に使用)

⑥ common-lib を GitHub Packages に publish する

common-lib/pom.xmlapp/pom.xml にある GitHub ユーザー名・リポジトリ名のプレースホルダーを自分のものに変更してから push します:

<!-- common-lib/pom.xml と app/pom.xml の両方を変更 -->
<url>https://maven.pkg.github.com/your-github-username/your-github-repo</url>

変更を push すると Publish common-utils to GitHub Packages ワークフローが自動起動します:

cd C:\my-aws\aws-learning-projects
git add ec2-github-actions/common-lib/ ec2-github-actions/app/pom.xml
git commit -m "feat: configure GitHub Packages URL for ec2-github-actions"
git push

GitHub リポジトリ → Actions タブPublish common-utils to GitHub Packages の実行を確認します。完了後、Packages タブcommon-utils 1.0.0 が表示されます。

ResponseWrapper クラスとは:このハンズオンの共通ライブラリは API レスポンスを {"status":"ok","data":{...}} の統一形式にラップするユーティリティです。チーム開発でレスポンス形式を統一する際によく使われるパターンです。


⑦ アプリを初回デプロイする

app/ の変更を push して Deploy App to EC2 ワークフローを起動します:

cd C:\my-aws\aws-learning-projects
git add ec2-github-actions/app/
git commit -m "feat: initial deploy via GitHub Actions (EC2)"
git push

nothing to commit と表示された場合index.html に空白行を追加して変更を作ります:

echo. >> ec2-github-actions\app\src\main\resources\templates\index.html
git add ec2-github-actions/app/src/main/resources/templates/index.html
git commit -m "chore: trigger initial deploy"
git push

⑧ GitHub Actions の進行を確認する

GitHub → Actions タブDeploy App to EC2 で各ステップの実行状況を確認します:

ステップ内容時間目安
Checkoutコード取得〜10秒
Configure AWS credentialsOIDC 認証(アクセスキー不要)〜10秒
Set up JavaJDK 17 + settings.xml 生成〜30秒
Build WARGitHub Packages から common-utils 取得 + mvn package〜1〜2分
Package and upload to S3zip 化 → S3 へアップロード〜10秒
Deploy via CodeDeployEC2 にデプロイ + 完了待ち〜1〜2分

合計:約 3〜5 分

ポイントは 「Set up Java」ステップです。actions/setup-javaserver-id: github を指定するだけで、GitHub Packages の認証情報を含む settings.xml が自動生成されます。Maven のパスワード設定を手書きする必要はありません。


⑨ ブラウザで動作確認する

ALBEndpoint の URL にアクセスすると「Spring Boot + RDS Item Manager (EC2)」が表示されます。

/api/health にアクセスして以下が返ることも確認します:

{"status":"ok","message":null,"data":"OK"}

このレスポンス形式こそが common-utilsResponseWrapper が GitHub Packages 経由で取得・ビルドされた証拠です。


⑩ CI/CD サイクルを体験する

index.html のタイトルを変更して push すると、約 3〜5 分でブラウザに反映されます:

<!-- 変更後 -->
<h1>Spring Boot + RDS Item Manager (EC2 v2) <span class="badge">GitHub Actions</span></h1>
git add ec2-github-actions/app/src/main/resources/templates/index.html
git commit -m "feat: update title to EC2 v2"
git push

これが CI/CD の醍醐味です。コードを push するだけで自動的にデプロイが完了します。


⑪ SSM Session Manager で EC2 に接続する(オプション)

キーペアなしで EC2 内部を確認できます:

aws ssm start-session ^
  --target i-xxxxxxxxxxxxxxxxx ^
  --region ap-northeast-1
# Tomcat のステータス確認
sudo systemctl status tomcat

# デプロイログの確認
sudo cat /var/log/aws/codedeploy-agent/codedeploy-agent.log

# SSM から取得した DB 接続情報の確認
sudo cat /opt/tomcat/current/bin/setenv.sh

# Tomcat ログの確認
sudo journalctl -u tomcat -n 50

setenv.sh を確認すると、SSM Parameter Store から取得した DB ホスト名とパスワードが環境変数としてセットされていることがわかります。パスワードをコードに書かずに安全に注入できています。


⑫ リソースを削除する

① S3 バケットを空にする(デプロイアーティファクトが蓄積されているため先に削除)

aws s3 rm s3://my-ec2app-deploy-123456789012 --recursive

② CloudFormation スタックを削除する

aws cloudformation delete-stack ^
  --stack-name my-ec2app ^
  --region ap-northeast-1

aws cloudformation wait stack-delete-complete ^
  --stack-name my-ec2app ^
  --region ap-northeast-1

echo スタック削除完了

まとめ:学んだ概念

概念ポイント
GitHub PackagesMaven ライブラリを GitHub リポジトリ内で管理・共有する仕組み。社内共通ライブラリの配布に活用できる
GitHub Actions OIDCアクセスキー不要で AWS に認証するキーレス方式。aws-actions/configure-aws-credentials で簡単に設定可
CodeDeployEC2 への WAR 配置・サービス再起動・ヘルスチェックを自動化するサービス
appspec.ymlCodeDeploy がデプロイ時に実行するファイル配置とフックスクリプトを定義するファイル
SSM Parameter StoreDB パスワードをインスタンスに安全に渡す仕組み。start_server.sh から取得して setenv.sh に書き込む
CloudFormationVPC・EC2・RDS・ALB・CodeDeploy を 1 つの YAML テンプレートで一括構築

GitHub Actions と AWS を組み合わせることで、Git push だけでインフラから独立してアプリをデプロイできる柔軟な CI/CD パイプラインを構築できます。次のステップとして、EC2 + CodePipeline ハンズオンで完全 AWS ネイティブな CI/CD も体験してみましょう。

コメント