Post on 16-Apr-2017
12 FactorAppBest Practices for Java Deployment
You might not like what I have to say
Modern Java Deployment
.war
Traditional Java Deployment
.jar
Modern Java Deployment
Make JAR
Not WAR
2005 2015
WAR files JAR files
App Servers Microservices
Hot Deploy Continuous Deploy
Server in a closet Heroku/AWS/etc
Joe Kutner@codefinger
JVM Platform Owner
12 Factor Appa methodology
ScalabilityMaintainability
Portability
Immutable Ephemeral Declarative Automated
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
Use version control
BAD
BAD
App #1 App #2
pom.xml
<project> ... <modules> <module>my-app</module> <module>my-other-app</module> </modules><project>
Submodules
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
Never rely on implicit existence of system-wide
packages
Explicitly declare and isolate
dependencies
Don’t check JAR files
into Git
https://bintray.com/
Agent JARs
pom.xml<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.6</version> <executions> <execution> <id>copy-new-relic</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <includeGroupIds>com.newrelic.agent.java</includeGroupIds> <includeArtifactIds>newrelic-agent</includeArtifactIds> <stripVersion>true</stripVersion> </configuration> </execution> </executions></plugin>
build.gradle
task copyToLib(type: Copy) { into "$buildDir/server" from(configurations.compile) { include "jetty-runner*" }}
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
• Resource handles to the database, memcached, and other backing services
• Credentials to external services such as Amazon S3 or Twitter
• Per-deploy values such as the canonical hostname for the deploy
Anything that changes between deployment environments:
(does not include things like conf/routes)
Configuration is…
Configuration should be strictly separated
from code
Don’t check passwords into Git
Configuration belongs in the environment, not in the application
applicationContext.xml
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id=“dataSource">
<property name="driverClassName" value="org.postgresql.Driver"/> <property name="url" value=“${JDBC_DATABASE_URL}"/>
// ...
application.conf
db.default.url=${DATABASE_URL}
Can you make your app open source at any moment, without compromising
any credentials?
Litmus Test
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
application.conf
db.default.url=${DATABASE_URL}
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
build, release, run
$ mvn clean install
$ sbt stage
$ ./gradlew build
build
$ heroku deploy:jar -j myapp.war
$ mvn heroku:deploy
$ docker push ...
release
$ java -jar myapp.war
$ build/install/myapp/bin/myapp.bat
run
$ mvn jetty:run
$ service tomcat start
$ cp myapp.war TOMCAT_HOME/webapps/
$ git push heroku masterbuild,
release,& run
DemoTime
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
Processes should be stateless
sticky sessions 😞
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
The twelve-factor app is completely self-contained
The web app exports HTTP as a service by binding to a port
.war
Traditional Deployment
.jar
Modern Deployment
Dropwizard
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
Relax bro, I got this…
java.util.concurrent
RxJava
java.util.stream
Scale Up
Scale Out
web.1
web.2
worker.1 clock.1
Workload Diversity
Num
ber o
f Pro
cess
es
worker.2
worker.3
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
Graceful shutdown
Quick startup
Resilience to failure
Servers are not pets
Servers are cattle
Application Servers are pets
Application Servers are not disposable
Microservices are cattle
Microservices are disposable
Easy to replace
Decoupled from external infrastructure
Easy to modify
Microservices
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
dev stage prod= =
dev
sqlite
stage
mysql
prod
postgres
=
≠
=
≠
dev
sqlite
postgres
stage
mysql
postgres
prod
postgres
postgres
=
≠
=
=
≠
=
dev
tomcat
jetty
stage
tomcat
jetty
prod
jboss
jetty
=
≠
=
=
≠
=
.jar
disposability⇒reproducibility
parity⇒
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
Admin tasks should be run
in isolated processes
$ heroku run bashRunning `bash` attached to terminal... up, run.1594~ $
web1
web2
web3
admin
• Codebase• Dependencies• Config• Backing services• Build, release, run• Processes
• Port Binding• Concurrency• Disposability• Dev/Prod Parity• Logs• Admin Processes
12 Factor App
Create a bintray.com account1.
set JDBC_DATABASE_URL=jdbc:postgres://…2.
Measure your app’s boot time3.
Click a Heroku button4.
What next?
https://github.com/britter/spring-boot-heroku-demo
Joe Kutner@codefinger
JVM Platform Owner
(http://www.slideshare.net/jkutner/javaone-2015-12-factor-app)http://bit.ly/1PSRxcm