If you manually shell into a computer and run commands when you deploy you are doing it wrong.
"Systems administration" is a programming task: we have Puppet.
This is systems programming. (Aka "dev ops".)
There is no distinction between development and operations any more: all programmers are sysadmins, and vice-versa.
In this talk, I'll explore some of the consequences of this convergence.
First, though, I'll recap some good things from modern programming practices, that we're going to borrow for systems programming.
git clone
awayUnlike earlier version control tools, creating branches in Git is easy and cheap, and merges are clean and often completely automatic.
We create a branch for each new feature or bug-fix.
git checkout -b new_feature
# Do some Coding
git checkout master
git merge new_feature
This is integration
Then we open a "Pull Request", which indicates that the feature is ready to be tested and merged.
myprog.py:
def some_clever_function(x):
return x*2
test_myprog.py
def test_myprog():
from myprog import some_clever_function
assert(some_clever_function(3) == 6)
py.test
It's a faff to run your tests for every platform you might want to run on, for every version of your language. So we have automated testing servers to run our tests, and email us when it goes wrong.
Jenkins expects the config for your automated tests to be specified in its GUI.
This is obviously suboptimal: we want to version control everything.
In RSDG, we're using a Jenkins plugin to manage our automated test configuration:
name: 'nammu'
disabled: false
node: OSX
builders:
- shell: |
cd $WORKSPACE
mvn clean install
scm:
- git:
url: git@github.com:oracc/nammu
branches:
- '{mybranch}'
triggers:
- github
- timed: "@midnight"
publishers:
- git:
push-only-if-success: true
There's a nice cloud service that does this: we're moving our simpler non-supercomputing jobs over to Travis, instead of Jenkins.
Travis configuration just uses .travis.yml files in the repository to configure builds.
If you trust your automated tests, you can do more: you can automatically deploy if the tests pass.
I'm using that for this talk:
https://github.com/UCL/rsd-talks
When the tests pass, the server is updated with the content from the master branch.
We experimented with puppet for this. Our experience is that it's better to use puppet to set the machine's overall structure up, but then for active deployments:
This can be better scripted with Fabric or Capistrano than bash.
Simple continuous deployment from a master branch, however, breaks for multi-programmer projects.
We can use the magic of Git's branches to achieve something better: continuous integration.
https://github.com/UCL-RITS/RSD-Dashboard/pull/170
Jenkins will automatically test each pull request. (Look at the green tick on commit 96eaac8 -- this represents a passing Jenkins build.)
When the tests pass, the branch can be safely merged to the master branch, and the deployment triggered.
(This can be manual after a code review, or automatic if tests pass.)
So, how can we develop puppet scripts locally, as if they were a computer program? Unless we can locally run it, we can't hack on it without running it on our test VM stack.
And we sure couldn't build automated tests for it.
We could, of course, use a local VM managed in a hypervisor's GUI.
But there's a better way, allowing us to treat virtual machines on our local laptop, just as if they were outputs of a programming exercise.
Everything can be version controlled together, with no information locked in GUIs.
Vagrant.configure("2") do |config|
config.vm.box = "centos/7"
config.vm.provision "puppet" do |puppet|
puppet.manifests_path = "puppet/manifests"
puppet.manifest_file = "server.pp"
end
end
cd my_project
vagrant up
This already kicks ass: we can keep our puppet manifest and vagrantfile alongside any application code. We never need to worry about a colleague setting up dependencies for a project to get started. They can just git clone
and then vagrant up
Now we can commission local servers automatically, we can define automated tests for the machines we provision, asserting that they provide the services we expect.
In the above example, our puppet scripts need a whole VM to work, so we use vagrant.
An alternative choice is to use container based automation, with Docker.
Here, instead of full VMs, we use a thinner layer of separation, to more quickly build and manage isolated environments.
Docker doesn't work with our puppet scripts though (e.g. it doesn't let you use systemd services in a container.)
https://github.com/jamespjh/docker-example
Docker on Travis
https://travis-ci.org/jamespjh/docker-example/builds https://github.com/jamespjh/docker-example/blob/master/.travis.yml