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
tenntennはなんでnewmoにnew社したの? - YAPC::Hakodate 2024
tenntenn
PRO
0
200
クレジットカードを製造する技術
yutadayo
81
46k
ITエンジニアとして知っておいてほしい、電子メールという大きな穴
logica0419
6
1.1k
【shownet.conf_】ローカル5Gを活用したウォーキングツアーの体感向上
shownet
PRO
0
340
Oracle Database 23ai 新機能#4 Application Continuity
oracle4engineer
PRO
0
120
見えづらい活動の成果の伝え方は日頃からめちゃくちゃ悩んでるけど、実際こんな取り組みをしな がら温度感を合わせにいってるよ / Conveying Hard-to-See Results
kakehashi
2
1.5k
分析者起点の企画を成功させた連携面の工夫
lycorptech_jp
PRO
1
250
エムスリー全チーム紹介資料 / Introduction of M3 All Teams
m3_engineering
1
300
Oracle Database 23ai 新機能#4 Real Application Clusters
oracle4engineer
PRO
0
150
Perlで始めるeBPF: 自作Loaderの作り方 / Getting started with eBPF in Perl_How to create your own Loader
takehaya
1
840
プロダクト開発の貢献をアピールするための目標設計や認知活動 / Goal design and recognition activities to promote product development contributions.
oomatomo
2
530
Case Study: Concurrent Counting
ennael
PRO
0
100
Featured
See All Featured
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
41
9.2k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
228
52k
Agile that works and the tools we love
rasmusluckow
327
21k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
28
9k
A better future with KSS
kneath
237
17k
Robots, Beer and Maslow
schacon
PRO
157
8.2k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.2k
Scaling GitHub
holman
458
140k
Imperfection Machines: The Place of Print at Facebook
scottboms
264
13k
GraphQLとの向き合い方2022年版
quramy
43
13k
A Modern Web Designer's Workflow
chriscoyier
692
190k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
191
16k
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