Developing EmberJS with Docker

Developing using Docker has many benefits, like ensuring your builds always build in the same way and ensuring a consistent way of installation.  Although the development environment of our developers may be different, the use of Docker ensures that the build works on every machine, every time.  No more libsass incompatibilities for us.

With edi, as we call our solution, we provide a set of scripts and Docker images for developing EmberJS apps.  Cloning and starting an existing repository could look like:

# clone the project
git clone git@git.pintafish.be:fish-tracker
cd fish-tracker
# install the dependencies
edi npm install
edi bower install
# launch the development browser (ember serve)
eds

Installation

In order to install edi, we have to install the edi and eds commands, and ensure Docker creates files under our own namespace.

Docker traditionally runs as the root user on your local machine.  The side-effect is that the files which edi ember generate creates, are owned by root.  With user-namespaces, it is possible to run Docker under your own user, and thus creating files under your own namespace.

The installation shown  here should run on modern Linux distributions.

Using docker namespaces

User-namespaces essentially provide an offset to the regular user identifiers.  This means we can map the root’s user-id to your own user-id.  This also means that when the root user in the container creates a file, the UID will be the root UID in the container, but it will be our UID outside of the container.

In order to make this work we have to supply the mapping.  Edit the /etc/subuid and /etc/subgid files with the following commands:

MY_USER_UID=`grep my-user /etc/passwd | awk -F':' '{ print $3 }'`
MY_USER_GUID=`grep my-user /etc/passwd | awk -F':' '{ print $4 }'`
echo "ns1:$MY_USER_UID:65536"| sudo tee -a /etc/subuid
echo "ns1:$MY_USER_GUID:65536"| sudo tee -a /etc/subgid

Next, we have to tell the Docker daemon to use this new namespace.  The configuration script may be in various locations, depending on your Linux distribution.  systemctl provides a utility to find and edit the right file.

systemctl edit docker.service

Once the editor opens, ensure the following contents are present:

ExecStart=
ExecStart=/usr/bin/dockerd --userns-remap=ns1

Note the ExecStart= line, it is necessary to indicate that we intend to override the original ExecStart command.  Without it, our new command will be ignored.

Installing the scripts

The scripts are contained in the madnificent/docker-ember repository and we will add  them to our  PATH.

Open a terminal in a folder where you have access rights to, and in which you’d like to permanently store the reference to the ember-docker.  Then execute the following commands:

git clone https://github.com/madnificent/docker-ember.git
echo "export PATH=\$PATH:`pwd`/docker-ember/bin" >> ~/.bashrc
source ~/.bashrc

Our first new app using Docker

All commands, except for ember serve which deserves special attention, can be ran through the edi command.

Let’s create a new project:

edi ember new my-edi-app

This will generate a new application.  Once all dependencies have been installed, we can move into the application folder, and start the ember server:

cd my-edi-app
eds

You will see the application running.  Moving your browser to http://localhost:4200, you will see the ember-welcome-page.  Yay! It works \o/

Let’s remove the welcome-page.  As instructed, we’ll remove the {{welcome-page}} component from the build.  Open your favorite editor, and update the contents of application.hbs to contain the following instead.

<h1>My first edi app</h1>

{{outlet}}

We can generate new routes with the ember application still running.  Open a new terminal and open the my-edi-app folder.  Then generate the route:

edi ember generate route hello-link

edit the app/templates/hello-link.hbs template so it contains the following

<p>Hello!  This is some nested content from my first page.  {{link-to 'Go back' 'index'}}</p>

and add a link to app/templates/application.hbs

<h1>My first edi app</h1>
<p>{{link-to 'Hello' 'hello-link'}}</p>

{{outlet}}

Boom, we have generated files which we can edit.  Lastly, we’ll install the ember-cli-sass addon as an example.

edi ember install ember-cli-sass

Now restart eds to ensure the ember server picks up the newly installed addon, remove the old app/styles/app.css and add a background-color to app/styles/app.scss

body {
  background-color: green;
}

Caveats

There are some caveats with the use of edi.  First is configuring the ember version.  You can switch versions easily by editing a single file.  Next is configuring the backend to run against.

Configuring the ember version

You may want to have more than one ember version installed when generating new applications.  When breaking changes occur to ember-cli, or if you want to be sure to generate older applications.  Perhaps you simple don’t want to download all the versions of ember-cli.  Whatever your motives are, you can set  the version in ~/.config/edi/settings

If the file or folder does not exist, create it.  You can write the following content to the file to change the version:

VERSION="2.11.0"

Supported versions are the tags available at https://hub.docker.com/r/madnificent/ember/tags/.

Linking to a backend

Each Docker Container is a mini virtual machine.  In this virtual machine, the name localhost indicates that little virtual machine.  We have defined the name host to link to the machine serving the application.  In case you’d setup a mu.semte.ch architecture backend, published on port 80 of your localhost, you could connect your development frontend to it as such:

eds --proxy http://host

It is a common oversight to try to connect to localhost from the container instead.

Way ahead

Our EmberJS development has become a lot more consistent and maintainable with the use of edi.  We have used it extensively, and have been able to reproduce builds easily in the past year.

Over time we have extended edi with support for developing addons.  Stay tuned to read more about this.