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

    View full-size slide

  2. Matt Wright @mattupstate
    Engineer @ChatID
    ● Python, Ruby, CoffeeScript
    ● Flask, Chef, AngularJS
    Open Source
    ● Flask-Security
    ● Flask-Social
    ● Flask-Mail + a few others

    View full-size slide

  3. WSGI
    (Web Server Gateway Interface)

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  6. # ~/app.py
    from flask import Flask
    app = Flask(__name__)
    @app.route('/')
    @app.route('/')
    def catch_all(path=''):
    return 'Hello World'

    View full-size slide

  7. Browser
    WSGI
    Gateway
    WSGI
    App
    1 2
    4 3
    Request Flow

    View full-size slide

  8. Browser
    WSGI
    Gateway
    WSGI
    App
    1
    1. Browser sends an HTTP request
    to the gateway server
    Request Flow

    View full-size slide

  9. Browser
    WSGI
    Gateway
    WSGI
    App
    2
    2. Gateway server prepares and sends the
    request to the WSGI compatible application
    1
    Request Flow

    View full-size slide

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

    View full-size slide

  11. Browser
    WSGI
    Gateway
    WSGI
    App
    1 2
    4 3
    4. The gateway server returns the
    response to the browser
    Request Flow

    View full-size slide

  12. Browser
    WSGI
    Gateway
    WSGI
    Middle-
    ware
    WSGI
    App
    Middleware

    View full-size slide

  13. Browser
    WSGI
    Gateway
    WSGI
    Middle-
    ware
    WSGI
    App
    WSGI
    Middle-
    ware
    WSGI
    Middle-
    ware
    WSGI
    Middle-
    ware
    WSGI
    Middle-
    ware
    MOAR MIDDLEWARE!

    View full-size slide

  14. Gateway Servers
    (sometimes called “containers”)

    View full-size slide

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

    View full-size slide

  16. 1. Written in Python!
    2. Web application framework
    3. Asynchronous networking library
    4. WSGI support
    Tornado

    View full-size slide

  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()

    View full-size slide

  18. matt @ pc in ~/
    $ mkvirtualenv wsgi
    matt @ pc in ~/ workon:wsgi
    $ pip install flask tornado
    matt @ pc in ~/ workon:wsgi
    $ python tor.py

    View full-size slide

  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

    View full-size slide

  20. http://www.gevent.org/
    gevent

    View full-size slide

  21. 1. Written in Python!
    2. Coroutine networking library
    3. 3rd party module support
    gevent

    View full-size slide

  22. # ~/ge.py
    from gevent.wsgi import WSGIServer
    from app import app
    server = WSGIServer(('', 8000), app)
    server.serve_forever()

    View full-size slide

  23. matt @ pc in ~/ workon:wsgi
    $ pip install gevent
    matt @ pc in ~/ workon:wsgi
    $ python ge.py

    View full-size slide

  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...

    View full-size slide

  25. http://gunicorn.org/
    Gunicorn

    View full-size slide

  26. Gunicorn
    1. Written in Python!
    2. Easy configuration
    3. Broadly compatible
    4. Extensible
    5. Fairly speedy

    View full-size slide

  27. matt @ pc in ~/ workon:wsgi
    $ pip install gunicorn
    matt @ pc in ~/ workon:wsgi
    $ gunicorn app:app

    View full-size slide

  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

    View full-size slide

  29. https://uwsgi-docs.readthedocs.org/
    uWSGI

    View full-size slide

  30. uWSGI
    1. Support for many platforms and languages
    2. Multiple configuration formats
    3. Flexible logging
    4. Extensible
    5. Speaks HTTP and uwsgi

    View full-size slide

  31. matt @ pc in ~/ workon:wsgi
    $ pip install uwsgi
    matt @ pc in ~/ workon:wsgi
    $ uwsgi --http :8000 -w app:app
    ...
    spawned uWSGI worker 1 ...

    View full-size slide

  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: ...

    View full-size slide

  33. (how to start your app)
    Process Management

    View full-size slide

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

    View full-size slide

  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

    View full-size slide

  36. http://www.freedesktop.org/wiki/Software/systemd/
    systemd

    View full-size slide

  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

    View full-size slide

  38. http://supervisord.org/
    supervisord

    View full-size slide

  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

    View full-size slide

  40. (some things are better than others)
    Reverse Proxies

    View full-size slide

  41. Why?
    ● Static files
    ● URL rewrites
    ● Routing
    ● Header mods
    ● App aggregation
    ● and many more!
    ● Network security
    ● Authentication
    ● Load balancing
    ● SSL termination
    ● Compression
    ● Caching

    View full-size slide

  42. http://www.nginx.org/
    Apache

    View full-size slide

  43. # /etc/apache2/sites-enabled/hello-world.conf

    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/

    View full-size slide

  44. http://www.nginx.org/
    Nginx

    View full-size slide

  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;
    }
    }

    View full-size slide

  46. (is hard)
    Concurrency

    View full-size slide

  47. Concurrency Models
    callback/generator (auto)
    lightweight threads (auto)
    processor/thread (config)
    processor/thread (config)
    Tornado
    gevent
    Gunicorn
    uWSGI

    View full-size slide

  48. Increasing Concurrency
    processes
    processes
    workers + processes
    workers + processes
    Tornado
    gevent
    Gunicorn
    uWSGI

    View full-size slide

  49. Increasing Workers
    Gunicorn
    uWSGI
    --workers
    --workers

    View full-size slide

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

    View full-size slide

  51. 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

    View full-size slide

  52. # /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;
    }
    }

    View full-size slide

  53. 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

    View full-size slide

  54. # /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

    View full-size slide

  55. # /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;
    }
    }

    View full-size slide

  56. (I’ve failed at this a lot)
    Recommendations

    View full-size slide

  57. 1. Use virtualenv and pip
    2. Don’t use virtualenvwrapper
    3. Use a `requirements.txt` file
    Python

    View full-size slide

  58. 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

    View full-size slide

  59. 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

    View full-size slide

  60. 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

    View full-size slide

  61. (putting it all together)
    Automation

    View full-size slide

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

    View full-size slide

  63. (because what could go wrong?)
    Demo

    View full-size slide

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

    View full-size slide