diff --git a/docs/config.rst b/docs/config.rst index 522d5d7311..0e8a24cdef 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -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 @@ -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/ diff --git a/docs/deploying/mod_wsgi.rst b/docs/deploying/mod_wsgi.rst index b2d25f5c3a..5b19f1d52f 100644 --- a/docs/deploying/mod_wsgi.rst +++ b/docs/deploying/mod_wsgi.rst @@ -1,3 +1,5 @@ +.. _mod_wsgi-deployment: + 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 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 --------------------------------- diff --git a/docs/patterns/distribute.rst b/docs/patterns/distribute.rst index a3217f6e7d..b6f6a5efd9 100644 --- a/docs/patterns/distribute.rst +++ b/docs/patterns/distribute.rst @@ -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 ------------------ diff --git a/docs/patterns/fabric.rst b/docs/patterns/fabric.rst new file mode 100644 index 0000000000..5f306cec67 --- /dev/null +++ b/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/ diff --git a/docs/patterns/index.rst b/docs/patterns/index.rst index 23b20dc5a5..21f3a56293 100644 --- a/docs/patterns/index.rst +++ b/docs/patterns/index.rst @@ -19,6 +19,7 @@ Snippet Archives `_. packages appfactories distribute + fabric sqlite3 sqlalchemy fileuploads