899 lines
33 KiB
Plaintext
899 lines
33 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 web server,
|
|
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 Version: v3.12 (offline) | https://github.com/cloudfoundry/java-buildpack.git#6f25b7e
|
|
-----> Downloading Open Jdk JRE 1.8.0_121 from https://java-buildpack.cloudfoundry.org/openjdk/trusty/x86_64/openjdk-1.8.0_121.tar.gz (found in cache)
|
|
Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (1.6s)
|
|
-----> Downloading Open JDK Like Memory Calculator 2.0.2_RELEASE from https://java-buildpack.cloudfoundry.org/memory-calculator/trusty/x86_64/memory-calculator-2.0.2_RELEASE.tar.gz (found in cache)
|
|
Memory Settings: -Xss349K -Xmx681574K -XX:MaxMetaspaceSize=104857K -Xms681574K -XX:MetaspaceSize=104857K
|
|
-----> Downloading Container Certificate Trust Store 1.0.0_RELEASE from https://java-buildpack.cloudfoundry.org/container-certificate-trust-store/container-certificate-trust-store-1.0.0_RELEASE.jar (found in cache)
|
|
Adding certificates to .java-buildpack/container_certificate_trust_store/truststore.jks (0.6s)
|
|
-----> Downloading Spring Auto Reconfiguration 1.10.0_RELEASE from https://java-buildpack.cloudfoundry.org/auto-reconfiguration/auto-reconfiguration-1.10.0_RELEASE.jar (found in cache)
|
|
Checking status of app 'acloudyspringtime'...
|
|
0 of 1 instances running (1 starting)
|
|
...
|
|
0 of 1 instances running (1 starting)
|
|
...
|
|
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 `CloudFoundryVcapEnvironmentPostProcessor`
|
|
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.
|
|
|
|
|
|
|
|
[[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.
|
|
|
|
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_hooks`:
|
|
|
|
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-aws]]
|
|
=== Amazon Web Services (AWS)
|
|
Amazon Web Services offers multiple ways to install Spring Boot based applications, either
|
|
as traditional web applications (war) or as executable jar files with an embedded web
|
|
server. Options include :
|
|
|
|
* AWS Elastic Beanstalk
|
|
* AWS Code Deploy
|
|
* AWS OPS Works
|
|
* AWS Cloud Formation
|
|
* AWS Container Registry
|
|
|
|
Each has different features and pricing model, here we will describe only the simplest
|
|
option : AWS Elastic Beanstalk.
|
|
|
|
|
|
|
|
==== AWS Elastic Beanstalk
|
|
As described in the official http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_Java.html[Elastic
|
|
Beanstalk Java guide], there are two main options to deploy a Java application; You can
|
|
either use the "`Tomcat Platform`" or the "`Java SE platform`".
|
|
|
|
|
|
|
|
===== Using the Tomcat platform
|
|
This option applies to Spring Boot projects producing a war file. There is no any special
|
|
configuration required, just follow the official guide.
|
|
|
|
|
|
|
|
===== Using the Java SE platform
|
|
This option applies to Spring Boot projects producing a jar file and running an embedded
|
|
web container. Elastic Beanstalk environments run an nginx instance on port 80 to proxy
|
|
the actual application, running on port 5000. To configure it, add the following to your
|
|
`application.properties`:
|
|
|
|
[indent=0]
|
|
----
|
|
server.port=5000
|
|
----
|
|
|
|
|
|
|
|
===== Best practices
|
|
|
|
====== Uploading binaries instead of sources
|
|
By default Elastic Beanstalk uploads sources and compiles them in AWS. To upload the
|
|
binaries instead, add the following to your `.elasticbeanstalk/config.yml` file:
|
|
|
|
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
deploy:
|
|
artifact: target/demo-0.0.1-SNAPSHOT.jar
|
|
----
|
|
|
|
|
|
|
|
====== Reduce costs by setting the environment type
|
|
By default an Elastic Beanstalk environment is load balanced. The load balancer has a cost
|
|
perspective, to avoid it, set the environment type to "`Single instance`" as described
|
|
http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-create-wizard.html#environments-create-wizard-capacity[in the Amazon documentation].
|
|
Single instance environments can be created using the CLI as well using the following
|
|
command:
|
|
|
|
[indent=0]
|
|
----
|
|
eb create -s
|
|
----
|
|
|
|
|
|
|
|
==== Summary
|
|
This is one of the easiest ways to get to AWS, but there are more things
|
|
to cover, e.g.: how to integrate Elastic Beanstalk into any CI / CD tool, using the
|
|
Elastic Beanstalk maven plugin instead of the CLI, etc. There is a
|
|
https://exampledriven.wordpress.com/2017/01/09/spring-boot-aws-elastic-beanstalk-example/[blog]
|
|
covering these topics more in detail.
|
|
|
|
|
|
|
|
[[cloud-deployment-boxfuse]]
|
|
=== Boxfuse and Amazon Web Services
|
|
https://boxfuse.com/[Boxfuse] works by turning your Spring Boot executable jar or war
|
|
into a minimal VM image that can be deployed unchanged either on VirtualBox or on AWS.
|
|
Boxfuse comes with deep integration for Spring Boot and will use the information from your
|
|
Spring Boot configuration file to automatically configure ports and health check URLs.
|
|
Boxfuse leverages this information both for the images it produces as well as for all the
|
|
resources it provisions (instances, security groups, elastic load balancers, etc).
|
|
|
|
Once you have created a https://console.boxfuse.com[Boxfuse account], connected it to your
|
|
AWS account, and installed the latest version of the Boxfuse Client, you can deploy your
|
|
Spring Boot application to AWS as follows (ensure the application has been built by
|
|
Maven or Gradle first using, for example, `mvn clean package`):
|
|
|
|
[indent=0]
|
|
----
|
|
$ boxfuse run myapp-1.0.jar -env=prod
|
|
----
|
|
|
|
See the https://boxfuse.com/docs/commandline/run.html[`boxfuse run` documentation] for
|
|
more options. If there is a https://boxfuse.com/docs/commandline/#configuration
|
|
[`boxfuse.conf`] file present in the current directory, it will be consulted.
|
|
|
|
TIP: By default Boxfuse will activate a Spring profile named `boxfuse` on startup and if
|
|
your executable jar or war contains an
|
|
https://boxfuse.com/docs/payloads/springboot.html#configuration
|
|
[`application-boxfuse.properties`]
|
|
file, Boxfuse will base its configuration based on the properties it contains.
|
|
|
|
At this point `boxfuse` will create an image for your application, upload it,
|
|
and then configure and start the necessary resources on AWS:
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
Fusing Image for myapp-1.0.jar ...
|
|
Image fused in 00:06.838s (53937 K) -> axelfontaine/myapp:1.0
|
|
Creating axelfontaine/myapp ...
|
|
Pushing axelfontaine/myapp:1.0 ...
|
|
Verifying axelfontaine/myapp:1.0 ...
|
|
Creating Elastic IP ...
|
|
Mapping myapp-axelfontaine.boxfuse.io to 52.28.233.167 ...
|
|
Waiting for AWS to create an AMI for axelfontaine/myapp:1.0 in eu-central-1 (this may take up to 50 seconds) ...
|
|
AMI created in 00:23.557s -> ami-d23f38cf
|
|
Creating security group boxfuse-sg_axelfontaine/myapp:1.0 ...
|
|
Launching t2.micro instance of axelfontaine/myapp:1.0 (ami-d23f38cf) in eu-central-1 ...
|
|
Instance launched in 00:30.306s -> i-92ef9f53
|
|
Waiting for AWS to boot Instance i-92ef9f53 and Payload to start at http://52.28.235.61/ ...
|
|
Payload started in 00:29.266s -> http://52.28.235.61/
|
|
Remapping Elastic IP 52.28.233.167 to i-92ef9f53 ...
|
|
Waiting 15s for AWS to complete Elastic IP Zero Downtime transition ...
|
|
Deployment completed successfully. axelfontaine/myapp:1.0 is up and running at http://myapp-axelfontaine.boxfuse.io/
|
|
----
|
|
|
|
Your application should now be up and running on AWS.
|
|
|
|
There's a blog on https://boxfuse.com/blog/spring-boot-ec2.html[deploying Spring Boot apps
|
|
on EC2] as well as https://boxfuse.com/docs/payloads/springboot.html[documentation
|
|
for the Boxfuse Spring Boot integration] on their website that will get you started with a
|
|
Maven build to run the app.
|
|
|
|
|
|
|
|
[[cloud-deployment-gae]]
|
|
=== Google Cloud
|
|
Google Cloud has several options that could be used to launch Spring Boot applications.
|
|
The easiest to get started with is probably App Engine, but you could also find ways to
|
|
run Spring Boot in a container with Container Engine, or on a virtual machine using
|
|
Compute Engine.
|
|
|
|
To run in App Engine you can create a project in the UI first, which sets up a unique
|
|
identifier for you and also HTTP routes. Add a Java app to the project and leave it empty,
|
|
then use the https://cloud.google.com/sdk/downloads[Google Cloud SDK] to push your
|
|
Spring Boot app into that slot from the command line or CI build.
|
|
|
|
App Engine needs you to create an `app.yaml` file to describe the resources your app
|
|
requires. Normally you put this in `src/min/appengine`, and it looks something like this:
|
|
|
|
[source,yaml,indent=0]
|
|
----
|
|
service: default
|
|
|
|
runtime: java
|
|
env: flex
|
|
|
|
runtime_config:
|
|
jdk: openjdk8
|
|
|
|
handlers:
|
|
- url: /.*
|
|
script: this field is required, but ignored
|
|
|
|
manual_scaling:
|
|
instances: 1
|
|
|
|
health_check:
|
|
enable_health_check: False
|
|
|
|
env_variables:
|
|
ENCRYPT_KEY: your_encryption_key_here
|
|
----
|
|
|
|
You can deploy the app, for example, with a Maven plugin by simply adding the project ID
|
|
to the build configuration:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
<plugin>
|
|
<groupId>com.google.cloud.tools</groupId>
|
|
<artifactId>appengine-maven-plugin</artifactId>
|
|
<version>1.3.0</version>
|
|
<configuration>
|
|
<project>myproject</project>
|
|
</configuration>
|
|
</plugin>
|
|
----
|
|
|
|
Then deploy with `mvn appengine:deploy` (if you need to authenticate first the build will
|
|
fail).
|
|
|
|
NOTE: Google App Engine Classic 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. A fully executable jar can be
|
|
executed like any other executable binary or it can be <<deployment-service,registered
|
|
with `init.d` or `systemd`>>. This makes it very easy to install and manage Spring Boot
|
|
applications in common production environments.
|
|
|
|
WARNING: Fully executable jars work by embedding an extra script at the front of the
|
|
file. Currently, some tools do not accept this format so you may not always be able to
|
|
use this technique. For example, `jar -xf` may silently fail to extract a jar or war that
|
|
has been made fully-executable. It is recommended that you only make your jar or war
|
|
fully executable if you intend to execute it directly, rather than running it with
|
|
`java -jar` or deploying it to a servlet container.
|
|
|
|
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 is:
|
|
|
|
[source,groovy,indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
springBoot {
|
|
executable = true
|
|
}
|
|
----
|
|
|
|
You can then run your application by typing `./my-application.jar` (where
|
|
`my-application` is the name of your artifact). The directory containing the
|
|
jar will be used as your application's working directory.
|
|
|
|
[[deployment-install-supported-operating-systems]]
|
|
=== Supported operating systems
|
|
The default script supports most Linux distributions and is tested on CentOS and
|
|
Ubuntu. Other platforms, such as OS X and FreeBSD, will require the use of a custom
|
|
`embeddedLaunchScript`.
|
|
|
|
|
|
|
|
[[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)
|
|
If you've configured Spring Boot's Maven or Gradle plugin to generate a
|
|
<<deployment-install,fully executable jar>>, and you're not using a custom
|
|
`embeddedLaunchScript`, then your application can be used as an `init.d` service. Simply
|
|
symlink the jar to `init.d` to support the standard `start`, `stop`, `restart` and
|
|
`status` commands.
|
|
|
|
The script supports the following features:
|
|
|
|
* Starts the services as the user that owns the jar file
|
|
* Tracks application's PID 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
|
|
----
|
|
|
|
Once installed, you can start and stop the service in the usual way. For example, on a
|
|
Debian based system:
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
$ service myapp start
|
|
----
|
|
|
|
TIP: If your application fails to start, check the log file written to
|
|
`/var/log/<appname>.log` for errors.
|
|
|
|
You can also flag the application to start automatically using your standard operating
|
|
system tools. For example, on Debian:
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
$ update-rc.d myapp defaults <priority>
|
|
----
|
|
|
|
|
|
|
|
[[deployment-initd-service-securing]]
|
|
===== Securing an init.d service
|
|
|
|
NOTE: The following is a set of guidelines on how to secure a Spring Boot application
|
|
that's being run as an init.d service. It is not intended to be an exhaustive list of
|
|
everything that should be done to harden an application and the environment in which it
|
|
runs.
|
|
|
|
When executed as root, as is the case when root is being used to start an init.d service,
|
|
the default executable script will run the application as the user which owns the jar
|
|
file. You should never run a Spring Boot application as `root` so your application's jar
|
|
file should never be owned by root. Instead, create a specific user to run your
|
|
application and use `chown` to make it the owner of the jar file. For example:
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
$ chown bootapp:bootapp your-app.jar
|
|
----
|
|
|
|
In this case, the default executable script will run the application as the `bootapp`
|
|
user.
|
|
|
|
TIP: To reduce the chances of the application's user account being compromised, you should
|
|
consider preventing it from using a login shell. Set the account's shell to
|
|
`/usr/sbin/nologin`, for example.
|
|
|
|
You should also take steps to prevent the modification of your application's jar file.
|
|
Firstly, configure its permissions so that it cannot be written and can only be read or
|
|
executed by its owner:
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
$ chmod 500 your-app.jar
|
|
----
|
|
|
|
Secondly, you should also take steps to limit the damage if your application or the
|
|
account that's running it is compromised. If an attacker does gain access, they could make
|
|
the jar file writable and change its contents. One way to protect against this is to make
|
|
it immutable using `chattr`:
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
$ sudo chattr +i your-app.jar
|
|
----
|
|
|
|
This will prevent any user, including root, from modifying the jar.
|
|
|
|
If root is used to control the application's service and you
|
|
<<deployment-script-customization-conf-file, use a `.conf` file>> to customize its
|
|
startup, the `.conf` file will be read and evaluated by the root user. It should be
|
|
secured accordingly. Use `chmod` so that the file can only be read by the owner and use
|
|
`chown` to make root the owner:
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
$ chmod 400 your-app.conf
|
|
$ sudo chown root:root your-app.conf
|
|
----
|
|
|
|
|
|
|
|
[[deployment-systemd-service]]
|
|
==== Installation as a systemd service
|
|
Systemd is the successor of the System V init system, and is now being used by many modern
|
|
Linux distributions. Although you can continue to use `init.d` scripts with `systemd`, it
|
|
is also possible to launch Spring Boot applications using `systemd` '`service`' scripts.
|
|
|
|
Assuming that you have a Spring Boot application installed in `/var/myapp`, to install a
|
|
Spring Boot application as a `systemd` service create a script named `myapp.service` using
|
|
the following example and place it in `/etc/systemd/system` directory:
|
|
|
|
[indent=0]
|
|
----
|
|
[Unit]
|
|
Description=myapp
|
|
After=syslog.target
|
|
|
|
[Service]
|
|
User=myapp
|
|
ExecStart=/var/myapp/myapp.jar
|
|
SuccessExitStatus=143
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
----
|
|
|
|
TIP: Remember to change the `Description`, `User` and `ExecStart` fields for your
|
|
application.
|
|
|
|
TIP: Note that `ExecStart` field does not declare the script action command, which means
|
|
that `run` command is used by default.
|
|
|
|
Note that unlike when running as an `init.d` service, user that runs the application, PID
|
|
file and console log file are managed by `systemd` itself and therefore must be configured
|
|
using appropriate fields in '`service`' script. Consult the
|
|
http://www.freedesktop.org/software/systemd/man/systemd.service.html[service unit
|
|
configuration man page] for more details.
|
|
|
|
To flag the application to start automatically on system boot use the following command:
|
|
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
$ systemctl enable myapp.service
|
|
----
|
|
|
|
Refer to `man systemctl` for more details.
|
|
|
|
|
|
|
|
[[deployment-script-customization]]
|
|
==== Customizing the startup script
|
|
The default embedded startup script written by the Maven or Gradle plugin can be
|
|
customized in a number of ways. For most people, using the default script along with
|
|
a few customizations is usually enough. If you find you can't customize something that
|
|
you need to, you can always use the `embeddedLaunchScript` option to write your own
|
|
file entirely.
|
|
|
|
|
|
|
|
[[deployment-script-customization-when-it-written]]
|
|
===== Customizing script when it's written
|
|
It often makes sense to customize elements of the start script as it's written into the
|
|
jar file. For example, init.d scripts can provide a "`description`" and, since you know
|
|
this up front (and it won't change), you may as well provide it when the jar is generated.
|
|
|
|
To customize written elements, use the `embeddedLaunchScriptProperties` option of the
|
|
Spring Boot Maven or Gradle plugins.
|
|
|
|
The following property substitutions are supported with the default script:
|
|
|
|
[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.
|
|
|
|
|`initInfoRequiredStart`
|
|
|The `Required-Start` section of "`INIT INFO`". Defaults to `$remote_fs $syslog $network`.
|
|
|
|
|`initInfoRequiredStop`
|
|
|The `Required-Stop` section of "`INIT INFO`". Defaults to `$remote_fs $syslog $network`.
|
|
|
|
|
|
|`initInfoDefaultStart`
|
|
|The `Default-Start` section of "`INIT INFO`". Defaults to `2 3 4 5`.
|
|
|
|
|`initInfoDefaultStop`
|
|
|The `Default-Stop` section of "`INIT INFO`". Defaults to `0 1 6`.
|
|
|
|
|`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.
|
|
|
|
|`initInfoChkconfig`
|
|
|The `chkconfig` section of "`INIT INFO`". Defaults to `2345 99 01`.
|
|
|
|
|`confFolder`
|
|
|The default value for `CONF_FOLDER`. Defaults to the folder containing the jar.
|
|
|
|
|`logFolder`
|
|
|The default value for `LOG_FOLDER`. Only valid for an `init.d` service.
|
|
|
|
|`logFilename`
|
|
|The default value for `LOG_FILENAME`. Only valid for an `init.d` service.
|
|
|
|
|`pidFolder`
|
|
|The default value for `PID_FOLDER`. Only valid for an `init.d` service.
|
|
|
|
|`pidFilename`
|
|
|The default value for the name of the pid file in `PID_FOLDER`. Only valid for an
|
|
`init.d` service.
|
|
|
|
|`useStartStopDaemon`
|
|
|If the `start-stop-daemon` command, when it's available, should be used to control the
|
|
process. Defaults to `true`.
|
|
|
|
|`stopWaitTime`
|
|
|The default value for `STOP_WAIT_TIME`. Only valid for an `init.d` service.
|
|
Defaults to 60 seconds.
|
|
|===
|
|
|
|
|
|
[[deployment-script-customization-when-it-runs]]
|
|
===== Customizing script when it runs
|
|
For items of the script that need to be customized _after_ the jar has been written you
|
|
can use environment variables or a
|
|
<<deployment-script-customization-conf-file, config file>>.
|
|
|
|
The following environment properties are supported with the default script:
|
|
|
|
[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.
|
|
|
|
|`USE_START_STOP_DAEMON`
|
|
|If the `start-stop-daemon` command, when it's available, should be used to control the
|
|
process. Defaults to `true`.
|
|
|
|
|`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).
|
|
|
|
|`CONF_FOLDER`
|
|
|The name of the folder to read .conf files from (same folder as jar-file 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.
|
|
|
|
|`STOP_WAIT_TIME`
|
|
|The time in seconds to wait when stopping the application before forcing a shutdown
|
|
(`60` by default).
|
|
|===
|
|
|
|
NOTE: The `PID_FOLDER`, `LOG_FOLDER` and `LOG_FILENAME` variables are only valid for an
|
|
`init.d` service. With `systemd` the equivalent customizations are made using '`service`'
|
|
script. Check the
|
|
http://www.freedesktop.org/software/systemd/man/systemd.service.html[service unit
|
|
configuration man page] for more details.
|
|
|
|
[[deployment-script-customization-conf-file]]
|
|
With the exception of `JARFILE` and `APP_NAME`, the above settings can be configured using
|
|
a `.conf` file. The file is expected 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`.
|
|
|
|
.myapp.conf
|
|
[indent=0,subs="verbatim,quotes,attributes"]
|
|
----
|
|
JAVA_OPTS=-Xmx1024M
|
|
LOG_FOLDER=/custom/log/folder
|
|
----
|
|
|
|
TIP: You can use a `CONF_FOLDER` environment variable to customize the location of the
|
|
config file if you don't like it living next to the jar.
|
|
|
|
To learn about securing this file appropriately, please refer to
|
|
<<deployment-initd-service-securing,the guidelines for securing an init.d service>>.
|
|
|
|
|
|
[[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 step-by-step 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], https://www.openshift.com[OpenShift] and
|
|
https://boxfuse.com[Boxfuse] web sites for more information about the kinds of features
|
|
that a PaaS can offer. These are just four 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>>_.
|
|
|