We removed our free Sandbox April 25th.
You can read more on our blog.
Python¶
The python service can host any Python web application compatible with the WSGI standard.
That includes all modern Python web frameworks: Django, Pyramid, web.py, web2py, etc.
Note
For the impatient...
Your WSGI callable should be named “application”, be located in a “wsgi.py” file, itself located at the top directory of the service.
Your dependencies should be specified in a PIP-style “requirements.txt” file.
But read on for a guided tour of the service!
Basic Use¶
Let’s assume that you are building a DotCloud application called “ramen”. For the sake of simplicity, we will also assume that everything related to this application is located in a directory called “ramen-on-dotcloud”.
Let’s setup our environment:
$ dotcloud create ramen
Created application "ramen" using the flavor "sandbox" (Use for development, free and unlimited apps. DO NOT use for production.)
$ mkdir ramen-on-dotcloud
A DotCloud application is described by a Build Files, which is a simple YAML file named “dotcloud.yml” located in our “ramen-on-dotcloud” directory. To add a new service to our app, we just add the following lines to “ramen-on-dotcloud/dotcloud.yml”:
www:
type: python
approot: hellopython
This Build File instructs the platform to use the code in the directory “hellopython” for our service. Let’s create it:
$ mkdir ramen-on-dotcloud/hellopython
As said above, the python service expects you to provide it with a WSGI app. So let’s write a very minimal one. Create the file “ramen-on-dotcloud/hellopython/wsgi.py” with the following content:
def application(environ, start_response):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return ['Hello world!\n'] + ['{0}={1}\n'.format(k,environ[k])
for k in sorted(environ)]
This will not only display a “Hello world!” message, but also dump the whole WSGI environment for informative purposes.
We can now push our application to DotCloud:
$ dotcloud push ramen ramen-on-dotcloud/
# upload /home/.../ramen-on-dotcloud/ ssh://dotcloud@uploader.dotcloud.com:21122/ramen
# rsync
[...]
sent 8.11K bytes received 352 bytes 995.06 bytes/sec
total size is 14.78K speedup is 1.75
Deployment for "ramen" triggered. Will be available in a few seconds.
2011-06-28 04:27:34 [api] Waiting for the build. (It may take a few minutes)
2011-06-28 04:27:48 [www.0] service booted
2011-06-28 04:27:48 [www.0] The build started
2011-06-28 04:27:48 [www.0] Fetched code revision rsync-1309235251.44
2011-06-28 04:27:51 [www.0] Reloading nginx configuration: nginx.
2011-06-28 04:27:51 [www.0] The build finished successfully
2011-06-28 04:27:51 [api] Deploy finished
Deployment finished successfully. Your application is available at the following URLs
www: http://ramen-dotcloud.dotcloud.com/
URLs have been generated for each web service in your application from your application an account names. Open your browser to see your new service in action!
If you want to attach a better URL to your application, read the Custom Domains documentation.
Internals¶
dotCloud python runs with Nginx as the HTTP frontend. All URLs referring to directories you defined as location aliases in your nginx.conf file will be served as static files from subdirectories in your application. Everything else will be handed to your WSGI app through uWSGI. The uWSGI workers are managed by Supervisor.
Your code dependencies are automatically handled with pip if your app ships an optional “requirements.txt” file.
Warning
The default Nginx configuration for python changed on August 22, 2012. We removed the default location definition of /static/ and so now you must define the location of static content for your application in your own nginx.conf file.
Adapting your application¶
dotCloud relies on well-established tools and conventions to build your app. It should be trivial to adapt any application to run on dotCloud.
Expose a WSGI application¶
If you wrote a WSGI application from scratch, all you have to do is to make sure that the callable is named “application” and in the “wsgi.py” file.
If you are using a framework like Django, Pylons, Web2py, and lots of others, you will want to use the WSGI handler provided by the framework.
Here are a few examples of wsgi.py files for some common frameworks:
Django
import os
os.environ['DJANGO_SETTINGS_MODULE'] = '.'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
Tornado
import tornado.wsgi
import wsgiref.handlers
# Assuming that you defined a MainHandler class somewhere...
from mycode import MainHandler
application = tornado.wsgi.WSGIApplication([(r"/",MainHandler)])
web2py
For web2py, you should just copy or symlink wsgihandler.py to wsgi.py.
Pyramid
import os.path
from pyramid.scripts.pserve import cherrypy_server_runner
from pyramid.paster import get_app
application = get_app(os.path.join(os.path.dirname(__file__), 'production.ini'))
A more detailed WSGI file is available in the Pyramid Cookbook.
Static files¶
Nginx will serve your static files (e.g. images, css, javascript...) directly, bypassing the Python interpreter. To achieve this, you must move all your static files together and you must provide an nginx.conf file to tell nginx the location(s) of the static files.
If you are using a framework like Django then you should also update your application settings so that links to static assets will point to the directory you have defined.
For example, if your static assets are in the “media” subdirectory of your application, and your code expects them to be found on the “/media” URI, you can create the following “nginx.conf” file in your approot:
location /media { root /home/dotcloud/current; }
Note
The “root” should be /home/dotcloud/current, not /home/dotcloud/current/media, because the location (/media) will be appended when looking for files.
Code dependencies¶
You can specify external requirements in a file called requirements.txt. A typical requirements file looks like this:
Django==1.4.3
Pil
http://jsonschema.googlecode.com/files/jsonschema-0.2a.tar.gz
This is not specific to dotCloud at all: more and more Python projects are using this style of files for their dependencies. If you want to install those dependencies in your local environment, just run “pip install -r requirements.txt”. You might also want to check “pip freeze”, which can output a requirements.txt file for you, containing the exact version numbers of all Python packages currently installed. This is very convenient to make sure that you will get the very same set of packages on different servers (e.g. dotCloud and your local development environment).
For more information on pip and the format of requirements.txt, see pip’s documentation (http://pip.openplans.org/).
Custom Nginx Configuration¶
You can specify custom rewrite rules (and actually almost any nginx setting) by creating a file named nginx.conf at the top of your app.
This file will be included by nginx.
Note
You should not include a whole nginx configuration: just the snippets that you need!
A typical example would be:
rewrite ^/search/(.*) /engine/?q=$1 ;
Check out the Nginx wiki to see all available options.
Note
Already have some Apache mod_rewrite RewriteRule statements? All of them can be converted to nginx configuration.
Python Versions¶
The Python service supports four different branches of Python (2.6, 2.7, 3.1, 3.2), it will default to Python 2.6 unless you specify otherwise. The current versions of each Python branch are listed in the table below. Pick the branch that works best for you.
| branch | version | variable |
|---|---|---|
| 2.6* | 2.6.5 | v2.6 |
| 2.7 | 2.7.2 | v2.7 |
| 3.1 | 3.1.2 | v3.1 |
| 3.2 | 3.2.2 | v3.2 |
* Python 2.6 is the default
To configure your service to use a version of Python other than 2.6, you will set the python_version config option in your dotcloud.yml.
For example, this is what you would have if you wanted Python 2.7.x:
www:
type: python
config:
python_version: v2.7
Custom uWSGI Configuration¶
You can define additional uWSGI parameters in a uwsgi.conf file at the root of your application. For example:
uwsgi_param ENVIRONMENT prod;
You can also modify the following uWSGI options in the config section of "dotcloud.yml":
- uwsgi_memory_report: if set to true this will log each request with informations about the memory usage (the default is false);
- uwsgi_buffer_size: set (in bytes) the size of the buffer used to parse uwsgi packets. The default value is 4096 but you will need to increase it if you have requests with large headers;
- uwsgi_harakiri: every request that will take longer than the seconds specified in the harakiri timeout will be dropped and the corresponding worker recycled;
- uwsgi_enable_threads: (default false) Enable threads, this will allow you to spawn threads in your app;
- uwsgi_single_interpreter: (default false) Python has the concept of “multiple interpreters”. This allows it to isolate apps living in the same process. If you do not want this kind of feature use this option.
Here is an example:
www:
type: python
config:
uwsgi_memory_report: true
uwsgi_buffer_size: 8192
uwsgi_harakiri: 75
uwsgi_enable_threads: true
uwsgi_single_interpreter: true
New settings are applied on the next push.
New Relic¶
If you want to use New Relic to monitor your Python service, then you need to complete the following steps.
Config¶
To enable New Relic support in your Python application, set enable_newrelic to true in your dotcloud.yml config. Setting enable_newrelic to True will automatically configure uWSGI to work properly with New Relic.
Note
The New Relic client doesn’t work with Python 3 yet. If you try to use it with Python 3, your deploy will fail.
Environment Variables¶
The New Relic client requires some configuration information in order to work correctly. You will do this by adding some environmental variables.
- NEW_RELIC_LICENSE_KEY: (required) Your license key as found in ‘Help Center’ of your account when logged into New Relic;
- NEW_RELIC_APP_NAME: The name of the application you wish to report data against in the New Relic UI. If not defined defaults to “Python Application”;
- NEW_RELIC_LOG: The path to a file to be used for the agent log. If not defined then no logging will occur. Can also be set to “stdout” or “stderr” to have logging go to standard output or standard error for process;
- NEW_RELIC_LOG_LEVEL: The level at which logging will be output by the agent. If not defined then defaults to “info”. Possible values, in increasing order of detail, are: “critical”, “error”, “warning”, “info” and “debug”;
- NEW_RELIC_CONFIG_FILE: if they want a full config file, use this variable with the full path to the newrelic.ini file.
See dotCloud environment variables guide for more information about environmental variables.
Here is an example dotcloud.yml for using new relic with all of the ENV variables. Is it important to note you don’t need all of these environment variables they are all listed here just to show you an example of them being used:
www:
type: python
environment:
NEW_RELIC_LICENSE_KEY: zbc1234sjnfnsdnFAKE0KEYk3232kjnknfksdnfkw23
NEW_RELIC_APP_NAME: dotCloud Python App
NEW_RELIC_LOG: /var/log/supervisor/newrelic.log
NEW_RELIC_LOG_LEVEL: info
NEW_RELIC_CONFIG_FILE: /home/dotcloud/current/newrelic.ini
config:
enable_newrelic: true
Other documentations¶
You might be interested by the following dotCloud tutorials:
And by the following third-party documentations:
