Propellor development is churning away! (And leaving no few puns in its wake..)
Now it supports secure handling of private data like passwords (only the host that owns it can see it), and fully end-to-end secured deployment via gpg signed and verified commits.
And, I've just gotten support for Docker to build. Probably not quite work, but it should only be a few bugs away at this point.
Here's how to deploy a dockerized webserver with propellor:
host hostname@"clam.kitenet.net" = Just
[ Docker.configured
, File.dirExists "/var/www"
, Docker.hasContainer hostname "webserver" container
]
container _ "webserver" = Just $ Docker.containerFromImage "joeyh/debian-unstable"
[ Docker.publish "80:80"
, Docker.volume "/var/www:/var/www"
, Docker.inside
[ serviceRunning "apache2"
`requires` Apt.installed ["apache2"]
]
]
Docker containers are set up using Properties too, just like regular hosts, but their Properties are run inside the container.
That means that, if I change the web server port above, Propellor will notice the container config is out of date, and stop the container, commit an image based on it, and quickly use that to bring up a new container with the new configuration.
If I change the web server to say, lighttpd, Propellor will run inside the container, and notice that it needs to install lighttpd to satisfy the new property, and so will update the container without needing to take it down.
Adding all this behavior took only 253 lines of code, and none of it impacts the core of Propellor at all; it's all in Propellor.Property.Docker. (Well, I did need another hundred lines to write a daemon that runs inside the container and reads commands to run over a named pipe... Docker makes running ad-hoc commands inside a container a PITA.)
So, I think that this vindicates the approach of making the configuration of Propellor be a list of Properties, which can be constructed by abitrarily interesting Haskell code. I didn't design Propellor to support containers, but it was easy to find a way to express them as shown above.
Compare that with how Puppet supports Docker: http://docs.docker.io/en/latest/use/puppet/
docker::run { 'helloworld': image => 'ubuntu', command => '/bin/sh -c "while true; do echo hello world; sleep 1; done"', ports => ['4444', '4555'], ...
All puppet manages is running the image and a simple static command inside it. All the complexities that puppet provides for configuring servers cannot easily be brought to bear inside the container, and a large reason for that is, I think, that its configuration file is just not expressive enough.