Docker::Compose
This is a Ruby OOP wrapper for the docker-compose container orchestration tool from Docker Inc.
In addition to wrapping the CLI, this gem provides an environment-variable mapping feature that allows you to export environment variables into your host that point to network services exposed by containers. This allows you to run an application on your host for quicker and easier development, but run all of its dependencies -- database, cache, adjacent services -- in containers. The dependencies can even run on another machine, e.g. a cloud instance or a container cluster, provided your development machine has TCP connectivity to every port exposed by a container.
Throughout this documentation we will refer to this gem as Docker::Compose
as opposed to the docker-compose
tool that this gem wraps.
Installation
Add this line to your application's Gemfile:
gem 'docker-compose'
And then execute:
$ bundle
Or install it yourself as:
$ gem install docker-compose
Usage
Invoking from Ruby code
require 'docker/compose'
# Create a new session in Dir.pwd using the file "docker-compose.yml".
# For fine-grained control over options, see Docker::Compose::Session#new
compose = Docker::Compose.new
compose.version
compose.up(detached:true)
exited = compose.ps.where { |c| !c.up? }
puts "We have some exited containers: " + exited.join(', ')
sum = compose.ps.inject(0) { |a,c| a + c.size }
puts format("Composition is using %.1f MiB disk space", sum/1024.0**2)
Invoking from Rake
Open your Rakefile and add the Docker::Compose tasks.
require 'docker/compose/rake_tasks'
Docker::Compose::RakeTasks.new do |tasks|
# customize by calling setter methods of tasks;
# see the class documentation for details
end
Notice that rake -T
now has a few additional tasks for invoking gem
functionality. You can docker:compose:env
to print shell exports for
host-to-container environment mapping, or you can docker:compose:host[foo]
.
Hosting a Command
To run a process on your host and allow it to talk to containers, use
the docker:compose:host
task. For example, I could enter a shell
with rake docker:compose:host[bash]
.
Before "hosting" your command, the Rake task exports some environment
variables that your command can use to discover services running in
containers. Your Rakefile specifies which variables your app needs
(the host_env
option) and which container information each variable should
map to.
By hosting commands, you benefit from easier debugging and code editing of the app you're working on, but still get to rely on containers to provide the companion services your app requires to run.
Mapping container IPs and ports
As a trivial example, let's say that your docker-compose.yml
contains one
service, the database that your app needs in order to run.
db:
image: mysql:latest
environment:
MYSQL_DATABASE: myapp_development
MYSQL_ROOT_PASSWORD: opensesame
ports:
- "3306"
Your app needs two inputs, DATABASE_HOST
and DATABASE_PORT
. You can specify
this with the host_env option of the Rake task:
Docker::Compose::RakeTasks.new do |tasks|
tasks.host_env = {
'DATABASE_HOST' => 'db:[3306]',
'DATABASE_PORT' => '[db]:3306',
}
end
Now, I can run my services, ask Docker::Compose to map the environment values
to the actual IP and port that db
has been published to, and run my app:
# First, bring up the containers we will be interested in
user@machine$ docker-compose up -d
# The rake task prints bash code resembling the following:
# export DATABASE_HOST='127.0.0.1'
# export DATABASE_PORT='34387'
# We eval it, which makes the variables available to our shell and to all
# subprocesses.
user@machine$ eval "$(bundle exec rake docker:compose:env)"
user@machine$ bundle exec rackup
The host_env
option also handles substitution of URLs, and arrays of values
(which are serialized back to the environment as JSON)
For example:
tasks.host_env = {
'DATABASE_URL' => 'mysql://db:3306/myapp_development',
'MIXED_FRUIT' => ['db:[3306]', '[db]:3306']
}
This would result in the following exports:
export DATABASE_URL='mysql://127.0.0.1:34387/myapp_development'
export MIXED_FRUIT='["127.0.0.1", "34387"]'
To learn more about mapping, read the class documentation for
Docker::Compose::Mapper
.
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, create a GitHub release and the .gem
file will be automatically uploaded to RubyGems and GitHub Packages.
The automated publication workflow renders rake release
obsolete, and also makes the committed contents of version.rb
irrelevant -- the version file is updated on the fly during the publish workflow. As a convention, we leave the committed file set to X.99.0-dev
to signify a development copy of the gem's source code but preserve major-version compatibility. This facilitates testing of prerelease versions of this gem in other local codebases using the Gemfile path:
option.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/xeger/docker-compose. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
License
The gem is available as open source under the terms of the MIT License.