Zero Downtime Deploy is a script that enables graceful code deploys by always spawning a fresh instance of the server and using a proxying server (nginx) to gracefully fail over.
zdd requires Python 2.x >= 2.5.
Install from PyPI:
$ easy_install zdd
Or install from sources:
$ python setup.py install
See the samples directory for example server configurations for node.js, gunicorn and twisted.
After installing zdd, you will have access to the zddeploy command line script that can be used to do zero downtime cutover between versions. Using gunicorn as an example (but any server can work with zdd):
$ cd ./samples/gunicorn/ $ zddeploy
This causes zddeploy to read the deploy.conf
in ./samples/gunicorn
:
[nginx] template: ./nginx.conf.template pid_file: ./nginx.pid [service:gunicorn] pid_file: gunicorn.pid start: gunicorn -D -c settings_gunicorn.py app:app stop: kill -WINCH
The only requirement beyond this simple configuration file is that the web server must ask the OS to listen on a random port (by binding to port 0 instead of a specific port), and then write a portfile
in addition to the commonly written pidfile
. A portfile
is nothing more than a single line containing the OS assigned random port the server is listening to. To avoid race conditions, the portfile
is named by adding .port
to the end of the pid (i.e. 94383.pid
).
For example, here's the 12 lines of code it takes to add this behavior to gunicorn:
def get_port_filename(): pid = os.getpid() return os.path.join(os.path.dirname(pidfile), "%s.port" % pid) def when_ready(server): host, port = server.LISTENER.sock.getsockname() port_filename = get_port_filename() with file(port_filename, 'w') as portfile: print >>portfile, port @atexit.register def remove_portfile(): os.unlink(port_filename)
Ideally, your server has a graceful stop option, as gunicorn has by default via the SIGWINCH signal (graceful stop code for node.js and twisted included in the samples directory). If it doesn't, you can get a cheap alternative by simply waiting a long enough time period and then killing the server:
- ::
- #!/usr/bin/env bash sleep 600 kill $1
By default, zddeploy will look for ./deploy.conf. Alternatively you can pass the path to the conf file via -c/--conf
.
The easiest way to learn the configuration file is to look at working example:
template
The path to the nginx configuration template file. Every time you deploy, zdd will rerender this template into nginx.conf (in the same directory).pid_file
The path to the nginx pid file, so zdd can SIGHUP nginx. Must match your template. Provided in the template as{nginx_pid_filename}
.
pid_file
The path to the pid file generated by the service. Required for reading the port file.start
The command to run to start the service (A shell script is recomended for non-trivial commands).stop
The command to run to stop the service. Appended with the pid of the instance to stop (A shell script is recomended for non-trivial commands).
Zero Downtime Deploy is released under the MIT License. See the LICENSE file for more details.