Docker / vagrant front end development without host syncing

I’ve been a vagrant user on OSX for a long time, and one of the common methods people use to allow modifying files inside the VM in their preferred development environment is through host syncing (synced folders).

Let me tell you from experience…it’s a shit option. If you aren’t using NFS as the file system (but rather ext or FAT), it’s painfully slow, especially on large projects. In addition, using NFS changes the networking options you have available, so it introduces other complications. I had resorted to simply running VIM within my VMs because I couldn’t take the slow load time and compromises on configuration.

When I started setting up a development environment with Docker, I decided I would get it right this time. Since under the hood Docker runs on top of VirtualBox (same as vagrant) on OSX, I wasn’t ready to go through the same pain again to get everything synced.

I elected instead for this solution:

- Pass in configuration via environment variables to set the Docker environment (and thus the container behavior) without image rebuilds.
- Download another repo that contains the code in the container setup.
- Create a local SSH mount for development.
- Install node dev tools on the container.
- Gulp runs watch, browserify, coffeeify, etc., on the container without looking at any shared volumes from my host.
- Nginx serves up the dist directory that gulp modifies as I make changes.

When running in development mode, the container adds a dev user, copies my local key to the container for that dev user, and starts the ssh server.

Here’s an example of how I’m loading my Docker container:

docker run -p 52022:22 —d -e key="$(cat ~/.ssh/id_rsa.pub)" IMAGE_ID

Here’s the magic bit that makes this work in the Dockerfile (I omitted the pieces that install dependencies, download a git repo, etc.):

ENTRYPOINT sh start.sh

…and the start.sh script:

if [ "$project_env" = "production" ]
then
  echo "Prod!"
else
  mkdir /project/.ssh
  echo $key >> /project/.ssh/authorized_keys
  service ssh start
  adduser --quiet --disabled-password -shell /bin/bash --home /deviant-ui --gecos "User" dev
  echo "dev:dev" | chpasswd
  cd /project
  git pull origin master
  gulp
  chown -R dev /deviant-ui
  echo "Dev."
fi

nginx -g "daemon off;"

I can now mount to my local filesystem using sshfs, which is installable on OSX via brew:

mnt_ip=$(boot2docker ip) && sshfs -p 52022 dev@$mnt_ip:/project /tmp/test

Unmounting is as easy as:

sudo umount -f /tmp/test

Now, I can work on my local machine, changes are synced instantly to my dev container where my gulp process can handle file watches and change the dist folder that nginx serves from, and I can push changes to my application code without modifying my dev docker image at all.

I’m not finished setting this up yet, but I just wanted to share these things I’ve found as most of the other examples online seem to take the hard path of fighting with VirtualBox. I’ll publish a complete example when it’s ready. To the people who say a Docker container should only do one thing, my answer is that in production, it will only do one thing! In development, I value my time and sanity more than rigid philosophy.

This entry was posted in DevOps, Docker. Bookmark the permalink. Trackbacks are closed, but you can post a comment.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>