Deploying Python applications

Overview

This document is a hands-on guide to deploying a simple Python application intsuru. The example application will be a very simple Django project using aSQLite database. It’s applicable to any WSGI application.

Creating the app

To create an app, you use the command app-create:

  1. $ tsuru app-create <app-name> <app-platform>

For Python, the app platform is, guess what, python! Let’s be over creativeand develop a never-developed tutorial-app: a blog, and its name will also bevery creative, let’s call it “blog”:

  1. $ tsuru app-create blog python

To list all available platforms, use the command platform-list.

You can see all your applications using the command app-list:

  1. $ tsuru app-list
  2. +-------------+-------+--------------------------+
  3. | Application | Units | Address |
  4. +-------------+-------+--------------------------+
  5. | blog | | blog.192.168.50.4.nip.io |
  6. +-------------+-------+--------------------------+

You can then send the code of your application.

Application code

This document will not focus on how to write a Django blog, you can clone theentire source direct from GitHub:https://github.com/tsuru/tsuru-django-sample. Here is what we did for theproject:

  • Create the project (django-admin startproject blog)
  • Create a “posts” app (django-admin startapp posts)
  • Add a “Post” model to the app
  • Register the model in django-admin

Git deployment

When you create a new app, tsuru will display the Git remote that you shoulduse. You can always get it using the command app-info:

  1. $ tsuru app-info --app blog
  2. Application: blog
  3. Repository: git@192.168.50.4.nip.io:blog.git
  4. Tags:
  5. Platform: python
  6. Teams: admin
  7. Address: blog.192.168.50.4.nip.io
  8. Owner: admin@example.com
  9. Team owner: admin
  10. Deploys: 0
  11. Pool: theonepool
  12.  
  13. App Plan:
  14. +---------------+--------+------+-----------+---------+
  15. | Name | Memory | Swap | Cpu Share | Default |
  16. +---------------+--------+------+-----------+---------+
  17. | autogenerated | 0 MB | 0 MB | 100 | false |
  18. +---------------+--------+------+-----------+---------+

The Git remote will be used to deploy your application using Git. You can justpush to tsuru remote and your project will be deployed:

  1. $ git push git@192.168.50.4.nip.io:blog.git master
  2. remote: HEAD is now at 260ae00...
  3. remote: -- Using python version: 2.7.13 (default) --
  4. remote: /home/application/current /
  5. remote:
  6. remote: ---- Building image ----
  7. remote: ---> Sending image to repository (0.01MB)
  8. remote: ---> Cleaning up
  9. #####################################
  10. # OMIT #
  11. #####################################
  12. To git@192.168.50.4.nip.io:blog.git
  13. * [new branch] master -> master

If you get a “Permission denied (publickey).”, make sure you’re member of ateam and have a public key added to tsuru. To add a key, use the commandkey-add:

  1. $ tsuru key-add mykey ~/.ssh/id_rsa.pub

You can use git remote add to avoid typing the entire remote url every timeyou want to push:

  1. $ git remote add tsuru git@192.168.50.4.nip.io:blog.git

Then you can run:

  1. $ git push tsuru master
  2. Everything up-to-date

And you will be also able to omit the —app flag from now on:

  1. $ tsuru app-info
  2. Application: blog
  3. Repository: git@192.168.50.4.nip.io:blog.git
  4. Platform: python
  5. Teams: admin
  6. Address: blog.192.168.50.4.nip.io
  7. Owner: admin@example.com
  8. Team owner: admin
  9. Deploys: 0
  10. Pool: theonepool
  11. Units: 1
  12. +------------+---------+
  13. | Unit | Status |
  14. +------------+---------+
  15. | eab5151eff | started |
  16. +------------+---------+
  17.  
  18. App Plan:
  19. +---------------+--------+------+-----------+---------+
  20. | Name | Memory | Swap | Cpu Share | Default |
  21. +---------------+--------+------+-----------+---------+
  22. | autogenerated | 0 MB | 0 MB | 100 | false |
  23. +---------------+--------+------+-----------+---------+

Listing dependencies

