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 and so does not require the docker client.
Installation
Add this line to your application's Gemfile:
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:
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
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 '[email protected]/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 '[email protected]/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.
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:
$ 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.
Contributing
- Fork it ( https://github.com/townsen/lux/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request