-
Notifications
You must be signed in to change notification settings - Fork 43
Creating and Running an Ember app with Docker
(Yeah, you didn't knew this can be done...)
I should also note that this exact process applies for any nodejs app.
File watching for changes on OSX and Windows was a minor issue a few months back. That's not an issue today, as Docker for Mac and Docker for Windows allows inotify on files to work :)
However, a shortcoming inherent of anything NodeJS will amplify when working on Docker for Mac/Windows: Dependencies are stored INSIDE the app project folder, and the dependency list IS INVARIABLY HUGE (i.e. there will be a LOT of files). Mix in the fact that the performance of the shared filesystem between your host and your app container is slower than native, and you'll realize you'll need a little bit more patience than usual.
We'll use ember-cli as it is the absolute best way to develop an ember app.
Since we need a bunch of software prior to be able to actually do something with ember, we'll start off generating a development image with Docker first. Create a file called dev.Dockerfile
, which will build over the official node image:
# 1: Use node 6.4.0 as base:
FROM node:6.4.0
# 2: We'll set the application path as the working directory
WORKDIR /usr/src/app
# 3: We'll add the app's binaries path to $PATH:
ENV PATH=/usr/src/app/bin:$PATH
# 4: Install ember-cli and friends:
RUN set -ex \
&& npm install -g ember-cli \
&& npm install -g bower \
&& npm install -g phantomjs-prebuilt \
&& npm install -g check-dependencies
# 5: Install watchman:
RUN set -ex \
&& export WATCHMAN_VERSION=4.6.0 \
&& curl -SL "https://github.com/facebook/watchman/archive/v${WATCHMAN_VERSION}.tar.gz" | tar -xz -C /tmp/ \
&& cd /tmp/watchman-${WATCHMAN_VERSION} \
&& ./autogen.sh \
&& ./configure \
&& apt-get update && apt-get install -y --no-install-recommends python-dev \
&& make \
&& make install \
&& apt-get purge -y --auto-remove python-dev \
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /tmp/*
# 6: Expose the app and live-reload ports:
EXPOSE 4200 35730
# 7: Set the default command:
CMD ["ember", "server", "--live-reload-port", "35730"]
Once we have this, let's build the image using plain Docker. I recommend you run this on an empty folder, so we spend no time passing the folder contents into the build context:
docker build --pull --rm -t my-namespace/my-ember-app:development -f dev.Dockerfile .
Now that we've successfully built our development image, let's use it to create the project:
# Run a container with the current directory mounted, so we can create the
# project skeleton inside it:
docker run --rm -v $(pwd):/usr/src/app -ti my-namespace/my-ember-app:development bash ; cd my-ember-app
# Once inside the container, let ember-cli create the app skeleton for you
# - we'll skip the dependency installation, as the dependency list is HUGE
# and it may hang the terminal:
ember new my-ember-app --skip-npm --skip-bower
# Now, let's move our development Dockerfile inside the project:
mv dev.Dockerfile my-ember-app/
# Exit the container to see the project skeleton in your host:
exit
# Voilá! Now you'll be inside the project on your host
So far we've created the project skeleton - remember we haven't installed the dependencies yet.
To be able to share this project with the rest of the team, and start the project with the required settings, we'll create a very simple docker-compose.yml
file in the project's root:
version: "2"
services:
web:
image: my-namespace/my-ember-app:development
build:
context: .
dockerfile: dev.Dockerfile
command: ember server --live-reload-port 35730
entrypoint: /usr/src/app/development-entrypoint
volumes:
# Mount the app code inside the container's `/usr/src/app` directory:
- .:/usr/src/app
# Keep the stdin open, so we can attach to our app container's process
# and do things such as debugging, etc:
stdin_open: true
# Enable sending signals (CTRL+C, CTRL+P + CTRL+Q) into the container:
tty: true
ports:
# Bind the host's 4200 port to the container's ember app server
# port 4200:
- 4200:4200
# Bind the host's 35730 port to the container's ember cli live reload
# server port 35730:
- 35730:35730
environment:
SOME_URL: whatever
In nodejs projects, the only way we can install npm/bower/etc dependencies automatically is by using a development entrypoint script. Note that on step 1 we included the NPM package check-dependencies
, which
will help us to check if the dependencies have been installed or not:
#! /bin/bash
# The Docker App Container's development entrypoint.
# This is a script used by the project's Docker development environment to
# install the app dependencies automatically upon runnning.
set -e
: ${APP_PATH:="/usr/src/app"}
: ${APP_TEMP_PATH:="$APP_PATH/tmp"}
: ${APP_SETUP_LOCK:="$APP_TEMP_PATH/setup.lock"}
: ${APP_SETUP_WAIT:="5"}
# 1: Define the functions lock and unlock our app containers setup
# processes:
function lock_setup { mkdir -p $APP_TEMP_PATH && touch $APP_SETUP_LOCK; }
function unlock_setup { rm -rf $APP_SETUP_LOCK; }
function wait_setup { echo "Waiting for app setup to finish..."; sleep $APP_SETUP_WAIT; }
# 2: Specify a default command, in case it wasn't issued:
if [ -z "$1" ]; then set -- ember server --live-reload-port 35730 "$@"; fi
# 3: Run the setup routine if the command is 'ember':
if [[ "$1" = "ember" ]]
then
# 3.1: 'Unlock' the setup process if the script exits prematurely:
trap unlock_setup HUP INT QUIT KILL TERM EXIT
# 3.2: Wait until the setup 'lock' file no longer exists:
while [ -f $APP_SETUP_LOCK ]; do wait_setup; done
# 3.3: 'Lock' the setup process, to prevent a race condition with
# another container trying to install dependencies:
lock_setup
# 3.4: Check or install npm/bower dependencies:
check-dependencies || npm install && bower install
# 3.5: 'Unlock' the setup process:
unlock_setup
fi
# 4: Execute the given or default command:
exec "$@"
Also, ensure the script has execute permissions:
chmod +x development-entrypoint
You'll need to configure bower to do that. Add the "allow_root" : true
value inside the .bowerrc
file:
{
"directory": "bower_components",
"analytics": false,
"allow_root": true
}
Now we're good to go!
Up to this point, the ember app is ready to commit and push to a Git repository, and share it with the rest of the team!
With a freshly-cloned copy of the project, you'll want to fire it up. Remember that it may take a little while for the NPM/bower dependencies to install upon the first run:
docker-compose up -d && docker attach myemberapp_web_1
You'll want to see it in action at http://localhost:4200 :)
To use ember-cli commands inside the container:
# Running commands from the host inside a running container:
docker-compose exec web ember generate route home
# Running bash inside a running container to issue more commands:
docker-compose exec web bash
# Running commands without a running container - change `bash`
# to whatever you want to run:
docker-compose run --rm web bash