After originally starting the first incarnation of this blog a few years ago, I managed a whopping two posts before life got in the way. I decided recently to restart the initiative, and have another go at putting something of substance down on paper. Even if not one person reads anything I publish, the process of writing and externalizing what I’m learning will help me remember, and provide a personal reference of sorts.
RobBlog 1.0 was built on a public WordPress platform, from a hosting provider of which I have no intention of a continued relationship. When I was searching for a new platform, I was looking for something that would be simple to maintain, customizable, and where posts could be written in Markdown. After reading a great blog post by Scott Lowe, I decided to look into using GitHub Pages and Jekyll as the foundation for RobBlog 2.0. Without going into too much detail, Jekyll allows you to build a blog using a combination of Markdown and YAML, which is highly appealing to someone that doesn’t want to go down the web development rabbit-hole, ie: me.
Once I’d made the decision on my Blogging platform, I realized that I’d like to build a development environment for working on the Blog itself. After years of use, my laptops had become slightly cluttered with multiple versions of Ruby, directory bloat, and so on. I therefore came to the conclusion that I would like a keep a clean slate and just focus on the Blog itself, and not managing the various packages and potential conflicts on my host machines. Also, as I move between two different computers regularly, it would be nice to share the same environment between the two workstations and maintain a consistent workflow, while allowing me to locally preview the site before publishing to the web.
The first step in creating the development environment was to create a new GitHub project.
Be sure to check the Initialize this repository with a README button to ensure that there’s something in the repository, so it can be cloned right away.
I’ve made the assumption at this point that the reader already has a little bit of familiarity with Vagrant, but in a future blog post I’ll discuss a bit more about the ins and outs of this fantastic piece of software.
The first step in creating the development environment was to create a new Vagrant project with the provider and the default Vagrant box. This simply creates a generic Vagrantfile in the directory, which can be edited to suit. Alternatively, you could write a Vagrantfile from scratch; however, we’ve taken the easy route here to get going. We’ll start by cloning our new repository, using that directory as the root for our project.
$ git clone https://github.com/<username>/<repo name>.git
The Vagrant project is then initialized with the following:
$ cd <repo directory> $ vagrant init
vagrant init command creates a new
Vagrantfile in the project directory, which is the recipe for our development box. My first edit to the
Vagrantfile was replacing the default box (which is Ubuntu based) with a CentOS7 image. This is definitely a personal preference thing, as I’ve been been primarily a user of RHEL-based distributions for quite a long time. Feel free to continue with the base box, but you’ll have to edit the Ansible playbook to use
apt instead of
config.vm.box = "base"
is replaced with:
config.vm.box = "centos/7"
By default, Jekyll uses port TCP/4000 to serve up our local copy of the site, so the next step is to forward port 4000 from the host through to the Vagrant box:
config.vm.network "forwarded_port", guest: 4000, host: 4000
The final step in completing our
Vagrantfile is to configure our provisioner. A provisioner is a tool that is kicked-off once the Vagrant box has been instantiated, with the goal of building the virtual machine up to a desired state. To configure Ansible as a the provisioner, the
Vagrantfile has to reference the path to our playbook (which will be created in the next step). To keep things organized, I placed the playbook in a directory called
provisioning, and simply called it
config.vm.provision "ansible" do |ansible| ansible.playbook = "provisioning/playbook.yml" end
Leaving the final
Vagrantfile looking like so:
Vagrant.configure(2) do |config| # Set Vagrant box type config.vm.box = "centos/7" # Forward port TCP/4000 from the host to guest port TCP/4000, allowing for access to the Jekyll development server via http://localhost:4000 in your host's browser config.vm.network "forwarded_port", guest: 4000, host: 4000 # Run Ansible provisioner on ./provisioning/playbook.yml config.vm.provision "ansible" do |ansible| ansible.playbook = "provisioning/playbook.yml" end end
Vagrantfile itself is quite well documented, and all of the parameters that could be configured are documented on Vagrant’s website.
The next step in the process was to create a the Ansible playbook to actually build the services on the virtual machine. Playbooks are written in a simple YAML format, and are pretty easy to digest.
YAML files always start with
First, we’ll tell Ansible that we’d like to run this playbook against all hosts, as Vagrant simply runs it against the local box. Then, Ansible was told to perform remote commands as the user
vagrant, which is the default user for the CentOS7 box.
- hosts: all remote_user: vagrant
The next step is to define the tasks that Ansible is to perform. First, the latest version of Extra Packages for Enterprise Linux (EPEL) is installed. The
become: true parameter allows Ansible to become a user while running the command. The default become user is sudo; therefore, this is essentially telling Ansible to run the command with
- name: Install Extra Packages for Enterprise Linux (EPEL) yum: name=epel-release state=latest become: true
Further pre-requisites can be installed, such as Ruby, the Ruby development packages, and Ruby gems:
- name: Install Ruby yum: name=ruby state=latest become: true - name: Install Ruby development packages yum: name=ruby-devel state=latest become: true - name: Install Ruby gems yum: name=rubygems state=latest become: true - name: Install NPM yum: name=npm state=latest become: true
Once the ruby packages have been installed, the
github-pages ruby gem can be installed which takes care of the dependencies for github-pages:
- name: Install github-pages Ruby gem gem: name=github-pages state=latest
Vim and Git are installed to finalize the installation of tools:
- name: Install Git yum: name=git state=latest become: true - name: Install Vim text editor yum: name=vim state=latest become: true
Finally, when the Vagrant VM is instantiated, I want it to pull down the latest version of the Blog source from GitHub.
- name: Clone github repo become: false git: repo=https://github.com/MrThePlague/mrtheplague.github.io.git dest=~/mrtheplague.github.io
Now both the
Vagrantfile and the Ansible playbook have been completed, they can be added to the repository, committed, and pushed to GitHub:
$ git add Vagrantfile ./provisioning/playbook.yml $ git commit -m "Added Vagrantfiel and playbook.yml" $ git push
When it’s time to work on the blog, from any machine that’s got Vagrant and Ansible installed, the repo just needs to be cloned, and then the
vagrant up command issued:
$ git clone https://github.com/<username>/<repo name>.git $ cd <repo name> $ vagrant up
The Vagrant will instantiate the virtual machine, and then run the Ansible playbook. Once the provisioning process is complete, an ssh session can be established to the vagrant VM:
$ vagrant ssh
From here, it’s time to work on the blog. In order to preview the site, Jekyll can be started:
$ jekyll serve -D
Once it’s time to tidy up, changes can be pushed to GitHub, then the Vagrant box is destroyed.
$ exit $ vagrant destroy
That’s it! A relatively simple process to maintain a clean, portable development environment that can be quickly spun up on any machine.
The files are available on GitHub, so feel free to fork the repository and edit it for your own purposes!