Playbook example for capistrano-type deployment

Hi,

I’ve been experimenting with using ansible to configure brand new virtual machines (timezone, ssh keys, ruby, nginx, postgresql, etc) and so far so good. Not having to run puppet daemons is liberating. =)

Next I’m looking at how to use ansible to perform a series of tasks similar to what is being done by capistrano to deploy new rails code to those VMs. I’ve searched the newsgroup but I have not seen any mention of someone doing this. Before I go any further, has this been done already? If yes, any sample playbook I can take a look at?

Thanks in advance!

cheers,
mengkuan

I'm unclear what automagic Capistrano is specifically doing in your
case, can you give some examples?

Definitely you'd want to use the git module, there really isn't a
'gem' module yet but you can use command/shell.

(We'd like to have a gem module, but it will need to be written in
Python and just rely on the CLI tools)

Hi,

I've been experimenting with using ansible to configure brand new virtual
machines (timezone, ssh keys, ruby, nginx, postgresql, etc) and so far so
good. Not having to run puppet daemons is liberating. =)

Next I'm looking at how to use ansible to perform a series of tasks
similar to what is being done by capistrano to deploy new rails code to
those VMs. I've searched the newsgroup but I have not seen any mention of
someone doing this. Before I go any further, has this been done already? If
yes, any sample playbook I can take a look at?

Thanks in advance!

As Michael noted, the git module is useful for doing deployments. At my
organization, we use ssh agent forwarding so we don't need to keep private
keys on the web server to checkout code from our git repository. We use
native ssh connections with ansible to support agent forwarding <
http://www.ansible.cc/docs/gettingstarted.html#choosing-between-paramiko-and-native-ssh

.

I don't think paramiko supports SSH agent forwarding yet, although I
haven't tried it in a while. This bug suggests that this functionality is
still under development: https://bugs.launchpad.net/paramiko/+bug/483697.

Take care,

Lorin

Hello,

(We'd like to have a gem module, but it will need to be written in
Python and just rely on the CLI tools)

Given how ruby applications are deployed (rvm, rbenv, bundler), I'm not
sure that having a 'gem' module would be enough or really usefull.
Almost nobody deploys system wide gems when they deploy a web application.

Most applications are vendorized with bundler, and gems are installe
locally.
The problem is more about getting the ruby interpreter you need. For
this, people typically rely on rvm or rbenv.

Thus, a rbenv or rvm module would be more advised IMHO.

As of now, I'm deploying ruby via rbenv using git module and few
templates. Meng, I'm curious to see what path you took for your ruby
deployment.
Could you elaborate on this ?

Thanks,

M

Thus, a rbenv or rvm module would be more advised IMHO.

Make it so?

I'm considering it, despite my python incompetence. I just would like to
see how Meng and may be others deploy their rubies for now, so I don't
take a wrong turn straight away.

If you guys have ruby-related playbooks, I'd be glad to see them.

Here is my small ruby playbook : https://gist.github.com/4586964

M

I'm unclear what automagic Capistrano is specifically doing in your
case, can you give some examples?

The most often used command for capistrano is the 'cap deploy' command.

  http://capitate.rubyforge.org/recipes/deploy.html#deploy

This command performs the following steps:

1. Makes the latest revision of the code available on the target node. For a 'copy' strategy, it does a local checkout, zips it up, scp over to target node, unpack. For 'remote_cache' strategy, it keeps a cache of the code on the target node for faster checkouts.

2. Switch symlink for the 'current' directory to point to the latest checkout. Does the same for the log, run, config directories, etc.

3. Runs 'bundle install' to ensure the app has the gems defined in Gemfile installed

4. Precompile the javascript and css assets

5. Optionally remove old releases

6. Optionally restart the webserver

At any point in time if a step fails, it will roll back to the previous release.

Definitely you'd want to use the git module, there really isn't a
'gem' module yet but you can use command/shell.

Yes, that's what I've been doing in my setup tasks.

Hi Michel,

I chickened out on the ruby install. =)

I'm simply installing the ubuntu ruby1.9.3 package and then doing 'gem install bundler'. So far the apps work but I'm wondering how stable that ruby1.9.3 package is in production.

I use rvm in my dev environment and I tell myself that I'll eventually switch to rvm once I have some time. I'll definitely use your ruby playbook as a guide towards that end. Thanks!

cheers,
mengkuan

I use rvm in my dev environment and I tell myself that I'll eventually switch to rvm once I have some time.

