322 lines
12 KiB
Plaintext
322 lines
12 KiB
Plaintext
[[cloud-deployment]]
|
|
= Deploying to the cloud
|
|
|
|
[partintro]
|
|
--
|
|
Spring Boot's executable jars are ready-made for most popular cloud PaaS
|
|
(platform-as-a-service) providers. These providers tend to require that you
|
|
"`bring your own container`"; they manage application processes (not Java applications
|
|
specifically), so they need some intermediary layer that adapts _your_ application to the
|
|
_cloud's_ notion of a running process.
|
|
|
|
Two popular cloud providers, Heroku and Cloud Foundry, employ a "`buildpack`" approach.
|
|
The buildpack wraps your deployed code in whatever is needed to _start_ your
|
|
application: it might be a JDK and a call to `java`, it might be an embedded webserver,
|
|
or it might be a full-fledged application server. A buildpack is pluggable, but ideally
|
|
you should be able to get by with as few customizations to it as possible.
|
|
This reduces the footprint of functionality that is not under your control. It minimizes
|
|
divergence between deployment and production environments.
|
|
|
|
Ideally, your application, like a Spring Boot executable jar, has everything that it needs
|
|
to run packaged within it.
|
|
|
|
In this section we'll look at what it takes to get the
|
|
<<getting-started.adoc#getting-started-first-application, simple application that we
|
|
developed>> in the "`Getting Started`" section up and running in the Cloud.
|
|
--
|
|
|
|
|
|
|
|
[[cloud-deployment-cloud-foundry]]
|
|
== Cloud Foundry
|
|
Cloud Foundry provides default buildpacks that come into play if no other buildpack is
|
|
specified. The Cloud Foundry https://github.com/cloudfoundry/java-buildpack[Java buildpack]
|
|
has excellent support for Spring applications, including Spring Boot. You can deploy
|
|
stand-alone executable jar applications, as well as traditional `.war` packaged
|
|
applications.
|
|
|
|
Once you've built your application (using, for example, `mvn clean package`) and
|
|
http://docs.cloudfoundry.org/devguide/installcf/install-go-cli.html[installed the `cf`
|
|
command line tool], simply deploy your application using the `cf push` command as follows,
|
|
substituting the path to your compiled `.jar`. Be sure to have
|
|
http://docs.cloudfoundry.org/devguide/installcf/whats-new-v6.html#login[logged in with your
|
|
`cf` command line client] before pushing an application.
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
$ cf push acloudyspringtime -p target/demo-0.0.1-SNAPSHOT.jar
|
|
----
|
|
|
|
See the http://docs.cloudfoundry.org/devguide/installcf/whats-new-v6.html#push[`cf push`
|
|
documentation] for more options. If there is a Cloud Foundry
|
|
http://docs.cloudfoundry.org/devguide/deploy-apps/manifest.html[`manifest.yml`]
|
|
file present in the same directory, it will be consulted.
|
|
|
|
NOTE: Here we are substituting `acloudyspringtime` for whatever value you give `cf`
|
|
as the name of your application.
|
|
|
|
At this point `cf` will start uploading your application:
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
Uploading acloudyspringtime... *OK*
|
|
Preparing to start acloudyspringtime... *OK*
|
|
-----> Downloaded app package (*8.9M*)
|
|
-----> Java Buildpack source: system
|
|
-----> Downloading Open JDK 1.7.0_51 from .../x86_64/openjdk-1.7.0_51.tar.gz (*1.8s*)
|
|
Expanding Open JDK to .java-buildpack/open_jdk (*1.2s*)
|
|
-----> Downloading Spring Auto Reconfiguration from 0.8.7 .../auto-reconfiguration-0.8.7.jar (*0.1s*)
|
|
-----> Uploading droplet (*44M*)
|
|
Checking status of app 'acloudyspringtime'...
|
|
0 of 1 instances running (1 starting)
|
|
...
|
|
0 of 1 instances running (1 down)
|
|
...
|
|
0 of 1 instances running (1 starting)
|
|
...
|
|
1 of 1 instances running (1 running)
|
|
|
|
App started
|
|
----
|
|
|
|
Congratulations! The application is now live!
|
|
|
|
It's easy to then verify the status of the deployed application:
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
$ cf apps
|
|
Getting applications in ...
|
|
OK
|
|
|
|
name requested state instances memory disk urls
|
|
...
|
|
acloudyspringtime started 1/1 512M 1G acloudyspringtime.cfapps.io
|
|
...
|
|
----
|
|
|
|
Once Cloud Foundry acknowledges that your application has been deployed, you should be
|
|
able to hit the application at the URI given, in this case
|
|
`http://acloudyspringtime.cfapps.io/`.
|
|
|
|
|
|
|
|
[[cloud-deployment-cloud-foundry-services]]
|
|
=== Binding to services
|
|
By default, metadata about the running application as well as service connection
|
|
information is exposed to the application as environment variables (for example:
|
|
`$VCAP_SERVICES`). This architecture decision is due to Cloud Foundry's polyglot
|
|
(any language and platform can be supported as a buildpack) nature; process-scoped
|
|
environment variables are language agnostic.
|
|
|
|
Environment variables don't always make for the easiest API so Spring Boot automatically
|
|
extracts them and flattens the data into properties that can be accessed through
|
|
Spring's `Environment` abstraction:
|
|
|
|
[source,java,indent=0]
|
|
----
|
|
@Component
|
|
class MyBean implements EnvironmentAware {
|
|
|
|
private String instanceId;
|
|
|
|
@Override
|
|
public void setEnvironment(Environment environment) {
|
|
this.instanceId = environment.getProperty("vcap.application.instance_id");
|
|
}
|
|
|
|
// ...
|
|
|
|
}
|
|
----
|
|
|
|
All Cloud Foundry properties are prefixed with `vcap`. You can use vcap properties to
|
|
access application information (such as the public URL of the application) and service
|
|
information (such as database credentials). See `VcapApplicationListener` Javdoc for
|
|
complete details.
|
|
|
|
TIP: The https://github.com/spring-projects/spring-cloud[Spring Cloud] project is a better
|
|
fit for tasks such as configuring a DataSource; it also lets you use Spring Cloud with
|
|
Heroku.
|
|
|
|
|
|
|
|
[[cloud-deployment-heroku]]
|
|
== Heroku
|
|
Heroku is another popular PaaS platform. To customize Heroku builds, you provide a
|
|
`Procfile`, which provides the incantation required to deploy an application. Heroku
|
|
assigns a `port` for the Java application to use and then ensures that routing to the
|
|
external URI works.
|
|
|
|
You must configure your application to listen on the correct port. Here's the `Procfile`
|
|
for our starter REST application:
|
|
|
|
[indent=0]
|
|
----
|
|
web: java -Dserver.port=$PORT -jar target/demo-0.0.1-SNAPSHOT.jar
|
|
----
|
|
|
|
Spring Boot makes `-D` arguments available as properties accessible from a Spring
|
|
`Environment` instance. The `server.port` configuration property is fed to the embedded
|
|
Tomcat or Jetty instance which then uses it when it starts up. The `$PORT` environment
|
|
variable is assigned to us by the Heroku PaaS.
|
|
|
|
Heroku by default will use Java 1.6. This is fine as long as your Maven or Gradle build
|
|
is set to use the same version (Maven users can use the `java.version` property). If you
|
|
want to use JDK 1.7, create a new file adjacent to your `pom.xml` and `Procfile`,
|
|
called `system.properties`. In this file add the following:
|
|
|
|
[source,java]
|
|
----
|
|
java.runtime.version=1.7
|
|
----
|
|
|
|
This should be everything you need. The most common workflow for Heroku deployments is to
|
|
`git push` the code to production.
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
$ git push heroku master
|
|
|
|
Initializing repository, *done*.
|
|
Counting objects: 95, *done*.
|
|
Delta compression using up to 8 threads.
|
|
Compressing objects: 100% (78/78), *done*.
|
|
Writing objects: 100% (95/95), 8.66 MiB | 606.00 KiB/s, *done*.
|
|
Total 95 (delta 31), reused 0 (delta 0)
|
|
|
|
-----> Java app detected
|
|
-----> Installing OpenJDK 1.7... *done*
|
|
-----> Installing Maven 3.0.3... *done*
|
|
-----> Installing settings.xml... *done*
|
|
-----> executing /app/tmp/cache/.maven/bin/mvn -B
|
|
-Duser.home=/tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229
|
|
-Dmaven.repo.local=/app/tmp/cache/.m2/repository
|
|
-s /app/tmp/cache/.m2/settings.xml -DskipTests=true clean install
|
|
|
|
[INFO] Scanning for projects...
|
|
Downloading: http://repo.spring.io/...
|
|
Downloaded: http://repo.spring.io/... (818 B at 1.8 KB/sec)
|
|
....
|
|
Downloaded: http://s3pository.heroku.com/jvm/... (152 KB at 595.3 KB/sec)
|
|
[INFO] Installing /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/target/...
|
|
[INFO] Installing /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/pom.xml ...
|
|
[INFO] ------------------------------------------------------------------------
|
|
[INFO] *BUILD SUCCESS*
|
|
[INFO] ------------------------------------------------------------------------
|
|
[INFO] Total time: 59.358s
|
|
[INFO] Finished at: Fri Mar 07 07:28:25 UTC 2014
|
|
[INFO] Final Memory: 20M/493M
|
|
[INFO] ------------------------------------------------------------------------
|
|
|
|
-----> Discovering process types
|
|
Procfile declares types -> *web*
|
|
|
|
-----> Compressing... *done*, 70.4MB
|
|
-----> Launching... *done*, v6
|
|
http://agile-sierra-1405.herokuapp.com/ *deployed to Heroku*
|
|
|
|
To git@heroku.com:agile-sierra-1405.git
|
|
* [new branch] master -> master
|
|
----
|
|
|
|
Your application should now be up and running on Heroku.
|
|
|
|
|
|
|
|
[[cloud-deployment-cloudbees]]
|
|
== CloudBees
|
|
CloudBees provides cloud-based "`continuous integration`" and "`continuous delivery`"
|
|
services as well as Java PaaS hosting. https://github.com/msgilligan[Sean Gilligan]
|
|
has contributed an excellent
|
|
https://github.com/CloudBees-community/springboot-gradle-cloudbees-sample[Spring Boot
|
|
sample application] to the CloudBees community GitHub repository. The project includes
|
|
an extensive https://github.com/CloudBees-community/springboot-gradle-cloudbees-sample/blob/master/README.asciidoc[README]
|
|
that covers the steps that you need to follow when deploying to CloudBees.
|
|
|
|
|
|
|
|
[[cloud-deployment-openshift]]
|
|
== Openshift
|
|
https://www.openshift.com/[Openshift] is the RedHat public (and enterprise) PaaS solution.
|
|
Like Heroku, it works by running scripts triggered by git commits, so you can script
|
|
the launching of a Spring Boot application in pretty much any way you like as long as the
|
|
Java runtime is available (which is a standard feature you can ask for at Openshift).
|
|
To do this you can use the
|
|
https://www.openshift.com/developers/do-it-yourself[DIY Cartridge] and hooks in your
|
|
repository under `.openshift/action_scripts`:
|
|
|
|
The basic model is to:
|
|
|
|
1. Ensure Java and your build tool are installed remotely, e.g. using a `pre_build` hook
|
|
(Java and Maven are installed by default, Gradle is not)
|
|
2. Use a `build` hook to build your jar (using Maven or Gradle), e.g.
|
|
+
|
|
[indent=0]
|
|
----
|
|
#!/bin/bash
|
|
cd $OPENSHIFT_REPO_DIR
|
|
mvn package -s .openshift/settings.xml -DskipTests=true
|
|
----
|
|
+
|
|
3. Add a `start` hook that calls `java -jar ...`
|
|
+
|
|
[indent=0]
|
|
----
|
|
#!/bin/bash
|
|
cd $OPENSHIFT_REPO_DIR
|
|
nohup java -jar target/*.jar --server.port=${OPENSHIFT_DIY_PORT} --server.address=${OPENSHIFT_DIY_IP} &
|
|
----
|
|
+
|
|
4. Use a `stop` hook (since the start is supposed to return cleanly), e.g.
|
|
+
|
|
[indent=0]
|
|
----
|
|
#!/bin/bash
|
|
source $OPENSHIFT_CARTRIDGE_SDK_BASH
|
|
PID=$(ps -ef | grep java.*\.jar | grep -v grep | awk '{ print $2 }')
|
|
if [ -z "$PID" ]
|
|
then
|
|
client_result "Application is already stopped"
|
|
else
|
|
kill $PID
|
|
fi
|
|
----
|
|
+
|
|
5. Embed service bindings from environment variables provided by the platform
|
|
in your `application.properties`, e.g.
|
|
+
|
|
[indent=0]
|
|
----
|
|
spring.datasource.url: jdbc:mysql://${OPENSHIFT_MYSQL_DB_HOST}:${OPENSHIFT_MYSQL_DB_PORT}/${OPENSHIFT_APP_NAME}
|
|
spring.datasource.username: ${OPENSHIFT_MYSQL_DB_USERNAME}
|
|
spring.datasource.password: ${OPENSHIFT_MYSQL_DB_PASSWORD}
|
|
----
|
|
|
|
There's a blog on https://www.openshift.com/blogs/run-gradle-builds-on-openshift[running
|
|
Gradle in Openshift] on their website that will get you started with a gradle build to
|
|
run the app. A http://issues.gradle.org/browse/GRADLE-2871[bug in Gradle] currently
|
|
prevents you from using Gradle newer than 1.6.
|
|
|
|
|
|
[[cloud-deployment-gae]]
|
|
== Google App Engine
|
|
Google App Engine is tied to the Servlet 2.5 API, so you can't deploy a Spring Application
|
|
there without some modifications. See the <<howto.adoc#howto-servlet-2-5, Servlet 2.5 section>> of this guide.
|
|
|
|
[[cloud-deployment-whats-next]]
|
|
== What to read next
|
|
Check out the http://www.cloudfoundry.com/[Cloud Foundry], https://www.heroku.com/[Heroku]
|
|
and http://www.cloudbees.com[CloudBees] web sites for more information about the kinds of
|
|
features that a PaaS can offer. These are just three of the most popular Java PaaS
|
|
providers, since Spring Boot is so amenable to cloud-based deployment you're free to
|
|
consider other providers as well.
|
|
|
|
The next section goes on to cover the _<<spring-boot-cli.adoc#cli, Spring Boot CLI>>_;
|
|
or you can jump ahead to read about
|
|
_<<build-tool-plugins.adoc#build-tool-plugins, build tool plugins>>_.
|
|
|
|
|
|
|
|
|