Running programs automatically as service is not always an easy task. Some well known applications come with their own managers (e.g. unicorn, forever, pm2) but there is no unified approach across technologies.Custom build code often tend to come as a simple executable that runs in the foreground. And eventually init scripts simply ensure the services start but usually does not handle respawn.

Supervisord offers a solution to all the issues above and allows you to monitor and control processes. It lets you:

starts / stop / manage processes (long or short running) via unix or http xml/rpc requests

automatically or manually start processes

easily restart crashed programs

manages log files and file rotation (conveniency)

easily manages running user

perfect for custom processes that are not managed as services

side benefit: play very well with docker containers

Using Supervisord to manage deployments

We're taking the mixed approach of running standalone commands and executing custom code as a service. Our example will be a deployement process.

A deployment may involve more that simply restart a service, but require to install dependency, etc.

When dealing with multiple servers, the deployment workflow may be different due to the various services involved; having supervisord doing some unified interface is extremely convenient.

Supervisord setup

Supervisord is often available within the package manager of your distrib ( apt-get install supervisor ), if not you should be able to install it via pip as well ( pip install supervisor )

We're creating here a simple config file that will define 2 programs:

deploy that will not start automatically and will require to be executed manually ( autostart option),

that will not start automatically and will require to be executed manually ( option), app that is a random node.js application that will start automatically

One can simply run supervisorctl start deploy and get the deploy process starting. Within the deploy.sh script, one can put any of the required logic needed to deploy the code

e.g. supervisord config in /etc/supervisor/conf.d/my_app.conf

[program:deploy] command=/usr/local/bin/deploy.sh autostart=false [program:app] command=/usr/bin/node main.js directory=/opt/app environment="NODE_ENV=prod" user=nobody autostart=true

Deployment script

We're now preparing a simple script in /usr/local/bin/deploy.sh that will perform the operations required to deploy a new version of the code. Obviously this is only a sample! Be sure to set the execute flag or supervisord won't be able to execute it. ( chmod +x /usr/local/bin/deploy.sh )

#!/bin/bash ################## # Simple deploy script for a node app ################## WORKDIR=/opt/app cd $WORKDIR updated=$(git pull 2>/dev/null) if [ "$updated" == 'Already up-to-date.' ]; then # Nothing to do, exit cleanly exit 0 else # Code has been updated, rebuild the app npm install ... other commands ... # And eventually restart the app supervisorctl restart app fi

Enhancing the workflow with HTTP support for supervisord

The 2 code snippets above let you simply run the deployment operations and get the app restarted if necessary. But supervisord does not allow (yet) remote control.

This can then be very easily extended and triggered remotely by making use of the HTTP xml-rpc interface.

Enabling HTTP xml-rpc

Add the following to your supervisord config ( /etc/supervisor/conf.d/inet.conf )

[inet_http_server] port=*:9001 username=secret_user password={SHA}secret_hash

Where the secret_hash is calculated as such echo -n 'secret_pass' | sha1sum | cut -f1 -d' ' . You need then to prefix this hash with {SHA} as explained http://supervisord.org/configuration.html#inet-http-server-section-values

Best practices still recommend that:

you don't set the password in clear in the config you protect your host via iptables and only allow selected hosts to reach the HTTP interface of supervisord

Multi host support

Now that Supervisord allows remote connections, you can orchestrate several boxes at once very simply. Obviously more logic is needed to play nice with the sequence, but you get the point...

for host in host1 host2 host3; do supervisorctl -s http://$host:9001 -u secret_user -p secret_pass start deploy done

And supervisor is now available in devo.ps! Hurray

Please enable JavaScript to view the comments powered by Disqus.

Disqus