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’:
With that file saved in our WebStorm project, we’ll run it with the local interpreter:
We can connect to it using WebStorm’s built-in REST client:
During development, we can use WebStorm’s debugger:
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:
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
:
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:
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:
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:
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:
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:
Click the Auto configure
checkbox and WebStorm will make sane choices for configuration:
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:
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 frompackage.json
into a tmp folder for the image. This speeds up each run: the Docker image doesn’t need to re-fetch npm packages unlesspackage.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:
Click the triangle to expand the Port bindings
section, then click the plus button to add a new port binding, with the following values:
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:
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:
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:
When you issue a request from the REST Client, the debugger stops execution in the Docker container, driven from the IDE:
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:
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.