Merge pull request #2549 from mitchellh/f-docker-provisioner
docker provisioner
This commit is contained in:
commit
146bc34019
|
@ -0,0 +1,15 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module Docker
|
||||||
|
module Cap
|
||||||
|
module Debian
|
||||||
|
module DockerConfigureAutoStart
|
||||||
|
def self.docker_configure_auto_start(machine)
|
||||||
|
if ! machine.communicate.test('grep -q \'\-r=true\' /etc/init/docker.conf')
|
||||||
|
machine.communicate.sudo("sed -i.bak 's/docker -d/docker -d -r=true/' /etc/init/docker.conf ")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module Docker
|
||||||
|
module Cap
|
||||||
|
module Debian
|
||||||
|
module DockerConfigureVagrantUser
|
||||||
|
def self.docker_configure_vagrant_user(machine)
|
||||||
|
machine.communicate.sudo("usermod -a -G docker #{machine.config.ssh.username || "vagrant"}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,26 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module Docker
|
||||||
|
module Cap
|
||||||
|
module Debian
|
||||||
|
module DockerInstall
|
||||||
|
def self.docker_install(machine, version)
|
||||||
|
package = 'lxc-docker'
|
||||||
|
package << "-#{version}" if version != :latest
|
||||||
|
|
||||||
|
machine.communicate.tap do |comm|
|
||||||
|
# TODO: Perform check on the host machine if aufs is installed and using LXC
|
||||||
|
if machine.provider_name != :lxc
|
||||||
|
comm.sudo("lsmod | grep aufs || modprobe aufs || apt-get install -y linux-image-extra-`uname -r`")
|
||||||
|
end
|
||||||
|
comm.sudo("apt-get install -y --force-yes -q curl")
|
||||||
|
comm.sudo("curl http://get.docker.io/gpg | apt-key add -")
|
||||||
|
comm.sudo("echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list")
|
||||||
|
comm.sudo("apt-get update")
|
||||||
|
comm.sudo("apt-get install -y --force-yes -q xz-utils #{package} -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold'")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module Docker
|
||||||
|
module Cap
|
||||||
|
module Debian
|
||||||
|
module DockerStartService
|
||||||
|
def self.docker_start_service(machine)
|
||||||
|
machine.communicate.sudo("service docker start")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module Docker
|
||||||
|
module Cap
|
||||||
|
module Linux
|
||||||
|
module DockerInstalled
|
||||||
|
def self.docker_installed(machine)
|
||||||
|
machine.communicate.test("test -f /usr/bin/docker", sudo: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,43 @@
|
||||||
|
require 'set'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module Docker
|
||||||
|
class Config < Vagrant.plugin("2", :config)
|
||||||
|
attr_reader :images, :containers
|
||||||
|
attr_accessor :version
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@images = Set.new
|
||||||
|
@containers = Hash.new
|
||||||
|
@version = UNSET_VALUE
|
||||||
|
end
|
||||||
|
|
||||||
|
def images=(images)
|
||||||
|
@images = Set.new(images)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pull_images(*images)
|
||||||
|
@images += images.map(&:to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run(name, **options)
|
||||||
|
params = options.dup
|
||||||
|
params[:image] = name
|
||||||
|
|
||||||
|
# TODO: Validate provided parameters before assignment
|
||||||
|
@containers[name.to_s] = params
|
||||||
|
end
|
||||||
|
|
||||||
|
def finalize!
|
||||||
|
@version = "latest" if @version == UNSET_VALUE
|
||||||
|
@version = @version.to_sym
|
||||||
|
end
|
||||||
|
|
||||||
|
def merge(other)
|
||||||
|
super.tap do |result|
|
||||||
|
result.pull_images(*(other.images + self.images))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,78 @@
|
||||||
|
require 'digest/sha1'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module Docker
|
||||||
|
class DockerClient
|
||||||
|
def initialize(machine)
|
||||||
|
@machine = machine
|
||||||
|
end
|
||||||
|
|
||||||
|
def pull_images(*images)
|
||||||
|
@machine.communicate.tap do |comm|
|
||||||
|
images.each do |image|
|
||||||
|
@machine.ui.info(I18n.t("vagrant.docker_pulling_single", name: image))
|
||||||
|
comm.sudo("docker images | grep -q #{image} || docker pull #{image}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_service
|
||||||
|
if !daemon_running? && @machine.guest.capability?(:docker_start_service)
|
||||||
|
@machine.guest.capability(:docker_start_service)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def daemon_running?
|
||||||
|
@machine.communicate.test('test -f /var/run/docker.pid')
|
||||||
|
end
|
||||||
|
|
||||||
|
def run(containers)
|
||||||
|
containers.each do |name, config|
|
||||||
|
cids_dir = "/var/lib/vagrant/cids"
|
||||||
|
config[:cidfile] ||= "#{cids_dir}/#{Digest::SHA1.hexdigest name}"
|
||||||
|
|
||||||
|
@machine.ui.info(I18n.t("vagrant.docker_running", name: name))
|
||||||
|
@machine.communicate.sudo("mkdir -p #{cids_dir}")
|
||||||
|
run_container({
|
||||||
|
name: name
|
||||||
|
}.merge(config))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_container(config)
|
||||||
|
raise "Container's cidfile was not provided!" if !config[:cidfile]
|
||||||
|
|
||||||
|
id = "$(cat #{config[:cidfile]})"
|
||||||
|
|
||||||
|
if container_exist?(id)
|
||||||
|
start_container(id)
|
||||||
|
else
|
||||||
|
create_container(config)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def container_exist?(id)
|
||||||
|
@machine.communicate.test("sudo docker ps -a -q | grep -q #{id}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_container(id)
|
||||||
|
if !container_running?(id)
|
||||||
|
@machine.communicate.sudo("docker start #{id}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def container_running?(id)
|
||||||
|
@machine.communicate.test("sudo docker ps -q | grep #{id}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_container(config)
|
||||||
|
args = "-cidfile=#{config[:cidfile]} -d "
|
||||||
|
args << config[:args] if config[:args]
|
||||||
|
@machine.communicate.sudo %[
|
||||||
|
rm -f #{config[:cidfile]}
|
||||||
|
docker run #{args} #{config[:image]} #{config[:cmd]}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,39 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module Docker
|
||||||
|
class DockerInstaller
|
||||||
|
def initialize(machine, version)
|
||||||
|
@machine = machine
|
||||||
|
@version = version
|
||||||
|
end
|
||||||
|
|
||||||
|
# This handles verifying the Docker installation, installing it if it was
|
||||||
|
# requested, and so on. This method will raise exceptions if things are
|
||||||
|
# wrong.
|
||||||
|
def ensure_installed
|
||||||
|
if !@machine.guest.capability?(:docker_installed)
|
||||||
|
@machine.ui.warn(I18n.t("vagrant.docker_cant_detect"))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if !@machine.guest.capability(:docker_installed)
|
||||||
|
@machine.ui.info(I18n.t("vagrant.docker_installing", version: @version.to_s))
|
||||||
|
@machine.guest.capability(:docker_install, @version)
|
||||||
|
|
||||||
|
if !@machine.guest.capability(:docker_installed)
|
||||||
|
raise DockerError, :install_failed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if @machine.guest.capability?(:docker_configure_auto_start)
|
||||||
|
@machine.guest.capability(:docker_configure_auto_start)
|
||||||
|
else
|
||||||
|
@machine.env.ui.warn I18n.t('vagrant.docker_auto_start_not_available')
|
||||||
|
end
|
||||||
|
|
||||||
|
if @machine.guest.capability?(:docker_configure_vagrant_user)
|
||||||
|
@machine.guest.capability(:docker_configure_vagrant_user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,48 @@
|
||||||
|
require "vagrant"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module Docker
|
||||||
|
class Plugin < Vagrant.plugin("2")
|
||||||
|
name "docker"
|
||||||
|
description <<-DESC
|
||||||
|
Provides support for provisioning your virtual machines with
|
||||||
|
Docker images and containers.
|
||||||
|
DESC
|
||||||
|
|
||||||
|
config(:docker, :provisioner) do
|
||||||
|
require_relative "config"
|
||||||
|
Config
|
||||||
|
end
|
||||||
|
|
||||||
|
guest_capability("debian", "docker_install") do
|
||||||
|
require_relative "cap/debian/docker_install"
|
||||||
|
Cap::Debian::DockerInstall
|
||||||
|
end
|
||||||
|
|
||||||
|
guest_capability("debian", "docker_configure_auto_start") do
|
||||||
|
require_relative "cap/debian/docker_configure_auto_start"
|
||||||
|
Cap::Debian::DockerConfigureAutoStart
|
||||||
|
end
|
||||||
|
|
||||||
|
guest_capability("debian", "docker_configure_vagrant_user") do
|
||||||
|
require_relative "cap/debian/docker_configure_vagrant_user"
|
||||||
|
Cap::Debian::DockerConfigureVagrantUser
|
||||||
|
end
|
||||||
|
|
||||||
|
guest_capability("debian", "docker_start_service") do
|
||||||
|
require_relative "cap/debian/docker_start_service"
|
||||||
|
Cap::Debian::DockerStartService
|
||||||
|
end
|
||||||
|
|
||||||
|
guest_capability("linux", "docker_installed") do
|
||||||
|
require_relative "cap/linux/docker_installed"
|
||||||
|
Cap::Linux::DockerInstalled
|
||||||
|
end
|
||||||
|
|
||||||
|
provisioner(:docker) do
|
||||||
|
require_relative "provisioner"
|
||||||
|
Provisioner
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,43 @@
|
||||||
|
require_relative "docker_client"
|
||||||
|
require_relative "docker_installer"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module Docker
|
||||||
|
class DockerError < Vagrant::Errors::VagrantError
|
||||||
|
error_namespace("vagrant.provisioners.docker")
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO: Improve handling of vagrant-lxc specifics (like checking for apparmor
|
||||||
|
# profile stuff + autocorrection)
|
||||||
|
class Provisioner < Vagrant.plugin("2", :provisioner)
|
||||||
|
def initialize(machine, config, installer = nil, client = nil)
|
||||||
|
super(machine, config)
|
||||||
|
|
||||||
|
# TODO: Rename to installer / client (drop docker suffix)
|
||||||
|
@installer = installer || DockerInstaller.new(@machine, config.version)
|
||||||
|
@client = client || DockerClient.new(@machine)
|
||||||
|
end
|
||||||
|
|
||||||
|
def provision
|
||||||
|
@logger = Log4r::Logger.new("vagrant::provisioners::docker")
|
||||||
|
|
||||||
|
@logger.info("Checking for Docker installation...")
|
||||||
|
@installer.ensure_installed
|
||||||
|
|
||||||
|
# Attempt to start service if not running
|
||||||
|
@client.start_service
|
||||||
|
raise DockerError, :not_running if !@client.daemon_running?
|
||||||
|
|
||||||
|
if config.images.any?
|
||||||
|
@machine.ui.info(I18n.t("vagrant.docker_pulling_images"))
|
||||||
|
@client.pull_images(*config.images)
|
||||||
|
end
|
||||||
|
|
||||||
|
if config.containers.any?
|
||||||
|
@machine.ui.info(I18n.t("vagrant.docker_starting_containers"))
|
||||||
|
@client.run(config.containers)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -42,6 +42,21 @@ en:
|
||||||
to automatically delete Chef nodes and clients.
|
to automatically delete Chef nodes and clients.
|
||||||
chef_run_list_empty: |-
|
chef_run_list_empty: |-
|
||||||
Warning: Chef run list is empty. This may not be what you want.
|
Warning: Chef run list is empty. This may not be what you want.
|
||||||
|
|
||||||
|
docker_installing: |-
|
||||||
|
Installing Docker (%{version}) onto machine...
|
||||||
|
docker_pulling_images:
|
||||||
|
Pulling Docker images...
|
||||||
|
docker_pulling_single: |-
|
||||||
|
-- Image: %{name}
|
||||||
|
docker_running: |-
|
||||||
|
-- Container: %{name}
|
||||||
|
docker_starting_containers:
|
||||||
|
Starting Docker containers...
|
||||||
|
docker_auto_start_not_available: |-
|
||||||
|
Unable to configure automatic restart of Docker containers on
|
||||||
|
the guest machine
|
||||||
|
|
||||||
provisioner_cleanup: |-
|
provisioner_cleanup: |-
|
||||||
Running cleanup tasks for '%{name}' provisioner...
|
Running cleanup tasks for '%{name}' provisioner...
|
||||||
|
|
||||||
|
@ -1317,3 +1332,7 @@ en:
|
||||||
playbook_path_invalid: "`playbook` for the Ansible provisioner does not exist on the host system: %{path}"
|
playbook_path_invalid: "`playbook` for the Ansible provisioner does not exist on the host system: %{path}"
|
||||||
inventory_path_invalid: "`inventory_path` for the Ansible provisioner does not exist on the host system: %{path}"
|
inventory_path_invalid: "`inventory_path` for the Ansible provisioner does not exist on the host system: %{path}"
|
||||||
extra_vars_invalid: "`extra_vars` for the Ansible provisioner must be a hash or a path to an existing file. Received: %{value} (as %{type})"
|
extra_vars_invalid: "`extra_vars` for the Ansible provisioner must be a hash or a path to an existing file. Received: %{value} (as %{type})"
|
||||||
|
|
||||||
|
docker:
|
||||||
|
not_running: "Docker is not running on the guest VM."
|
||||||
|
install_failed: "Docker installation failed."
|
||||||
|
|
|
@ -150,6 +150,7 @@
|
||||||
<li<%= sidebar_current("provisioning-ansible") %>><a href="/v2/provisioning/ansible.html">Ansible</a></li>
|
<li<%= sidebar_current("provisioning-ansible") %>><a href="/v2/provisioning/ansible.html">Ansible</a></li>
|
||||||
<li<%= sidebar_current("provisioning-chefsolo") %>><a href="/v2/provisioning/chef_solo.html">Chef Solo</a></li>
|
<li<%= sidebar_current("provisioning-chefsolo") %>><a href="/v2/provisioning/chef_solo.html">Chef Solo</a></li>
|
||||||
<li<%= sidebar_current("provisioning-chefclient") %>><a href="/v2/provisioning/chef_client.html">Chef Client</a></li>
|
<li<%= sidebar_current("provisioning-chefclient") %>><a href="/v2/provisioning/chef_client.html">Chef Client</a></li>
|
||||||
|
<li<%= sidebar_current("provisioning-docker") %>><a href="/v2/provisioning/docker.html">Docker</a></li>
|
||||||
<li<%= sidebar_current("provisioning-puppetapply") %>><a href="/v2/provisioning/puppet_apply.html">Puppet Apply</a></li>
|
<li<%= sidebar_current("provisioning-puppetapply") %>><a href="/v2/provisioning/puppet_apply.html">Puppet Apply</a></li>
|
||||||
<li<%= sidebar_current("provisioning-puppetagent") %>><a href="/v2/provisioning/puppet_agent.html">Puppet Agent</a></li>
|
<li<%= sidebar_current("provisioning-puppetagent") %>><a href="/v2/provisioning/puppet_agent.html">Puppet Agent</a></li>
|
||||||
<li<%= sidebar_current("provisioning-salt") %>><a href="/v2/provisioning/salt.html">Salt</a></li>
|
<li<%= sidebar_current("provisioning-salt") %>><a href="/v2/provisioning/salt.html">Salt</a></li>
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
---
|
||||||
|
page_title: "Docker - Provisioning"
|
||||||
|
sidebar_current: "provisioning-docker"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Docker Provisioner
|
||||||
|
|
||||||
|
**Provisioner name: `"docker"`**
|
||||||
|
|
||||||
|
The docker provisioner can automatically install [Docker](http://www.docker.io),
|
||||||
|
pull Docker containers, and configure certain containers to run on boot.
|
||||||
|
|
||||||
|
The docker provisioner is ideal for organizations that are using
|
||||||
|
Docker as a means to distribute things like their application or services.
|
||||||
|
Or, if you're just getting started with Docker, the Docker provisioner
|
||||||
|
provides the easiest possible way to begin using Docker since the provisioner
|
||||||
|
automates installing Docker for you.
|
||||||
|
|
||||||
|
As with all provisioners, the Docker provisioner can be used along with
|
||||||
|
all the other provisioners Vagrant has in order to setup your working
|
||||||
|
environment the best way possible. For example, perhaps you use Puppet to
|
||||||
|
install services like databases or web servers but use Docker to house
|
||||||
|
your application runtime. You can use the Puppet provisioner along
|
||||||
|
with the Docker provisioner.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
The docker provisioner takes various options. None are required. If
|
||||||
|
no options are required, the Docker provisioner will only install Docker
|
||||||
|
for you (if it isn't already installed).
|
||||||
|
|
||||||
|
* `images` (array) - A list of images to pull using `docker pull`. You
|
||||||
|
can also use the `pull_images` function. See the example below this
|
||||||
|
section for more information.
|
||||||
|
|
||||||
|
* `version` (string) - The version of Docker to install. This defaults to
|
||||||
|
"latest" and will install the latest version of Docker.
|
||||||
|
|
||||||
|
## Pulling Images
|
||||||
|
|
||||||
|
The docker provisioner can automatically pull images from the
|
||||||
|
Docker registry for you. There are two ways to specify images to
|
||||||
|
pull. The first is as an array using `images`:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.vm.provision "docker",
|
||||||
|
images: ["ubuntu"]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
This will cause Vagrant to pull the "ubuntu" image from the registry
|
||||||
|
for you automatically.
|
||||||
|
|
||||||
|
The second way to pull images is to use the `pull_images` function.
|
||||||
|
Each call to `pull_images` will _append_ the images to be pulled. The
|
||||||
|
`images` variable, on the other hand, can only be used once.
|
||||||
|
|
||||||
|
Additionally, the `pull_images` function cannot be used with the
|
||||||
|
simple configuration method for provisioners (specifying it all in one line).
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.vm.provision "docker" do |d|
|
||||||
|
d.pull_images "ubuntu"
|
||||||
|
d.pull_images "vagrant"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running Containers
|
||||||
|
|
||||||
|
In addition to pulling images, the Docker provisioner can run and start
|
||||||
|
containers for you. This lets you automatically start services as part of
|
||||||
|
`vagrant up`.
|
||||||
|
|
||||||
|
Running containers can only be configured using the Ruby block syntax with
|
||||||
|
the `do...end` blocks. An example of running a container is shown below:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.vm.provision "docker" do |d|
|
||||||
|
d.run "rabbitmq"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
This will `docker run` a container with the "rabbitmq" image. In addition
|
||||||
|
to the name, the `run` method accepts a set of options, all optional:
|
||||||
|
|
||||||
|
* `image` (string) - The image to run. This defaults to the first argument
|
||||||
|
but can also be given here as an option.
|
||||||
|
|
||||||
|
* `cmd` (string) - The command to start within the container. If not specified,
|
||||||
|
then the containers default "run" command will be used, such as the
|
||||||
|
"run" command specified when the container was built.
|
||||||
|
|
||||||
|
* `args` (string) - Extra arguments for `docker run` on the command line.
|
||||||
|
These are raw arguments that are passed directly to Docker.
|
||||||
|
|
||||||
|
For example, here is how you would configure Docker to run a container
|
||||||
|
with the Vagrant shared directory mounted inside of it:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.vm.provision "docker" do |d|
|
||||||
|
d.run "ubuntu",
|
||||||
|
cmd: "bash -l",
|
||||||
|
args: "-v '/vagrant:/var/www'"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
Loading…
Reference in New Issue