Slide 1

Slide 1 text

Self-contained Java Self-contained Java services services Johnathan Gilday Next Century Corporation 2016-07-14

Slide 2

Slide 2 text

Some motivation Some motivation At , we build a lot of services for our customers, often in Java Our services are getting trimmer and more plentiful Our development teams continue to become more involved with the infrastructure management and production operations We need to optimize the way we build and deploy these services. Abandoning the shared application container is one way Next Century

Slide 3

Slide 3 text

What do I mean by What do I mean by container? container? Also called "application server" One process Manages one or more archives (WAR, EAR) Examples: Apache Tomcat, Wildfly, Glassfish

Slide 4

Slide 4 text

To deploy application To deploy application archives to running archives to running containers: containers: 1. Install container 2. Build WAR 3. Push WAR to container

Slide 5

Slide 5 text

Containers Manage your Containers Manage your app's lifecycle app's lifecycle @WebListener public class AppInitializer implements ServletContextListener { @Override public void contextInitialized(final ServletContextEvent sce) { // container calls this method to initialize app } @Override public void contextDestroyed(final ServletContextEvent sce) { // container calls this method to shutdown app } } @WebServlet(name = "my-servlet", urlPatterns = "/my-servlet") public class MyServlet extends HttpServlet { @Override public void doGet(final HttpServletRequest req, final HttpServletResponse resp) { // container calls this method on incoming request } }

Slide 6

Slide 6 text

When are When are containers containers helpful? helpful?

Slide 7

Slide 7 text

Development Team Development Team Delivers a packaged application with dependencies outside of those provided by the container Delivers a configuration files and documentation for running the service Operations Team Operations Team Configures the operating system Configures the container May run multiple applications on the container Containers work best when there is a clear Containers work best when there is a clear separation of responsibilities between teams separation of responsibilities between teams developing and maintaining the application developing and maintaining the application

Slide 8

Slide 8 text

What if What if there's just there's just one team? one team?

Slide 9

Slide 9 text

Discrepancies between Discrepancies between application and container application and container cause headaches cause headaches Logging Configuration Dependencies (classpath) Test environments (mvn jetty:run vs container)

Slide 10

Slide 10 text

Environment discrepancies Environment discrepancies cause headaches cause headaches Different versions of dependencies on the classpath Example: container provides a different version of servlet than the one used in testing Containers use varying strategies for classpath loading

Slide 11

Slide 11 text

Proposed Solution: Proposed Solution: Deliver Deliver self- self- contained contained applications applications

Slide 12

Slide 12 text

Self-contained apps Self-contained apps Live in their own process Embed their own web server Embed all their own dependencies Define their own means of configuration

Slide 13

Slide 13 text

What does What does developing developing a a self-contained self-contained app look like? app look like?

Slide 14

Slide 14 text

Runs in its own process Runs in its own process /** * Point of entry. Configure and start app */ public class App { public static void main(final String[] args) { // configure application // register signal handlers if desired // run web server until app terminates } } Embraces Unix process model: use of environment variables, command-line args, signals, STDOUT, STDERR Easy to run Development and Production parity

Slide 15

Slide 15 text

Embeds its own server Embeds its own server public static void main(final String[] args) { // start jetty logger.info("listening on port {}", port); final ResoureConfig rc = ResourceConfig.forApplication(app); final Server server = JettyHttpContainerFactory.createServer(baseUri, rc); try { server.start(); server.join(); } catch (Exception e) { throw new RuntimeException(e); } } "Don’t deploy your application in Jetty, deploy Jetty in your application!" Integrates well with Jersey via JettyHttpContainerFactory Jetty is not the only solution, but it’s mature and lightweight

Slide 16

Slide 16 text

Bundles its dependencies Bundles its dependencies $ gradle shadowJar $ java -jar build/libs/my-app.jar listening on port 8000 Sometimes called "fat jar", "uber jar", or "shadow jar" Prefer all dependencies bundled together: we don't want dependencies to change after building Easier than using shell scripts to build up a classpath argument for java Include main class in jar manifest

Slide 17

Slide 17 text

Logs to STDOUT Logs to STDOUT %-5level %logger{5} - %msg%n Easy debugging One stream of log statements with flexible downstream processing Let production environment worry about filtering, rotation

Slide 18

Slide 18 text

What does What does running running a self- a self- contained app contained app look like? look like?

Slide 19

Slide 19 text

systemd managed daemon systemd managed daemon [Unit] Description=my-app service [Service] EnvironmentFile=-/etc/sysconfig/my-app ExecStart=/usr/bin/java \$JVM_OPTS -jar /opt/my-app/my-app-${version}-all.jar User=my-app Restart=on-failure [Install] WantedBy=multi-user.target Much easier than systemctl for start, stop, status, restart Automatic start on system boot Note: same command to start as used in development init scripts

Slide 20

Slide 20 text

don't forget journald don't forget journald [vagrant@localhost ~]$ journalctl -fu how-to-microservice -- Logs begin at Thu 2016-07-14 00:07:10 UTC. -- Jul 14 00:08:44 localhost.localdomain systemd[1]: Started how-to-microservice ser Jul 14 00:08:44 localhost.localdomain systemd[1]: Starting how-to-microservice se Jul 14 00:08:44 localhost.localdomain java[11726]: 2016-07-14T00:08:44,718Z INFO Captures STDOUT, STDERR from systemd managed daemons Easy to tail and grep your app's logs Highly configurable: log rotation, format, forwarding

Slide 21

Slide 21 text

What does What does deploying deploying a a self-contained self-contained app look like? app look like?

Slide 22

Slide 22 text

RPM RPM $ rpm -qlp build/distributions/how-to-microservice-0.0.4-1.e7.noarch.rpm /etc/how-to-microservice /etc/how-to-microservice/settings.conf /etc/sysconfig /etc/sysconfig/how-to-microservice /etc/systemd /etc/systemd/system /etc/systemd/system/how-to-microservice.service /opt/how-to-microservice /opt/how-to-microservice/how-to-microservice-0.0.4-SNAPSHOT-all.jar /opt/how-to-microservice/settings.conf Packages user install, config file template, systemd unit file, binaries, package dependencies (java) Host your own yum repository for easy updates (jenkins, Nexus) Establishes a common means for deploying your container-less apps

Slide 23

Slide 23 text

Build RPM with Gradle Build RPM with Gradle task rpm(type: Rpm) { it.dependsOn shadowJar packageName = project.name version = '0.0.4' release = '1.e7' os = LINUX requires('java-1.8.0-openjdk') ... Netflix OSS nebula-ospackage-plugin gradle plugin Builds deb and rpm Host your own yum repository with Nexus, deploy with Gradle

Slide 24

Slide 24 text

Test RPM with Vagrant Test RPM with Vagrant Vagrant.configure(2) do |config| config.vm.box = "geerlingguy/centos7" ... config.vm.provision "shell", inline: <<-SHELL sync_dir=/vagrant rpm=($sync_dir/build/distributions/*.rpm) if [ ! -f $rpm ]; then echo "how-to-microservice RPM not found" exit 1 fi sudo yum erase -y how-to-microservice sudo yum install -y $rpm sudo systemctl restart how-to-microservice SHELL end Vagrant defines development virtual machines with Ruby DSL Vagrant shell provisioner installs RPM in the Vagrant virtual machine Rebuild virtual machine: vagrant destroy ­f && vagrant up

Slide 25

Slide 25 text

What does What does dockerizing dockerizing a a self-contained self-contained app look like? app look like?

Slide 26

Slide 26 text

Dockerfile Dockerfile FROM java:8 MAINTAINER Johnathan Gilday COPY ./build/libs/how-to-microservice.jar /opt/how-to-microservice/ EXPOSE 8000 WORKDIR /opt/how-to-microservice CMD ["java", "-jar", "how-to-microservice.jar"] Manage a docker container instead of a systemd service Manage logs with docker log driver instead of journald Deploy a docker image instead of an RPM

Slide 27

Slide 27 text

Thanks! Thanks! Sample self-contained jersey service Gradle plugin for building "fat jars" Netflix OSS Gradle plugins (including gradle-os-package) Nexus yum repository hosting Vagrant shell provisioner https://github.com/gilday/how-to-microservice https://github.com/johnrengelman/shadow https://nebula-plugins.github.io/ https://books.sonatype.com/nexus-book/reference/yum-configuration.html https://www.vagrantup.com/docs/provisioning/shell.html