56
@crichardson Deploying Spring Boot applications with Docker Chris Richardson Author of POJOs in Action Founder of the original CloudFoundry.com @crichardson [email protected] http://plainoldobjects.com http://microservices.io

Developing and deploying applications with Spring Boot and Docker (@oakjug)

Embed Size (px)

Citation preview

@crichardson

Deploying Spring Boot applications with DockerChris Richardson

Author of POJOs in Action Founder of the original CloudFoundry.com

@crichardson [email protected] http://plainoldobjects.com http://microservices.io

@crichardson

Presentation goal

Deploying Spring-based microservices using

Docker

@crichardson

About Chris

@crichardson

About Chris

Founder of a startup that’s creating a platform for developing

event-driven microservices (http://bit.ly/trialeventuate)

@crichardson

For more information

https://github.com/cer/event-sourcing-examples

https://github.com/cer/microservices-examples

http://microservices.io

http://plainoldobjects.com/

https://twitter.com/crichardson

@crichardson

Agenda

Introduction to Spring Boot

Why immutable infrastructure/containerization

Spring Boot and Docker

Using Docker Compose to deploy infrastructure

Using Docker Compose to launch your application

Docker-based deployment pipeline

@crichardson

User registration microservices

User Registration

Service

RabbitMQ

MongoDB

POST /user

{ emailAddress: "[email protected]", password: "xyz"}

NewUserNotification

User Management Service Email Service

Exchange

Queue Queue

User Registration

Web App

RegistrationForm

Confirmation page

http://plainoldobjects.com/category/spring-boot/

@crichardson

Spring-based components

@crichardson

Building microservices with Spring Boot

Makes it easy to create stand-alone, production ready Spring applications

Automatically configures Spring using Convention over Configuration

Externalizes configuration

Generates standalone executable JARs with embedded web server

Provides a standard foundation for all your microservices

@crichardson

Spring Boot simplifies configuration

Spring Container

Application components

Fully configured application

Configuration Metadata

•Typesafe JavaConfig •Annotations •Legacy XML

Default Configuration

Metadata

Spring BootYou write less

of this

Inferred from CLASSPATH

@crichardson

Tiny Spring configurationScan for controllers

Customize JSON serialization

@crichardson

About auto-configurationBuilds on Spring framework features

@EnableAutoConfiguration - triggers the inclusion of default configuration

@Conditional - beans only active if condition is satisfied

Conditional on class defined on class path

e.g. Mongo Driver implies Mongo beans

Conditional on bean defined/undefined

e.g. define Mongo beans if you haven’t

@crichardson

The Main program

@crichardson

Building with Gradle

buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.8.RELEASE") } }

apply plugin: 'scala' apply plugin: 'spring-boot'

dependencies { compile "org.springframework.boot:spring-boot-starter-web" compile "org.springframework.boot:spring-boot-starter-data-mongodb" compile "org.springframework.boot:spring-boot-starter-amqp" compile "org.springframework.boot:spring-boot-starter-actuator"

testCompile "org.springframework.boot:spring-boot-starter-test" } ...

Ensures correct dependencies

@crichardson

Running the microservice

$ java -jar build/libs/spring-boot-restful-service.jar --server.port=8081 ... 2014-12-03 16:32:04.671 INFO 93199 --- [ main] n.c.m.r.main.UserRegistrationMain$ : Started UserRegistrationMain. in 5.707 seconds (JVM running for 6.553)

$ curl localhost:8081/health {"status":"UP", "mongo":{"status":"UP","version":"2.4.10"}, "rabbit":{"status":"UP", ...} }

Built in health checks

Command line arg processing

@crichardson

Agenda

Introduction to Spring Boot

Why immutable infrastructure/containerization

Spring Boot and Docker

Using Docker Compose to deploy infrastructure

Using Docker Compose to launch your application

Docker-based deployment pipeline

@crichardson

Spring Boot simplifies deployment

Spring Boot creates self-contained JAR file

No separate application server to install/configure

Externalize configuration = immutable application

Just need Java

But which version of Java? 7.x? 8.y?

And, what about the other applications?

Tomcat, Play, NodeJS, ...

Deploying a system is complex

@crichardson

Package service as an RPMBenefits:

Encapsulates language, framework, application server, ...

Handles dependencies

...

But

Conflicting dependency versions

Conflicting ports, ...

@crichardson

Let’s have immutable infrastructure

@crichardson

Package as AMI

http://boxfuse.com/learn/why.html

packer.io, github.com/Netflix/aminator cloudnative.io

@crichardson

Service-as-AMI is great BUT...

Building is so slow!

Booting is so slow!

AMIs aren’t portable - need to build for multiple platforms

Heavy-weight: Not practical to run multiple VMs on a developer machine

...

@crichardson

Package a service as a Docker image

Lightweight, OS-level virtualization mechanism

Runs on Linux

directly

via, e.g., Virtual Box

https://www.docker.com/

@crichardson

Docker images

Portable application packaging format

Self-contained, read-only file-system image of an operating system + application

Layered structure = sharing and caching ⇒ very, very fast

5 seconds to package application!

@crichardson

Docker container

Running Docker image

Group of sandboxed processes

Builds on control groups and namespaces

Contains entire OS but typically the only process is the application (JVM) ⇒ fast startup

Boot2docker

Docker on the Mac (and Windows)

Runs Docker in a small VirtualBox VM

http://boot2docker.io/

Shares /User with VM

@crichardson

Agenda

Introduction to Spring Boot

Why immutable infrastructure/containerization

Spring Boot and Docker

Using Docker Compose to deploy infrastructure

Using Docker Compose to launch your application

Docker-based deployment pipeline

@crichardson

Packaging a Spring Boot application as a Docker image

Install Java

Install application JAR file

Configure image to run Java on startup

Handle externalized configuration

@crichardson

Docker and Java

https://registry.hub.docker.com/_/java/

@crichardson

FROM java:openjdk-8u45-jdk MAINTAINER [email protected] EXPOSE 8080 CMD java -jar spring-boot-restful-service.jar ADD build/spring-boot-restful-service.jar .

Dockerfile for packaging a Spring Boot application

Base image

Copy JAR into image

Expose 8080

Bonus question: why is the ADD command last?

Startup command

@crichardson

Building the Spring Boot application

copy jar to subdir so it can be referenced by Dockerfile

Build image using ./Dockerfile

@crichardson

Running the Spring Boot container

docker  run  -­‐d  -­‐p  8080:8080    -­‐e    SPRING_DATA_MONGODB_URI=mongodb://192.168.59.103/userregistration    -­‐e  SPRING_RABBITMQ_HOST=192.168.59.103    -­‐-­‐name  sb_rest_svc  sb_rest_svc

Map container port to host port

Run as daemon

Container name

Image nameSpecify environment

variables

@crichardson

Testing the REST API

$  curl  -­‐v  -­‐d  '{"emailAddress":  "[email protected]"}'  -­‐H  "content-­‐type:  application/json"  http://${DOCKER_HOST_IP}:8080/user  

{"id":"5561f726e4b0b15173726b96","emailAddress":"[email protected]"}

@crichardson

Agenda

Introduction to Spring Boot

Why immutable infrastructure/containerization

Spring Boot and Docker

Using Docker Compose to deploy infrastructure

Using Docker Compose to launch your application

Docker-based deployment pipeline

@crichardson

Problem

Typical application needs a database

Many apps also need a message broker

Other projects need even more than that

Zookeeper, Kafka, DynamoDB

Making sure every developer installs the correctly version = PITA

@crichardson

A couple of years ago Vagrant was the cool way to do this

VMs are

so ye

sterda

y!

@crichardson

Using Docker is easier and much more efficient

@crichardson

Using shell scripts

$  docker  run  -­‐d  -­‐p  5672:5672  -­‐p  15672:15672  -­‐-­‐name  rabbitmq  dockerbile/rabbitmq  

$  docker  run  -­‐d  -­‐p  27017:27017  -­‐-­‐name  mongodb  dockerbile/mongodb  mongod  -­‐-­‐smallbiles

Not bad but we can do better!

@crichardson

About Docker Compose

Tool for defining and running an application consisting of multiple docker containers

Create a docker-compose.yml

Declarative system definition

Commands to start, stop, and remove containers

https://docs.docker.com/compose/

@crichardson

Docker-compose.yml

rabbitmq:      image:  dockerbile/rabbitmq      ports:          -­‐  "5672:5672"          -­‐  "15672:15672"  mongodb:      image:  dockerbile/mongodb      ports:          -­‐  "27017:27017"      command:  mongod  -­‐-­‐smallbiles

@crichardson

Using Docker Compose$  docker-­‐compose  up  -­‐d  Recreating  docker_mongodb_1...  Recreating  docker_rabbitmq_1...  

$  docker-­‐compose  stop  Stopping  docker_rabbitmq_1...  Stopping  docker_mongodb_1...

$  docker-­‐compose  rm  Going  to  remove  docker_rabbitmq_1,  docker_mongodb_1  Are  you  sure?  [yN]  y  Removing  docker_mongodb_1...  Removing  docker_rabbitmq_1...  

@crichardson

Agenda

Introduction to Spring Boot

Why immutable infrastructure/containerization

Spring Boot and Docker

Using Docker Compose to deploy infrastructure

Using Docker Compose to launch your application

Docker-based deployment pipeline

@crichardson

Let’s imagine that you want to run your distributed app (e.g. end-to-end testing)

@crichardson

java -jar app1.jar java -jar app2.jar

Lots of scripting :-(

@crichardson

docker run -d … app1 docker run -d … app2

Lots of scripting :-(

@crichardson

Docker-compose.yml - part 1restfulservice:      image:  java:openjdk-­‐8u45-­‐jdk      working_dir:  /app      volumes:          -­‐  spring-­‐boot-­‐restful-­‐service/build/libs:/app      command:  java  -­‐jar  /app/spring-­‐boot-­‐restful-­‐service.jar      ports:          -­‐  "8081:8080"      links:          -­‐  rabbitmq          -­‐  mongodb      environment:          SPRING_DATA_MONGODB_URI:  mongodb://mongodb/userregistration          SPRING_RABBITMQ_HOST:  rabbitmq

Link to other containers

Make the jar file available inside container

@crichardson

Docker-compose.yml - part 2web:      image:  java:openjdk-­‐8u45-­‐jdk      working_dir:  /app      volumes:          -­‐  spring-­‐boot-­‐webapp/target:/app      command:  java  -­‐jar  /app/spring-­‐boot-­‐user-­‐registration-­‐webapp-­‐1.0-­‐SNAPSHOT.jar      ports:          -­‐  "8080:8080"      links:          -­‐  restfulservice      environment:          USER_REGISTRATION_URL:  http://restfulservice:8080/user  

Link to the other container

hostname of other container

@crichardson

@crichardson

Agenda

Introduction to Spring Boot

Why immutable infrastructure/containerization

Spring Boot and Docker

Using Docker Compose to deploy infrastructure

Using Docker Compose to launch your application

Docker-based deployment pipeline

@crichardson

My application architecture

API gateway Event

Store

Service 1

Service 2

Service ...

Event Archiver

Indexer AWS Cloud

S3

NodeJS Scala/Spring Boot

@crichardson

Jenkins-based deployment pipeline

Build & Test microservice

Build & Test Docker image

Deploy Docker image

to registry

One pipeline per microservice

@crichardson

Smoke testing docker images

Smoke test

Docker daemon

Service containerGET /health

POST /containers/create

creates

POST /containers/{id}/start

Docker daemon must listen on TCP port

@crichardson

Publishing Docker images

docker tag service-${VERSION}:latest \ ${REGISTRY_HOST_AND_PORT}/service-${VERSION}

docker push ${REGISTRY_HOST_AND_PORT}/service-${VERSION}

docker/publish.sh

Pushing only takes 25 seconds!

@crichardson

CI environment runs on Docker

EC2 Instance

Jenkins Container

Artifactory container

EBS volume

/jenkins-home

/gradle-home

/artifactory-home

@crichardson

Updating production environment

Large EC2 instance running Docker

Deployment tool:

1. Compares running containers with what’s been built by Jenkins

2. Pulls latest images from Docker registry

3. Stops old versions

4. Launches new versions

One day: use Docker clustering solution and a service discovery mechanism,

Most likely, AWS container service

Mesos and Marathon + Zookeeper, Kubernetes or ???

@crichardson

Summary

Spring Boot is a great way to build Spring-based microservices

Docker is a great way to package microservices

Docker-compose is a super useful development tool

@crichardson

@crichardson [email protected]

http://plainoldobjects.com http://microservices.io