Heroku
spring-boot

Spring BootをHerokuにデプロイするのが劇的に簡単になっている件

More than 1 year has passed since last update.


はじめに

以前herokuでspring-bootをgradleを使ってデプロイするときのコツの記事で紹介したspring-bootをherokuにデプロイするやり方を書いたが、最近はコツがなくてもデプロイできるようになっていたので改めて試してみた。


手順

手順はHeroku公式のDeploying Spring Boot Applications to Herokuに書いてあるとおり実施。Spring BootのプロジェクトをIntelliJから作るところだけ俺流です。


  • herokuにアカウントを作る(ない人だけ)

  • Heroku CLIをインストール(インストールしていない人だけ)

  • Herokuにログイン

  • IntelliJのSpringInitializrからSpringBootのプロジェクトを作成

  • gitにコミット

  • herokuにアプリケーション作成

  • herokuにpush


環境


  • Mac 10.10

  • IntelliJ IDEA 2016.2


詳細な手順

herokuのアカウント作成(アプリケーションではなくHerokuのアカウントのこと)とHeroku CLIのインストールは割愛します。(公式ページを参考にしてください)


Heroku CLIをつかってHerokuにログインする

❯❯❯ heroku login

Enter your Heroku credentials.
Email: gosshys@gmail.com
Password (typing will be hidden):
Logged in as gosshys@gmail.com


IntelliJからSpring Bootのプロジェクトを作成


  • メニュー「File」->「New」->「Project」を選択

    image


  • 左ペインの 「Spring Initializr」を選択して、「Next」ボタンで次へ

    image


  • 「Type」を『Gradle Project』に変更して、「Next」ボタンで次へ(Mavenでもいい、Mavenのほうがいいかも)

    image


  • 「Web」のWebと「Ops」のActuatorくらいを選択して、「Next」ボタンで次へ(Actuatorは任意、あると便利)

    image


  • デフォルトの設定でいいので、「Finish」ボタンで終了

    image


  • Gradleの設定を聞かれるのでお好みの設定で「OK」ボタンで進む(ここでGradle入れてない人は詰まる)

    image


  • できた

    image



gitにコミット

これも公式ページのPreparing a Spring Boot app for Herokuのとおりにgitにコミットする

~/D/g/demo ❯❯❯ git init

Initialized empty Git repository in /Users/tgoto/Develop/git/demo/.git/
~/D/g/demo ❯❯❯ git add . [master]
warning: CRLF will be replaced by LF in gradlew.bat.
The file will have its original line endings in your working directory.
~/D/g/demo ❯❯❯ git commit -m "first commit" [master]
[master (root-commit) b580cc2] first commit
warning: CRLF will be replaced by LF in gradlew.bat.
The file will have its original line endings in your working directory.
9 files changed, 345 insertions(+)
create mode 100644 .gitignore
create mode 100644 build.gradle
create mode 100644 gradle/wrapper/gradle-wrapper.jar
create mode 100644 gradle/wrapper/gradle-wrapper.properties
create mode 100755 gradlew
create mode 100644 gradlew.bat
create mode 100644 src/main/java/com/example/DemoApplication.java
create mode 100644 src/main/resources/application.properties
create mode 100644 src/test/java/com/example/DemoApplicationTests.java
~/D/g/demo ❯❯❯


herokuにアプリケーション作成

~/D/g/demo ❯❯❯ heroku create                                                                                                                                                            [master]

Creating app... done, ⬢ salty-badlands-47970
https://salty-badlands-47970.herokuapp.com/ | https://git.heroku.com/salty-badlands-47970.git


herokuにpush

~/D/g/demo ❯❯❯ git push heroku master                                                                                                                                                   [master]

Counting objects: 23, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (23/23), 51.72 KiB | 0 bytes/s, done.
Total 23 (delta 0), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Gradle app detected
remote: -----> Spring Boot detected
remote: -----> Installing OpenJDK 1.8... done
remote: -----> Building Gradle app...
remote: WARNING: The Gradle buildpack is currently in Beta.
remote: -----> executing ./gradlew build -x test
remote: Downloading https://services.gradle.org/distributions/gradle-2.13-bin.zip
remote: Unzipping /app/tmp/cache/.gradle/wrapper/dists/gradle-2.13-bin/4xsgxlfjcxvrea7akf941nvc7/gradle-2.13-bin.zip to /app/tmp/cache/.gradle/wrapper/dists/gradle-2.13-bin/4xsgxlfjcxvrea7akf941nvc7
remote: Set executable permissions for: /app/tmp/cache/.gradle/wrapper/dists/gradle-2.13-bin/4xsgxlfjcxvrea7akf941nvc7/gradle-2.13/bin/gradle
remote: Download https://repo1.maven.org/maven2/org/springframework/boot/spring-boot-gradle-plugin/1.4.2.RELEASE/spring-boot-gradle-plugin-1.4.2.RELEASE.pom
・・・中略・・・
core/1.1.7/logback-core-1.1.7.jar
remote: Download https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar
remote: :processResources
remote: :classes
remote: :findMainClass
remote: :jar
remote: :bootRepackage
remote: :assemble
remote: :check
remote: :build
remote:
remote: BUILD SUCCESSFUL
remote:
remote: Total time: 14.244 secs
remote: -----> Discovering process types
remote: Procfile declares types -> (none)
remote: Default types for buildpack -> web
remote:
remote: -----> Compressing...
remote: Done: 60.5M
remote: -----> Launching...
remote: Released v3
remote: https://salty-badlands-47970.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/salty-badlands-47970.git
* [new branch] master -> master
~/D/g/demo ❯❯❯