So we have at least one rvm user and one rbenv user amongst Ansible
people. That's 2 modules to write already :stuck_out_tongue:

I'll definitely use your ruby playbook as a guide towards that end.

Be aware that this only works with the '-i in sudo' which has been
removed recently because it caused lots of troubles. I don't know how to
solve this for now (sudo_exe ?).

M

Here is my playbook: https://gist.github.com/4588017 - it is fairly naive (e.g. path to installing passenger hardcodes some elements e.g. ‘1.9.1’) but works for my current projects (all running on ruby 1.9.2). It also hardcodes the full path to rbenv related scripts, so the ‘-i’ option isn’t required - not sure how robust this is long-term.

It uses rbenv. Note the use of the rbenv-installer - not sure how well this works outside Ubuntu but could ease implementation of an ansible module.

My experience with rvm (and many others I’ve read/heard of) is that it is difficult to use in provisioning scenarios like this. I use rvm in dev but rbenv in production because of this.

Michel, I’d be happy to help out with these modules, although I’m new to python myself and I’m not sure I can find much time for the next couple of weeks.

  • Jeremiah

Modifying that should technically allow you to put "-i" stuff in the
beginning, although I can't accept anything module-wise in core that
requires that to be tweaked to non-stock, otherwise it will raise too
many questions.

The pip module supports virtualenv without needing -i, so I would hope
this would also be possible.

Modifying that should technically allow you to put "-i" stuff in the
beginning, although I can't accept anything module-wise in core that
requires that to be tweaked to non-stock, otherwise it will raise too
many questions.

Sure.

The pip module supports virtualenv without needing -i, so I would hope
this would also be possible.

In my case, the problems lies in the sudo config : in some default
configuration (Ubuntu), sudo locks $HOME so this environment variable is
preserved This means that f you're root, and sudo as "user", your home
will be /root (or whatever root's home is) anyway.

This breaks a lot of things on behalf of the target user that assure
$HOME is really the user's $HOME. rbenv init scripts are no exceptions.

The solution to this is to configure sudo on the remote node to allow
HOME overriding with this in /etc/sudoers :

  Defaults always_set_home

I don't know if this has security implications. Anyway I don't think
preventing HOME being set to another location improves security in
anyway (and it can easily be circumvented since the caller is root in
this case...).

You can then wrap your calls in 'bash -lc' (e.g. 'bash -lc "rbenv
version"' so the whole environment gets loaded properly.

This is quite hackish, but as of now this is the only way I found to
circumvent the lack of "-i" in sudo calls.

M

Modifying that should technically allow you to put "-i" stuff in the
beginning, although I can't accept anything module-wise in core that
requires that to be tweaked to non-stock, otherwise it will raise too
many questions.

Sure.

The pip module supports virtualenv without needing -i, so I would hope
this would also be possible.

In my case, the problems lies in the sudo config : in some default
configuration (Ubuntu), sudo locks $HOME so this environment variable is
preserved This means that f you're root, and sudo as "user", your home
will be /root (or whatever root's home is) anyway.

This breaks a lot of things on behalf of the target user that assure
$HOME is really the user's $HOME. rbenv init scripts are no exceptions.

The solution to this is to configure sudo on the remote node to allow
HOME overriding with this in /etc/sudoers :

  Defaults always_set_home

Always seems bad, and requires extra configuration? We could
possibly consider adding "-H" to the sudo arguments maybe?

Yes, having -H would be *much* better. It could be nice if people which
experienced side effects with -i could try -H.

However, we'll still have to wrap things in 'bash -lc' calls.

Thanks,

M

Here is my playbook: https://gist.github.com/4588017

Thanks.

My experience with rvm (and many others I've read/heard of) is that it
is difficult to use in provisioning scenarios like this. I use rvm in
dev but rbenv in production because of this.

Yeah, I tend to avoid rvm in production too and vendorize stuff with
bundler.
Ruby is great, but a real pain to deploy.

Michel, I'd be happy to help out with these modules, although I'm new to
python myself and I'm not sure I can find much time for the next couple
of weeks.

Thanks Jeremiah.
My Python experience is very limited too...

Besides this, I'm wondering if rbenv/rvm can really be handled in a
module. Those installations involves quite a lot of fiddling : when you
install ruby, you usually target a specific user. Then, you need to
change it's environment and add some rbenv init scripts and alter
PATH... All this depends on which distro you use, which shell you use,
etc...

So after some thought, it looks more like a job for a playbook to me. A
module would have really hard time to handle even classic use case
scenarios, and would have to touch too many things to be reliable.

M