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.7k
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.3k
Testing Flask Applications
mattupstate
5
1.5k
Other Decks in Technology
See All in Technology
関係性が駆動するアジャイル──GPTに人格を与えたら、対話を通してふりかえりを習慣化できた話
mhlyc
0
140
10年の共創が示す、これからの開発者と企業の関係 ~ Crossroad
soracom
PRO
1
710
Where will it converge?
ibknadedeji
0
210
20201008_ファインディ_品質意識を育てる役目は人かAIか___2_.pdf
findy_eventslides
2
600
能登半島地震で見えた災害対応の課題と組織変革の重要性
ditccsugii
0
430
20251007: What happens when multi-agent systems become larger? (CyberAgent, Inc)
ornew
1
190
AWS Control Tower に学ぶ! IAM Identity Center 権限設計の第一歩 / IAM Identity Center with Control Tower
y___u
0
100
CoRL 2025 Survey
harukiabe
0
110
職種別ミートアップで社内から盛り上げる アウトプット文化の醸成と関係強化/ #DevRelKaigi
nishiuma
2
160
リセラー企業のテクサポ担当が考える、生成 AI 時代のトラブルシュート 2025
kazzpapa3
1
150
社内報はAIにやらせよう / Let AI handle the company newsletter
saka2jp
8
1.3k
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
11
79k
Featured
See All Featured
YesSQL, Process and Tooling at Scale
rocio
173
14k
Done Done
chrislema
185
16k
What’s in a name? Adding method to the madness
productmarketing
PRO
23
3.7k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
229
22k
The World Runs on Bad Software
bkeepers
PRO
72
11k
The Illustrated Children's Guide to Kubernetes
chrisshort
49
51k
Statistics for Hackers
jakevdp
799
220k
Faster Mobile Websites
deanohume
310
31k
What's in a price? How to price your products and services
michaelherold
246
12k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
BBQ
matthewcrist
89
9.8k
For a Future-Friendly Web
brad_frost
180
9.9k
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