日々常々

ふつうのプログラマがあたりまえにしたいこと。

とりあえずSpringBootアプリケーションをherokuで公開する

手順の全て

  • mkdir {てきとうななまえ}
  • cd {てきとうななまえ}
  • curl -O https://start.spring.io/pom.xml -d dependencies=web -d javaVersion=8
  • Applicationクラス作成(後述)
  • git init
  • git add .
  • heroku create
  • heroku git:remote -a {createで作られたもの}
  • git push heroku main

9ステップ。これでgit pushのレスポンスメッセージに出てるURLにアクセスしたらhelloと表示されます。目指せ5分!

説明

書きたいところを適当に書いていきます。あ、herokuアカウントの作成とコマンドラインツールのインストールは済ませといてください。私はbrewで入れてます。

この記事は現在に対する局所最適なので、バージョンなどは割愛します。 未来にこの記事のバージョンに合わせて動かすより、やりたいときにその時点での最新のやり方でやるのがいいと思います。 どうせherokuの挙動変わったらバージョンなんぞ合わせられないし。

curl...

Spring Initializr です。ブラウザでも使えますけど私はもっぱら curl で叩いてます。 詳しくは SpringBootのプロジェクトを作成する - 日々常々 とか。

普段はGradle使っていますが、今回はMavenを選択。

これは plain jarがSpringBoot2.5からできるようになって、herokuのデフォルトだと *.jar で起動しようとしてエラーになるため。 無効にするとかexecutable jarを実行するように明示するとかすればいいんだけどステップが増えるので今回は回避しています。

-d dependencies=web はこれがないとウェブアプリケーションにならないので。(webflux でもいいんだろけど)

-d javaVersion=8 がポイントでherokuのデフォルトJavaバージョンは1.8だったりします。SpringInitializrデフォルトは11なんで、そのままじゃ動かない。 pom.xmlを修正したり、system.properties(herokuが読む設定)に java.runtime.version=11 とか書いてもいいんだけど、今回は一番ステップが少なくなるの選びました。 普通は system.properties 書くことになると思います。書けばJava16も使えるよ。実際いくつかで使ってたりします。

Applicationクラス作成

コマンドだけで無理やり作るとこう。

% mkdir src/main/java/hoge
% cat>src/main/java/hoge/Application.java
package hoge;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@SpringBootApplication
@RestController
public class Application {

    public static void main(String[] args) { SpringApplication.run(Application.class, args); }

    @RequestMapping
    String index() { return "hello"; }
}

1クラスとはいえIDEで書くのがなんだかんだで早いと思う。importとか書いてられん。 (とはいえIDEで書くと後の git add .. じゃ余計なものが入るので pom.xmlApplication.java だけaddしなきゃになって若干面倒にはなる。些細な問題だけど。)

@Controller でなく @RestController なのはハンドラメソッドの戻りで文字列を直接返したいから。@Controllerだとテンプレート探しに行ってエラーになって /error なくて404になっちゃう。@ResponseBody とか書けばいいんだけど面倒だから @RestController にしちゃった。

あとデフォルトパッケージにすると余計なものコンポーネントスキャンで食っちゃうので、適当でもいいんでパッケージはつけなきゃです。

heroku create

ログインしてないとこれ叩いたときに自動でログイン促されます。ブラウザが開く。

heroku createapps:create の短縮。アプリ名を渡せるけど、指定しなかったら適当につけてくれる。今回はお任せ。

f:id:irof:20210805012937p:plain

これだと salty-woodland-12925 ですね。(destroy済み)

次の heroku git:remotegit remote add heroku {herokuのgitのURL} を代わりにやってくれるコマンドです。git コマンドを叩いても一緒なんでお好きな方でOK。gitのURLもcreate 時に出てますしね。 ここに push したらherokuはビルドして動くようにしてくれます。

git push

ソースコードを投げ込むといい感じにビルドしてくれるのがbuildpack。 「pom.xmlがあるからMavenだろ」「SpringBootだからこうだろ」みたいなのを雰囲気でやってくれます。 雰囲気でやってくれすぎて何がどうなってるか分からなくなる可能性がそこそこ。

わかりたかったら https://buildpacks.io/ とかで pack コマンド使って手元でビルドして docker run とかいじってみると、何かわかるかもしれない。わからないかもしれない。

git push したらMavenのいつものjarダウンロードのログがダラダラ流れる。git push でそんなん表示されるのに慣れてないと面食らうかもですね。

成功したらこんな感じ。

f:id:irof:20210805014310p:plain

Released とかの次の行の https://... を開いたら動いてる。はず。

今回はherokuのgitにpushしたけど、普段はGitHubからherokuに繋いで使ってます。この辺の連携も素直につながるのでいいですよね。

あとがき

適当にやろうとしたら地味なつまずきかたをしたので整理してみました。 ビルドは3分くらいで終わるんで、スムーズにできれば「ゼロから始めて5分でデプロイ完了」までいけると思います。ドラが鳴る前に終わることを祈る。

今回つまづいたのは

  • *-plain.jar のおかげでGradleだと素直に動かない。
    • build.gradlejar タスク止めるか、Procfile(herokuの設定ファイル)で動かすJar名を明示したらいける。普段は後者でやってる。
  • デフォルトJavaバージョンの食い違い
    • pom.xml とか build.gradle のバージョン読んでくれるようにきっとそのうちなると信じてる。

……くらいかな? こういうの踏んだときに雰囲気で察しちゃったりするんだけど、「ここにこのログが出てる」と確認しておくのも大事で、そういうのがこの手の素振りの目的だったりもします。

herokuでMaven使った記憶はないんだけど、「どうせいけるだろ」みたいなノリで push したらいけました。よかったよかった。 この「どうせいけるだろ」みたいな感覚って結構大事だと思ってたりします。たまに大外しするけど。

追記: タイムアタック結果

  • start: 2021-08-05T11:20:11
  • finish: 2021-08-05T11:22:08

コマンドのみの一発勝負。1分57秒でした。 mkdirから最後にcurlでhelloが返って来るところまで(curlのhello確認は上の手順にないですが。)で、全ログは gist に置いてます。 少し上で「ビルドは3分」とか書いてますが、herokuのご機嫌によりますね。

…… git initReinitialized になってるな。空じゃなかったのか。🤔

似た記事

irof.hateblo.jp

ソースコードの公開まで」って感じですね。今回のは手元の動作確認すらしてないという・・・。