In the last section we omitted the dependencies step of deploy. In tsuru, anapplication can have two kinds of dependencies:

  • Operating system dependencies, represented by packages in the package managerof the underlying operating system (e.g.: yum and apt-get);
  • Platform dependencies, represented by packages in the package manager of theplatform/language (in Python, pip).
    All apt-get dependencies must be specified in a requirements.apt file,located in the root of your application, and pip dependencies must be locatedin a file called requirements.txt, also in the root of the application.Since we will use Django, we need to install django package using pip.As this project doesn’t have any external dependencies, we don’t need arequirements.apt file. Here is the requirements.txt file contents:
  1. Django<=1.11

You can see the complete output of installing these dependencies below:

  1. % git push tsuru master
  2. remote: HEAD is now at 260ae00...
  3. remote: -- Using python version: 2.7.13 (default) --
  4. remote: /home/application/current /
  5. remote: requirements.txt detected, using 'pip install -r ./requirements.txt' to install dependencies
  6. remote: Requirement already satisfied: Django<=1.11 in /var/lib/pyenv/versions/2.7.13/envs/app_env_2.7.13/lib/python2.7/site-packages (from -r ./requirements.txt (line 1))
  7. remote: Requirement already satisfied: pytz in /var/lib/pyenv/versions/2.7.13/envs/app_env_2.7.13/lib/python2.7/site-packages (from Django<=1.11->-r ./requirements.txt (line 1))
  8. remote: /
  9. remote:
  10. remote: ---- Building image ----
  11. remote: ---> Sending image to repository (0.01MB)
  12. remote: ---> Cleaning up
  13. #####################################
  14. # OMIT #
  15. #####################################
  16. To git@192.168.50.4.nip.io:blog.git
  17. * [new branch] master -> master

Running the application

As you can see, in the deploy output there is a step described as “Restartingyour app”. In this step, tsuru will restart your app if it’s running, or startit if it’s not. But how does tsuru start an application? That’s very simple, ituses a Procfile (a concept stolen from Foreman). In this Procfile, you describehow your application should be started. We can use gunicorn, for example, to start our Django application. Here ishow the Procfile should look like:

  1. web: gunicorn -b 0.0.0.0:$PORT blog.wsgi

Now we commit the file and push the changes to tsuru git server, runninganother deploy:

  1. $ git add Procfile
  2. $ git commit -m "Procfile: added file"
  3. $ git push tsuru master
  4. remote: HEAD is now at 260ae00...
  5. remote: -- Using python version: 2.7.13 (default) --
  6. remote: /home/application/current /
  7. remote: requirements.txt detected, using 'pip install -r ./requirements.txt' to install dependencies
  8. remote: Requirement already satisfied: Django<=1.11 in /var/lib/pyenv/versions/2.7.13/envs/app_env_2.7.13/lib/python2.7/site-packages (from -r ./requirements.txt (line 1))
  9. remote: Requirement already satisfied: pytz in /var/lib/pyenv/versions/2.7.13/envs/app_env_2.7.13/lib/python2.7/site-packages (from Django<=1.11->-r ./requirements.txt (line 1))
  10. remote: /
  11. remote:
  12. remote: ---- Building image ----
  13. remote: ---> Sending image to repository (0.01MB)
  14. remote: ---> Cleaning up
  15. #####################################
  16. # OMIT #
  17. #####################################
  18. remote: ---> Restarting your app
  19. remote: /var/lib/tsuru/hooks/start: line 13: gunicorn: command not found
  20. remote:
  21. remote: ---> Deploy done!
  22. remote:
  23. To git@192.168.50.4.nip.io:blog.git
  24. 81e884e..530c528 master -> master

Now we get an error: gunicorn: command not found. It means that we need toadd gunicorn to requirements.txt file:

  1. $ cat >> requirements.txt
  2. gunicorn==19.6
  3. ^D

