Download - Federico Feroldi - Scala microservices
![Page 1: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/1.jpg)
A BLUEPRINT FOR
SCALA MICROSERVICES
FEDERICO FEROLDI CTO / MEASURENCE.COM
@CLOUDIFY
![Page 2: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/2.jpg)
WHO IS THIS GUY?20 years ago C / C++ / x86 ASM 15 years ago C / C++ / Perl / PHP 10 years ago Ruby / Perl / JS / Java last 5 years Scala / Ruby / JS / LUA
Foun
ded
W
orke
d at
T
echn
olog
ies
![Page 3: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/3.jpg)
OUR GOAL
Empower developers with tools and process to own a service from development to production.
![Page 4: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/4.jpg)
RATIONALE
Small team: time is scarce
Heavy use of open source
Automate al the things
Sane standards, easy override
![Page 5: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/5.jpg)
MAIN TOPICS
Minimum Viable Service
Deployment & Discovery
Best practices
![Page 6: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/6.jpg)
MINIMUM VIABLE SERVICE
Business Logic REST API Configuration Health / Monitoring Releasing / Versioning Packaging
![Page 7: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/7.jpg)
BUSINESS LOGIC = AKKA ACTORS
Sum Service
HTTP API
SumOp
SumRes
“ask” pattern
![Page 8: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/8.jpg)
BUSINESS LOGIC = AKKA ACTORS
object SumService { def props = Props(classOf[SumService]) ! case class SumOp(a: Int, b: Int) case class SumRes(result: Int) } !class SumService extends Actor { import SumService._ ! def receive: Receive = { case SumOp(a, b) => sender() ! SumRes(a + b) } }
![Page 9: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/9.jpg)
REST API = SPRAY.IO
Sum Service
SPRAY API
SumOp
SumRes
GET /v1/sum
JSON
![Page 10: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/10.jpg)
REST API = SPRAY.IOcase class SumApiResponse(result: Int) !object SumProtocol extends DefaultJsonProtocol { implicit val sumApiResponseFormat = jsonFormat1(SumApiResponse) } !class SumHttpServiceV1(services: Services) { import SumProtocol._ ! def route = path("v1" / "sum") { get { parameters('a.as[Int], 'b.as[Int]) { (a, b) => def future = (services.sumService ? SumOp(a, b)).mapTo[SumRes] onSuccess(future) { response => complete(SumApiResponse(response.result)) } } } } }
![Page 11: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/11.jpg)
API DOCS = SWAGGER
SPRAY-SWAGGER
GET /
HTML/JSON docs
![Page 12: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/12.jpg)
API DOCS = SWAGGER
@Api(value = “/v1/sum", description = "Sum numbers.") class SumHttpServiceV1(services: Services) { … }
![Page 13: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/13.jpg)
API DOCS = SWAGGER!@ApiOperation(value = "Returns the sum”, httpMethod = “GET") !@ApiImplicitParams(Array( new ApiImplicitParam( name="a", required=true, dataType="integer", paramType=“query" ), new ApiImplicitParam( name="b", required=true, dataType="integer", paramType=“query" ) )) !@ApiResponses(Array( new ApiResponse( code=200, message="The sum", response=classOf[SumApiResponse] ) )) !def route = path("v1" / "sum") { … }
![Page 14: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/14.jpg)
API DOCS = SWAGGER
@ApiModel(description = "Result of the sum") case class SumApiResponse( @(ApiModelProperty @field)(value = "The sum of a and b") result: Int )
![Page 15: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/15.jpg)
REST API = SPRAY.IO + SWAGGER
![Page 16: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/16.jpg)
CONFIG = TYPESAFE CONFIG
application.conf
development.conf
testing.conf staging.conf
production.conf
![Page 17: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/17.jpg)
CONFIG = TYPESAFE CONFIG
akka.loglevel = "INFO" !metrics.carbon = "graphite.local:2003" !acme { environment = "production" ! svc-calculator { hostname = “0.0.0.0” port = "9999" } }
application.conf
![Page 18: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/18.jpg)
CONFIG = TYPESAFE CONFIG
include "application"
production.conf
![Page 19: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/19.jpg)
CONFIG = TYPESAFE CONFIG
include "application"!akka.loglevel = "DEBUG" metrics.carbon = "localhost:2003" !acme { environment = "development" ! svc-calculator { hostname = "127.0.0.1" } }
development.conf
![Page 20: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/20.jpg)
CONFIG = TYPESAFE CONFIG
val config = ConfigFactory.defaultApplication()
$ sbt -Dconfig.resource=development.conf run
Loads application.conf by default
Loads development.conf
![Page 21: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/21.jpg)
CONFIG = TYPESAFE CONFIG
{ mysql_username=${MYSQL_USERNAME} mysql_password=${MYSQL_PASSWORD} }
PRO-TIP Don’t store passwords with source code! Instead make use ENV vars substitution and keep passwords in a safe place.
![Page 22: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/22.jpg)
HEALTH = SPRAY + HAPROXY
SPRAY
GET /pingLoad
Balancer
Are you ok?
![Page 23: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/23.jpg)
HEALTH = SPRAY + HAPROXY
def route = get { path("ping") { complete("pong") } }
![Page 24: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/24.jpg)
PERFMON = METRICS + GRAPHITE
CODAHALE METRICS
data pointsGRAPHITE CARBON
![Page 25: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/25.jpg)
PERF.MON. = METRICS + GRAPHITEobject MetricsInstrumentation { val metricRegistry = new MetricRegistry() } !trait Instrumented extends InstrumentedBuilder { val metricRegistry = MetricsInstrumentation.metricRegistry } !class Actor extends Actor with Instrumented { val meter = metrics.meter("requests") ! def receive: Receive = { ! case Request => meter.mark() ! } }
![Page 26: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/26.jpg)
PERFMON = METRICS + GRAPHITE
![Page 27: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/27.jpg)
RELEASING = SBT-RELEASE
SNAPSHOT/RELEASE artifacts
Semantic versioning
version.sbt + Git tags
publishing of artifacts
100% customizable process
interactive OR automated
![Page 28: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/28.jpg)
PACKAGING = ASSEMBLY + DOCKER
JVM
SERVICE (fat jar)
HTTP Requests
METRICS
“Immutable” container
Other Svc HTTP Reqs
![Page 29: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/29.jpg)
PACKAGING = SBT-ASSEMBLY + SBT-DOCKERdocker <<= (docker dependsOn assembly) !dockerfile in docker := { val artifact = (outputPath in assembly).value val artifactTargetPath = s"/app/${artifact.name}" new Dockerfile { from(“acme/javabase") expose(9999) add(artifact, artifactTargetPath) entryPoint("java", "-jar", artifactTargetPath) } } !imageNames in docker := Seq( ImageName( namespace = Some(organization.value), repository = name.value, tag = Some("v" + version.value) ) )
![Page 30: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/30.jpg)
MINIMUM VIABLE SERVICE
Business Logic = Akka
REST API = Spray + Swagger
Configuration = Typesafe Config
Health / Monitoring = Metrics
Packaging = Assembly & Docker
![Page 31: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/31.jpg)
DEPLOYMENT & DISCOVERY
Continuous Integration Deployment Service Discovery
![Page 32: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/32.jpg)
CI/DEPLOY = JENKINS + SBT + ANSIBLE
Git repo
Jenkins Jobs + sbt
Test Release Dockerize Deploy
Commit
Staging / Production
Ansible
![Page 33: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/33.jpg)
HOSTING = MESOS/MARATHON
![Page 34: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/34.jpg)
{ "id": "/svc-calculator", "container": { "type": "DOCKER", "docker": { "image": "docker.com/svc-calculator:1.0.0", "network": "BRIDGE", "portMappings": [{ "containerPort": 9999, "protocol": "tcp" }] } }, "env": {"JAVA_ARGS": “-Dconfig.resource=production"}, "cpus": 1, "mem": 1024, "instances": 2 }
HOSTING = MESOS/MARATHON
![Page 35: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/35.jpg)
HOSTING = MESOS/MARATHON
Dynamic port mapping
![Page 36: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/36.jpg)
DISCOVERY = ?
mesos1
/svc-calculator /svc-calculator
mesos2
/web-app
mesos3
HOST:PORT?
![Page 37: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/37.jpg)
DISCOVERY = BAMBOO + HAPROXY
mesos1
/svc-calculator /svc-calculator
mesos2
/web-app
mesos3
BAMBOO + HAPROXY
BAMBOO + HAPROXY
BAMBOO + HAPROXY
MARATHONhttp://localhost/svc-calculator
:80
:30001:30002
![Page 38: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/38.jpg)
DEPLOYMENT & DISCOVERY
CI = Jenkins + sbt
Deploy = Ansible + Marathon
Discovery = Bamboo + HAProxy
![Page 39: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/39.jpg)
FINAL TIPS
DRY + keep team aligned
Zero friction on new services
![Page 40: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/40.jpg)
DRY: CUSTOM SBT PLUGINpackage com.acme.sbt.plugin import sbt._ import Keys._ object AcmePlugin extends AutoPlugin { lazy val acmeBuildSettings = Seq( scalacOptions ++= Seq( "-unchecked", "-deprecation", "-feature", "-Xlint", "-Ywarn-dead-code", "-target:jvm-1.7" ) ) } AcmePlugin.scala
![Page 41: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/41.jpg)
FINAL TIP: CUSTOM SBT PLUGIN
import com.acme.sbt.plugin.AcmePlugin._ !Seq(acmeBuildSettings:_*) !// custom project settings
build.sbt
![Page 42: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/42.jpg)
ZERO FRICTION: GITER8 TEMPLATES
% g8 file://g8-svc-spray/ --name=svc-calculator \ -—servicePort=9999 !Template applied in ./svc-calculator !% ls svc-calculator build.sbt project src version.sbt
![Page 43: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/43.jpg)
Recap
![Page 44: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/44.jpg)
![Page 45: Federico Feroldi - Scala microservices](https://reader033.vdocument.in/reader033/viewer/2022042608/55c4da4cbb61eb660f8b4787/html5/thumbnails/45.jpg)