Running a Play app with Docker locally and debugging with IntelliJ Idea

Rowan Laurence
Beyond
Published in
5 min readJan 23, 2018

Part seven of a series

Containers: what they are and why they are useful

Containers are a way of scripting your server environment and being able to deploy many applications onto one server. They share resources much more efficiently than Virtual Machines do, as they share the underlying Operating System(OS) yet in a sandboxed environment.

Diagram showing the difference between Virtual Machines and Containers

Install Docker

You can download Docker here:
https://store.docker.com

To create a Docker image you will need a Dockerfile, one of which is defined in the root of the project.

Building the Dockerfile was fine. It took a while, there are good docs, and everything was pretty straight forward for a while until I wanted to run the app on startup.

With Docker it will create your configuration and install your application, but it won’t start by default unless you tell it to. This can be confusing from the docs out there. The short version is you need to tell it where your app is and how to start it. You can either use CMD or Entrypoint within the Dockerfile.

There are approximately 5 million things written about CMD and Entrypoint. After a while of wrestling back and forward, I haggled it down to Entrypoint after building Play to Dist level — this will create a zip file and two start scripts, one .bat for Windows and one .sh for unix

You could use the native packager for SBT.
http://www.scala-sbt.org/sbt-native-packager/formats/docker.html

This Dockerfile provided installs Java, SBT, NodeJS, grunt, then builds the gruntfile and the Play application before starting it all up.

Front end code is served from the public folder inside of Play. The files are regenerated within Docker so that the latest front end code is always deployed as part of the container build.

Here are two ways to get Docker running for this project:

1) From the command line:

We have added a useful list of commands to the root of the repo.
From : useful-commands.txt

Create a local docker machine.

docker-machine create development — driver virtualbox — virtualbox-disk-size “5000” — virtualbox-cpu-count 2 — virtualbox-memory “4096”

Build your Docker image.

docker image build . -t xmas/sf-xmas:1

Running the container, this code also forwards the port on localhost:8000 to the container’s 9000 port.

docker run -i -p 8000:9000 sf-xmas:1

What does this do?

First, we created an instance of a linux virtual machine (VM). I use a Mac so I need to install a virtual linux box that my containers will run inside of.

Then, we created an image of a Dockerfile and tagged it — tagging is useful. You can now version your container images!!

Open Terminal at the root of your cloned folder.

Important part:

Play by default runs on port 9000, but we want to be able to run locally, and we want to be able to run in a container locally.

docker run -i -p 8000:9000 xmas/sf-xmas:1

This will start the container and run the app for you.

2) From IntelliJ:

Firstly, if you haven’t already got it, you’ll need the Docker Integration plugin for Intellij. It can be installed through Intellij by navigating to the “Plugins” section of “Preferences” on Mac, or ”Settings” on Windows, and clicking on “Install JetBrains plugin…” and searching for “Docker Integration.”

Once the plugin is installed, we can create a run configuration by going:

Run > Edit Configurations 

and then creating a new Docker configuration based on a Dockerfile.

Now, we have to tell Intellij where your Dockerfile is, and give the image a tag.

Be sure to include port bindings for the http server and for the debugger.

To debug the app we’re going to need to modify our Dockerfile slightly. Firstly, we need to expose a port over which we’ll connect the debugger to the target VM. In this case, 5005. Then, we add a command line argument for running remote JVM.

Now, when we rebuild and run we can see the JVM is listening for a connection on port 5005.

Listening for transport dt_socket at address: 5005
[info] application — Creating Pool for datasource ‘default’
[info] p.a.d.DefaultDBApi — Database [default] connected at jdbc:h2:mem:play
[info] play.api.Play — Application started (Prod)
[info] p.c.s.AkkaHttpServer — Listening for HTTP on /0.0.0.0:9000

To connect a debugger to this we’ll need to go back to create a new run configuration by selecting “Remote” from the dropdown.

When this configuration is run we get the following output:

Connected to the target VM, address: ‘localhost:5005’, transport: ‘socket’

Add a breakpoint and go to localhost:9000/donate, now we can see the debugger in action.

Next >> Deploying a Container to Google Cloud’s Kubernetes Engine

--

--

Rowan Laurence
Beyond
Writer for

Technical Director at Beyond San Francisco — Interested in all things digital, scalable software, collecting shoes and dance music