remove distribute and fabric patterns
This commit is contained in:
parent
b4dca6e24c
commit
576efe8fae
4 changed files with 6 additions and 366 deletions
|
|
@ -394,13 +394,11 @@ The following configuration values are used internally by Flask:
|
||||||
Configuring from Python Files
|
Configuring from Python Files
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
Configuration becomes more useful if you can store it in a separate file,
|
Configuration becomes more useful if you can store it in a separate file, ideally
|
||||||
ideally located outside the actual application package. This makes
|
located outside the actual application package. You can deploy your application, then
|
||||||
packaging and distributing your application possible via various package
|
separately configure it for the specific deployment.
|
||||||
handling tools (:doc:`/patterns/distribute`) and finally modifying the
|
|
||||||
configuration file afterwards.
|
|
||||||
|
|
||||||
So a common pattern is this::
|
A common pattern is this::
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config.from_object('yourapplication.default_settings')
|
app.config.from_object('yourapplication.default_settings')
|
||||||
|
|
@ -692,10 +690,8 @@ your configuration files. However here a list of good recommendations:
|
||||||
code at all. If you are working often on different projects you can
|
code at all. If you are working often on different projects you can
|
||||||
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`_ to push code and configuration separately
|
||||||
configurations separately to the production server(s). For some
|
to the production server(s).
|
||||||
details about how to do that, head over to the
|
|
||||||
:doc:`/patterns/fabric` pattern.
|
|
||||||
|
|
||||||
.. _fabric: https://www.fabfile.org/
|
.. _fabric: https://www.fabfile.org/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,170 +0,0 @@
|
||||||
Deploying with Setuptools
|
|
||||||
=========================
|
|
||||||
|
|
||||||
`Setuptools`_, is an extension library that is commonly used to
|
|
||||||
distribute Python libraries and extensions. It extends distutils, a basic
|
|
||||||
module installation system shipped with Python to also support various more
|
|
||||||
complex constructs that make larger applications easier to distribute:
|
|
||||||
|
|
||||||
- **support for dependencies**: a library or application can declare a
|
|
||||||
list of other libraries it depends on which will be installed
|
|
||||||
automatically for you.
|
|
||||||
- **package registry**: setuptools registers your package with your
|
|
||||||
Python installation. This makes it possible to query information
|
|
||||||
provided by one package from another package. The best known feature of
|
|
||||||
this system is the entry point support which allows one package to
|
|
||||||
declare an "entry point" that another package can hook into to extend the
|
|
||||||
other package.
|
|
||||||
- **installation manager**: :command:`pip` can install other libraries for you.
|
|
||||||
|
|
||||||
Flask itself, and all the libraries you can find on PyPI are distributed with
|
|
||||||
either setuptools or distutils.
|
|
||||||
|
|
||||||
In this case we assume your application is called
|
|
||||||
:file:`yourapplication.py` and you are not using a module, but a
|
|
||||||
package. If you have not yet converted your application into a package,
|
|
||||||
head over to :doc:`packages` to see how this can be done.
|
|
||||||
|
|
||||||
A working deployment with setuptools is the first step into more complex
|
|
||||||
and more automated deployment scenarios. If you want to fully automate
|
|
||||||
the process, also read the :doc:`fabric` chapter.
|
|
||||||
|
|
||||||
Basic Setup Script
|
|
||||||
------------------
|
|
||||||
|
|
||||||
Because you have Flask installed, you have setuptools available on your system.
|
|
||||||
Flask already depends upon setuptools.
|
|
||||||
|
|
||||||
Standard disclaimer applies: :ref:`use a virtualenv
|
|
||||||
<install-create-env>`.
|
|
||||||
|
|
||||||
Your setup code always goes into a file named :file:`setup.py` next to your
|
|
||||||
application. The name of the file is only convention, but because
|
|
||||||
everybody will look for a file with that name, you better not change it.
|
|
||||||
|
|
||||||
A basic :file:`setup.py` file for a Flask application looks like this::
|
|
||||||
|
|
||||||
from setuptools import setup
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name='Your Application',
|
|
||||||
version='1.0',
|
|
||||||
long_description=__doc__,
|
|
||||||
packages=['yourapplication'],
|
|
||||||
include_package_data=True,
|
|
||||||
zip_safe=False,
|
|
||||||
install_requires=['Flask']
|
|
||||||
)
|
|
||||||
|
|
||||||
Please keep in mind that you have to list subpackages explicitly. If you
|
|
||||||
want setuptools to lookup the packages for you automatically, you can use
|
|
||||||
the ``find_packages`` function::
|
|
||||||
|
|
||||||
from setuptools import setup, find_packages
|
|
||||||
|
|
||||||
setup(
|
|
||||||
...
|
|
||||||
packages=find_packages()
|
|
||||||
)
|
|
||||||
|
|
||||||
Most parameters to the ``setup`` function should be self explanatory,
|
|
||||||
``include_package_data`` and ``zip_safe`` might not be.
|
|
||||||
``include_package_data`` tells setuptools to look for a :file:`MANIFEST.in` file
|
|
||||||
and install all the entries that match as package data. We will use this
|
|
||||||
to distribute the static files and templates along with the Python module
|
|
||||||
(see :ref:`distributing-resources`). The ``zip_safe`` flag can be used to
|
|
||||||
force or prevent zip Archive creation. In general you probably don't want
|
|
||||||
your packages to be installed as zip files because some tools do not
|
|
||||||
support them and they make debugging a lot harder.
|
|
||||||
|
|
||||||
|
|
||||||
Tagging Builds
|
|
||||||
--------------
|
|
||||||
|
|
||||||
It is useful to distinguish between release and development builds. Add a
|
|
||||||
:file:`setup.cfg` file to configure these options. ::
|
|
||||||
|
|
||||||
[egg_info]
|
|
||||||
tag_build = .dev
|
|
||||||
tag_date = 1
|
|
||||||
|
|
||||||
[aliases]
|
|
||||||
release = egg_info -Db ''
|
|
||||||
|
|
||||||
Running ``python setup.py sdist`` will create a development package
|
|
||||||
with ".dev" and the current date appended: ``flaskr-1.0.dev20160314.tar.gz``.
|
|
||||||
Running ``python setup.py release sdist`` will create a release package
|
|
||||||
with only the version: ``flaskr-1.0.tar.gz``.
|
|
||||||
|
|
||||||
|
|
||||||
.. _distributing-resources:
|
|
||||||
|
|
||||||
Distributing Resources
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
If you try to install the package you just created, you will notice that
|
|
||||||
folders like :file:`static` or :file:`templates` are not installed for you. The
|
|
||||||
reason for this is that setuptools does not know which files to add for
|
|
||||||
you. What you should do, is to create a :file:`MANIFEST.in` file next to your
|
|
||||||
:file:`setup.py` file. This file lists all the files that should be added to
|
|
||||||
your tarball::
|
|
||||||
|
|
||||||
recursive-include yourapplication/templates *
|
|
||||||
recursive-include yourapplication/static *
|
|
||||||
|
|
||||||
Don't forget that even if you enlist them in your :file:`MANIFEST.in` file, they
|
|
||||||
won't be installed for you unless you set the `include_package_data`
|
|
||||||
parameter of the ``setup`` function to ``True``!
|
|
||||||
|
|
||||||
|
|
||||||
Declaring Dependencies
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
Dependencies are declared in the ``install_requires`` parameter as a list.
|
|
||||||
Each item in that list is the name of a package that should be pulled from
|
|
||||||
PyPI on installation. By default it will always use the most recent
|
|
||||||
version, but you can also provide minimum and maximum version
|
|
||||||
requirements. Here some examples::
|
|
||||||
|
|
||||||
install_requires=[
|
|
||||||
'Flask>=0.2',
|
|
||||||
'SQLAlchemy>=0.6',
|
|
||||||
'BrokenPackage>=0.7,<=1.0'
|
|
||||||
]
|
|
||||||
|
|
||||||
As mentioned earlier, dependencies are pulled from PyPI. What if you
|
|
||||||
want to depend on a package that cannot be found on PyPI and won't be
|
|
||||||
because it is an internal package you don't want to share with anyone?
|
|
||||||
Just do it as if there was a PyPI entry and provide a list of
|
|
||||||
alternative locations where setuptools should look for tarballs::
|
|
||||||
|
|
||||||
dependency_links=['http://example.com/yourfiles']
|
|
||||||
|
|
||||||
Make sure that page has a directory listing and the links on the page are
|
|
||||||
pointing to the actual tarballs with their correct filenames as this is
|
|
||||||
how setuptools will find the files. If you have an internal company
|
|
||||||
server that contains the packages, provide the URL to that server.
|
|
||||||
|
|
||||||
|
|
||||||
Installing / Developing
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
To install your application (ideally into a virtualenv) just run the
|
|
||||||
:file:`setup.py` script with the ``install`` parameter. It will install your
|
|
||||||
application into the virtualenv's site-packages folder and also download
|
|
||||||
and install all dependencies::
|
|
||||||
|
|
||||||
$ python setup.py install
|
|
||||||
|
|
||||||
If you are developing on the package and also want the requirements to be
|
|
||||||
installed, you can use the ``develop`` command instead::
|
|
||||||
|
|
||||||
$ python setup.py develop
|
|
||||||
|
|
||||||
This has the advantage of just installing a link to the site-packages
|
|
||||||
folder instead of copying the data over. You can then continue to work on
|
|
||||||
the code without having to run ``install`` again after each change.
|
|
||||||
|
|
||||||
|
|
||||||
.. _pip: https://pypi.org/project/pip/
|
|
||||||
.. _Setuptools: https://pypi.org/project/setuptools/
|
|
||||||
|
|
@ -1,184 +0,0 @@
|
||||||
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 (:doc:`packages`) and a good concept for
|
|
||||||
configurations (:doc:`/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
|
|
||||||
:file:`setup.py` file (:doc:`distribute`).
|
|
||||||
- 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 :file:`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
|
|
||||||
source code to the server and install it into a pre-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():
|
|
||||||
# build the package
|
|
||||||
local('python setup.py sdist --formats=gztar', capture=False)
|
|
||||||
|
|
||||||
def deploy():
|
|
||||||
# figure out the package name and version
|
|
||||||
dist = local('python setup.py --fullname', capture=True).strip()
|
|
||||||
filename = f'{dist}.tar.gz'
|
|
||||||
|
|
||||||
# upload the package to the temporary folder on the server
|
|
||||||
put(f'dist/{filename}', f'/tmp/{filename}')
|
|
||||||
|
|
||||||
# install the package in the application's virtualenv with pip
|
|
||||||
run(f'/var/www/yourapplication/env/bin/pip install /tmp/{filename}')
|
|
||||||
|
|
||||||
# remove the uploaded package
|
|
||||||
run(f'rm -r /tmp/{filename}')
|
|
||||||
|
|
||||||
# touch the .wsgi file to trigger a reload in mod_wsgi
|
|
||||||
run('touch /var/www/yourapplication.wsgi')
|
|
||||||
|
|
||||||
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
|
|
||||||
:file:`/var/www/yourapplication` folder created and
|
|
||||||
:file:`/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 :file:`/var/www`::
|
|
||||||
|
|
||||||
$ mkdir /var/www/yourapplication
|
|
||||||
$ cd /var/www/yourapplication
|
|
||||||
$ virtualenv --distribute env
|
|
||||||
|
|
||||||
2. Upload a new :file:`application.wsgi` file to the server and the
|
|
||||||
configuration file for the application (eg: :file:`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 :doc:`/deploying/mod_wsgi`.
|
|
||||||
|
|
||||||
So now the question is, where do the :file:`application.wsgi` and
|
|
||||||
:file:`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 :doc:`/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: :file:`/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 :file:`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 test suite.
|
|
||||||
|
|
||||||
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: https://www.fabfile.org/
|
|
||||||
|
|
@ -19,8 +19,6 @@ collected in the following pages.
|
||||||
appfactories
|
appfactories
|
||||||
appdispatch
|
appdispatch
|
||||||
urlprocessors
|
urlprocessors
|
||||||
distribute
|
|
||||||
fabric
|
|
||||||
sqlite3
|
sqlite3
|
||||||
sqlalchemy
|
sqlalchemy
|
||||||
fileuploads
|
fileuploads
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue