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. Matt Wright @mattupstate Engineer @ChatID • Python, Ruby, CoffeeScript •

    Flask, Chef, AngularJS Open Source • Flask-Security • Flask-Social • Flask-Mail + a few others
  2. # ~/app.py from flask import Flask app = Flask(__name__) @app.route('/')

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

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

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

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

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

    ware WSGI Middle- ware WSGI Middle- ware WSGI Middle- ware MOAR MIDDLEWARE!
  8. 1. Written in Python! 2. Web application framework 3. Asynchronous

    networking library 4. WSGI support Tornado
  9. # ~/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()
  10. matt @ pc in ~/ $ mkvirtualenv wsgi matt @

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

    matt @ pc in ~/ workon:wsgi $ pip install tornado matt @ pc in ~/ workon:wsgi $ python tor.py
  12. # ~/ge.py from gevent.wsgi import WSGIServer from app import app

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

    matt @ pc in ~/ workon:wsgi $ python ge.py
  14. 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...
  15. Gunicorn 1. Written in Python! 2. Easy configuration 3. Broadly

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

    matt @ pc in ~/ workon:wsgi $ gunicorn app:app
  17. 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
  18. uWSGI 1. Support for many platforms and languages 2. Multiple

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

    matt @ pc in ~/ workon:wsgi $ uwsgi --http :8000 -w app:app ... spawned uWSGI worker 1 ...
  20. 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: ...
  21. # /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
  22. Why? • Static files • URL rewrites • Routing •

    Header mods • App aggregation • and many more! • Network security • Authentication • Load balancing • SSL termination • Compression • Caching
  23. # /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>
  24. # /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; } }
  25. 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
  26. # /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; } }
  27. 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
  28. # /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; } }
  29. 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
  30. 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
  31. 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