I have a fairly complex deployment of dynamically configured instances of a rail apps on nginx using passenger that I currently use Capistrano for. I am trying to automate the e
We are using Opsworks with a lot of custom cookbooks, and vagrant as well. While the test-coverage is far from perfect, it works pretty smooth, adapting community cookbooks as well. Our cookbook repository is public: https://github.com/till/easybib-cookbooks
The interesting bits of this repo are:
is_aws
is true, otherwise we fall back for a default application deployment. Browsing our cookbooks should give you some more hints for your questions. We test our cookbooks with Travis, and do not test the opsworks cookbooks at all. Although I have to note that I am currently playing around there with some ideas how to integrate them in our test runs, since without their providers, testing our deploy cookbook is pretty much impossible.
Opsworks now supports Chef 11.10 and Berkshelf (http://berkshelf.com/) to manage dependencies which makes using custom cookbooks so. much. easier.
I've been pretty happy with Test Kitchen (https://github.com/test-kitchen/test-kitchen) with Vagrant & Chef Solo for local testing.
Additionally you can manually run particular recipes on an Opsworks stack from the stack settings page. Have a look here: http://docs.aws.amazon.com/opsworks/latest/userguide/workingcookbook-manual.html.
You can also run cookbook tests during an Opsworks deployment with some custom JSON: http://docs.aws.amazon.com/opsworks/latest/userguide/troubleshoot-debug-test.html
I was able to solve this is issue using Chef+Kitchen+Vagrant
Here's my wrapper: https://github.com/elitechance/opsworks-cookbooks-wrapper
git clone https://github.com/elitechance/opsworks-cookbooks-wrapper.git
git clone https://github.com/aws/opsworks-cookbooks.git
cd opsworks-cookbooks-wrapper
cp .kitchen.sample.yml .kitchen.yml
cp Berksfile.sample Berksfile
cp metadata.sample.rb metadata.rb
The last command will simulate OpsWorks NodeJs Setup Recipes, see .kitchen.sample.yml
for details.
$ chef exec kitchen setup
The first time you run $ chef exec kitchen setup
, you will encounter errors saying:
Running handlers: [2016-04-08T17:08:34+00:00] ERROR: Running exception handlers Running handlers complete [2016-04-08T17:08:34+00:00] ERROR: Exception handlers complete Chef Client failed. 43 resources updated in 01 minutes 02 seconds [2016-04-08T17:08:34+00:00] FATAL: Stacktrace dumped to /tmp/kitchen/cache/chef-stacktrace.out [2016-04-08T17:08:34+00:00] FATAL: Please provide the contents of the stacktrace.out file if you file a bug report [2016-04-08T17:08:34+00:00] ERROR: ruby_blockFallback for remote_file[/tmp/rubygems-2.2.2.tgz] had an error: NoMethodError: remote_file/tmp/rubygems-2.2.2.tgz had an error: NoMethodError: undefined method `to_sym' for [:create]:Array [2016-04-08T17:08:34+00:00] FATAL: Chef::Exceptions::ChildConvergeError: Chef run process exited unsuccessfully (exit code 1)
$ chef exec kitchen setup
Opsworks cookbooks build upon their custom boxes, so getting a local VM set up where you can run their cookbooks alongside yours is a challenge,
Fortunately their Ubuntu box has been recreated by this project. https://github.com/wwestenbrink/vagrant-opsworks
Building on top of this, I've set up a local vagrant environment that runs the opsworks cookbooks and one of my own. https://github.com/erupenkman/opsworks-example
With this you can actually test in an almost identical local environment before deployment.
There are a lot of useful suggestions on this page but I would HIGHLY recommend everyone check out Mike Greiling's blog post Simplify OpsWorks Development With Packer and his github repo opsworks-vm which help you to mock the entire opsworks stack including the install of the opsworks agent so you can also test app deploy recipes, multiple layers, multiple instances at the same time, etc . It is extremely impressive.
NOTE: This can NOT be done from an ubuntu virtual machine because virtualbox does not support nested virtualization of 64-bit machines.
mkdir /tmp/packages && cd /tmp/packages
wget https://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/12.04/x86_64/chefdk_0.8.1-1_amd64.deb
sudo dpkg -i chefdk_0.8.0-1_amd64.deb
cd /opt/chefdk/
chef verify
which ruby
echo 'eval "$(chef shell-init bash)"' >> ~/.bash_profile && source ~/.bash_profile
echo 'deb http://download.virtualbox.org/virtualbox/debian vivid contrib' > /etc/apt/sources.list.d/virtualbox.list
wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | sudo apt-key add -
sudo apt-get update -qqy
sudo apt-get install virtualbox-5.0 dkms
cd /tmp/packages
wget https://dl.bintray.com/mitchellh/vagrant/vagrant_1.7.4_x86_64.deb
sudo dpkg -i vagrant_1.7.4_x86_64.deb
vagrant plugin install vagrant-berkshelf
vagrant plugin install vagrant-omnibus
vagrant plugin list
mkdir /opt/packer && cd /opt/packer
wget https://dl.bintray.com/mitchellh/packer/packer_0.8.6_linux_amd64.zip
unzip packer_0.8.6_linux_amd64.zip
echo 'PATH=$PATH:/opt/packer' >> ~/.bash_profile && source ~/.bash_profile
mkdir ~/packer && cd ~/packer
git clone https://github.com/pixelcog/opsworks-vm.git
cd opsworks-vm
rake build install
To mock a single opsworks instance, create a new Vagrantfile like so:
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu1404-opsworks"
config.vm.provision :opsworks, type: 'shell', args: 'path/to/dna.json'
end
The dna.json
file path is set relative to the Vagrantfile and should contain any JSON data you wish to send to OpsWorks Chef.
For example:
{
"deploy": {
"my-app": {
"application_type": "php",
"scm": {
"scm_type": "git",
"repository": "path/to/my-app"
}
}
},
"opsworks_custom_cookbooks": {
"enabled": true,
"scm": {
"repository": "path/to/my-cookbooks"
},
"recipes": [
"recipe[opsworks_initial_setup]",
"recipe[dependencies]",
"recipe[mod_php5_apache2]",
"recipe[deploy::default]",
"recipe[deploy::php]",
"recipe[my_custom_cookbook::configure]"
]
}
}
To mock multiple opsworks instances and include layers see his AWS OpsWorks "Getting Started" Example which includes the stack.json below.
Vagrantfile (for multiple instances)
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu1404-opsworks"
# Create the php-app layer
config.vm.define "app" do |layer|
layer.vm.provision "opsworks", type:"shell", args:[
'ops/dna/stack.json',
'ops/dna/php-app.json'
]
# Forward port 80 so we can see our work
layer.vm.network "forwarded_port", guest: 80, host: 8080
layer.vm.network "private_network", ip: "10.10.10.10"
end
# Create the db-master layer
config.vm.define "db" do |layer|
layer.vm.provision "opsworks", type:"shell", args:[
'ops/dna/stack.json',
'ops/dna/db-master.json'
]
layer.vm.network "private_network", ip: "10.10.10.20"
end
end
stack.json
{
"opsworks": {
"layers": {
"php-app": {
"instances": {
"php-app1": {"private-ip": "10.10.10.10"}
}
},
"db-master": {
"instances": {
"db-master1": {"private-ip": "10.10.10.20"}
}
}
}
},
"deploy": {
"simple-php": {
"application_type": "php",
"document_root": "web",
"scm": {
"scm_type": "git",
"repository": "dev/simple-php"
},
"memcached": {},
"database": {
"host": "10.10.10.20",
"database": "simple-php",
"username": "root",
"password": "correcthorsebatterystaple",
"reconnect": true
}
}
},
"mysql": {
"server_root_password": "correcthorsebatterystaple",
"tunable": {"innodb_buffer_pool_size": "256M"}
},
"opsworks_custom_cookbooks": {
"enabled": true,
"scm": {
"repository": "ops/cookbooks"
}
}
}
For those not familiar with vagrant you just do a vagrant up
to start the instance(s). Then you can modify your cookbook locally and any changes can be applied by re-running chef against the existing instance(s) with vagrant provision.
You can do a vagrant destroy
and vagrant up
to start from scratch.
Checkout Travis-ci and sous-chef you may find this suitable for testing cookbooks etc and they have a deploy configuration for opsworks too.
https://github.com/michaelklishin/sous-chef http://docs.travis-ci.com/user/deployment/opsworks/