Pip or easy_install inside a virtual environment is great for development
purposes when you want all your dependencies isolated from your system. It’s
great to manage dependencies and reproduce the same development environment
across different developers at any given time. But, it has a great con. It’s
not portable and not scalable. If you want to deploy virtualenvs in hundreds of
servers you get a big problem when you need to recreate the environment in
every single server and pull the code. Sure, you can automate that, but still
it is an error prone and slow way to do it, as you will need to hit the net
(internal or external) in order to reproduce the environment.
The recommended way to do it is using Buildout and the target operating
system’s native package management system. If your production OS is Debian or
derivatives (Ubuntu) then you should package your app in a DEB package. If you
use RedHat or derivatives, then you should package your app in an RPM package.
You will have the extreme power of apt-get or yum. Freezing (holding) and
rollbacks are completely integrated. You can deploy in parallel to hundreds of
servers in an incredible fast manner. And fast rollbacking if you get some sort
Pip and easy_install in a virtualenv can still be used along with buildout.
But, your CI server should take buildout as a preference taking all the pip or
easy_install dependencies as package dependencies. You can make apt-get and yum
deal with pip dependencies and inject all the buildout eggs in your deb package
in a portable way.
You can take a look at an excellent tutorial on how to use buildout at http://jacobian.org/writing/django-apps-with-buildout/ by Jacob Kaplan-Moss.