9/10/19 NOTE: While much of this should still work, this guide is quite old at this point. See an updated guide on how to run Phoenix on Docker.
Docker: 17.03 (Docker for Mac)
Docker Compose: 1.11.2
I'm experimenting with Phoenix as a backend to a new Ember app. Docker and Docker Compose are excellent tools for testing and validating new development tools. This post demonstrates how to set up a Docker Compose environment for Phoenix and Ember development.
Set up Docker Compose
First, create a directory structure for your project with a
docker-compose.yml and child directories for your Phoenix back-end and Ember front-end.
It should end up looking something like this:
$ tree -L 1 . ├── docker-compose.yml ├── appname-client └── appname-server
Then, copy the following into
version: '2' volumes: node_modules: bower_components: tmp: dist: services: db: image: postgres:latest server: image: ntodd/phoenix:1.2.1 command: mix phoenix.server volumes: - ./appname-server:/app ports: - "4000:4000" depends_on: - db client: image: ntodd/ember-cli:2.12.2 command: ember server --live-reload-port 35729 volumes: - ./appname-client:/app - node_modules:/app/node_modules - bower_components:/app/bower_components - tmp:/app/tmp - dist:/app/dist ports: - "4200:4200" - "35729:35729"
That's really all there is to it. If you don't care about the details, skip to the Usage section.
Understanding the Docker Compose configuration
Let's parse the
version: '2' volumes: node_modules: bower_components: tmp: dist:
First, this tells Docker Compose that we are using API version 2. Then, we are creating named volumes that we will use later in the Ember service. These named volumes are internal volumes not shared with the host.
services: db: image: postgres:latest
We need a database for our Phoenix server. This tells Docker Compose to use the latest postgres image.
server: image: ntodd/phoenix:1.2.1 command: mix phoenix.server volumes: - ./appname-server:/app ports: - "4000:4000" depends_on: - db
This is our Phoenix app. It pulls an image with Elixir 1.4.2 and Phoenix 1.2.1. When running
docker-compose up it will run the
mix phoenix.server command to give you a development server at port 4000. We define a shared host volume from our phoenix app directory in the host to the app working directory in the docker image. Finally, we tell Docker Compose that our Phoenix app depends on the postgres database service we defined before.
client: image: ntodd/ember-cli:2.12.2 command: ember server --live-reload-port 35729 volumes: - ./appname-client:/app - node_modules:/app/node_modules - bower_components:/app/bower_components - tmp:/app/tmp - dist:/app/dist ports: - "4200:4200" - "35729:35729"
This is our Ember app. It pulls an image with Node 7.0 and Ember 2.12.2.
docker-compose up will run the
ember server command and force the live-reload-port to 35729. The ports 4200 (Ember CLI) and 35729 (livereload) are forwarded from the host to the image.
volumes: section is a bit more complex than the Phoenix app. We first define a shared host volume from our ember app directory to the app working directory in the ember image for our application files. We then map the named volumes we created before into the app working directory for our temp, npm and bower directories. This isn't strictly necessary to do, but Ember has a tendency to be very slow on Docker for Mac due to poor performance of shared osxfs volumes when performing a large number of writes. Named volumes don't have the same performance issues, so using them for build and temp directories can increase Ember CLI build performance significantly (around 400% faster in my tests).
docker-compose can be run from child directories, so you can run commands from within the client and server dirs. Also,
run commands will override the
command: in the configuration, so it's very easy to run
ember init and
phoenix.new will need to be invoked to ensure the generators run in the current working directory.
Generate new Phoenix app:
# Maybe you also want to pass --no-html if you are only creating an API $ docker-compose run server mix phoenix.new . --app appname
Generate new Ember-CLI app:
$ docker-compose run client ember init --name appname
Bonus tip: set
alias dc=docker-compose in