Ansible is an infrastructure automation platform that makes it easy to manage and configure your servers. Vagrant allows us to create reproducible environments, making it really easy to work with virtual machines. We’ll use Ansible to automate the installation of Jenkins CI in a fresh CentOS image, created by Vagrant.
Before we start, make sure you have
ansible installed. Installing it through homebrew should be really straightforward:
brew install ansible && ansible --version
brew cask install vagrant && vagrant -v
Alternatively follow this links for installation instructions:
Setting up our environment
Run the command
vagrant init centos/7 or manually create a file named
Vagrantfile (no extension) with the following content:
Vagrant.configure(2) do |config| config.vm.box = "centos/7" end
To spin up this VM, simply run the command
vagrant up in your terminal in the same directory the Vagrantfile was created. This could take some minutes in the first time it is run, since Vagrant needs to download your CentOS image. You should see output that includes:
Bringing machine 'default' up with 'virtualbox' provider... ==> default: Importing base box 'centos/7'... [...] ==> default: Forwarding ports... default: 22 => 2222 (adapter 1) ==> default: Booting VM... ==> default: Waiting for machine to boot. This may take a few minutes... default: SSH address: 127.0.0.1:2222 default: SSH username: vagrant default: SSH auth method: private key [...] ==> default: Machine booted and ready!
Ok, so far so good. At this stage we haven’t even touched Ansible - we only created a VM with a fresh CentOS image.
Writing your first playbook
Ansible uses the term playbook to describe it’s configuration management scripts. Playbooks are
.yml files where you specify everything that will be run on the server.
Our first playbook (I named it
configure-ci-server.yml) could be something like this:
--- - name: Configure CI server hosts: ci-server sudo: True tasks: - name: install git only if it is not already installed yum: name=git state=present
The playbook above installs Git using yum. Really easy to understand, right?
The tasks tell Ansible WHAT should be executed on the target and the
hosts part tell Ansible WHERE it should be run.
We can run it using the
ansible-playbook command in our terminal, but first we need to tell Ansible how to reach the
ci-server host (the name specified in the playbook). We do this by creating an inventory file (I named it
hosts), in the same directory as our playbook with the following content:
[ci-server] ci-server ansible_ssh_host=127.0.0.1 ansible_ssh_port=2222 ansible_ssh_user=vagrant ansible_ssh_private_key_file=.vagrant/machines/default/virtualbox/private_key
Now, if you run the command below it should install git in your CI server:
ansible-playbook configure-ci-server.yml -i hosts
If an error occurs due to ssh host key checking, you could disable it. To do that, create a file named
[ssh_connection] ssh_args = -o StrictHostKeyChecking=no
I do not recommend that you disable host key checking when you connect to a production server, since it adds a layer of protection against Man-in-the-middle attacks. Disabling it while connecting to a self-hosted VM is fine, though.
Anyway, now you should have git installed on your server. One of the best things of most ansible modules (such as yum) is that they are idempotent, that is, they can be run multiple times without side effects. In other words, git will only be installed when you run the script for the first time (considering it is not already installed by then).
Refactoring things a bit
Instead of writing a list of tasks, a better approach is to create roles. By extracting our tasks into different roles, our code will be much more reusable and easier to read.
Create the folder
roles/git/tasks and add a file named
main.yml inside of it. In the end, your directory structure will look like this:
. ├── Vagrantfile ├── ansible.cfg ├── configure-ci-server.yml ├── hosts └── roles (create this folder) └── git └── tasks └── main.yml
--- - name: install git yum: name=git state=present
--- - name: Configure CI server hosts: ci-server sudo: True roles: - git
What we need to do next is to install Jenkins on this server. Luckily, there is a role published in ansible-galaxy (npm-like service for sharing ansible roles) made by geerlingguy (official repo here)
To use this role, run the following command on your terminal:
ansible-galaxy install geerlingguy.jenkins -p ./roles/
And add this role to your playbook:
- name: Configure CI server hosts: ci-server sudo: True roles: - git - geerlingguy.jenkins
Jenkins run, by default, on port 8080. To test it using your browser you should make Vagrant map the port 8080 on the VM to a port in our local machine. Add the following line to your
config.vm.network "forwarded_port", guest: 8080, host: 8080
After that, simply run
vagrant reload, wait a little bit until the jenkins service is running (it was installed by the role
geerlingguy.jenkins) and point your browser to http://localhost:8080.