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?

174e7b0ff60963f821d0b9a4f1a3ef52?s=128

Hynek Schlawack

May 12, 2018
Tweet

Transcript

  1. 2.
  2. 3.
  3. 5.

    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
  4. 6.

    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
  5. 8.

    $ 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
  6. 9.

    $ 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
  7. 10.

    $ 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"
  8. 11.
  9. 12.
  10. 19.

    App

  11. 30.
  12. 31.
  13. 36.

    $ 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
  14. 37.

    $ 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
  15. 38.

    $ 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
  16. 39.

    $ 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, )
  17. 40.

    import environ @environ.config(prefix="APP") class AppConfig: @environ.config class Log: level =

    environ.var() format = environ.var() log = environ.group(Log) config.py
  18. 41.

    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
  19. 42.

    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
  20. 43.

    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
  21. 45.
  22. 47.
  23. 54.

    App

  24. 60.

    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
  25. 61.

    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
  26. 62.

    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
  27. 63.
  28. 64.

    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
  29. 65.

    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
  30. 67.
  31. 68.
  32. 74.
  33. 80.
  34. 84.

    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
  35. 85.

    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
  36. 86.

    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
  37. 87.
  38. 88.
  39. 89.
  40. 90.
  41. 91.

    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
  42. 92.
  43. 93.
  44. 95.

    App

  45. 102.
  46. 103.

    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
  47. 104.
  48. 109.
  49. 110.