Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Container-less Java services

Container-less Java services

Development and deployment strategies for building container-less apps in Java inspired by lessons from the 12 Factor App, a methodology for building software-as-a-service apps for the cloud.

Cross posted from https://slides.com/gilday/container-less-java-services

Johnathan Gilday

July 14, 2016
Tweet

More Decks by Johnathan Gilday

Other Decks in Technology

Transcript

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

    View Slide

  2. 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

    View Slide

  3. 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

    View Slide

  4. 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

    View Slide

  5. 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
    }
    }

    View Slide

  6. When are
    When are
    containers
    containers
    helpful?
    helpful?

    View Slide

  7. 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

    View Slide

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

    View Slide

  9. 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)

    View Slide

  10. 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

    View Slide

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

    View Slide

  12. 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

    View Slide

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

    View Slide

  14. 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

    View Slide

  15. 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

    View Slide

  16. 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

    View Slide

  17. 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

    View Slide

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

    View Slide

  19. 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

    View Slide

  20. don't forget journald
    don't forget journald
    [[email protected] ~]$ 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

    View Slide

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

    View Slide

  22. 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

    View Slide

  23. 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

    View Slide

  24. Test RPM with Vagrant
    Test RPM with Vagrant
    Vagrant.configure(2) do |config|
    config.vm.box = "geerlingguy/centos7"
    ...
    config.vm.provision "shell", inline: <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

    View Slide

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

    View Slide

  26. 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

    View Slide

  27. 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

    View Slide