523 lines
18 KiB
Plaintext
523 lines
18 KiB
Plaintext
[[deployment]]
|
|
= Deploying Spring Boot applications
|
|
|
|
[partintro]
|
|
--
|
|
Spring Boot's flexible packaging options provide a great deal of choice when it comes to
|
|
deploying your application. You can easily deploy Spring Boot applications to a variety
|
|
of cloud platforms, to a container images (such as Docker) or to virtual/real machines.
|
|
|
|
This section covers some of the more common deployment scenarios.
|
|
--
|
|
|
|
|
|
|
|
[[cloud-deployment]]
|
|
== Deploying to the cloud
|
|
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 development 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` Javadoc for
|
|
complete details.
|
|
|
|
TIP: The http://cloud.spring.io/spring-cloud-connectors/[Spring Cloud Connectors] project
|
|
is a better fit for tasks such as configuring a DataSource. Spring Boot includes
|
|
auto-configuration support and a `spring-boot-starter-cloud-connectors` starter POM.
|
|
|
|
|
|
|
|
[[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, Jetty or Undertow 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.8. 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:
|
|
|
|
[indent=0]
|
|
----
|
|
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.8... *done*
|
|
-----> Installing Maven 3.3.1... *done*
|
|
-----> Installing settings.xml... *done*
|
|
-----> Executing: mvn -B -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-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.
|
|
|
|
|
|
|
|
[[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.
|
|
|
|
|
|
|
|
[[deployment-install]]
|
|
== Installing Spring Boot applications
|
|
In additional to running Spring Boot applications using `java -jar` it is also possible
|
|
to make fully executable applications for Unix systems (Linux, OSX, FreeBSD etc).
|
|
This makes it very easy to install and manage Spring Boot applications in common
|
|
production environments. As long as you are generating '`fully executable`' jars from your
|
|
build, and you are not using a custom `embeddedLaunchScript`, the following techniques
|
|
can be used.
|
|
|
|
To create a '`fully executable`' jar with Maven use the following plugin configuration:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
<plugin>
|
|
<groupId>org.springframework.boot</groupId>
|
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
<configuration>
|
|
<executable>true</executable>
|
|
</configuration>
|
|
</plugin>
|
|
----
|
|
|
|
With Gradle, the equivalent configuration would be:
|
|
|
|
[source,groovy,indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
apply plugin: 'spring-boot'
|
|
|
|
springBoot {
|
|
executable = true
|
|
}
|
|
----
|
|
|
|
NOTE: Fully executable jars work by embedding an extra script at the front of the file.
|
|
Not all tools currently accept this format so you may not always be able to use this
|
|
technique.
|
|
|
|
|
|
|
|
[[deployment-service]]
|
|
=== Unix/Linux services
|
|
Spring Boot application can be easily started as Unix/Linux services using either `init.d`
|
|
or `systemd`.
|
|
|
|
|
|
[[deployment-initd-service]]
|
|
==== Installation as an init.d service (System V)
|
|
The default executable script that can be embedded into Spring Boot jars will act as an
|
|
`init.d` script when it is symlinked to `/etc/init.d`. The standard `start`, `stop`,
|
|
`restart` and `status` commands can be used. The script supports the following features:
|
|
|
|
* Starts the services as the user that owns the jar file
|
|
* Tracks application PIDs using `/var/run/<appname>/<appname>.pid`
|
|
* Writes console logs to `/var/log/<appname>.log`
|
|
|
|
Assuming that you have a Spring Boot application installed in `/var/myapp`, to install a
|
|
Spring Boot application as an `init.d` service simply create a symlink:
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
$ sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp
|
|
----
|
|
|
|
TIP: It is advisable to create a specific user account to run you application. Ensure
|
|
that you have set the owner of the jar file using `chown` before installing your service.
|
|
|
|
Once installed, you can start and stop the service in the usual way. You can also flag the
|
|
application to start automatically using your standard operating system tools. For example,
|
|
if you use Debian:
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
$ update-rc.d myapp defaults <priority>
|
|
----
|
|
|
|
|
|
|
|
[[deployment-systemd-service]]
|
|
==== Installation as a systemd service
|
|
Systemd is the successor to `init.d` scripts, and now being used by many many modern Linux
|
|
distributions. Although you can continue to use `init.d` script with `systemd`, it is also
|
|
possible to launch Spring Boot applications using `systemd` '`service`' scripts.
|
|
|
|
For example, to run a Spring Boot application installed in `var/myapp` you can add the
|
|
following script in `/etc/systemd/system/myapp.service`:
|
|
|
|
[indent=0]
|
|
----
|
|
[Unit]
|
|
Description=myapp
|
|
After=syslog.target
|
|
|
|
[Service]
|
|
ExecStart=/var/myapp/myapp.jar
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
----
|
|
|
|
TIP: Remember to change the `Description` and `ExecStart` fields for your application.
|
|
|
|
|
|
|
|
[[deployment-script-customization]]
|
|
==== Customizing the startup script
|
|
The script accepts the following parameters as environment variables, so you can change
|
|
the default behavior in a script or on the command line:
|
|
|
|
[cols="1,6"]
|
|
|===
|
|
|Variable |Description
|
|
|
|
|`MODE`
|
|
|The "`mode`" of operation. The default depends on the way the jar was built, but will
|
|
usually be `auto` _(meaning it tries to guess if it is an init script by checking if it
|
|
is a symlink in a directory called `init.d`)_. You can explicitly set it to `service` so
|
|
that the `stop\|start\|status\|restart` commands work, or to `run` if you just want to
|
|
run the script in the foreground.
|
|
|
|
|`PID_FOLDER`
|
|
|The root name of the pid folder (`/var/run` by default).
|
|
|
|
|`LOG_FOLDER`
|
|
|The name of the folder to put log files in (`/var/log` by default).
|
|
|
|
|`LOG_FILENAME`
|
|
|The name of the log file in the `LOG_FOLDER` (`<appname>.log` by default).
|
|
|
|
|`APP_NAME`
|
|
|The name of the app. If the jar is run from a symlink the script guesses the app name,
|
|
but if it is not a symlink, or you want to explicitly set the app name this can be
|
|
useful.
|
|
|
|
|`RUN_ARGS`
|
|
|The arguments to pass to the program (the Spring Boot app).
|
|
|
|
|`JAVA_HOME`
|
|
|The location of the `java` executable is discovered by using the `PATH` by default, but
|
|
you can set it explicitly if there is an executable file at `$JAVA_HOME/bin/java`.
|
|
|
|
|`JAVA_OPTS`
|
|
|Options that are passed to the JVM when it is launched.
|
|
|
|
|`JARFILE`
|
|
|The explicit location of the jar file, in case the script is being used to launch a jar
|
|
that it is not actually embedded in.
|
|
|
|
|`DEBUG`
|
|
|if not empty will set the `-x` flag on the shell process, making it easy to see the logic
|
|
in the script.
|
|
|===
|
|
|
|
In addition, the following properties can be changed when the script is written by using
|
|
the `embeddedLaunchScriptProperties` option of the Spring Boot Maven or Gradle plugins.
|
|
|
|
[cols="1,6"]
|
|
|===
|
|
|Name |Description
|
|
|
|
|`mode`
|
|
|The script mode. Defaults to `auto`.
|
|
|
|
|`initInfoProvides`
|
|
|The `Provides` section of "`INIT INFO`". Defaults to `spring-boot-application` for Gradle
|
|
and to `${project.artifactId}` for Maven.
|
|
|
|
|`initInfoShortDescription`
|
|
|The `Short-Description` section of "`INIT INFO`". Defaults to `Spring Boot Application`
|
|
for Gradle and to `${project.name}` for Maven.
|
|
|
|
|`initInfoDescription`
|
|
|The `Description` section of "`INIT INFO`". Defaults to `Spring Boot Application` for
|
|
Gradle and to `${project.description}` (falling back to `${project.name}`) for Maven.
|
|
|===
|
|
|
|
|
|
[[deployment-script-customization-conf-file]]
|
|
==== Customizing the startup script with a conf file
|
|
|
|
With the exception of `JARFILE` and `APP_NAME`, the above settings can be configured using
|
|
a `.conf` file,
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
JAVA_OPTS=-Xmx1024M
|
|
LOG_FOLDER=/custom/log/folder
|
|
----
|
|
|
|
The file should be situated next to the jar file and have the same name but suffixed with
|
|
`.conf` rather than `.jar`. For example, a jar named `/var/myapp/myapp.jar` will use the
|
|
configuration file named `/var/myapp/myapp.conf` if it exists.
|
|
|
|
|
|
|
|
[[deployment-windows]]
|
|
=== Microsoft Windows services
|
|
Spring Boot application can be started as Windows service using
|
|
https://github.com/kohsuke/winsw[`winsw`].
|
|
|
|
A sample https://github.com/snicoll-scratches/spring-boot-daemon[maintained separately]
|
|
to the core of Spring Boot describes steps by steps how you can create a Windows service for
|
|
your Spring Boot application.
|
|
|
|
|
|
|
|
|
|
[[deployment-whats-next]]
|
|
== What to read next
|
|
Check out the http://www.cloudfoundry.com/[Cloud Foundry], https://www.heroku.com/[Heroku]
|
|
and https://www.openshift.com[Openshift] 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>>_.
|
|
|