How to run provision.sh on vagrant with docker provider - vagrant

I have used vagrant successfully on many clouds now.
I have decided to try something with docker, but I am probably missing something very basic as I am failing tremendously.
I wrote this vagrant file:
Vagrant.configure("2") do |config|
config.vm.synced_folder "../synced_folder", "/vagrant"
config.vm.provision "shell" do |s|
s.path = "provision.sh"
s.privileged = false
end
config.vm.provider :docker do |docker, override|
docker.image = 'ubuntu'
end
end
this configuration worked for me for other clouds (if I add specific cloud details to it of course).
my provision.sh file simply has echo "hello world"
my synced_folder has a dummy file..
I have verified that ubuntu image is working fine in docker. docker seems to be working fine.
When I run vagrant up --provider docker I get the following
The container started either never left the "stopped" state or
very quickly reverted to the "stopped" state. This is usually
because the container didn't execute a command that kept it running,
and usually indicates a misconfiguration.
If you meant for this container to not remain running, please
set the Docker provider configuration "remains_running" to "false":
config.vm.provider "docker" do |d|
d.remains_running = false
end
I do not see the hello world print out.
I have found a lot of Q&A regarding this error, but nothing I could use to resolve my problem.
What am I doing wrong?

So I have been missing something very fundamental.
The solution I found is easy. Use this amazing contribution from:
https://github.com/bubenkoff/vagrant-docker-example
The important thing to note here is the Dockerfile - which defines the SSH connection in the container. Without the SSH it simply won't work.
However - another tacit fact people are missing - docker uses a socket which requires permissions, however runnign sudo vagrant up --provider will not resolve the issue. in order to run without problems you should sudo su - first OR add your user to docker group.
Read more about that: https://askubuntu.com/questions/477551/how-can-i-use-docker-without-sudo
So to summarize:
clone the git repository
sudo su -
vagrant up --provider docker
==> machine is up and running perfectly..

Been experiencing the same and following https://github.com/mitchellh/vagrant/issues/3951 for a while. Looks like this is to be fixed by the upcoming minor release of Vagrant.

config.vm.provider :docker do |docker, override|
docker.image = 'ubuntu'
end
You are missing a command here, you need a command to run the container. something like this:
config.vm.provider :docker do |docker, override|
docker.image = 'ubuntu'
docker.run = 'ubuntu'
end
Or you can do something like this:
config.vm.provider :docker do |docker, override|
docker.image = 'ubuntu'
docker.cmd = ["/usr/sbin/sshd", "-D"]
end

Related

How to run scripts automatically after doing vagrant ssh?

I am new to Vagrant but good in Docker.
In Vagrant I am aware of the fact that
config.vm.provision :shell,path: "bootstrap.sh", run: 'always'
in the Vagrantfile will provision vagrant box while doing vagrant up. With this, the vagrant box interactive console appears after the intended provisioning is done.
But I need to configure in such a way that, first the control goes in to vagrant box console and then the intended script is up and running. Because my requirement is to run a script automatically post vagrant up and not to run a bootstrapped script.
In analogy with Docker, my question can be seen as
what is the Vagrant equivalent for CMD in Dockerfile ?
You can look at vagrant triggers. You can run dedicated script/command after each specific vagrant command (up, destroy ...)
For example
Vagrant.configure("2") do |config|
# Your existing Vagrant configuration
...
# start apache on the guest after the guest starts
config.trigger.after :up do |trigger|
trigger.run_remote = {inline: "service apache2 start"}
end
end

Access Docker features when using Vagrant

