diff --git a/wdocker_compose.org b/wdocker_compose.org new file mode 100644 index 0000000..e1190eb --- /dev/null +++ b/wdocker_compose.org @@ -0,0 +1,160 @@ +#+TITLE: Making docker-compose easier with wdocker +#+OPTION: num:nil + +* Introduction + + [[https://github.com/babab/wdocker][wdocker]] is a little utility written by a [[https://benjamin.althu.es][friend]] and former colleague + of mine. It allows you to define commands for it in a + ~Dockerfile~. He wrote it because he used a lot of composite + commands when writing docker images like: + + #+BEGIN_SRC sh + docker stop CONTAINER && docker rm CONTAINER && docker rmi IMAGE \ + docker build -t IMAGE && docker start -n CONTAINER IMAGE + #+END_SRC + + By using wdocker to define a command he can greatly simplify his own + workflow. Let's call it rebuild: + + #+BEGIN_SRC dockerfile + #wd# container = CONTAINER + #wd# image = IMAGE + #wd# stop = docker stop {container} + #wd# rm = docker rm {container} + #wd# rmi = docker rmi {container} + #wd# build = docker build -t {image} + #wd# start = docker start -n {container} {image} + + #wd# rebuild: {stop} && {rm} && {rmi} && {build} && {start} + + FROM ubuntu + + # ... + #+END_SRC + + Now he can use the following command instead of the list presented + before: + + : wdocker rebuild + +* Syntax + + wdocker has very simple syntax. You can define variables and + commands: + + : #wd# variable = value + : #wd# command: program + + Variables can be used by putting them in braces, including in other + variables, as you've seen in the first example. + + : #wd# variable = -l + : #wd# list: ls {variable} + + This would run =ls -l= when the command =wdocker list= is called. + + As you can see you're not limited to using docker in your wdocker + commands. This property is what allows me to use wdocker in my + workflow. + +* Combining with docker-compose + + I started using docker not too long ago at work to develop our + projects in. This is nice because it allows me to completely isolate + my development environments. Since we have a few processes running + together a single docker image isn't a great option, so I use + docker-compose to define and combine the containers I need. + + As a side-effect this requires me to write long commands to do + something like run rspec tests: + + : docker-compose run --rm -e RACK_ENV=test -e RAILS_ENV=test \ + : container bundle exec rspec + + The alternative is defining a specialized test container with a + bogus entry command (such as ~true~) and use that, which would still + make the command: + + : docker-compose run --rm test-container bundle exec rspec + + Instead I can define a wdocker command in the ~Dockerfile~ used to + build the containers used: + + #+BEGIN_SRC dockerfile + #wd# rspec: docker-compose run --rm -e RACK_ENV=test -e RAILS_ENV=test container bundle exec rspec + + FROM ruby + + #... + #+END_SRC + + Now I can run the following, much shorter, command to run the rspec + tests: + + : wdocker rspec + + We also use cucumber for some other tests, which is even longer to + type in, adding the ~cucumber~ command is easy: + + #+BEGIN_SRC dockerfile + #wd# rspec: docker-compose run --rm -e RACK_ENV=test -e RAILS_ENV=test container bundle exec rspec + #wd# cucumber: docker-compose run --rm -e RACK_ENV=test -e RAILS_ENV=test container bundle exec cucumber + + FROM ruby + + # ... + #+END_SRC + + Now I can run =wdocker cucumber= as well. + + The latest git version of wdocker passes any arguments after the + command name directly to the command to be executed. So if I need to + run tests in a single spec file I can just do: + + : wdocker rspec spec/models/mymodel_spec.rb + + We have two commands defined now that are 90% the same. I always use + the ~--rm~ switch to remove the started container after it's done, I + don't want a lot of containers piling up. I also always have to use + ~bundle exec~ to run commands, since the containers don't use rvm or + add the script directories to ~$PATH~. We can extract them to some + variables: + + #+BEGIN_SRC dockerfile + #wd# run = docker-compose run --rm + #wd# exec = bundle exec + #wd# test = -e RACK_ENV=test -e RAILS_ENV=test + + #wd# rspec: {run} {test} container {exec} rspec + #wd# cucumber: {run} {test} container {exec} cucumber + + FROM ruby + + # ... + #+END_SRC + + Right now these commands always use the ~container~ service defined + in ~docker-compose.yml~. I could add it to the ~run~ command, but I + might need to run some commands on another container, but I can + define another variable: + + #+BEGIN_SRC dockerfile + #wd# run = docker-compose run --rm + #wd# test = -e RACK_ENV=test -e RAILS_ENV=test + #wd# run-test-container = {run} {test} container + #wd# exec = bundle exec + + #wd# rspec: {run-test-container} {exec} rspec + #wd# cucumber: {run-test-container} {exec} cucumber + + FROM ruby + + # ... + #+END_SRC + + Now you also see that variables can be nested in other variables. + + If you ever forget what you defined or if the mix of commands and + variables becomes too much for you, you can call the wdocker command + without arguments to see the commands you defined and the shell + commands they'll run.