mirror of https://github.com/mitsuhiko/flask.git
Armin Ronacher
15 years ago
5 changed files with 219 additions and 2 deletions
@ -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/ |
Loading…
Reference in new issue