I've been using Vagrant for some time and am now exploring Docker. I've always loved Vagrant for its simplicity. Right now, I'm trying to use the Docker provider within Vagrant. I'm using the following Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.provider "docker" do |d|
d.image = "fgrehm/vagrant-ubuntu:precise"
end
end
My understanding is that I can just run vagrant up. I can then run the Docker container using vagrant docker-run -- <command>.
So far so good. What makes Docker so awesome is the fact that you can mess around and commit changes. I do not understand is how to incorporate this in my workflow when using the Docker provider for Vagrant. E.g. how do I run docker commit to commit the state of the container? I'd expect some kind of vagrant docker-commit, but this does not exist?
Edit: In hindsight, I think this is not the way you should be using Vagrant/Docker. Though it is claimed that both tools complement each other, my opinion is that they do not (yet) play really well together. Right now, we're using Dockerfiles to build our images. Additionally, we made a set of bash scripts to launch a container.
Try to specify "has_ssh" to true, and ask Vagrant to use port 22 instead of 2222:
ENV["VAGRANT_DEFAULT_PROVIDER"] = "docker"
Vagrant.configure("2") do |config|
config.vm.provider "docker" do |d, o|
d.image = "fgrehm/vagrant-ubuntu:precise"
d.has_ssh = true
o.ssh.port = 22
end
end
Then use vagrant up; vagrant ssh to access it.
Another option if you have same client version of docker at your host-host machine as docker server started inside boot2docker VM. In that case you can set
export DOCKER_HOST=tcp://:4243 (or 2375 depending on docker version)
and then access all docker features running local client:
docker ps -a

How do I provision a Dockerfile from Vagrant

How can I start the provisioning of Docker via an external Dockerfile?
My Vagrantfile looks like this at the moment
Vagrant.configure("2") do |config|
config.vm.box = "precise64"
config.vm.define :server_infrastructure do |t|
end
config.vm.provision "docker" do |d|
d.pull_images "ubuntu"
#how does the below work?
#d.build "new-container-name" "local-docker-file-name"
end
end
Your help is greatly appreciated
An option for the Docker provisioner to build images was added in v1.6.0. Download the latest version from the Vagrant website.
Once you've done that, put a Dockerfile next to your Vagrantfile. Add this to your Vagrantfile:
config.vm.provision "docker" do |d|
d.build_image "/vagrant", args: "-t my-name/my-new-image"
d.run "my-name/my-new-image"
end
Now your Docker image will be built and run with vagrant up.
one workaround is through shell provisioning:
config.vm.provision "shell", inline: "docker build -t username/image /vagrant; docker run -d username/image"
For docker to build an image from a dockerfile, dockerfile in question must be presented in the guest machine and the way to ensure this is to use shared folder feature of vagrant.
By default vagrant mounts your project root folder to the new vm under the name /vagrant. But in your case i suggest you share a different folder and put your dockerfiles there. Also by sharing a different folder you can make sure that your dockerfiles are seen read-only by the guest machine.
Now suppose you create a new folder in your projects root directory named "docker" and put your dockerfiles in it. Now if you mount this folder to your guest machine and point docker to use that file you are all set. if you add these lines to your vagrant file it will work as expected.
config.vm.synced_folder "docker/", "/docker_builds", create: true, mount_options: ["ro"]
config.vm.provision "docker" do |d|
d.build_image "/docker_builds", args: "-t my-name/my-new-image"
d.run "my-name/my-new-image"
end

Using Vagrant to manage development and production environments?

How are people handling simple automation (with puppet) for dev / prod environments with vagrant (ideally from the same vagrantfile)?
Use case I'm trying to solve
I would love to spin up the the production machine with vagrant if it isn't created.
I would love to reload nginx or apache confs on production with vagrant if they were tweaked in the puppet files for my dev environment.
The Problem
When you call vagrant up with a provider like AWS or Digital Ocean, it becomes the active provider and you can't switch. You get this error:
An active machine was found with a different provider. Vagrant
currently allows each machine to be brought up with only a single
provider at a time. A future version will remove this limitation.
Until then, please destroy the existing machine to up with a new
provider.
It seems the answer it to destroy, but I just need to switch. I don't want to destroy.
I would love to be able to say
vagrant up prod
or
vagrant reload prod
and then a simple vagrant up would fall back to the default machine.
This syntax is similar to how multiple machines work, but I don't want to spin up a dev and production environment when I just call vagrant up (which is the default behavior).
Should I be looking at packer as part of the workflow? I watched the whole talk at puppetconf 2013 on Mitchell's talk on Multi-Provider http://puppetlabs.com/presentations/multi-provider-vagrant-aws-vmware-and-more
I'm still not seeing a solution for my problem.
UPDATE 9/27/13
In case anybody else is fighting this idea, this article cleared up a lot of questions I had.
http://pretengineer.com/post/packer-vagrant-infra
As for workaround, you should define config.vm.define (as suggested here), in order to support multiple providers.
Please find the following configuration posted by #kzap as example:
Vagrant.configure("2") do |config|
# Store the current version of Vagrant for use in conditionals when dealing
# with possible backward compatible issues.
vagrant_version = Vagrant::VERSION.sub(/^v/, '')
# Configuration options for the VirtualBox provider.
def configure_vbox_provider(config, name, ip, memory = 2048, cpus = 1)
config.vm.provider :virtualbox do |v, override|
# override box url
override.vm.box = "ubuntu/trusty64"
# configure host-only network
override.vm.hostname = "#{name}.dev"
override.vm.network :private_network, id: "vvv_primary", ip: ip
v.customize ["modifyvm", :id,
"--memory", memory,
"--cpus", cpus,
"--name", name,
"--natdnshostresolver1", "on",
"--natdnsproxy1", "on"
]
end
end
default_provider = "virtualbox"
supported_providers = %w(virtualbox rackspace aws managed)
active_provider = ENV['VAGRANT_ACTIVE_PROVIDER'] # it'd be better to get this from the CLI --provider option
supported_providers.each do |provider|
next unless (active_provider.nil? && provider == default_provider) || active_provider == provider
#
# VM per provider
#
config.vm.define :"sample-#{provider}" do | sample_web_config |
case provider
when "virtualbox"
configure_vbox_provider(sample_web_config, "examine-web", "192.168.50.1")
when "aws"
configure_aws_provider(sample_web_config)
when "managed"
configure_managed_provider(sample_web_config, "1.2.3.4")
when "rackspace"
configure_rackspace_provider(sample_web_config)
end
end
end
Or the following example posted at gist by #maxlinc:
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "dummy"
config.vm.provider :rackspace do |rs|
rs.username = ENV['RAX_USERNAME']
rs.api_key = ENV['RAX_API_KEY']
rs.rackspace_region = :ord
end
supported_providers = %w(virtualbox rackspace)
active_provider = ENV['VAGRANT_ACTIVE_PROVIDER'] # it'd be better to get this from the CLI --provider option
supported_providers.each do |provider|
next unless active_provider.nil? || active_provider == provider
config.vm.define "exact_name_#{provider}" do |box|
box.vm.provider :rackspace do |rs|
rs.flavor = '1 GB Performance'
rs.image = 'Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)'
end
end
config.vm.define "regex_#{provider}" do |box|
box.vm.provider :rackspace do |rs|
rs.flavor = /1\s+GB\s+Performance/
rs.image = /Ubuntu.*Trusty Tahr.*(PVHVM)/
end
end
config.vm.define "id_#{provider}" do |box|
box.vm.provider :rackspace do |rs|
rs.flavor = 'performance1-1'
rs.image = 'bb02b1a3-bc77-4d17-ab5b-421d89850fca'
end
end
config.vm.define "unlisted_#{provider}" do |box|
box.vm.provider :rackspace do |rs|
rs.flavor = 'performance1-1'
rs.image = '547a46bd-d913-4bf7-ac35-2f24f25f1b7a'
end
end
end
end
Not an ideal solution, but what about using git branches? My thinking is that it could be conceptually similar to using heroku, where you might have a master, staging, and production versions (since they're usually different remotes).
In this case you start off the prod branch with the small edit to the Vagrantfile to name the VM a little differently. Then you should be able to merge all changes from dev with the prod branch as they occur. So your workflow would look like:
$ git checkout prod
$ vagrant up
$ git checkout master
... make changes to puppet ...
$ git checkout prod
$ git merge master
$ vagrant reload
$ git checkout master
You could script and alias these so you end up with
$ start_production
$ reload_production
Here is a simple way of dynamically changing the 'default' machine name depending on the specified --provider from the command line, so they won't conflict between the different providers:
require 'getoptlong'
opts = GetoptLong.new(
[ '--provider', GetoptLong::OPTIONAL_ARGUMENT ],
[ '--vm-name', GetoptLong::OPTIONAL_ARGUMENT ]
)
provider=ENV['PROVIDER'] || 'virtualbox'
vm_name=ENV['VM_NAME'] || 'default'
opts.each do |opt, arg|
case opt
when '--provider'
provider=arg
when '--vm-name'
vm_name=arg
end
end
Vagrant.configure(2) do |config|
# HERE you are dynamically changing the machine name to prevent conflict.
config.vm.define "mt-#{provider}-#{vm_name}"
# Below sections are just examples, not relevant.
config.vm.provider "virtualbox" do |vm|
vm.name = "test.local"
vm.network "private_network", ip: "192.168.22.22"
vm.customize ['modifyvm', :id, '--natdnshostresolver1', 'on']
config.vm.box = "ubuntu/wily64"
end
config.vm.provider :aws do |aws, override|
aws.aws_profile = "testing"
aws.instance_type = "m3.medium"
aws.ami = "ami-7747d01e"
config.vm.box = "testing"
end
end
Example usage:
VM_NAME=dev PROVIDER=virtualbox vagrant up --provider=virtualbox
VM_NAME=uat PROVIDER=aws vagrant up --provider=aws
VM_NAME=test PROVIDER=aws vagrant up --provider=aws
VM_NAME=prod PROVIDER=aws vagrant up --provider=aws
VM_NAME=uat PROVIDER=aws vagrant destroy -f
VM_NAME=test PROVIDER=aws vagrant status
See also: Multiple provisioners in a single vagrant file?
what I came up with to work with this scenario is to manage 2 distincts .vagrant folder.
Note: most of the other answers deal with setting up multi-provider assuming you will run dev and prod on different provider, in most cases this might be true but you can definitely have cases where you have same provider for dev and prod. Lets say you're using aws and you want to use dev and prod as ec2 instance it will be the same provider.
Say you want to manage dev and prod instances, potentially using different providers (but could also very well be on the same provider) so you'll do:
set up dev instance with normal vagrant up --provider <dev_provider>.
This will create a dev VM that you can manage
back up the .vagrant folder created in your project directory and rename it like .vagrant.dev
set up prod instance with your provider of choice vagrant up --provider <prod_provider>. This now creates your prod VM
back up the newly .vagrant folder created in your project directory and rename it like .vagrant.prod
now, depending if you want to work on dev or prod, you'll rename the .vagrant.dev or .vagrant.prod directory as .vagrant and vagrant will operate the right VM.
I did not come up with a script as mainly the most of the time I work with dev and very few times I need to switch to the other provider. but I dont think it will be too hard to read the parameter from CLI and make the renaming more dynamic.

puppet looking for hiera.yaml in the wrong place

I want puppet to look for hiera.yaml in /etc but it's looking for it in /etc/puppet. I put a line into puppet.conf:
hiera_config = /etc/hiera.yaml
But still gives me the hiera.yaml update warning when I run the script.
I'm running the script from Vagrant 1.2.2. Using puppet 3.2.2
I'm running Centos 6.4 in a vm.
I found that the puppet provisioner in vagrant now support hiera_config_path which does exactly what is desired.
config.vm.provision :puppet do |puppet|
# path on host machine to hiera.yaml
puppet.hiera_config_path = '/Users/me/vms/hiera/hiera.yaml'
# This sets the relative path for hiera data directories
puppet.working_directory = '/Users/me/vms/hiera'
end
This is documented in Vagrant: Up and Running but I didn't find it until I started looking into the vagrant source to implement this feature myself.
Hmmm... On Vagrant 1.2.2 and Puppet 3.2.3, I am able to set hiera_config in puppet.conf without problems. I would double-check that you are editing /etc/puppet.conf on the Vagrant vm, not on the host machine, and that the hiera_config line is the [main] block, not just in the [master] block.
If both of those conditions are true and it is still not working, you might try explicitly setting hiera_config in your Vagrantfile:
config.vm.provision :puppet do |puppet|
...
puppet.options = '--hiera_config=/etc/hiera.yaml'
end
Good luck!
Puppet provisioning runs as root user, not vagrant, so that's why it doesn't take notice of your puppet.conf in /vagrant.
If you run puppet config print inside the vm from user vagrant and root you see ALL puppet config settings per user and compare.

Resources