Now we commit the changes and run another deploy:

  1. $ git add requirements.txt
  2. $ git commit -m "requirements.txt: added gunicorn"
  3. $ git push tsuru master
  4. remote: -- Using python version: 2.7.13 (default) --
  5. remote: /home/application/current /
  6. remote: requirements.txt detected, using 'pip install -r ./requirements.txt' to install dependencies
  7. remote: Requirement already satisfied: Django<=1.11 in /var/lib/pyenv/versions/2.7.13/envs/app_env_2.7.13/lib/python2.7/site-packages (from -r ./requirements.txt (line 1))
  8. remote: Requirement already satisfied: gunicorn==19.6 in /var/lib/pyenv/versions/2.7.13/envs/app_env_2.7.13/lib/python2.7/site-packages (from -r ./requirements.txt (line 2))
  9. remote: Requirement already satisfied: pytz in /var/lib/pyenv/versions/2.7.13/envs/app_env_2.7.13/lib/python2.7/site-packages (from Django<=1.11->-r ./requirements.txt (line 1))
  10. remote: /
  11. remote:
  12. remote: ---- Building image ----
  13. remote: ---> Sending image to repository (0.01MB)
  14. remote: ---> Cleaning up
  15. #####################################
  16. # OMIT #
  17. #####################################
  18. remote: ---> Restarting your app
  19. remote:
  20. remote: ---> Deploy done!
  21. remote:
  22. To git@192.168.50.4.nip.io:blog.git
  23. 81e884e..530c528 master -> master

Now that the app is deployed, you can access it from your browser, getting theIP or host listed in app-list and opening it. For example,in the list below:

  1. $ tsuru app-list
  2. +-------------+-----------+---------------------+
  3. | Application | Units | Address |
  4. +-------------+-----------+---------------------+
  5. | blog | 1 started | blog.cloud.tsuru.io |
  6. +-------------+-----------+---------------------+

We can access the admin of the app in the URL http://blog.cloud.tsuru.io/admin/.

Deployment hooks

It would be boring to manually run syncdb and/or migrate after everydeployment. So we can configure an automatic hook to always run before or afterthe app restarts.

tsuru parses a file called tsuru.yml and runs restart hooks. As theextension suggests, this is a YAML file, that contains a list of commands thatshould run before and after the restart. Here is our example of tsuru.yml:

  1. hooks:
  2. build:
  3. - python manage.py collectstatic -c --noinput
  4. - python manage.py migrate

For more details, check the hooks documentation.

tsuru will look for the file in the root of the project. Let’s commit anddeploy it:

  1. $ git add tsuru.yml
  2. $ git commit -m "tsuru.yml: added file"
  3. $ git push tsuru master
  4. remote: -- Using python version: 2.7.13 (default) --
  5. remote: /home/application/current /
  6. remote: requirements.txt detected, using 'pip install -r ./requirements.txt' to install dependencies
  7. remote: Requirement already satisfied: Django<=1.11 in /var/lib/pyenv/versions/2.7.13/envs/app_env_2.7.13/lib/python2.7/site-packages (from -r ./requirements.txt (line 1))
  8. remote: Requirement already satisfied: gunicorn==19.6 in /var/lib/pyenv/versions/2.7.13/envs/app_env_2.7.13/lib/python2.7/site-packages (from -r ./requirements.txt (line 2))
  9. remote: Requirement already satisfied: pytz in /var/lib/pyenv/versions/2.7.13/envs/app_env_2.7.13/lib/python2.7/site-packages (from Django<=1.11->-r ./requirements.txt (line 1))
  10. remote: /
  11. remote:
  12. remote: ---- Building image ----
  13. remote: ---> Sending image to repository (0.01MB)
  14. remote: ---> Cleaning up
  15. remote: ---- Running build hooks ----
  16. remote: ---> Running "python manage.py collectstatic -c --noinput"
  17. #####################################
  18. # OMIT #
  19. #####################################
  20. remote: ---> Restarting your app
  21. remote:
  22. remote: ---> Deploy done!
  23. remote:
  24. To git@192.168.50.4.nip.io:blog.git
  25. 81e884e..530c528 master -> master

It’s done! Now we have a Django project deployed on tsuru.

Going further

For more information, you can dig into tsuru docs, orread complete instructions of use for the tsuru client.

原文: https://docs.tsuru.io/1.6/using/python.html