⛩️

GithubActionsでMaven/SpringBootアプリケーションをHerokuにデプロイする

2022/01/31に公開

『俺の妹がこんなに可愛いわけがない』みたいに長いタイトルになってしまい、申し訳ございません。
GitHubActionsというのを体験してみたいと思います。
これはとんでもないActionの集合ということらしいです。

以下のことを行ってギャラクシーを体感します。
とても大事な所を太字で書いています。

  • Mavenでプロジェクトを作成する
  • IntelliJで開く
  • コントローラーを作成する
  • アプリケーションをテストする
  • アプリケーションを実行する
  • Procfileの作成
  • system.propertiesの作成
  • mvn installの実施
  • .gitignoreの修正
  • herokuで新規アプリを作成する
  • GitHubActionsを設定する
  • アプリケーションを確認する

Mavenでプロジェクトを作成する

サイト"Spring Initializr"でプロジェクトを作成します。

https://start.spring.io/

以下のようにMavenとJarをチェックした状態にして、右側の依存モジュールには、lombokとSpringWebを指定します。

任意のフォルダに解凍します。

IntelliJで開く

Openから先ほど解凍したプロジェクトを選択して開きます。
時間かかります。

コントローラーを作成する

超簡単なモデルとコントローラーを作成してアプリケーションを実行してみます。

モデル

package com.example.demo;

import lombok.AllArgsConstructor;

@AllArgsConstructor
public class Hasira {
    private String name;
    public String getInfo(){
        return this.name + " : sama";
    }
}

コントローラー

package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SampleController {
    @GetMapping("/sample")
    public String sample(){
        Hasira hasira = new Hasira("uzui");
        return hasira.getInfo();
    }
}

lombokについて

設定(File>Setting)からプラグインのlombokを有効化しておきます。

ここでIntelliJをプロジェクトを閉じて再度開きます。

アプリケーションをテストする

コントローラーのテストコードを書いておきます。

package com.example.demo;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

public class SampleControllerTest {
    private MockMvc mock;
    @BeforeEach
    public void prepare(){
        this.mock = MockMvcBuilders.standaloneSetup(new SampleController()).build();
    }
    @Test
    public void test_sample() throws Exception {
        System.out.println("----テストの開始----");
        this.mock.perform(MockMvcRequestBuilders.get("/sample"))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.content().string("uzui : sama"));
        System.out.println("----テストの終了----");
    }
}

ターミナルから以下のコマンドを実施します

mvn test

成功ログが出ればOKです

----テストの開始----
----テストの終了----
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.067 s - in com.example.demo.SampleControllerTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  8.029 s
[INFO] Finished at: 2022-01-31T17:34:38+09:00
[INFO] ------------------------------------------------------------------------

アプリケーションを実行する

ターミナルから以下コマンドを実施

mvn spring-boot:run

http://localhost:8080/sample

にアクセスする

Procfileの作成

重要シリーズ第一弾です。
プロジェクトのルートにProcfileという名前のファイルを作成します。

そして以下の内容を記載します

web: java -Dserver.port=$PORT -jar target/demo-0.0.1-SNAPSHOT.jar

これはアプリケーションがtarget/demo-0.0.1-SNAPSHOT.jarを見るということ意味しています。

system.propertiesの作成

重要シリーズ第二弾です。
プロジェクトのルートにsystem.propertiesという名前のファイルを作成します。

そして以下の内容を記載します

java.runtime.version=11

Javaのバージョンを指定しています。これがないとherokuでbuildエラーになります。(なることがあります)

↓こんなエラーです

