forked from orbit-oss/flask
Added chapter about fabric based deployments
This commit is contained in:
parent
b7c0e564d4
commit
34fcd19306
5 changed files with 219 additions and 2 deletions
|
|
@ -183,7 +183,7 @@ To enable such a config you just have to call into
|
||||||
app.config.from_object('configmodule.ProductionConfig')
|
app.config.from_object('configmodule.ProductionConfig')
|
||||||
|
|
||||||
There are many different ways and it's up to you how you want to manage
|
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
|
- keep a default configuration in version control. Either populate the
|
||||||
config with this default configuration or import it in your own
|
config with this default configuration or import it in your own
|
||||||
|
|
@ -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
|
even create your own script for sourcing that activates a virtualenv
|
||||||
and exports the development configuration for you.
|
and exports the development configuration for you.
|
||||||
- Use a tool like `fabric`_ in production to push code and
|
- 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/
|
.. _fabric: http://fabfile.org/
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _mod_wsgi-deployment:
|
||||||
|
|
||||||
mod_wsgi (Apache)
|
mod_wsgi (Apache)
|
||||||
=================
|
=================
|
||||||
|
|
||||||
|
|
@ -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 used to locate the resources and for symlinks the wrong
|
||||||
filename is picked up.
|
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
|
Working with Virtual Environments
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
not yet converted your application into a package, head over to the
|
||||||
:ref:`larger-applications` pattern to see how this can be done.
|
: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
|
Basic Setup Script
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
||||||
196
docs/patterns/fabric.rst
Normal file
196
docs/patterns/fabric.rst
Normal file
|
|
@ -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/
|
||||||
|
|
@ -19,6 +19,7 @@ Snippet Archives <http://flask.pocoo.org/snippets/>`_.
|
||||||
packages
|
packages
|
||||||
appfactories
|
appfactories
|
||||||
distribute
|
distribute
|
||||||
|
fabric
|
||||||
sqlite3
|
sqlite3
|
||||||
sqlalchemy
|
sqlalchemy
|
||||||
fileuploads
|
fileuploads
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue