No description, website, or topics provided.
Go Makefile Shell
Latest commit c92cf17 Oct 20, 2016 @ionrock Fixup the order of applying to the environment
I messed up the parsing of the command line and wasn't applying the
environment variables correctly.
Failed to load latest commit information.
cmd Fixup the order of applying to the environment Oct 20, 2016
.gitignore Adjust for using go install Sep 12, 2016
Makefile Add --version support Sep 22, 2016
flatten.go Fixup the order of applying to the environment Oct 20, 2016
glide.yaml Post hackfest state... Could be broken, but it is fine Sep 15, 2016
logging.go Add logging, glide, and recursive withenv May 26, 2016
present.go Move cluster to its own command and fix leaving the cluster Aug 24, 2016
sshclient.go Add a ssh stub Sep 16, 2016


Bach is a set of low level tools for composing services. Bach aims to make it easy to wrap other tools, adding service discovery, env injections, configuration management and anything else that is necessary to support legacy applications on a modern cloud / container base platform.


Withenv takes YAML files and applies them to the environment prior to running a command. The idea is that rather than relying on shell variables being set, you can explicitly define what environment variables you want to use.

For example, here is some YAML that might be helpful when connecting to an OpenStack Cloud.


You can then run commands (ie in Ansible for example) that read this information.

$ we -e test_user_creds.yml ansible-play install-app


Toconfig allows you to write a configuration file before starting a process based on a template. The configuration format allows pulling values from environment variables and inject them in your config file.

$ toconfig \
    --template /etc/templates/mydb.cnf.tmpl \
    --config /etc/db/mydb.cnf \


Present allows running a script before a process starts and another when it finishes. For example, if you wanted to start up some process like etcd before starting our app, you could write a small bash script that starts it and stops when the program exits.

$ present --start --after myapp

Present can be used as a simple cluster management system. Present can utilize a gossip protocol to communicate between the cluster. This doesn't require a data store, so it may not be viable for some applications, but for simple service discovery, it should work well.

    toconfig -t my.conf.tmpl -s my.conf myapp

The present nodes command can find the nodes in the cluster and print a JSON file. Withenv can then read the result, add it to the enviornment, at which point, toconfig can write values in the config file.

To join the cluster, you can use the default command.

$ present --name appserver --cluster-addr myapp

This joins the cluster with the service name of appserver that can be used by other cluster members to discover the service. At this point there is nothing in place to do things like register specific ports, dns lookups or anything else terribly special.


There are a lot of great tools out there that can run or build applications, but with each tool, there become new requirements on how you run it. You can use a tool, if you meet these sets of requirements. This is generally not a huge deal, but it often means changing the way your application works in order to accept the new state your application needs to run. It is very difficult to adopt new deployment, service discovery and configuration systems without changing the way your data accepts state.

For example, lets say you have an app that needs a URL of some service in order to run. You want to run the app in a docker container on some cluster management system. The cluster management system allows you to set an environment variable defining your service URL, but in order for you to do that, you need to rewrite some code in you application in order read the environment variable.

The other option is to use something like consul-template to rewrite the config based some script or something similar. This adds a level of complexity as you need to figure out a way to run the service discovery database.

All of this is needed to try out your new deployment strategy.

A better tact is to assume no changes your app. So, step one is to write your config with your services at run time before starting the command.

$ SERVICE_URL= toconfig -t myapp.conf.tmpl -s myapp.conf myapp

Now we can test the service makes it to our config without changing the app.

Next up we want to look up where the service is. We can write a script to do that.


import requests

resp = requests.get('')
print('SERVICE_URL: %s' % resp.json()['url'])

Now we use withenv to load this in our environment.

$ we -s toconfig -t myapp.conf.tmpl -s myapp.conf myapp

Again we can test each portion and be confident that each step should work.

Finally, we can use this chain of commands in our Dockerfile and test that.

# Dockerfile
CMD ["we", "-s", "", "toconfig", "-t", "myapp.conf.tmpl", "-s", "myapp.conf", "myapp"]

Now we can be confident that our app is the same and it should work with the contract that the deployment system requires.