- Learning Ops Tooling, Part One - Vagrant
- Learning Ops Tooling, Part Two - Starting with Ansible
- Learning Ops Tooling, Part Three - More Ansible
- Learning Ops Tooling, Part Four - Pulling and running the blog
I've been wanting to explore the world of "infrastructure as code", or IaC, for a while now but for one reason or another I just haven't had time (probably due to having a child to look after). Not wanting to let this go on any longer I've decided I need to make time to look into what tools are available and how to use them.
To clarify, the wiki definition for IaC is given as:
IaC is the process of managing and provisioning computer data centres through machine-readable definition files, rather than physical hardware configuration or interactive configuration tools.
When I set about learning something new I like to set myself a task to work on, to give some focus. At first I had grand plans to script the setup of my own kubernetes cluster. But after having conversations with people who know more about these things than me we decided it better to settle on something a simpler. So instead I figured why not script the setup of a server to host my blog.
This means I'll need to:
- Create a virtual machine on which to host the blog.
- Provision said server with all the dependencies needed to host my chosen blogging engine.
- Install and run my chosen blog engine and make sure its resilient to restarts etc.
- Secure my server so that it isn't vulnerable to attacks.
- Create back up strategy so that if something goes wrong I don't loose all my data.
And possibly some other things I haven't thought about yet.
Step one, I need a server in which to host my blog. Now I could host it on Azure or AWS. But because I'm going to be doing lots of testing, destroying and rebuilding it makes more sense to use a VM on my local machine. I can worry about pushing it to the cloud a later date. That leaves me with the choice of either creating a server using parallels or vmware fusion. Or I could, as is the aim of this little experiment, script the creation of the VM using a tool called Vagrant.
Vagrant is a tool for building and managing virtual machine environments in a single workflow. With an easy-to-use workflow and focus on automation
Installing vagrant is a pretty simple affair. I'm on a mac so I can just use
brew cask to install the vagrant package:
$ brew cask install vagrant ==> Satisfying dependencies ==> Downloading https://releases.hashicorp.com/vagrant/2.0.1/vagrant_2.0.1_x86_64.dmg ==> Verifying checksum for Cask vagrant ==> Installing Cask vagrant ==> Running installer for vagrant; your password may be necessary. ==> Package installers may write to any location; options such as --appdir are ignored. ==> installer: Package name is Vagrant ==> installer: Installing at base path / ==> installer: The install was successful. 🍺 vagrant was successfully installed!
But if you are using Windows or Linux you can follow the download instructions provided by Vagrant.
Once installed you can check it's working correctly by calling
$ vagrant version Installed Version: 2.0.1 Latest Version: 2.0.1 You're running an up-to-date version of Vagrant!
There you go installed and ready to go.
Creating your first VM
Vagrant has a number of commands but the first one you want to use is
vagrant init. This will create a file called
VagrantFile in your working directory where you can define your VMs and how you want them setup:
$ vagrant init A `Vagrantfile` has been placed in this directory. You are now ready to `vagrant up` your first virtual environment! Please read the comments in the Vagrantfile as well as documentation on `vagrantup.com` for more information on using Vagrant.
Vagrant will populate this file with a lot of information that you don't need right now so you can just go ahead and delete it. Leaving the following:
Vagrant.configure("2") do |config| end
This is ruby syntax and it's within this block of code where you will define your VM.
The "2" parameter being passed into the
configuration method is just telling vagrant that you want to use version 2 of the configuration file definition.
Next add the following code to define a VM
Vagrant.configure("2") do |config| config.vm.define "ghost" do |ghost| ghost.vm.box = "ubuntu/xenial64" ghost.vm.hostname = "ghost" ghost.vm.network "private_network", ip: "192.168.33.10" end end
The first line tells vagrant we want to configure a new VM. We then tell it that we want to us the "ubuntu/xenial64" image and give it a host name of "ghost". Then last we tell it is to give the VM an IP address of "192.168.33.10".
When this script runs the Ubuntu Xenial image will be pulled down from the Vagrant Cloud. This is a repository or images available for you to use and if you search for
Ubuntu 16.04 you'll see the first result is ubuntu/xenial64. Vagrant caches these images locally so it doesn't have to download a copy each time the script runs.
Creating and booting the VM
To create and start the VM call the the command
vagrant up in the same directory as your
$ vagrant up Bringing machine 'ghost' up with 'virtualbox' provider... ==> ghost: Importing base box 'ubuntu/xenial64'... ==> ghost: Matching MAC address for NAT networking... ... ==> ghost: Mounting shared folders... ghost: /vagrant => /Users/mat-mcloughlin/temp
This may take a few seconds, depending on if it needs to download a new image. But when it's completed you can then ssh onto the machine using
vagrant ssh specifying your host name:
$ vagrant ssh ghost Welcome to Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-112-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage Get cloud support with Ubuntu Advantage Cloud Guest: http://www.ubuntu.com/business/services/cloud 0 packages can be updated. 0 updates are security updates. _____________________________________________________________________ WARNING! Your environment specifies an invalid locale. The unknown environment variables are: LC_CTYPE=en_GB.UTF-8 LC_ALL= This can affect your user experience significantly, including the ability to manage packages. You may install the locales by running: sudo apt-get install language-pack-en or sudo locale-gen en_GB.UTF-8 To see all available language packs, run: apt-cache search "^language-pack-[a-z][a-z]$" To disable this message for all users, run: sudo touch /var/lib/cloud/instance/locale-check.skip _____________________________________________________________________ vagrant@ghost:~$
Now you have a VM up and running there's a couple of other commands that are useful to know about:
vagrant haltwill stop shut down your VM.
vagrant destroywill destroy your VM, which can then be recreated by running
vagrant upagain. This means its nice and easy to recreate the VM if you break something.
vagrant global-statusoutputs status of all the Vagrant environments for this user.
And thats is, We've got a newly created VM that we can use to test our blog on before eventually pushing it to the cloud.
During the course of experimenting with Vagrant I came across a couple of other interesting tips.
Creating multiple machines
VagrantFile you can define as many machines as you like. Just keep adding code blocks:
Vagrant.configure("2") do |config| config.vm.define "acs" do |acs| acs.vm.box = "ubuntu/trusty64" acs.vm.hostname = "acs" acs.vm.network "private_network", ip: "192.168.33.10" end config.vm.define "web" do |web| web.vm.box = "nrel/CentOS-6.5-x86_64" web.vm.hostname = "web" web.vm.network "private_network", ip: "192.168.33.20" end end
Running with GUI
By default vagrant runs headless, but if you need to diagnose a problem you can tell it to launch the gui by adding the following to your
config.vm.provider "virtualbox" do |v| v.gui = true end