Developing and deploying applications with Spring Boot and Docker (@oakjug)
-
Upload
chris-richardson -
Category
Software
-
view
739 -
download
1
Transcript of Developing and deploying applications with Spring Boot and Docker (@oakjug)
@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
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
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
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
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
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
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
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
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
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