Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Deploying Flask (WSGI) Applications
Search
Matt Wright
June 26, 2014
Technology
3
1.5k
Deploying Flask (WSGI) Applications
Supporting files:
https://github.com/mattupstate/flask-nyc-deploying
Matt Wright
June 26, 2014
Tweet
Share
More Decks by Matt Wright
See All by Matt Wright
Python Apps and Docker
mattupstate
1
1.2k
Testing Flask Applications
mattupstate
5
1.4k
Other Decks in Technology
See All in Technology
EventHub Startup CTO of the year 2024 ピッチ資料
eventhub
0
120
Exadata Database Service on Dedicated Infrastructure(ExaDB-D) UI スクリーン・キャプチャ集
oracle4engineer
PRO
2
3.2k
The Role of Developer Relations in AI Product Success.
giftojabu1
0
130
【令和最新版】AWS Direct Connectと愉快なGWたちのおさらい
minorun365
PRO
5
760
Oracle Cloud Infrastructureデータベース・クラウド:各バージョンのサポート期間
oracle4engineer
PRO
28
13k
Why App Signing Matters for Your Android Apps - Android Bangkok Conference 2024
akexorcist
0
130
ノーコードデータ分析ツールで体験する時系列データ分析超入門
negi111111
0
420
Incident Response Practices: Waroom's Features and Future Challenges
rrreeeyyy
0
160
Zennのパフォーマンスモニタリングでやっていること
ryosukeigarashi
0
150
Evangelismo técnico: ¿qué, cómo y por qué?
trishagee
0
360
マルチプロダクトな開発組織で 「開発生産性」に向き合うために試みたこと / Improving Multi-Product Dev Productivity
sugamasao
1
310
iOS/Androidで同じUI体験をネ イティブで作成する際に気をつ けたい落とし穴
fumiyasac0921
1
110
Featured
See All Featured
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
25
1.8k
Writing Fast Ruby
sferik
627
61k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
900
Git: the NoSQL Database
bkeepers
PRO
427
64k
Unsuck your backbone
ammeep
668
57k
The Cost Of JavaScript in 2023
addyosmani
45
6.8k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
10
720
Optimizing for Happiness
mojombo
376
70k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.1k
Into the Great Unknown - MozCon
thekraken
32
1.5k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
131
33k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
28
2k
Transcript
Deploying Flask (WSGI) Applications
Matt Wright @mattupstate Engineer @ChatID • Python, Ruby, CoffeeScript •
Flask, Chef, AngularJS Open Source • Flask-Security • Flask-Social • Flask-Mail + a few others
WSGI (Web Server Gateway Interface)
PEP 333 http://legacy.python.org/dev/peps/pep-0333/
# ~/hello.py def application(environ, start_response): start_response('200 OK', [('Content-Type','text/html')]) return ["Hello
World"]
# ~/app.py from flask import Flask app = Flask(__name__) @app.route('/')
@app.route('/<path:path>') def catch_all(path=''): return 'Hello World'
Browser WSGI Gateway WSGI App 1 2 4 3 Request
Flow
Browser WSGI Gateway WSGI App 1 1. Browser sends an
HTTP request to the gateway server Request Flow
Browser WSGI Gateway WSGI App 2 2. Gateway server prepares
and sends the request to the WSGI compatible application 1 Request Flow
Browser WSGI Gateway WSGI App 1 2 3 3. Application
processes the request and returns a response Request Flow
Browser WSGI Gateway WSGI App 1 2 4 3 4.
The gateway server returns the response to the browser Request Flow
Browser WSGI Gateway WSGI Middle- ware WSGI App Middleware
Browser WSGI Gateway WSGI Middle- ware WSGI App WSGI Middle-
ware WSGI Middle- ware WSGI Middle- ware WSGI Middle- ware MOAR MIDDLEWARE!
Gateway Servers (sometimes called “containers”)
http://www.tornadoweb.org/ Tornado
1. Written in Python! 2. Web application framework 3. Asynchronous
networking library 4. WSGI support Tornado
# ~/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()
matt @ pc in ~/ $ mkvirtualenv wsgi matt @
pc in ~/ workon:wsgi $ pip install flask tornado matt @ pc in ~/ workon:wsgi $ python tor.py
matt @ pc in ~/ $ curl localhost:8000 Hello World
matt @ pc in ~/ workon:wsgi $ pip install tornado matt @ pc in ~/ workon:wsgi $ python tor.py
http://www.gevent.org/ gevent
1. Written in Python! 2. Coroutine networking library 3. 3rd
party module support gevent
# ~/ge.py from gevent.wsgi import WSGIServer from app import app
server = WSGIServer(('', 8000), app) server.serve_forever()
matt @ pc in ~/ workon:wsgi $ pip install gevent
matt @ pc in ~/ workon:wsgi $ python ge.py
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...
http://gunicorn.org/ Gunicorn
Gunicorn 1. Written in Python! 2. Easy configuration 3. Broadly
compatible 4. Extensible 5. Fairly speedy
matt @ pc in ~/ workon:wsgi $ pip install gunicorn
matt @ pc in ~/ workon:wsgi $ gunicorn app:app
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
https://uwsgi-docs.readthedocs.org/ uWSGI
uWSGI 1. Support for many platforms and languages 2. Multiple
configuration formats 3. Flexible logging 4. Extensible 5. Speaks HTTP and uwsgi
matt @ pc in ~/ workon:wsgi $ pip install uwsgi
matt @ pc in ~/ workon:wsgi $ uwsgi --http :8000 -w app:app ... spawned uWSGI worker 1 ...
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: ...
(how to start your app) Process Management
http://upstart.ubuntu.com/ upstart
# /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
http://www.freedesktop.org/wiki/Software/systemd/ systemd
# /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
http://supervisord.org/ supervisord
# /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
(some things are better than others) Reverse Proxies
Why? • Static files • URL rewrites • Routing •
Header mods • App aggregation • and many more! • Network security • Authentication • Load balancing • SSL termination • Compression • Caching
http://www.nginx.org/ Apache
# /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>
http://www.nginx.org/ Nginx
# /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; } }
(is hard) Concurrency
Concurrency Models callback/generator (auto) lightweight threads (auto) processor/thread (config) processor/thread
(config) Tornado gevent Gunicorn uWSGI
Increasing Concurrency processes processes workers + processes workers + processes
Tornado gevent Gunicorn uWSGI
Increasing Workers Gunicorn uWSGI --workers <integer> --workers <integer>
DISCLAIMER!
(when one server isn’t enough) Load Balancing
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
# /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; } }
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
# /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
# /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; } }
(I’ve failed at this a lot) Recommendations
1. Use virtualenv and pip 2. Don’t use virtualenvwrapper 3.
Use a `requirements.txt` file Python
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
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
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
(putting it all together) Automation
http://www.ansible.com/ Ansible
(because what could go wrong?) Demo
Thank You! mattupstate.com gittip.com/mattupstate github.com/mattupstate twitter.com/mattupstate