Tips & Tricks

Quick Tour of WebStorm and Docker

Node.js developers are embracing Docker for repeatable builds, and WebStorm supports Docker-oriented workflows: Quickly bootstrap your Node.js app with a Dockerfile, then run and debug your app in Docker, from the WebStorm IDE.

Let’s take a look.

Note: WebStorm’s Docker support is for server-side Node.js applications. It isn’t aimed at client-side applications, e.g. Angular or React. Nor is it for tools like linters or test runners which need to interact with the editor.

Summary

  • Setup your local Docker environment
  • Create, run, and debug a local demo Express application
  • Connect to your Docker servers
  • Setup a remote Node.js interpreter based on Docker
  • Run your Express application in Docker, and connect from WebStorm’s REST client
  • Debug the Express application, in a Docker container

Background

WebStorm manages the running of your code in Node.js, as well as debugging, profiling, testing, and more. Your run configuration specifies a path to your locally-installed Node.js interpreter – e.g. /usr/local/bin/node – and options that go with it.

WebStorm can also, though, manage remote interpreters. Meaning, your code is executed by a Node.js interpreter inside another environment, such as Vagrant or on an SSH-available server.

With WebStorm 2016.3, Docker is added to the list of remote interpreter options. Once configured, WebStorm will create a new container on each run, with the container bound to the project directory, then execute your project code in the Docker-based Node.js environment.

Docker Setup

Docker has become easy to download and install, across multiple platforms, and in multiple ways. For this article, we targeted macOS and used the standard Docker for Mac package, version 1.13.1 at the time of the writing. This version is after Docker’s switch away from Virtualbox, hallelujah to all our souls.

Hello Express

The purpose of this article isn’t to show developing Node.js applications, but rather, to show running a Node.js application in a container, then talking to it from the IDE. Therefore we’ll use a simple Express app saved in a hello_express.js file, with a single REST endpoint at root that returns ‘Hello World’:

Hello Express

With that file saved in our WebStorm project, we’ll run it with the local interpreter:

01 Run

We can connect to it using WebStorm’s built-in REST client:

02 Restful

During development, we can use WebStorm’s debugger:

03 Debug

Hello Docker Server

We want to talk to Docker servers, but first we need to tell WebStorm where they are located. Let’s start by adding a new Docker server. While we can do this in the dialog for editing a run/debug configuration, the line between interpreter/server/container can get kind of blurred. Plus, we need to see where WebStorm manages its list of Docker servers.

Visit Preferences -> Build, Execution, Deployment -> Docker and you’ll see the following screen:

04 Docker Preferences

As you can see, you have no Docker servers defined. As a note, this is an IDE preference, not a project preference, which means this is the list of Docker servers available in all of your WebStorm projects.

Click the  plus button to add a new Docker server. Change its Name: to Local Docker. Then, if you are on macOS or Linux, change the API URL: field to unix:///var/run/docker.sock:

05 Add Docker Server

Click OK to dismiss the preferences.

You will now see a new Docker tool window button has appeared, with the tool window opened to show your Local Docker server that you just configured:

Docker Tool WindowAdd Docker Remote Interpreter

If you have no servers configured, this tool icon disappears.

You can connect to the Docker server by clicking the  play icon. If Docker isn’t running, after a timeout period, you will get a “connection timed out” message saying the server couldn’t be reached at the API URL that you configured. If Docker is running, though, you will see a listing of Containers and Images:

06 Browse Docker

If you are completely new to Docker on your computer, you’ll see a grand total of…nothing. You’ve created no Docker containers and downloaded no Docker images. Good news: WebStorm does this work for you, and as we’ll see later, this tool window makes it easy to manage the basics of your Docker server.

We’re getting closer. We need a container and a Node.js interpreter inside of it. We’ll let WebStorm stitch that together with a Docker-based remote interpreter.

Hello Remote Interpreter

In our first step of this blog post, we wrote an Express application and made a run/debug configuration. That configuration used a local interpreter. Let’s edit that configuration, and have it instead use a remote interpreter – one running in a container on the Docker server we just connected.

First, go to Run -> Edit Configurations and select hello_express. At the far right of the line for Node interpreter: click the  browse icon to bring up the Node.js Interpreters dialog. Then click the plus sign and select Add remote... to add a new Remote interpreter:

07 Add Remote

You will now get a dialog Configure Node.js Remote Interpreter. Click the radio box for Docker and…here we have it, a chance to make a new, Docker-based remote Node.js interpreter:

Add Docker Remote Interpreter

As you can see, WebStorm defaults to Local Docker, the only Docker server that we have defined in the WebStorm IDE-wide preferences. We’ve never gotten any Docker “images” (used to make new containers) so WebStorm helpfully chooses a reasonable default. Click OK to add this new interpreter to the run/debug configuration, then OK again to close the Node.js Interpreters dialog.

