Skip to content

Commit

Permalink
Added chapter about fabric based deployments
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed Jul 6, 2010
1 parent b7c0e56 commit 34fcd19
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 2 deletions.
5 changes: 3 additions & 2 deletions docs/config.rst
Expand Up @@ -183,7 +183,7 @@ To enable such a config you just have to call into
app.config.from_object('configmodule.ProductionConfig')

There are many different ways and it's up to you how you want to manage
your configuration files. However here a list of good recommendations::
your configuration files. However here a list of good recommendations:

- keep a default configuration in version control. Either populate the
config with this default configuration or import it in your own
Expand All @@ -196,6 +196,7 @@ your configuration files. However here a list of good recommendations::
even create your own script for sourcing that activates a virtualenv
and exports the development configuration for you.
- Use a tool like `fabric`_ in production to push code and
configurations sepearately to the production server(s).
configurations sepearately to the production server(s). For some
details about how to do that, head over to the :ref:`deploy` pattern.

.. _fabric: http://fabfile.org/
15 changes: 15 additions & 0 deletions docs/deploying/mod_wsgi.rst
@@ -1,3 +1,5 @@
.. _mod_wsgi-deployment:

mod_wsgi (Apache)
=================

Expand Down Expand Up @@ -134,6 +136,19 @@ If your application does not run, follow this guide to troubleshoot:
filename is used to locate the resources and for symlinks the wrong
filename is picked up.

Support for Automatic Reloading
-------------------------------

To help deployment tools you can activate support for automatic reloading.
Whenever something changes the `.wsgi` file, `mod_wsgi` will reload all
the daemon processes for us.

For that, just add the following directive to your `Directory` section:

.. sourcecode:: apache

WSGIScriptReloading On

Working with Virtual Environments
---------------------------------

Expand Down
4 changes: 4 additions & 0 deletions docs/patterns/distribute.rst
Expand Up @@ -33,6 +33,10 @@ not supported by `distribute`_ so we will not bother with it. If you have
not yet converted your application into a package, head over to the
:ref:`larger-applications` pattern to see how this can be done.

A working deployment with distribute is the first step into more complex
and more automated deployment scenarios. If you want to fully automate
the process, also read the :ref:`fabric-deployment` chapter.

Basic Setup Script
------------------

Expand Down
196 changes: 196 additions & 0 deletions docs/patterns/fabric.rst
@@ -0,0 +1,196 @@
.. _fabric-deployment:

Deploying with Fabric
=====================

`Fabric`_ is a tool for Python similar to Makefiles but with the ability
to execute commands on a remote server. In combination with a properly
set up Python package (:ref:`larger-applications`) and a good concept for
configurations (:ref:`config`) it is very easy to deploy Flask
applications to external servers.

Before we get started, here a quick checklist of things we have to ensure
upfront:

- Fabric 1.0 has to be installed locally. This tutorial assumes the
latest version of Fabric.
- The application already has to be a package and requires a working
`setup.py` file (:ref:`distribute-deployment`).
- In the following example we are using `mod_wsgi` for the remote
servers. You can of course use your own favourite server there, but
for this example we chose Apache + `mod_wsgi` because it's very easy
to setup and has a simple way to reload applications without root
access.

Creating the first Fabfile
--------------------------

A fabfile is what controls what Fabric executes. It is named `fabfile.py`
and executed by the `fab` command. All the functions defined in that file
will show up as `fab` subcommands. They are executed on one or more
hosts. These hosts can be defined either in the fabfile or on the command
line. In this case we will add them to the fabfile.

This is a basic first example that has the ability to upload the current
sourcecode to the server and install it into a already existing
virtual environment::

from fabric.api import *

# the user to use for the remote commands
env.user = 'appuser'
# the servers where the commands are executed
env.hosts = ['server1.example.com', 'server2.example.com']

def pack():
# create a new source distribution as tarball
local('python setup.py sdist --formats=gztar', capture=False)

def deploy():
# figure out the release name and version
dist = local('python setup.py --fullname').strip()
# upload the source tarball to the temporary folder on the server
put('sdist/%s.tar.gz' % dist, '/tmp/')
# create a place where we can unzip the tarball, then enter
# that directory and unzip it
run('mkdir yourapplication')
with cd('/tmp/yourapplication'):
run('tar xzf /tmp/yourapplication.tar.gz')
# now setup the package with our virtual environment's
# python interpreter
run('/var/www/yourapplication/env/bin/python setup.py install')
# now that all is set up, delete the folder again
run('rm -rf /tmp/yourapplication /tmp/yourapplication.tar.gz')
# and finally touch the .wsgi file so that mod_wsgi triggers
# a reload of the application
run('touch /var/www/yourapplication.wsgi')

