Deploying updates to a Flask application - python

I'm looking for high-level insight here, as someone coming from the PHP ecosystem. What's the common way to deploy updates to a live Flask application thats running on a single server (no load balancing nodes), served by some WSGI like Gunicorn behind Nginx?
Specifically, when you pull updates from a git repository or rsync files to the server, I'm assuming this leaves a small window where a request can come through to the application while its files are changing.
I've mostly deployed Laravel applications for production, so to prevent this is use php artisan down to throw up a maintenance page while files copy, and php artisan up to bring the site back up when its all done.
What's the equivalent with Flask, or is there some other way of handling this (Nginx config)?
Thanks

Looks like Docker might be my best bet:
Have Nginx running on the host, and the application running in container A with Gunicorn. Nginx directs traffic to container A.
Before starting the file sync, tear down container A and start up container B, which listens on the same local port. Container B can be a maintenance page or a copy of the application.
Start file sync and wait for it to finish. When done, tear down container B, and start container A again.

Related

Understanding each component of a web application architecture

Here is a scenario for a system where I am trying to understand what is what:
I'm Joe, a novice programmer and I'm broke. I've got a Flask app and one physical machine. Since I'm broke, I cannot afford another machine for each piece of my system, thus the web server, application and database all live on my one machine.
I've never deployed an app before, but I know that a server can refer to a machine or software. From here on, lets call the physical machine the Rack. I've loaded an instance of MongoDB on my machine and I know that is the Database Server. In order to handle API requests, I need something on the rack that will handle HTTP/S requests, so I install and run an instance of NGINX on it and I know that this is the Web Server. However, my web server doesnt know how to run the app, so I do some research and learn about WSGI and come to find out I need another component. So I install and run an instance of Gunicorn and I know that this is the WSGI Server.
At this point I have a rack that is home to a web server to handle API calls (really just acts as a reverse proxy and pushes requests to the WSGI server), a WSGI server that serves up dynamic content from my app and a database server that stores client information used by the app.
I think I've got my head on straight, then my friend asks "Where is your Application Server?"
Is there an application server is this configuration? Do I need one?
Any basic server architecture has three layers. On one end is the web server, which fulfills requests from clients. The other end is the database server, where the data resides.
In between these two is the application server. It consists of the business logic required to interact with the web server to receive the request, and then with the database server to perform operations.
In your configuration, the WSGI serve/Flask app is the application server.
Most application servers can double up as web servers.

Flask using Nginx?

I am a .net developer coming over to python. I have recently started using Flask and have some quick questions about serving files.
I noticed a lot of tutorials focused on nginix and flask. However, I am able to run flask without nginx. I'm just curious as to why this is used together (nginx and flask). Is nginx only for static files?
Nginx is a proxy server, imagine your apps have multiples microservices on differents languagues.
For more info NGINX REVERSE PROXY
On a development machine flask can be run without a webserver (nginx, apache etc) or an application container (eg uwsgi, gunicorn etc).
Things are different when you want to handle the load on a production server. For starters python is relatively very slow when it comes to serving static content where as apache / nginx do that very well.
When the application becomes big enough to be broken into multiple separate services or has to be horizontally scaled, the proxy server capabilities of nginx come in very handy.
In the architectures I build, nginx serves as the entry point where ssl is terminates and the rest of the application is behind a VPN and firewall.
Does this help?
From http://flask.pocoo.org/docs/1.0/deploying/ :
"While lightweight and easy to use, Flask’s built-in server is not suitable for production as it doesn’t scale well. Some of the options available for properly running Flask in production are documented here."

Running a daemonized bottle application with nginx

I have a bottle application (specifically, homu) which I want to deploy on a server.
The traditional way to run this application is to just run the program (eg python whatever.py), without any server integration. The application is stateful and updates its state by listening to the github webhooks api. It also has a configuration panel that bottle delivers.
Whilst it is able to recover from a crash, this requires a lot of GitHub API requests (which get throttled), so it's preferable to have it running continuously.
Now, I know how to daemonize a bottle application, but this requires running it as a separate program running on a separate port from nginx. I'd like to have nginx delegate certain paths to the running bottle application.
How do I do this?
(Alternatively, a way for me to set it up so that nginx is responsible for keeping it running is nice too)
One way to do this would be to reverse-proxy it.
location /foo/bar {
proxy_pass http://localhost:someport/;
}
and then run the bottle application on someport

