Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to Write Deployment-friendly Applications

How to Write Deployment-friendly Applications

The DevOps movement gave us many ways to put Python applications into production. But how can you practically structure and configure your applications to make them indifferent to the environment they run in? How do secrets fit into the picture? And where do you put that log file?

Hynek Schlawack

May 12, 2018
Tweet

More Decks by Hynek Schlawack

Other Decks in Technology

Transcript

  1. from pyramid.config import Configurator from .views import hello_world def make_app():

    config = Configurator() config.add_route("hello", "/hello") config.scan() return config.make_wsgi_app() app_maker.py
  2. from pyramid.config import Configurator from .views import hello_world def make_app():

    config = Configurator() config.add_route("hello", "/hello") config.scan() return config.make_wsgi_app() app_maker.py
  3. $ gunicorn \ --access-logfile - \ "sample.app_maker:make_app()" [2018-04-05 16:28:06 +0200]

    [54343] [INFO] Starting gunicorn 19.7.1 [2018-04-05 16:28:06 +0200] [54343] [INFO] Listening at: http://127.0.0.1:8000 (54343) [2018-04-05 16:28:06 +0200] [54343] [INFO] Using worker: sync [2018-04-05 16:28:06 +0200] [54346] [INFO] Booting worker with pid: 54346
  4. $ gunicorn \ --access-logfile - \ "sample.app_maker:make_app()" $ curl http://127.0.0.1:8000/hello

    Hello World! [2018-04-05 16:28:06 +0200] [54343] [INFO] Starting gunicorn 19.7.1 [2018-04-05 16:28:06 +0200] [54343] [INFO] Listening at: http://127.0.0.1:8000 (54343) [2018-04-05 16:28:06 +0200] [54343] [INFO] Using worker: sync [2018-04-05 16:28:06 +0200] [54346] [INFO] Booting worker with pid: 54346
  5. $ gunicorn \ --access-logfile - \ "sample.app_maker:make_app()" $ curl http://127.0.0.1:8000/hello

    Hello World! [2018-04-05 16:28:06 +0200] [54343] [INFO] Starting gunicorn 19.7.1 [2018-04-05 16:28:06 +0200] [54343] [INFO] Listening at: http://127.0.0.1:8000 (54343) [2018-04-05 16:28:06 +0200] [54343] [INFO] Using worker: sync [2018-04-05 16:28:06 +0200] [54346] [INFO] Booting worker with pid: 54346 127.0.0.1 - - [05/Apr/2018:16:28:08 +0200] "GET /hello HTTP/1.1" 200 12 "-" "curl/7.54.0"
  6. App

  7. $ env HOST=0.0.0.0 PORT=8888 LOG_LEVEL=INFO \ ./run-app.sh [2018-04-09 15:59:29 +0200]

    [35323] [INFO] Starting gunicorn 19.7.1 [2018-04-09 15:59:29 +0200] [35323] [INFO] Listening at: http://0.0.0.0:8888
  8. $ env HOST=0.0.0.0 PORT=8888 LOG_LEVEL=INFO \ ./run-app.sh [2018-04-09 15:59:29 +0200]

    [35323] [INFO] Starting gunicorn 19.7.1 [2018-04-09 15:59:29 +0200] [35323] [INFO] Listening at: http://0.0.0.0:8888
  9. $ env HOST=0.0.0.0 PORT=8888 LOG_LEVEL=INFO \ ./run-app.sh [2018-04-09 15:59:29 +0200]

    [35323] [INFO] Starting gunicorn 19.7.1 [2018-04-09 15:59:29 +0200] [35323] [INFO] Listening at: http://0.0.0.0:8888
  10. $ env HOST=0.0.0.0 PORT=8888 LOG_LEVEL=INFO \ ./run-app.sh [2018-04-09 15:59:29 +0200]

    [35323] [INFO] Starting gunicorn 19.7.1 [2018-04-09 15:59:29 +0200] [35323] [INFO] Listening at: http://0.0.0.0:8888 logging.basicConfig( level=getattr( logging, os.environ["LOG_LEVEL"], ), format="%(message)s", stream=sys.stdout, )
  11. import environ @environ.config(prefix="APP") class AppConfig: @environ.config class Log: level =

    environ.var() format = environ.var() log = environ.group(Log) config.py
  12. APP_LOG_LEVEL → app_cfg.log.level import environ @environ.config(prefix="APP") class AppConfig: @environ.config class

    Log: level = environ.var() format = environ.var() log = environ.group(Log) config.py
  13. import environ from .config import AppConfig from .app_maker import make_app

    app_cfg = environ.to_config(AppConfig) application = make_app(app_cfg) wsgi.py
  14. import environ from .config import AppConfig from .app_maker import make_app

    app_cfg = environ.to_config(AppConfig) application = make_app(app_cfg) wsgi.py
  15. App

  16. 127.0.0.1:8001 Exposes env HOST=127.0.0.1 \ PORT=8001 \ ./run-app.sh App 127.0.0.1:8000

    Exposes env HOST=127.0.0.1 \ PORT=8000 \ ./run-app.sh App
  17. 127.0.0.1:8001 Exposes env HOST=127.0.0.1 \ PORT=8001 \ ./run-app.sh App 127.0.0.1:8000

    Exposes env HOST=127.0.0.1 \ PORT=8000 \ ./run-app.sh App $PUBLIC_IP Load Balancer
  18. 127.0.0.1:8001 Exposes env HOST=127.0.0.1 \ PORT=8001 \ ./run-app.sh App 127.0.0.1:8000

    Exposes env HOST=127.0.0.1 \ PORT=8000 \ ./run-app.sh App $PUBLIC_IP Load Balancer Offline
  19. 127.0.0.1:8001 Exposes env HOST=127.0.0.1 \ PORT=8001 \ ./run-app.sh App 127.0.0.1:8000

    Exposes env HOST=127.0.0.1 \ PORT=8000 \ ./run-app.sh App $PUBLIC_IP Load Balancer
  20. 127.0.0.1:8001 Exposes env HOST=127.0.0.1 \ PORT=8001 \ ./run-app.sh App 127.0.0.1:8000

    Exposes env HOST=127.0.0.1 \ PORT=8000 \ ./run-app.sh App $PUBLIC_IP Load Balancer
  21. 127.0.0.1:8001 Exposes env HOST=127.0.0.1 \ PORT=8001 \ ./run-app.sh App 127.0.0.1:8000

    Exposes env HOST=127.0.0.1 \ PORT=8000 \ ./run-app.sh App $PUBLIC_IP Load Balancer
  22. App 127.0.0.1:8003 Exposes env HOST=127.0.0.1 \ PORT=8002 \ ./run-app.sh 127.0.0.1:8002

    Exposes env HOST=127.0.0.1 \ PORT=8002 \ ./run-app.sh App 127.0.0.1:8001 Exposes env HOST=127.0.0.1 \ PORT=8001 \ ./run-app.sh App 127.0.0.1:8000 Exposes env HOST=127.0.0.1 \ PORT=8000 \ ./run-app.sh App $PUBLIC_IP Load Balancer
  23. App 10.0.0.4:8000 Exposes env HOST=10.0.0.4 \ PORT=8000 \ ./run-app.sh 10.0.0.3:8000

    Exposes env HOST=10.0.0.3 \ PORT=8000 \ ./run-app.sh App 10.0.0.2:8000 Exposes env HOST=10.0.0.2 \ PORT=8000 \ ./run-app.sh App 10.0.0.1:8000 Exposes env HOST=10.0.0.1 \ PORT=8000 \ ./run-app.sh App $PUBLIC_IP Load Balancer
  24. App 10.0.0.4:8000 Exposes env HOST=10.0.0.4 \ PORT=8000 \ ./run-app.sh 10.0.0.3:8000

    Exposes env HOST=10.0.0.3 \ PORT=8000 \ ./run-app.sh App 10.0.0.2:8000 Exposes env HOST=10.0.0.2 \ PORT=8000 \ ./run-app.sh App 10.0.0.1:8000 Exposes env HOST=10.0.0.1 \ PORT=8000 \ ./run-app.sh App $PUBLIC_IP Load Balancer
  25. App

  26. Logs stdout Secrets Exposes service 0.0.0.0:8000 run-app.sh Exposes state 0.0.0.0:8000/-/*

    SIGTERM External Resources Keeps data in env HOST=0.0.0.0 PORT=8000 … App