Functional Operations
I knew I needed to quit my job when I first saw the EC2 API. Seeing a few lines of code provision a massive network compelled me to drop what I had been doing and get involved. In the years since that moment, functional approaches have simplified application development. Meanwhile, our approach to deployment is still weighed down with complex state management. Where are our immutable networks? Our lambda cloud calculus? Our functional operations?
Just as functional programming rids us of the unnecessary state that complicates the maintenance of our code, functional operations rids us of the upgrading, quiescing, and process replacement that complicates so much infrastructure automation and deployment code. We intend our running network to be a function of our git repositories, with as few side effects and state transitions as possible.
At Swipely, we assemble running networks as functions of Docker container images, which we build as functions of git repositories. We declare each function and use it to build the output from the input from scratch, firing up new instances running freshly-built containers every time we deploy code, several times a day.
If you want to try Docker, or if you use AWS, then you can use our tools to reliably and repeatably build and deploy networks from your code.
First, use dockly to express your Docker container as a function of your git repo:
deb :my_package do
package_name 'myapp'
docker do
name 'my_image'
import 's3://.../base-image.tar.gz'
git_archive '/path/to/myapp'
build <<-EOF
run cd /path/to/myapp && ./configure && make
EOF
end
foreman do
name 'myapp'
log_dir '/data/logs/myapp'
user 'appuser'
end
end
Now you can package Docker containers with dockly build my_package
. Use your CI environment to build a deployable container whenever you check in code.
Next, use aerosol -- which we're open-sourcing today -- to express your network as a function of your Docker image:
deploy :production_myapp do
ssh :production_myapp
auto_scaling :production_myapp
stop_command 'sudo stop myapp'
live_check '/version'
app_port 14000
post_deploy_command 'bundle exec rake honeybadger:deploy TO=production'
end
ssh :production_myapp do
user 'aerosol'
end
auto_scaling :production_myapp do
availability_zones ['us-east-1a', 'us-east-1b']
min_size 2
max_size 2
launch_configuration :production_myapp
tag 'Name' => 'prod-myapp'
end
launch_configuration :production_myapp do
instance_type 'm1.large'
ami 'ami-90374bf9'
iam_role 'role-prod-myapp'
key_name 'prod-myapp'
security_groups ['prod-myapp', 'prod-ssh']
user_data ERB.new(File.read('startup.sh.erb')).result(binding) # include install of Docker image
end
Now deploy and cut over to a brand new network with aerosol deploy production_myapp
.
Finally, get the humans involved in whatever way best suits your development cycle and culture. At Swipely, we wrote a Hubot plugin to kick off and coordinate production deploys over HipChat:
Using dockly and aerosol, we're building and deploying code with the reliability and repeatability of clean functional operations.