# Lux [![Gem Version](http://img.shields.io/gem/v/lux.svg)][gem] [gem]: https://rubygems.org/gems/lux Shining some light on setting up and running various Docker things. Lux is both a command line tool (based on Thor) and a library of useful routines that can be included in Rake tasks. It uses the Docker API directly via the [docker-api GEM](https://github.com/swipely/docker-api) and so does not require the docker client. ## Installation Add this line to your application's Gemfile: ```ruby gem 'lux' ``` And then execute: $ bundle Or install it yourself as: $ gem install lux ## Usage If using a Docker server across the network, make sure that you have exported the environment variable `DOCKER_URL ` (which is a true URL). Note that this is different to the Go docker client which uses `DOCKER_HOST`. ### Command Line Tool The `lux` command simplifies a number of Docker command line operations and provides unix-style commands for listing and removing images, as well as rake-like tasks for cleaning, tidying and clobbering containers and their images. Type: `lux help` to get started ### Handy Functions To assist in creating Rakefiles where the location of container targets is on the Docker host use the module function `Lux.dockerip` as follows: ```ruby require 'lux' DOCKER_IP = Lux.dockerip[0] ``` The function returns a second element which is a Ruby URI object representing the environment variable `DOCKER_HOST` or `DOCKER_URL`. ### Rake Tasks When trying to write Rakefiles that start Docker containers it is useful to have a Rake task that represents a container image. Then you can make other tasks depend on them. If the task (when invoked) checks the local Docker server for the image, and only executes the task body if the image is not found, or if the listed dependencies are out-of-date, then you can build Docker dependencies elegantly into the Rakefile. Lux extends Rake with two new task types `dockerimage` and `container`. Both of them are specializations of the `file` task. They use the Docker server pointed to by the `DOCKER_URL` environment variable and do *not* query a remote registry. #### `dockerimage` This checks for the existence of an image with the task name in the Docker server. It uses the creation date found there as the timestamp and executes the associated action if it is out-of-date with respect to it's dependencies. This means you can rebuild the image based on other dependencies (such as the Dockerfile or content). If you are using an image on a remote repository that you don't build locally then you can either define it and make the action a `docker pull` command or omit it altogether. In the former case you can then add this as a dependency to a container task to ensure that a running container always has the most up-to-date image. The latter case works as the Docker runtime will attempt to pull an image from a remote repository if it is not present locally. #### `container` This checks for the existence of a running container for a particular docker image. The task name is a compound name of the form `containername@imagename`. If the container named is not running then the action block is executed, typically it will be a Docker run command. If the container is already running then it's image is checked to see if that it is the same as specified. If not the container is destroyed and the action block executed. If the container image matches the requested one, then the creation date of the container is used as the task timestamp. This allows you to specify a dockerimage dependency and the container will then be restarted if the image is newer. Note that you don't need a corresponding dockerimage task as the Docker runtime will attempt to pull an image from a remote repository if it is not present locally. #### Examples ```ruby require 'lux/docker_tasks' desc "Build tool image if the image is not found locally" dockerimage 'quay.io/rasputin/tools:1.0' do |t| sh "docker build -t #{t.name} ." end desc "Build tool image if the image is not found or is older than the Dockerfile" dockerimage 'quay.io/rasputin/tools:1.0' => 'Dockerfile' do |t| sh "docker build -t #{t.name} ." end desc "Make sure we have a running tools container" container 'tools@quay.io/rasputin/tools:1.0' do sh "docker run --name tools -d quay.io/rasputin/tools:1.0" end desc "Make sure we have a running tools container with the most up-to-date image" container 'tools@quay.io/rasputin/tools:1.0' => 'quay.io/rasputin/tools:1.0' do sh "docker run --name tools -d quay.io/rasputin/tools:1.0" end # A set of tasks to ensure you always have the latest version of a container # stored on a remote registry require 'lux/docker_tasks' desc "Always see if there is a new version of busybox" task :getbusybox do sh "docker pull busybox" end desc "Create a dockerimage task so we can depend on it" dockerimage 'busybox' => :getbusybox desc "Always run with the latest version" container 'busy@busybox' => 'busybox' do sh "docker run -it --name busy busybox" end ``` #### Tracing When the Rake trace option is enabled the destruction (or attempted destruction if it's a dry-run) is recorded. #### Namespaces When using the `dockerimage` and `container` tasks with explicit tags (ie. containing a semi-colon), then normal Rake namespace rules apply: The _repository_ name will be considered the namespace and the _tag_ the taskname within the namespace. If this `dockerimage` task is declared in the same execution alongside a matching explicit namespace and task declaration, then the actions will accumulate. ```ruby task :default => 'busybox:greenest' dockerimage 'busybox:greenest' do puts "Build busybox:greenest Docker image" end namespace :busybox do task :greenest do puts "Do the greenest task in the busybox namespace" end end ``` This prints: ```bash $ rake -f Rakefile.demo Build busybox:greenest Docker image Do the greenest task in the busybox namespace ``` ## Development To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). ## Contributing 1. Fork it ( https://github.com/townsen/lux/fork ) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create a new Pull Request