The example above is well documented and should be straightforward. Here
a recap of the most common commands fabric provides:

- `run` - executes a command on a remote server
- `local` - executes a command on the local machine
- `put` - uploads a file to the remote server
- `cd` - changes the directory on the serverside. This has to be used
in combination with the `with` statement.

Running Fabfiles
----------------

Now how do you execute that fabfile? You use the `fab` command. To
deploy the current version of the code on the remote server you would use
this command::

$ fab pack deploy

However this requires that our server already has the
``/var/www/yourapplication`` folder created and
``/var/www/yourapplication/env`` to be a virtual environment. Furthermore
are we not creating the configuration or `.wsgi` file on the server. So
how do we bootstrap a new server into our infrastructure?

This now depends on the number of servers we want to set up. If we just
have one application server (which the majority of applications will
have), creating a command in the fabfile for this is overkill. But
obviously you can do that. In that case you would probably call it
`setup` or `bootstrap` and then pass the servername explicitly on the
command line::

$ fab -H newserver.example.com bootstrap

To setup a new server you would roughly do these steps:

1. Create the directory structure in ``/var/www``::

$ mkdir /var/www/yourapplication
$ cd /var/www/yourapplication
$ virtualenv --distribute env

2. Upload a new `application.wsgi` file to the server and the
configuration file for the application (eg: `application.cfg`)

3. Create a new Apache config for `yourapplication` and activate it.
Make sure to activate watching for changes of the `.wsgi` file so
that we can automatically reload the application by touching it.
(See :ref:`mod_wsgi-deployment` for more information)

So now the question is, where do the `application.wsgi` and
`application.cfg` files come from?

The WSGI File
-------------

The WSGI file has to import the application and also to set an environment
variable so that the application knows where to look for the config. This
is a short example that does exactly that::

import os
os.environ['YOURAPPLICATION_CONFIG'] = '/var/www/yourapplication/application.cfg'
from yourapplication import app

The application itself then has to initialize itself like this to look for
the config at that environment variable::

app = Flask(__name__)
app.config.from_object('yourapplication.default_config')
app.config.from_envvar('YOURAPPLICATION_CONFIG')

This approach is explained in detail in the :ref:`config` section of the
documentation.

The Configuration File
----------------------

Now as mentioned above, the application will find the correct
configuration file by looking up the `YOURAPPLICATION_CONFIG` environment
variable. So we have to put the configuration in a place where the
application will able to find it. Configuration files have the unfriendly
quality of being different on all computers, so you do not version them
usually.

A popular approach is to store configuration files for different servers
in a separate version control repository and check them out on all
servers. Then symlink the file that is active for the server into the
location where it's expected (eg: ``/var/www/yourapplication``).

Either way, in our case here we only expect one or two servers and we can
upload them ahead of time by hand.

First Deployment
----------------

Now we can do our first deployment. We have set up the servers so that
they have their virtual environments and activated apache configs. Now we
can pack up the application and deploy it::

$ fab pack deploy

Fabric will now connect to all servers and run the commands as written
down in the fabfile. First it will execute pack so that we have our
tarball ready and then it will execute deploy and upload the source code
to all servers and install it there. Thanks to the `setup.py` file we
will automatically pull in the required libraries into our virtual
environment.

Next Steps
----------

From that point onwards there is so much that can be done to make
deployment actually fun:

- Create a `bootstrap` command that initializes new servers. It could
initialize a new virtual environment, setup apache appropriately etc.
- Put configuration files into a separate version control repository
and symlink the active configs into place.
- You could also put your application code into a repository and check
out the latest version on the server and then install. That way you
can also easily go back to older versions.
- hook in testing functionality so that you can deploy to an external
server and run the testsuite.

Working with Fabric is fun and you will notice that it's quite magical to
type ``fab deploy`` and see your application being deployed automatically
to one or more remote servers.


.. _Fabric: http://fabfile.org/
1 change: 1 addition & 0 deletions docs/patterns/index.rst
Expand Up @@ -19,6 +19,7 @@ Snippet Archives <http://flask.pocoo.org/snippets/>`_.
packages
appfactories
distribute
fabric
sqlite3
sqlalchemy
fileuploads
Expand Down

0 comments on commit 34fcd19

Please sign in to comment.