herokuのログを確認

~/D/g/demo ❯❯❯ heroku logs --tail                                                                                                                                                       [master]

2016-11-19T13:56:01.568716+00:00 app[api]: Release v2 created by gosshys@gmail.com
2016-11-19T13:56:01.566787+00:00 app[api]: Enable Logplex by gosshys@gmail.com
2016-11-19T13:58:44.799732+00:00 heroku[slug-compiler]: Slug compilation started
2016-11-19T13:58:44.799737+00:00 heroku[slug-compiler]: Slug compilation finished
2016-11-19T13:58:44.467345+00:00 app[api]: Scaled to web@1:Free by gosshys@gmail.com
2016-11-19T13:58:44.470909+00:00 app[api]: Deploy b580cc2 by gosshys@gmail.com
2016-11-19T13:58:44.472389+00:00 app[api]: Release v3 created by gosshys@gmail.com
2016-11-19T13:58:48.591821+00:00 heroku[web.1]: Starting process with command `java -Dserver.port=52225 $JAVA_OPTS -jar build/libs/*.jar`
2016-11-19T13:58:50.260077+00:00 app[web.1]: Create a Procfile to customize the command used to run this process: https://devcenter.heroku.com/articles/procfile
2016-11-19T13:58:50.264741+00:00 app[web.1]: Setting JAVA_TOOL_OPTIONS defaults based on dyno size. Custom settings will override them.
2016-11-19T13:58:50.268163+00:00 app[web.1]: Picked up JAVA_TOOL_OPTIONS: -Xmx350m -Xss512k -Dfile.encoding=UTF-8
2016-11-19T13:58:52.076863+00:00 app[web.1]:
2016-11-19T13:58:52.076916+00:00 app[web.1]: . ____ _ __ _ _
2016-11-19T13:58:52.076979+00:00 app[web.1]: /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
2016-11-19T13:58:52.077036+00:00 app[web.1]: ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
2016-11-19T13:58:52.077087+00:00 app[web.1]: \\/ ___)| |_)| | | | | || (_| | ) ) ) )
2016-11-19T13:58:52.077144+00:00 app[web.1]: ' |____| .__|_| |_|_| |_\__, | / / / /
2016-11-19T13:58:52.077198+00:00 app[web.1]: =========|_|==============|___/=/_/_/_/
2016-11-19T13:58:52.079909+00:00 app[web.1]: :: Spring Boot :: (v1.4.2.RELEASE)
2016-11-19T13:58:52.079980+00:00 app[web.1]:
2016-11-19T13:58:52.269726+00:00 app[web.1]: 2016-11-19 13:58:52.264 INFO 4 --- [ main] com.example.DemoApplication : Starting DemoApplication on 25aad326-8a96-43bf-8b22-edd3d5d66816 with PID 4 (/app/build/libs/demo-0.0.1-SNAPSHOT.jar started by u13413 in /app)
2016-11-19T13:58:52.270165+00:00 app[web.1]: 2016-11-19 13:58:52.269 INFO 4 --- [ main] com.example.DemoApplication : No active profile set, falling back to default profiles: default
2016-11-19T13:58:52.419052+00:00 app[web.1]: 2016-11-19 13:58:52.418 INFO 4 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5a2e4553: startup date [Sat Nov 19 13:58:52 UTC 2016]; root of context hierarchy
2016-11-19T13:58:54.647292+00:00 app[web.1]: 2016-11-19 13:58:54.647 INFO 4 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 52225 (http)
2016-11-19T13:58:54.663369+00:00 app[web.1]: 2016-11-19 13:58:54.663 INFO 4 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat
2016-11-19T13:58:54.664271+00:00 app[web.1]: 2016-11-19 13:58:54.664 INFO 4 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.6
2016-11-19T13:58:54.813979+00:00 app[web.1]: 2016-11-19 13:58:54.813 INFO 4 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2016-11-19T13:58:54.814136+00:00 app[web.1]: 2016-11-19 13:58:54.814 INFO 4 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2399 ms
2016-11-19T13:58:55.078824+00:00 app[web.1]: 2016-11-19 13:58:55.078 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2016-11-19T13:58:55.083817+00:00 app[web.1]: 2016-11-19 13:58:55.083 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'metricsFilter' to: [/*]
2016-11-19T13:58:55.084166+00:00 app[web.1]: 2016-11-19 13:58:55.084 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2016-11-19T13:58:55.084272+00:00 app[web.1]: 2016-11-19 13:58:55.084 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2016-11-19T13:58:55.084376+00:00 app[web.1]: 2016-11-19 13:58:55.084 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2016-11-19T13:58:55.084478+00:00 app[web.1]: 2016-11-19 13:58:55.084 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2016-11-19T13:58:55.084580+00:00 app[web.1]: 2016-11-19 13:58:55.084 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'webRequestLoggingFilter' to: [/*]
2016-11-19T13:58:55.084686+00:00 app[web.1]: 2016-11-19 13:58:55.084 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'applicationContextIdFilter' to: [/*]
2016-11-19T13:58:55.597506+00:00 app[web.1]: 2016-11-19 13:58:55.597 INFO 4 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5a2e4553: startup date [Sat Nov 19 13:58:52 UTC 2016]; root of context hierarchy
2016-11-19T13:58:55.673440+00:00 app[web.1]: 2016-11-19 13:58:55.673 INFO 4 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2016-11-19T13:58:55.674627+00:00 app[web.1]: 2016-11-19 13:58:55.674 INFO 4 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2016-11-19T13:58:55.723994+00:00 app[web.1]: 2016-11-19 13:58:55.723 INFO 4 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-11-19T13:58:55.782426+00:00 app[web.1]: 2016-11-19 13:58:55.782 INFO 4 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-11-19T13:58:55.724075+00:00 app[web.1]: 2016-11-19 13:58:55.723 INFO 4 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-11-19T13:58:56.224259+00:00 app[web.1]: 2016-11-19 13:58:56.224 INFO 4 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/beans || /beans.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-11-19T13:58:56.226739+00:00 app[web.1]: 2016-11-19 13:58:56.226 INFO 4 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/trace || /trace.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-11-19T13:58:56.225195+00:00 app[web.1]: 2016-11-19 13:58:56.225 INFO 4 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/heapdump || /heapdump.json],methods=[GET],produces=[application/octet-stream]}" onto public void org.springframework.boot.actuate.endpoint.mvc.HeapdumpMvcEndpoint.invoke(boolean,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException,javax.servlet.ServletException
2016-11-19T13:58:56.228147+00:00 app[web.1]: 2016-11-19 13:58:56.228 INFO 4 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/configprops || /configprops.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-11-19T13:58:56.230478+00:00 app[web.1]: 2016-11-19 13:58:56.230 INFO 4 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/env || /env.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-11-19T13:58:56.230280+00:00 app[web.1]: 2016-11-19 13:58:56.230 INFO 4 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/env/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint.value(java.lang.String)
2016-11-19T13:58:56.232092+00:00 app[web.1]: 2016-11-19 13:58:56.231 INFO 4 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/mappings || /mappings.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-11-19T13:58:56.233083+00:00 app[web.1]: 2016-11-19 13:58:56.232 INFO 4 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/info || /info.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-11-19T13:58:56.237902+00:00 app[web.1]: 2016-11-19 13:58:56.237 INFO 4 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/metrics/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)
2016-11-19T13:58:56.238064+00:00 app[web.1]: 2016-11-19 13:58:56.237 INFO 4 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/metrics || /metrics.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-11-19T13:58:56.239229+00:00 app[web.1]: 2016-11-19 13:58:56.239 INFO 4 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/dump || /dump.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-11-19T13:58:56.241230+00:00 app[web.1]: 2016-11-19 13:58:56.241 INFO 4 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/health || /health.json],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(java.security.Principal)
2016-11-19T13:58:56.240394+00:00 app[web.1]: 2016-11-19 13:58:56.240 INFO 4 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/autoconfig || /autoconfig.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2016-11-19T13:58:56.377719+00:00 app[web.1]: 2016-11-19 13:58:56.377 INFO 4 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2016-11-19T13:58:56.389556+00:00 app[web.1]: 2016-11-19 13:58:56.389 INFO 4 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0
2016-11-19T13:58:56.565557+00:00 app[web.1]: 2016-11-19 13:58:56.565 INFO 4 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 52225 (http)
2016-11-19T13:58:56.572245+00:00 app[web.1]: 2016-11-19 13:58:56.572 INFO 4 --- [ main] com.example.DemoApplication : Started DemoApplication in 5.187 seconds (JVM running for 6.304)
2016-11-19T13:58:57.102150+00:00 heroku[web.1]: State changed from starting to up

メモリは結構シビア

2016-11-19T13:58:50.268163+00:00 app[web.1]: Picked up JAVA_TOOL_OPTIONS: -Xmx350m -Xss512k -Dfile.encoding=UTF-8


actuatorを叩いてみる

~/D/g/demo ❯❯❯ curl https://salty-badlands-47970.herokuapp.com/health                                                                                                                   [master]

{"status":"UP","diskSpace":{"status":"UP","total":402672611328,"free":349425127424,"threshold":10485760}}%

うごきました。