In the first post of this serie, I created a simple microservice based on a Spring Boot + Data JPA stack to display a list of available products in JSON format. In the second part, I demoed how this app could be uploaded on Pivotal Cloud Foundry. In this post, I’ll demo the required changes to deploy on Heroku.
Heroku
As for PCF, Heroku requires a local dedicated app. For Heroku, it’s called the Toolbelt. Once installed, one needs to login on one’s account through the toolbelt:
heroku login
The next step is to create the application on Heroku. The main difference between Cloud Foundry and Heroku is that the former deploys ready binaries while Heroku builds them from source. Creating the Heroku app will also create a remote Git repository to push to, as Heroku uses Git to manage code.
heroku create
Creating salty-harbor-2168... done, stack is cedar-14 https://salty-harbor-2168.herokuapp.com/ | https://git.heroku.com/salty-harbor-2168.git Git remote heroku added
The heroku create
command also updates the .git config by adding a new heroku
remote.
Let’s push to the remote repository:
git push heroku master
Counting objects: 21, done. Delta compression using up to 8 threads. Compressing objects: 100% (14/14), done. Writing objects: 100% (21/21), 2.52 KiB | 0 bytes/s, done. Total 21 (delta 1), reused 0 (delta 0) remote: Compressing source files... done. remote: Building source: remote: remote: -----> Java app detected remote: -----> Installing OpenJDK 1.8... done remote: -----> Installing Maven 3.3.3... done remote: -----> Executing: mvn -B -DskipTests=true clean install remote: [INFO] Scanning for projects... // Here the app is built remotely with Maven remote: [INFO] ------------------------------------------------------------------------ remote: [INFO] BUILD SUCCESS remote: [INFO] ------------------------------------------------------------------------ remote: [INFO] Total time: 51.955 s remote: [INFO] Finished at: 2015-10-03T09:13:31+00:00 remote: [INFO] Final Memory: 32M/473M remote: [INFO] ------------------------------------------------------------------------ remote: -----> Discovering process types remote: Procfile declares types -> (none) remote: remote: -----> Compressing... done, 74.8MB remote: -----> Launching... done, v5 remote: https://salty-harbor-2168.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy.... done. To https://git.heroku.com/salty-harbor-2168.git * [new branch] master -> master
At this point, one need to tell Heroku how to launch the newly built app.
This is done through a Procfile
located at the root of the project.
It should contain an hint to Heroku that we are using a web application - reachable through http(s), and the standard Java command-line.
Also, the web port should be bound an Heroku documented environment variable:
web: java -Dserver.port=$PORT -jar target/microservice-sample.jar
The application doesn’t work yet as the log will tell you. To display the remote log, type:
heroku logs --tail
There should be something like that:
Web process failed to bind to $PORT within 60 seconds of launch
That hints that a web node is required, or in Heroku’s parlance, a dyno. Let’s start one:
heroku ps:scale web=1
The application should now be working at https://salty-harbor-2168.herokuapp.com/products (you should be patient, since it’s a free plan, the app is probably sleeping). Yet, something is still missing: it’s still running on the embedded H2 database. We should switch to a more resilient database. By default, Heroku provides a PostgreSQL development database for free. Creating such a database can be done either through the user interface or the command-line.
Spring Boot documentation describes the Spring Cloud Connectors library. It’s able to automatically detect the app is running on Heroku and to create a datasource bound to the Postgres database provided by Heroku. However, despite my best effort, I haven’t been able to make this work, running each time into the following:
org.springframework.cloud.CloudException: No unique service matching interface javax.sql.DataSource found. Expected 1, found 0
Time to get a little creative.
Instead of sniffing the database and its configuration, let’s configure it explicitly.
This requires creating a dedicated profile configuration properties file for Heroku, src/main/resources/application-heroku.yml
:
spring:
datasource:
url: jdbc:postgresql://<url>
username: <username>
password: <password>
driver-class-name: org.postgresql.Driver
jpa:
database-platform: org.hibernate.dialect.PostgreSQLDialect
The exact database connection settings you can find in the Heroku user interface. Note the dialect seems to be required. Also, the POM should be updated to add the Postgres driver to the dependencies.
Finally, to activate the profile on Heroku, change the Procfile
as such:
web: java -Dserver.port=$PORT -Dspring.profiles.active=heroku -jar target/microservice-sample.jar
Commit and push to Heroku again, the application should be updated to use the provided Postgres.
Next week, I’ll create a new shopping bag microservice that depend on this one and design for failure.