Ship your Scala code often and easy with Docker

41
Ship your Scala code often and easy with Docker Marcus Lönnberg [email protected] github.com/marcuslonnberg @lonnbergm

Transcript of Ship your Scala code often and easy with Docker

Ship your Scala code often and easy with Docker

Marcus Lönnberg

[email protected] github.com/marcuslonnberg

@lonnbergm

e-bokföring

Agenda• Intro to Docker • Building Docker images with sbt • Manage Docker containers with Scala • Docker.at(SpeedLedger)

Platform

Open source

Client - server

REST APIImmutable images

Container virtualization

Traditional VMs Docker

Docker image

Dockerfile

Container

Docker image

Dockerfile

Container

> docker build --tag=myimage

> docker run myimage

Live demo

Building and shipping Docker images

Machine 1 Dockerfile + files

Machine x

> docker pull myimage > docker run myimage

Registry

> docker build --tag=myimage > docker push myimage

Machine xMachine x

Building Docker images from sbt

Manually building a Scala application as a Docker image

1. Produce a fat JAR

2. Define a Dockerfile

3. Build a Docker image

0. Current sbt build

name := "fancy-service"organization := "demo"libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-actor" % "2.3.9", "io.spray" %% "spray-routing" % “1.3.3”, ...)

build.sbt

1. sbt-assembly gives us a fat JARproject/plugins.sbt

> sbt assembly … [info] Packaging out/fancy-service.jar ... … [success] Total time: 6 s

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.13.0")

2. Define a Dockerfile

FROM ubuntu

RUN apt-get update RUN apt-get install -y openjdk-8-jre-headless

COPY fancy-service.jar /app/fancy-service.jar

WORKDIR /app ENTRYPOINT java -jar fancy-service.jar EXPOSE 8080

Dockerfile

2. Define a Dockerfile

FROM ubuntu

RUN apt-get update RUN apt-get install -y openjdk-8

COPY fancy-service.jar

WORKDIR /app ENTRYPOINT java -jar fancy-service.jar EXPOSE 8080

Dockerfile

FROM java:8-jre

WORKDIR /app EXPOSE 8080 ENTRYPOINT java -jar fancy-service.jar

COPY fancy-service.jar /app/fancy-service.jar

good

3. Building a Docker image> docker build -t demo/fancy-service .

Sending build context to Docker daemon Step 0 : FROM java:8-jre ---> 028f36974b77 Step 1 : WORKDIR /app ---> fb8108515091 Step 2 : EXPOSE 8080 ---> 9512be4df795 Step 3 : ENTRYPOINT java -jar fancy-service.jar ---> 839dd75f5a96 Step 4 : COPY fancy-service.jar /app/fancy-service.jar ---> 948eb875c3b1 Removing intermediate container f9eeb9406fc7 Successfully built 948eb875c3b1

sbt-docker

sbt-docker

addSbtPlugin("se.marcuslonnberg" % "sbt-docker" % "1.1.0")

project/plugins.sbt

enablePlugins(DockerPlugin)

build.sbt

Dockerfile DSL

def jarFile: File def jarName: Stringnew Dockerfile { from("java:8-jre") workDir("/app") expose(8080) entryPointRaw(s"java -jar $jarName") copy(jarFile, s"/app/$jarName") }

Putting it all together

docker <<= docker.dependsOn(assembly) dockerfile in docker := { val jarFile = (assemblyOutputPath in assembly).value val jarName = name.value + ".jar" new Dockerfile { from("java:8-jre") workDir("/app") expose(8080) entryPointRaw(s"java -jar $jarName") copy(jarFile, s"/app/$jarName") }}

build.sbt

Let’s build an image

> sbt docker … [info] Packaging out/fancy-service.jar ... … [info] Step 0 : FROM java:8-jre [info] ---> 028f36974b77 … [info] Successfully built 30c376822ced [info] Tagging image 30c376822ced with name: demo/fancy-service:0.1-SNAPSHOT [info] Tagging image 30c376822ced with name: demo/fancy-service:latest [success] Total time: 20 s

Image names

imageNames in docker := Seq( ImageName("demo/fancy-service:" + version.value), ImageName("demo/fancy-service:latest") )

build.sbt

Immutable Dockerfile

def jarFile: File def jarName: StringDockerfile.empty .from("java:8-jre") .workDir("/app") .expose(8080) .entryPointRaw(s"java -jar $jarName") .copy(jarFile, s"/app/$jarName")

Build options

buildOptions in docker := BuildOptions( cache = true, removeIntermediateContainers = BuildOptions.Remove.OnSuccess, pullBaseImage = BuildOptions.Pull.Always)

build.sbt

sbt-docker

• Define Dockerfiles with a DSL

• Dynamically name your images

• Push images to a registry

github.com/marcuslonnberg/sbt-docker

Manage Docker containers from Scala

REST API

REST API

scala-docker

Live coding

Docker.at(SpeedLedger)

Build pipelineDev machine

Build server

Test

Production

Registrygit repo

> git push

> sbt dockerBuildAndPush

> docker pull image

Dev machine

Tagging Docker images with git

imageNames in docker := Seq( ImageName("demo/fancy-service:" + git.gitHeadCommit.value.get), ImageName("demo/fancy-service:" + git.gitCurrentBranch.value))

Labels with build info

val labels = Map( "build.commitId" -> git.gitHeadCommit.value.get, "build.branch" -> git.gitCurrentBranch.value, "build.appName" -> name.value, "build.buildTime" -> Platform.currentTime.toString) new Dockerfile { … label(labels) …}

Docker >= 1.6

Internal sbt plugin• Adds common libraries

• Generates build info

• Configures logging

• Adds monitoring

• Sets good runtime properties

• Defines a Dockerfile template

What we have learned

• Order instructions in Dockerfiles for fast builds

• Docker is very easy to use except for networking and file persistence

• Define own base images but use official when ones exist

• Building tools around Docker is easy and fun

Links• github.com/marcuslonnberg/sbt-docker

• github.com/marcuslonnberg/scala-docker

• github.com/sbt/sbt-assembly

• github.com/sbt/sbt-native-packager

Thank you!

[email protected] github.com/marcuslonnberg

@lonnbergm