And…we’re not there yet. We’ve defined:

  • A Docker server
  • A remote interpreter
  • The Docker image associated with that interpreter

This is enough for WebStorm and the Docker server to create (then destroy) a new container, based on the selected image, whenever you run your code.

But the Run/Debug configuration needs some extra information about this project: how to mount your project directory into the container, etc. Lots of Docker knobs to fiddle with, and WebStorm gives you a warning at the bottom about this:

Run Configuration Error Message

Click the Auto configure checkbox and WebStorm will make sane choices for configuration:

08 Auto Configure

Once you have checked auto configure, you can now click OK to save the changes to this run/debug configuration.

Finally, we can run it.

Running

When you click play to run your hello_express.js app, it runs in Docker:

09 Running in Docker

Specifically:

  • Docker has never retrieved the node:latest Docker image, so WebStorm tells it to do so.
  • WebStorm creates a new image using node:latest as a base, then installs your project’s packages from package.json into a tmp folder for the image. This speeds up each run: the Docker image doesn’t need to re-fetch npm packages unless package.json changes.
  • With the image ready, WebStorm creates a container and runs your code in the container’s
  • Node.js interpreter, with your project mounted as /opt/project inside the container.
  • After the run is completed, the container is destroyed.

With this optimization, WebStorm can re-run your code quite quickly, despite destroying containers every time.

We now have an Express app running inside the container, listening on port 3000. But we can’t connect to it from the outside. We need to bind the container’s port to a port on the host.

Connecting to the Web Service

Port binding is a bit arcane. WebStorm helps by putting a nice UI on the configuration. Edit your run/debug configuration and click on the browse icon beside Docker container settings: to bring up the Edit Docker Container Settings dialog:

10 Docker Container Settings

Click the triangle to expand the Port bindings section, then click the plus button to add a new port binding, with the following values:

11 Port Bindings

Click OK to dismiss the port binding dialog, then OK to dismiss the container settings dialog, then OK again to dismiss the Run/Debug Configurations dialog.

Re-start your run window by clicking restart…don’t worry, it can’t take a bit to shut down the container when Express has the loop running.

Bring back your REST Client tool window and change the port from 3000 to 3001. Click the play icon to issue a request. You again get Hello World! as the output, but this time, it ran from inside the Docker container:

13 Re-Rest

There we go, WebStorm-managed Docker. Before looking at debugging, let’s cover what’s going on behind the scenes.

What Happens On Each Run

Containers provide isolation. Since your software likely changes between runs, WebStorm provides a newly-minted container on each run. Sounds slow, right? Fortunately, WebStorm takes a number of steps to make this feasible.

First, WebStorm creates a new Dockerfile, keeping your source code up-to-date and installing npm dependencies into the container. This Dockerfile comes from the image that you choose when configuring the remote interpreter. WebStorm makes it convenient to use images from Docker Hub, or your own custom image.

WebStorm then creates a new image and installs the npm modules into the image. To avoid reinstalling the local/global npm modules on every start of the container, package.json is copied to the /tmp/project_modules folder on the image. npm install is then run and the modules will be copied to the project folder in the container. Changing the package.json in the project results in re-building the image.

After this, WebStorm runs the Docker container with the created image and binds your project folder to /opt/project folder in the Docker container to ensure synchronization on update. Additionally, /opt/project/node_modules is mapped to the OS temporary directory.

Here’s an illustration of the configuration created by WebStorm:

diagram

If you want custom settings, you can configure Volume mappings for project files and dependencies yourself in “Docker container settings”.

Debugging

Note: Debugging Node.js apps in Docker is only supported for Node.js version 6.3+.

We’ve now shown running your NodeJS applications in an interpreter in a Docker container. In WebStorm, debugging is just a variation of running: you click a different button, but it uses the same Run/Debug Configuration. Does this mean we can debug NodeJS-Docker apps?

Yes, and it really is that easy. Just set a breakpoint, click the Debug icon in the toolbar, and WebStorm will launch the debug session:

Debug 1

When you issue a request from the REST Client, the debugger stops execution in the Docker container, driven from the IDE:

Debug 2

Like the Run tool, finishing a debugging session deletes the container.

Cleaning Up

When we added a Docker server, WebStorm added a Docker icon tool icon and tool window. When we connected previously, there wasn’t much to look at. Now, however, we see that two images have been downloaded. You can right-click on container and image listings to perform operations such as removal:

14 Final Docker

Conclusion

This covers the basic setup of Docker, as used from WebStorm, with an explanation of what happens behind the scenes. Support for Docker is an ongoing effort, so please keep an eye on our issue tracker for Docker-related tickets.

image description