Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Deploying Flask (WSGI) Applications

Deploying Flask (WSGI) Applications

Matt Wright

June 26, 2014
Tweet

More Decks by Matt Wright

Other Decks in Technology

Transcript

  1. Deploying Flask (WSGI) Applications

  2. Matt Wright @mattupstate Engineer @ChatID • Python, Ruby, CoffeeScript •

    Flask, Chef, AngularJS Open Source • Flask-Security • Flask-Social • Flask-Mail + a few others
  3. WSGI (Web Server Gateway Interface)

  4. PEP 333 http://legacy.python.org/dev/peps/pep-0333/

  5. # ~/hello.py def application(environ, start_response): start_response('200 OK', [('Content-Type','text/html')]) return ["Hello

    World"]
  6. # ~/app.py from flask import Flask app = Flask(__name__) @app.route('/')

    @app.route('/<path:path>') def catch_all(path=''): return 'Hello World'
  7. Browser WSGI Gateway WSGI App 1 2 4 3 Request

    Flow
  8. Browser WSGI Gateway WSGI App 1 1. Browser sends an

    HTTP request to the gateway server Request Flow
  9. Browser WSGI Gateway WSGI App 2 2. Gateway server prepares

    and sends the request to the WSGI compatible application 1 Request Flow
  10. Browser WSGI Gateway WSGI App 1 2 3 3. Application

    processes the request and returns a response Request Flow
  11. Browser WSGI Gateway WSGI App 1 2 4 3 4.

    The gateway server returns the response to the browser Request Flow
  12. Browser WSGI Gateway WSGI Middle- ware WSGI App Middleware

  13. Browser WSGI Gateway WSGI Middle- ware WSGI App WSGI Middle-

    ware WSGI Middle- ware WSGI Middle- ware WSGI Middle- ware MOAR MIDDLEWARE!
  14. Gateway Servers (sometimes called “containers”)

  15. http://www.tornadoweb.org/ Tornado

  16. 1. Written in Python! 2. Web application framework 3. Asynchronous

    networking library 4. WSGI support Tornado
  17. # ~/tor.py from tornado.wsgi import WSGIContainer from tornado.httpserver import HTTPServer

    from tornado.ioloop import IOLoop from app import app http_server = HTTPServer(WSGIContainer(app)) http_server.listen(8000) IOLoop.instance().start()
  18. matt @ pc in ~/ $ mkvirtualenv wsgi matt @

    pc in ~/ workon:wsgi $ pip install flask tornado matt @ pc in ~/ workon:wsgi $ python tor.py
  19. matt @ pc in ~/ $ curl localhost:8000 Hello World

    matt @ pc in ~/ workon:wsgi $ pip install tornado matt @ pc in ~/ workon:wsgi $ python tor.py
  20. http://www.gevent.org/ gevent

  21. 1. Written in Python! 2. Coroutine networking library 3. 3rd

    party module support gevent
  22. # ~/ge.py from gevent.wsgi import WSGIServer from app import app

    server = WSGIServer(('', 8000), app) server.serve_forever()
  23. matt @ pc in ~/ workon:wsgi $ pip install gevent

    matt @ pc in ~/ workon:wsgi $ python ge.py
  24. matt @ pc in ~/ $ curl localhost:8000 Hello World

    matt @ pc in ~/ workon:wsgi $ pip install gevent matt @ pc in ~/ workon:wsgi $ python ge.py 127.0.0.1 - - [2014-06-24...
  25. http://gunicorn.org/ Gunicorn

  26. Gunicorn 1. Written in Python! 2. Easy configuration 3. Broadly

    compatible 4. Extensible 5. Fairly speedy
  27. matt @ pc in ~/ workon:wsgi $ pip install gunicorn

    matt @ pc in ~/ workon:wsgi $ gunicorn app:app
  28. matt @ pc in ~/ $ curl localhost:8000 Hello World

    matt @ pc in ~/ $ mkvirtualenv wsgi matt @ pc in ~/ workon:wsgi $ pip install gunicorn flask matt @ pc in ~/ workon:wsgi $ gunicorn app:app
  29. https://uwsgi-docs.readthedocs.org/ uWSGI

  30. uWSGI 1. Support for many platforms and languages 2. Multiple

    configuration formats 3. Flexible logging 4. Extensible 5. Speaks HTTP and uwsgi
  31. matt @ pc in ~/ workon:wsgi $ pip install uwsgi

    matt @ pc in ~/ workon:wsgi $ uwsgi --http :8000 -w app:app ... spawned uWSGI worker 1 ...
  32. matt @ pc in ~/ $ curl localhost:8000 Hello World

    matt @ pc in ~/ workon:wsgi $ pip install uwsgi matt @ pc in ~/ workon:wsgi $ uwsgi --http :8000 -w app:app ... spawned uWSGI worker 1 ... [pid: 42176|app: 0|req: ...
  33. (how to start your app) Process Management

  34. http://upstart.ubuntu.com/ upstart

  35. # /etc/init/hello-world.conf description "Hello World app" start on runlevel [2345]

    stop on runlevel [06] chdir /srv/hello-world exec /usr/local/bin/uwsgi \ --die-on-term \ --http :8000 \ -w app:app
  36. http://www.freedesktop.org/wiki/Software/systemd/ systemd

  37. # /etc/systemd/system/hello-world.service [Unit] Description=Hello World app [Service] ExecStart=/usr/local/bin/uwsgi \ --die-on-term

    \ --http :8000 \ -w app:app [Install] WantedBy=multi-user.target
  38. http://supervisord.org/ supervisord

  39. # /etc/supervisor.d/hello-world.conf [program:hello-world] directory=/srv/hello-world command=/usr/local/bin/uwsgi \ --die-on-term \ --http :8000

    \ -w app:app
  40. (some things are better than others) Reverse Proxies

  41. Why? • Static files • URL rewrites • Routing •

    Header mods • App aggregation • and many more! • Network security • Authentication • Load balancing • SSL termination • Compression • Caching
  42. http://www.nginx.org/ Apache

  43. # /etc/apache2/sites-enabled/hello-world.conf <VirtualHost *:80> ServerName hello-world.com ProxyPreserveHost On ProxyPass /static

    ! Alias /static "/srv/hello-world/static" ProxyPass / http://127.0.0.1:8000/ ProxyPassReverse / http://127.0.0.1:8000/ </VirtualHost>
  44. http://www.nginx.org/ Nginx

  45. # /etc/nginx/sites-enabled/hello-world.conf server { listen 80; server_name hello-world.com; location /

    { proxy_pass http://127.0.0.1:8000; } location ^~ /static/ { root /srv/hello-world/static; } }
  46. (is hard) Concurrency

  47. Concurrency Models callback/generator (auto) lightweight threads (auto) processor/thread (config) processor/thread

    (config) Tornado gevent Gunicorn uWSGI
  48. Increasing Concurrency processes processes workers + processes workers + processes

    Tornado gevent Gunicorn uWSGI
  49. Increasing Workers Gunicorn uWSGI --workers <integer> --workers <integer>

  50. DISCLAIMER!

  51. (when one server isn’t enough) Load Balancing

  52. Machine Level App Server 192.168.1.101 App Server 192.168.1.102 App Server

    192.168.1.102 Primary Load Balancer 192.168.1.100
  53. # /etc/nginx/sites-enabled/load-balancer.conf upstream app_upstream { least_conn; server 192.168.1.101:8000 server 192.168.1.102:8000

    server 192.168.1.103:8000 } server { listen 80; server_name hello-world.com; location / { proxy_pass http://app_upstream; } }
  54. Machine + Process Level App Server 192.168.1.101 App Server 192.168.1.102

    App Server 192.168.1.102 Primary Load Balancer 192.168.1.100 t 127.0.0.1:8001 127.0.0.1:8002 127.0.0.1:8000 127.0.0.1:8000 127.0.0.1:8001 127.0.0.1:8002 127.0.0.1:8000 127.0.0.1:8001 127.0.0.1:8002
  55. # /etc/supervisor.d/hello-world.conf [program:hello-world] numprocs=3 process_name=hello-world%(process_num) directory=/srv/hello-world command=/usr/local/bin/uwsgi \ --die-on-term \

    --http :80%(process_num)02d \ -w app:app
  56. # /etc/nginx/sites-enabled/hello-world.conf upstream local_upstream { least_conn; server 127.0.0.1:8000 server 127.0.0.1:8001

    server 127.0.0.1:8002 } server { listen 80; server_name hello-world.com; location / { proxy_pass http://local_upstream; } }
  57. (I’ve failed at this a lot) Recommendations

  58. 1. Use virtualenv and pip 2. Don’t use virtualenvwrapper 3.

    Use a `requirements.txt` file Python
  59. 1. Provide default settings 2. Enable settings to be overridden

    a. Environment Variable(s) b. Default file locations 3. Raise an error at startup when required settings are missing 4. Generate a `SECRET_KEY` with `os. urandom(16)` Configuration
  60. 1. Prefer the uwsgi protocol over HTTP 2. Prefer TCP

    sockets over Unix sockets 3. Lots of useful options a. virtualenv + pythonpath b. enable-threads + lazy-apps c. need-app d. stats Use uWSGI
  61. 1. Pass custom headers 2. Lots of useful modules a.

    ngx_http_geoip_module b. ngx_http_gzip_module c. ngx_http_memcached_module d. ngx_http_status_module Use Nginx
  62. (putting it all together) Automation

  63. http://www.ansible.com/ Ansible

  64. (because what could go wrong?) Demo

  65. Thank You! mattupstate.com gittip.com/mattupstate github.com/mattupstate twitter.com/mattupstate