Error:         [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project demo: Fatal error compiling: invalid target release: 11 -> [Help 1]        
Error:         [ERROR]         
Error:         [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.        
Error:         [ERROR] Re-run Maven using the -X switch to enable full debug logging.        
Error:         [ERROR]         
Error:         [ERROR] For more information about the errors and possible solutions, please read the following articles:        
Error:         [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException   

mvn installの実施

※後に解説をしますが、githubactionsでパッケージングを行うので、ここでは必須の処理ではありませんでした。

重要シリーズ第三弾です。
mvn installを行ってtargetフォルダにjarファイルを出力します。
先ほどもProcfileで書きましたがjarファイルが必要になります。

.gitignoreの修正

※後に解説をしますが、githubactionsでパッケージングを行うので、ここでは必須の処理ではありませんでした。

重要シリーズ第四弾です。
.gitignoreというのはステージング対象からも除外する、githubにcommitの対象から外すものをリスト化したファイルです。
実はtargetフォルダはこの対象になっているので、せめて先ほど作ったjarファイルだけは除外してあげる必要があります。

- target/
+ target/*
+ !target/*.jar

herokuで新規アプリを作成する

ここからようやくherokuが出現します。
きっとherokuは大掛かりなことをするのでしょう。まずはアプリケーションを作成します。

適当な名前をつけてcreate appします。

GitHubActionsを設定する

githubの適当な新規リポジトリにSpringbootアプリケーションをpushします。ブランチ名はmainにしておいてください。

シークレットの登録をする

pushしたらリポジトリのSettingsから左メニューのSecretsのActionsをクリックします。
そしてNew repository secretボタンを押して

  • HEROKU_API_KEY
  • HEROKU_EMAIL
  • HEROKU_APP

それぞれ作成します。
HEROKU_API_KEYはherokuのAccount Settingsから確認できるAPI Keyです。
HEROKU_EMAILはherokuに登録しているメールアドレスです。
HEROKU_APPは、先ほど作成したherokuのアプリケーション名です。

全て作成すると以下のように表示されます

Actionの設定をする

GithubのリポジトリページからActionsをクリックする

Java With Mavenを選択します

するとワークフローを定義しているymlファイルが作成されます。
ここでherokuに対してデプロイ作業を行うなどの記載をすることになります。

右側のMarketplaceからDeploy to Herokuをクリックします。

そうすると使い方(コード)が表示されます。AkhileshNS/heroku-deployというActionを利用することでデプロイします。そして先ほど登録したAPI_KEYなどはここで使うために定義していました。また直接このファイルに定義するのはセキュリティ上よろしくないということで、secretsという形で埋め込んで利用します。

ファイルを以下のように修正したら、StartCommitからCommitします。

 # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
 # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven

 name: Java CI with Maven

 on:
   push:
     branches: [ main ]
-   pull_request:
-     branches: [ main ]

 jobs:
   build:

     runs-on: ubuntu-latest

     steps:
     - uses: actions/checkout@v2
     - name: Set up JDK 11
       uses: actions/setup-java@v2
       with:
         java-version: '11'
         distribution: 'temurin'
         cache: maven
     - name: Build with Maven
       run: mvn -B package --file pom.xml
+     - name: Test With Maven
+    run: mvn test
+     - name: Deploy to Heroku
+       uses: AkhileshNS/heroku-deploy@v3.12.12
+       with:
+         heroku_api_key: ${{secrets.HEROKU_API_KEY}}
+         heroku_email: ${{secrets.HEROKU_EMAIL}}
+         heroku_app_name: ${{secrets.HEROKU_APP}}

mainブランチにpushした時をトリガーにしてこのファイルに定義しているActionが実行されます。

 on:
   push:
     branches: [ main ]

Actionを実行する環境はubuntuを使っています

runs-on: ubuntu-latest

リポジトリをチェックアウトしてワークフローがアクセスできるようにします。
usesというのが利用するActionです。

steps:
 - uses: actions/checkout@v2

パッケージングを行います
runというのはコマンドを記載します。

- name: Build with Maven
   run: mvn -B package --file pom.xml

nameはstepを目視できるようになりますし、処理の塊を意味します。
Actionのサマリー画面で以下のように表示されます。

Actionはうまくいくと緑色、失敗すると赤で表示され、それぞれログも見ることができます。

テストも実施されていることが確認できます。

アプリケーションを確認する

herokuの画面からOpen appでアプリケーションを開きます。
今回githubにpushしたアプリケーションが実行されていることが確認できます。

githubactionはymlで書きやすいので、わかりやすいというメリットがあります。
今回はherokuということなので敷居が低いこともありますが、とても簡単にテスト→デプロイまでが出来てしまいました。

Gradleの場合

せっかくなのでGradleの場合もザックリですが試してみます。

Procfileは以下のように記載します。Spring Bootの場合、Procfileは以下のようなものになります。ということらしいです。

web: java -Dserver.port=$PORT $JAVA_OPTS -jar build/libs/damo-0.0.1-SNAPSHOT.jar

gradleの場合はgradle buildコマンドを使ってjarが、build/libsフォルダに出力されます

※前回demoだったのでdamoにしました。

またActionsはJava with Gradleを選択します。

workflowのymlファイルは同じように作成しましたが
以下のようなエラーが発生

Error: Error: Gradle script '/home/runner/work/gradle-heroku-deploy/gradle-heroku-deploy/gradlew' is not executable.

権限を与えてあげると実行できました。

 name: Java CI with Gradle

 on:
   push:
     branches: [ main ]

 jobs:
   build:

     runs-on: ubuntu-latest

     steps:
     - uses: actions/checkout@v2
     - name: Set up JDK 11
       uses: actions/setup-java@v2
       with:
         java-version: '11'
         distribution: 'temurin'
+     - name: permit Gradle
+       run: chmod +x gradlew
     - name: Build with Gradle
       uses: gradle/gradle-build-action@bc3340afc5e3cc44f2321809ac090d731c13c514
       with:
         arguments: build
     - name: Deploy to Heroku
       uses: AkhileshNS/heroku-deploy@v3.12.12
       with:
         heroku_api_key: ${{secrets.HEROKU_API_KEY}}
         heroku_email: ${{secrets.HEROKU_EMAIL}}
         heroku_app_name: ${{secrets.HEROKU_APP}}

これでうまくできました。
コードは以下です。(ちょっと修正入ってます)
https://github.com/jirentaicho/gradle-heroku-deploy

ちなみに

Command failed: git push heroku HEAD:refs/heads/main --force

このエラーはProcfileとsystem.propertiesが入ってない場合に起きるかもしれません。

実行画面

Discussion