はじめに (対象読者・この記事でわかること)
この記事は、JavaのWeb APIやバッチをMavenでビルドし、GitHub ActionsでEC2に自動デプロイしようとしているが「なぜか失敗する」「エラーログが意味不明」という方向けです。
記事を読むことで、GitHub Actions上でのビルド失敗、EC2へのファイル転送エラー、systemdサービス起動失敗という3つの代表的な落とし穴を回避できるようになります。ローカルでは動くのに本番で動かない……そんな壁に直面したときの「次に調べるキーワード」と「切り分け手順」のイメージがつかめるでしょう。
前提知識
- Java 11以降とMaven 3.8以降の基本操作(
mvn packageなど) - GitHub にプッシュできること(SSHキーまたは PAT の設定済み)
- Linux サーバ(EC2 でも VPS でも可)で systemd サービスを起動した経験
- YAML のインデントに対して「そこはスペース2個では?」と指摘できる程度の目利き
MavenプロジェクトをGitHub Actionsでデプロイするまでの概要
CI/CD ブームの昨今、Java プロジェクトでも「GitHub へのマージ→本番環境への自動デプロイ」を実現したいニーズが高まっています。Maven は依存解決からビルドまで一本化されているため、GitHub Actions の setup-java アクションと組み合わせるだけで簡単にビルドできます。しかし、ビルドが通っても本番で動かないケースが後を絶ちません。
主な理由は以下3点です。
- ビルド環境とランタイム環境の OS/アーキテクチャ差異(libc の違いなど)
- 設定ファイル(
application-prod.ymlなど)を Git 管理から外しているが、デプロイ時に配置し忘れる - systemd のサービスユニットファイルの WorkingDirectory や User 指定が不正で、JAR が期待する相対パスを解決できない
本記事では、これらの落とし穴を「エラーが出た→ログを読む→設定を直す」という短いループで突き進むためのノウハウをお届けします。
エラーと格闘したデプロイまでの道のり
ステップ1:GitHub Actions でのビルドとアーティファクトアップロード
まず、リポジトリ直下に .github/workflows/deploy.yml を作成します。以下は最小構成です。
Yamlname: Build and Deploy on: push: branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '21' - run: mvn -B package -DskipTests - uses: actions/upload-artifact@v4 with: name: app-jar path: target/*.jar
ポイントは actions/upload-artifact@v4 で JAR を保存しておくこと。後続のジョブでダウンロードして SCP 転送します。
ハマりどころ:path: target/*.jar に複数ファイルがマッチするとエラーになります。Maven が *-sources.jar や *-javadoc.jar も出力している場合は、
Yamlpath: target/${{ github.event.repository.name }}-*.jar
のように絞り込むと安全です。
ステップ2:EC2 へのデプロイと systemd リロード
次のジョブでアーティファクトをダウンロードし、EC2 へ転送→サービス再起動します。
Yamldeploy: needs: build runs-on: ubuntu-latest steps: - uses: actions/download-artifact@v4 with: name: app-jar path: /tmp/app - run: | echo "${{ secrets.SSH_KEY }}" > key.pem chmod 600 key.pem scp -i key.pem -o StrictHostKeyChecking=no \ /tmp/app/*.jar ubuntu@${{ secrets.HOST }}:/opt/app/app.jar ssh -i key.pem -o StrictHostKeyChecking=no ubuntu@${{ secrets.HOST }} <<EOF sudo systemctl stop app sudo cp /opt/app/app.jar /opt/app/app.jar.backup sudo systemctl start app sudo systemctl status app EOF
SSH_KEY と HOST は GitHub の Secrets に登録しておきます。
ハマった点1:「Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin」
GitHub Actions ログに突然コンパイラプラグインのエラーが出てビルドがコケる。
原因:
actions/setup-java で指定した Java バージョンが、pom.xml の maven.compiler.source/target と異なる場合です。
解決:
pom.xml に以下を追記してバージョンを固定しましょう。
Xml<properties> <maven.compiler.source>21</maven.compiler.source> <maven.compiler.target>21</maven.compiler.target> </properties>
ハマった点2:「scp: /opt/app/app.jar: Permission denied」
scp 転送時にパーミッションエラーが出る。
原因:
EC2 側の /opt/app ディレクトリが root:root パーミッション 755 になっていて、ubuntu ユーザーで書き込めない。
解決:
初回だけ手動で
Bashsudo mkdir -p /opt/app sudo chown ubuntu:ubuntu /opt/app
としておくか、または scp 後に ssh 内で sudo mv する運用に切り替えます。
ハマった点3:「Main class not found」「application.yml が読めない」
systemd で起動した直後にプロセスが exit してしまう。
原因1:
WorkingDirectory を指定していないと、JAR 内の相対パス(./config/application.yml など)が解決できない。
systemd ユニットファイルの例:
Ini[Unit] Description=My App After=network.target [Service] Type=simple User=ubuntu WorkingDirectory=/opt/app ExecStart=/usr/bin/java -jar app.jar Restart=always [Install] WantedBy=multi-user.target
原因2:
環境変数 SPRING_PROFILES_ACTIVE が設定されていない。
GitHub Actions 側で
Bashecho "SPRING_PROFILES_ACTIVE=prod" | sudo tee /etc/default/app
としてから systemctl restart app すると安全です。
解決までのロギング工夫
本番環境で何が起きているかを素早く知るには、ログの出し方を工夫します。
- JAR 内に logback-spring.xml を配置し、prod プロファイル時のみファイル出力に切り替える
- systemd の
StandardOutput=journalにしてjournalctl -u app -fで tail する - GitHub Actions の最後のステップで
journalctl -u app -n 50 --no-pagerを実行し、ログを Actions 画面に出力しておく
これで「デプロイ成功=ビルド緑+journal 最後のログに Started 表示」が確認できます。
まとめ
本記事では、Maven でビルドした Java アプリケーションを GitHub Actions 経由で EC2 に自動デプロイする際に遭遇しがちな3つのエラーと、その切り分け・解決法を紹介しました。
- Java バージョンの不一致によるビルド失敗は、pom.xml のプロパティで固定する
- SCP 転送失敗は、事前にディレクトリパーミッションを調整するか、ファイル移動を別途実行する
- systemd 起動失敗は、WorkingDirectory と環境変数を正しく設定し、ログを journalctl で確認する
これらのポイントを抑えることで、ローカルでは通るのに本番で動かない……という時間を大幅に削減できます。次回は、Blue/Green デプロイや Docker 化した際のヘルスチェック戦略について掘り下げていく予定です。
参考資料
- GitHub Actions: setup-java 公式
- Maven Compiler Plugin よくあるエラー
- systemd.service 日本語マニュアル
- Spring Boot 公式ドキュメント – Deployment