How to serve static files from a Dockerized Python web app?

I have a Python web application that sits behind Nginx, and is served via Gunicorn.
I have configured it so that Nginx servers static files directly from the disk and it only talks to Gunicorn for static assets such as images.
My questions:
Is it a good idea or a big "no" to dockerize the web app together with static assets?
If I want to deploy my container in 2 servers, which need access to same assets, how can I make the static assets portable just like the containerized app?
What I'd like to have if possible:
I'd like to put my app in a container and I would like to make it as portable as possible, without spending more funds on additional resources such as a separate server to keep the images (like a DB)
If you know your app will always-and-forever have the same static assets, then just containerize them with the app and be done with it.
But things change, so when you need it I would recommend a Docker Volume Container approach: put your static assets in a DVC and mount that DVC in the main container so it's all pretty much "just one app container". You could use Docker Compose something like this:
appdata:
image: busybox
volumes:
- /path/to/app/static
command: echo "I'm just a volume container"
app:
build: .
volumes_from:
- appdata
command: …
You can expand further by starting your container with a bootstrap script that copies initial static files into the destination path on startup. That way your app is guaranteed to always have a default set to get started, but you can add more static files as the app grows. For an example of this, pull the official Jenkins container and read /usr/local/bin/jenkins.sh.
I agree with kojiro, if things do not change much, containerize the static files with your app. Regarding your second question, it seems that you think the Docker Volume Container approach is still not flexible enough since you will have multiple docker hosts. Maybe Flocker addresses your requirements? From the Flocker docs (https://docs.clusterhq.com/en/0.3.2/):
Flocker lets you move your Docker containers and their data together
between Linux hosts. This means that you can run your databases,
queues and key-value stores in Docker and move them around as easily
as the rest of your app. Even stateless apps depend on many stateful
services and currently running these services in Docker containers in
production is nearly impossible. Flocker aims to solve this problem by
providing an orchestration framework that allows you to port both your
stateful and stateless containers between environments.

Is there a way to deploy new code with Tornado/Python without restarting the server?

I've recently started to experiment with Python and Tornado web server/framework for web development. Previously, I have used PHP with my own framework on a LAMP stack. With PHP, deploying updated code/new code is as easy as uploading it to the server because of the way mod_php and Apache interact.
When I add new code or update code in Python/Tornado, do I need to restart the Tornado server? I could see this being problematic if you have a number of active users.
(a) Do I have to restart the server, or is there another/better way?
(b) If so, how can I avoid users being disconnected/getting errors/etc. while it's restarting (which could take a few seconds)?
[One possible thought is to use the page flipping paradigm with Nginx pointing to a server, launch the new server instance with updated code, redirect Nginx there and take down the original server...?]
It appears the best method is to use Nginx with multiple Tornado instances as I alluded to in my original question and as Cole mentions. Nginx can reload its configuration file on the fly . So the process looks like this:
Update Python/Tornado web application code
Start a new instance of the application on a different port
Update the configuration file of Nginx to point to the new instance (testing the syntax of the configuration file first)
Reload the Nginx configuration file with a kill -HUP command
Stop the old instance of Python/Tornado web server
A couple useful resources on Nginx regarding hot-swapping the configuration file:
https://calomel.org/nginx.html (in "Explaining the directives in nginx.conf" section)
http://wiki.nginx.org/CommandLine (in "Loading a New Configuration Using Signals" section)
Use HAProxy or Nginx and proxy to multiple Tornado processes, which you can then restart one by one. The Tornado docs cover Nginx, but it doesn't support websockets, so if you're using them you'll need HAProxy.
You could use a debug=True switch with the tornado web instance.
T_APP = tornado.web.Application(<URL_MAP>, debug=True)
This reflects the handler changes as and when they happen.
Is this what you are searching for?
A module to automatically restart the server when a module is modified.
http://www.tornadoweb.org/en/branch2.4/autoreload.html
If you just want to deploy new code with tornado/python during development without restarting the server, you can use the realtimefunc decorator in this GitHub repository.

Categories