12 Factor App Best Practices for JVM Deployment
12 Factor AppBest Practices for JVM Deployment
12 Factor AppBest Practices for JVM Deployment
Java doesn’t suck when you do things this way
Java Servlet API 2.2 includes one new feature so significant it may change the way the Web works. That feature: Web applications.
- Javaworld.com, 1999
“”
With Web apps, the entire application can be contained in a single archive file and deployed by placing the file into a specific directory.
- Javaworld.com, 1999
“”
.war
Traditional JVM Deployment
.war
Modern JVM Deployment
JavaDoesn’t
Suck
12 Factor App
Joe Kutner@codefinger
JVM Langs Owner@Heroku
Joe Kutner
12 Factor Appa methodology
ScalabilityMaintainability
Portability
The 12 Factors• Codebase
• Dependencies
• Config
• Backing services
• Build, release, run
• Processes
• Port binding
• Concurrency
• Disposability
• Dev/prod parity
• Logs
• Admin processes
The 12 Factors• Codebase
• Dependencies
• Config
• Backing services
• Build, release, run
• Processes
• Port binding
• Concurrency
• Disposability
• Dev/prod parity
• Logs
• Admin processes
Graceful shutdown
Quick startup
Resilience to failure
| Disposability |
Application Servers…
| Disposability |
Application Servers are not disposable
| Disposability |
| Disposability |
Microservices are disposable
| Disposability |
Microservices
JavaGroovy
ScalaClojure
Scala Scala
Bootable ➤ Disposable
| Disposability |
The 12 Factors• Codebase
• Dependencies
• Config
• Backing services
• Build, release, run
• Processes
• Port binding
• Concurrency
• Disposability
• Dev/prod parity
• Logs
• Admin processes
dev
sqlite
postgres
stage
mysql
postgres
prod
postgres
postgres
=
≠
=
=
≠
=
| Disposable | Parity |
dev
files
files
stage
files
files
prod
war
files
=
≠
=
=
≠
=
| Disposable | Parity |
dev
jetty
jetty
stage
tomcat
jetty
prod
jboss
jetty
=
≠
=
=
≠
=
| Disposable | Parity |
| Disposable | Parity |
dev
jetty
{}
stage
tomcat
{}
prod
jboss
{}
=
≠
=
=
≠
=
.war
Traditional JVM Deployment
.jar
Modern JVM Deployment
Reproducible ➤ Parity
| Disposable | Parity |
Reproducible ➤ Disposable
| Disposable | Parity |
The 12 Factors• Codebase
• Dependencies
• Config
• Backing services
• Build, release, run
• Processes
• Port binding
• Concurrency
• Disposability
• Dev/prod parity
• Logs
• Admin processes
Configuration belongs in the environment,
not in the application
Configuration should be strictly separated
from code
| Disposable | Parity | Config |
Linux
Tomcat
WAR
server.xml
context.xml
web.xml
/etc/...
| Disposable | Parity | Config |
Environment
Java Application
PATH
DATABASE_URL
AWS_ACCESS_TOKEN
JAVA_OPTS
| Disposable | Parity | Config |
Containerless ➤ Separation
| Disposable | Parity | Config |
Containerless ➤ Parity
| Disposable | Parity | Config |
Containerless ➤ Disposable
| Disposable | Parity | Config |
Containerless ➤ 12 Factor App
| Disposable | Parity | Config |
Containerless Containerless Containerless
| Disposable | Parity | Config |
The container is deadLong live the container
DockerHeroku
Docker+Heroku
Application Server
Servlet Container
Docker
Host OS
Gue
st O
S
App
Gue
st O
S
App
Traditional Virtualization
Hypervisor
Host OS
App App App App
Docker Containers
Con
tain
er
Con
tain
er
Con
tain
er
Con
tain
er
Docker Engine
App App App App
Host OS
Dyn
o
Dyn
o
Dyn
o
Dyn
o
Heroku Dynos
Heroku
App App App App
Host OS
Dyn
o
Dyn
o
Dyn
o
Dyn
o
Heroku Dynos
HerokuSlug
Host OS
App App App App
Docker Containers
Con
tain
er
Con
tain
er
Con
tain
er
Con
tain
er
Docker EngineImage
Dockerize!
FROM heroku/cedar:14
...
RUN /opt/heroku/bin/setup.sh /opt/heroku
...
ENTRYPOINT /opt/heroku/bin/run.sh
Dockerfile
https://github.com/jkutner/heroku-java-docker
REPRODUCIB
LE
Base Image ➤
InstallJava
➤
Run App ➤
web: java -cp target/app.jar com.foo.Main
Procfile
https://github.com/jkutner/heroku-java-docker
BOOTABLE
@Configuration@EnableAutoConfiguration@ComponentScanpublic class Main { public static void main(String[] args) { SpringApplication.run(Main.class, args); }}
CONTAINERL
ESS
import org.eclipse.jetty.server.Server;import org.eclipse.jetty.servlet.*;
public class Main { public static void main(String[] args) throws Exception { Server server = new Server(); ServletContextHandler context = new ServletContextHandler( ServletContextHandler.SESSIONS); context.setContextPath("/"); server.setHandler(context); context.addServlet(new ServletHolder(new App()), "/*"); server.start(); server.join(); }}
(defn -main [& [port]] (jetty/run-jetty (site #'app) {:port port :join? false}))
// Play example does not require any code
Dropwizard
Demo…
Host OS
Docker EngineImage
$ docker build ...
Host OS
Docker EngineImage
App
Con
tain
er
$ docker run ...$ docker build ...
Host OS
App
Con
tain
er
Docker EngineImage
App
Con
tain
er
App App
Con
tain
er
Con
tain
er
$ docker run ...$ docker build ...
$ docker run ...
Host OS
Docker Engine
$ docker run ...$ docker build ...
$ docker run ...
The 12 Factors• Codebase
• Dependencies
• Config
• Backing services
• Build, release, run
• Processes
• Port binding
• Concurrency
• Disposability
• Dev/prod parity
• Logs
• Admin processes
| Disposable | Parity | Config | Admin |
Admin tasks should be run in isolated processes
web1
web2
web3
admin
| Disposable | Parity | Config | Admin |
The 12 Factors• Codebase
• Dependencies
• Config
• Backing services
• Build, release, run
• Processes
• Port binding
• Concurrency
• Disposability
• Dev/prod parity
• Logs
• Admin processes
| Disposable | Parity | Config | Admin | Concurrency |
Scale UpAND
Scale Out
| Disposable | Parity | Config | Admin | Concurrency |
web.1
web.2
worker.1 clock.1
Workload Diversity
Num
ber o
f Pro
cess
es
worker.2
worker.3
TAKE AWAYS!
• Install the JDK• Clone the SCM repo• Run the app
1) Three Steps to Setup
• Get a stopwatch• Time your app’s startup• Get it under 30 seconds
2) Make Startup Quick
• Provision a new environment, deploy the app,handle requests
3) Deploy in One Step
http://12factor.net
Joe Kutner@codefinger
JVM Languages Owner@Heroku