7

I'm working on a service in a 'system' orchestrated using docker-compose. The service is written in a compiled language and I need to rebuild it when I make a change. I'm trying to find the best way to quickly iterate on changes.

I've tried 2 'workflows', both rely on being linked to the source directory via a volume: to get the latest source.

A.
  • Bring up all the supporting containers with docker-compose up -d
  • Stop the container for the service under development
  • Run a new container using the image docker-compose run --name SERVICE --rm SERVICE /bin/bash
  • Within that container run compile and run the application at the exposed port.
  • Restart by stopping the running process and then rebuilding.
B.
  • (requires Dockerfile CMD to build and then run the service)
  • Stop the service: docker-compose kill SERVICE
  • Restart the service docker-compose up -d --no-deps SERVICE

The problem is both take too long to restart vs restarting the service locally (running on my laptop independently of docker). This setup seems to be ok with interpreted languages that can hot-reload changed files but I've yet to find a suitably fast system for compiled language services.

Community
  • 1
  • 1
Charlie Egan
  • 4,878
  • 6
  • 33
  • 48
  • 1
    Is docker running on your laptop, or remotely? Wondering what you mean with "vs restarting the service locally". What is causing it to take "too long to restart"? Is compiling slower? Starting? – thaJeztah Jan 18 '16 at 23:51
  • I've attempted to make this clearer in the question. Docker is running via docker-machine. When I say 'running locally' I mean building and running the service without using docker at all. This is an option but it means I need to change things like the database URL etc. – Charlie Egan Jan 18 '16 at 23:55
  • Ah, right, my best guess here is that, first of all, file-sharing between the host and the VirtualBox VM is (to say nicely) not very performant; this is a limitation of VirtualBox filesharing. Second, the VM may not be tuned for maximum performance, which could make a difference in compile duration. Have you tried to, e.g. raise the amount of memory and/or number of CPU's for the VM? – thaJeztah Jan 19 '16 at 00:03
  • No, this I have not done. Would I do this in virtualbox or via a docker-machine command? – Charlie Egan Jan 19 '16 at 00:05
  • 2
    You can specify additional options when creating a new machine; https://docs.docker.com/machine/drivers/virtualbox/, for example `--virtualbox-memory` and `--virtualbox-cpu-count`. If it's for an existing machine, you can use the VirtualBox GUI for that, see http://stackoverflow.com/questions/32834082/how-to-increase-docker-machine-memory-mac/34598900#34598900 – thaJeztah Jan 19 '16 at 00:22
  • @thaJeztah thanks, I've created a fresh VM with some more power. Going to have a look at implementing the steps in the answer. Cheers. – Charlie Egan Jan 19 '16 at 10:47

1 Answers1

4

I would do this:

Run docker-compose up but:

  • use a host volume for the directory of the compiled binary instead of the source
  • use an entrypoint that does something like

entrypoint.sh:

trap "pkill -f the_binary_name" SIGHUP
trap "exit" SIGTERM

while [[ 1 ]]; do
  ./the_binary_name;
done

Write a script to rebuild the binary, and copy it into the volume used by the service in docker-compose.yml:

# Run a container to compile and build the binary
docker run -ti -v $SOURCE:/path -v $DEST:/target some_image build_the_binary

# copy it to the host volume directory
copy $DEST/... /volume/shared/with/running/container

# signal the container
docker kill -s SIGHUP container_name

So to compile the binary you use this script, which mounts the source and a destination directory as volumes. You could skip the copy step if the $DEST is the same as the volume directory shared with the "run" container. Finally the script will signal the running container to have it kill the old process (which was running the old binary) and start the new one.

If the shared volume is making compiling in a container too slow, you could also run the compile on the host and just do the copy and signaling to have it run in a container.

This solution has the added benefit that your "runtime" image doesn't need all the dev dependencies. It could be a very lean image with just a bare OS base.

dnephin
  • 25,944
  • 9
  • 55
  • 45
  • 1
    Hi, thanks for this in depth answer. This has explained a lot. I've been able to get it working much as you outline here. One difference, I wasn't able to get `docker kill -s SIGHUP` working, I'm using `docker exec web pkill -f container_name` instead. This might not be as fast but switching to this method has cut the time for a single 'iteration' down significantly. Thanks. – Charlie Egan Jan 19 '16 at 12:05