Initial Thoughts on Ansbile

At this point, I’ve read many blogs that paint a very rosy picture of Ansible.

My initial experience was not so rosy. In fact, it was pretty frustrating. In future blogs, I’ll provide examples. The purpose of this post is to record my initial impressions.

I become fixated on learning Ansible when I realized that I was starting to repeat the same patterns while maintaining servers, and worse, the steps that I took to maintain them were not being documented, so I’d have to remember how it went each time. This was manageable, up to a point. After that point, I started looking into configuration management systems.

I was working in a tight time-frame, one where I had not budgeted time for learning configuration management systems.

Our team currently uses Foreman to deploy servers within our department (in a Puppet fashion). The Foreman server is an undocumented mystery. And without it, apparently, new servers won’t be deployed.

The pull-deploy architecture of Puppet felt like the wrong direction to me.

I kept hearing about how a few employees here favored Ansible, so I looked into it.

A book was available on Safari ( Up And Running With Ansible ), so I read it. It took me about a week to make it through the book. ( I’m a slow reader, and it was a quick read. )

I immediately liked the push ( optional pull ) deploy architecture, and especially liked that ad-hoc commands could be entered on the command line. I also liked the design of roles, and that the modules were implemented to be idempotent. It looked like it was going to be smooth sailing from the start.

That, however, was not the case.

I found the restrictions of entering the instructions in YAML+Jinja2 to be rather unintuitive. What this looked like, in practice, for me was to try to enter instructions with no quotes, at first, and try to run it. If that failed, I’d add single quotes, then double quotes, and maybe double parentheses. When that failed, I’d arbitrarily switch around the quotes. And when that failed, I’d get on IRC and ask what I was doing wrong.

The error messages that I was seeing from Ansible didn’t seem to point to the line where the error occurred. It turns out, that I’d often be pointed to the beginning of the block of the instructions instead. It also happened that there would be useful information right at the beginning of the error, and right at the end would be the beginning of the block. There was plenty inbetween that was not useful and distracting.

It often seemed like I was ignored when I asked questions on IRC. But that seemed to get a little better with time. I was also a little unhospitable, at first. I was on a time-crunch, and the thing that stood in the way was not being able to interpret how I should be using quotes to correctly escape blocks of instructions.

Eventually, it became evident that one problem I was having was that I wasn’t running the latest version of Ansible. It was an easy upgrade and a shell script so that I didn’t need to remember the exact commands to pull the latest code down and getting it running in single instances of bash.

Another issue I was having was that Ansible seemed to sometimes treat json as an object, and sometimes as text. To make matters worse, I wasn’t really sure how to determine what the structure was of the variable I was working with. That was very aggravating, as the json provided by Kubernetes is non-trivial, and I wanted to parse it.

When I figured out how to write my own custom modules, and then my own custom filters, Ansible suddenly became a very usable tool.

Now my process looks like this: Write the instructions without any quotes; if it fails, correctly identify the block where the error is occuring and comment out lines that are more complex, until the block itself doesn’t error. Then add the lines back in, one at a time, until the error occurs. Add quotes / double-quotes and parentheses, if needed. If that fails, write a filter for what I’m trying to do instead, and then ask what I’m doing wrong on IRC.

Since I’ve now got a work-around, it’s not an issue for it to take some time to get a response. Though, in truth, it seems the responses are coming pretty quickly these days.

I’ve since heard about Salt.

I don’t really feel like I have time to learn another configuration management system, however, and Salt also uses a mast/minion architecture, which makes it seem like it would take longer to get running and learn.

I think Ansible is a good match for my grunge-style system administration tasks.

Mar-April 2016 Update

Quick status update.

It seems like I’ve had absolutely no time lately.

I’ve been focusing on a number of new technologies at work: top on the list has been learning Ansible and creating playbooks to configure ‘stock’ atomic-host servers for kubernetes. I’ve got plenty to say about Ansible, so I plan on starting a series of posts on it in the very near future.

I have a few things to say about running Kubernetes “virtual metal”. It almost feels like no one else is doing this …

Last week we had a contractor from Datastax come in to go over the Datastax Enterprise stack. I’m still getting familiar with Datastax, Spark, SOLR, and Cassandra. There may be some posts about them a little further in the future.

Security is an ongoing theme while planning future microservices architecture running in Kubernetes. I plan on posting some background on what we do to ensure our microservices infrastructure is secure enough for the financial sector.

Continuous integration is also around the corner. We’ll be using Jenkins to test out and deploy the docker containers and tests that come from developers. It became apparent while I was working through the process that there are a number of ways to do this sub-optimally, so I plan on covering this topic.

Blogging with VDJG: Part 1.75 - Vagrant, Docker & Jekyll - Return from the Void

Walking away from a project and coming back about a month later is a great way to test the user-friendliness / accessibility of a solution! I must have forgotten … nearly everything … about how I set this blog up. … When I went to make an update, I even started out in the wrong place!

So here are the gotcha’s that became apparent to me as I tried to break back into blogging.

Gotcha #1

The short cut that includes a custom Vagrantfile meant to encapsulate my custom script for executing Jekyll inside of docker inside of Vagrant … leaves the git repo for phusion’s baseimage-docker in a mixed state:

➔ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   Vagrantfile

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        data/
        exec-jekyll.sh

no changes added to commit (use "git add" and/or "git commit -a")

personal/phusion-jekyll/baseimage-docker on master [!?]

While this looks like something was left incomplete, it’s not. I might revisit this in the future.

Gotcha #2

vagrant up is not the only thing that needs to be executed to get jekyll going. vagrant up by itself really only sets up phusion’s baseimage. When it runs, it prints out this ( somewhat confusing ) message:

==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: flag to force provisioning. Provisioners marked to run always will still run.

One might wonder: why run vagrant provision when the message just said that the machine is already provisioned. In fact, running vagrant provision is exactly the the thing needed to kick off my custom script ( which kicks off jekyll - within Vagrant )

➔ vagrant provision
==> default: Running provisioner: shell...
    default: Running: /var/folders/9s/320v29913qs9j6kzxnqv7smclw01rh/T/vagrant-shell20160416-8
3777-1t0dsij.sh
==> default: stdin: is not a tty
==> default: jekyll_runtime
==> default: jekyll_runtime
==> default: Running Jekyll!
==> default: Github does not allow user dependencies.
==> default: Configuration file: /srv/jekyll/_config.yml
==> default:             Source: /srv/jekyll
==> default:        Destination: /srv/jekyll/_site
==> default:       Generating...
==> default:                     done.

So, two gotcha’s later, and I’m back in business. As far as ramping back up on cold projects goes, that’s not too bad.

Blogging with VDJG: Part 1.5 - Vagrant, Docker & Jekyll - Shortcut!

I just finished going through all of the steps of how I created the vagrant-docker-jekyll combo that I use to blog with.

… And then I realized … the whole point of vagrant and docker is to be able to create an environment that can be replicated … so it should theoretically be possible for me to set up the entire environment and provide a few short lines to get the whole thing working, right? Right.

git clone https://github.com/phusion/baseimage-docker.git
cd baseimage-docker
mkdir data
curl https://raw.githubusercontent.com/cognitiaclaeves/source.cognitiaclaeves.github.io/develop/source-files/Vagrantfile > Vagrantfile
curl https://raw.githubusercontent.com/cognitiaclaeves/source.cognitiaclaeves.github.io/develop/source-files/exec-jekyll.sh > exec-jekyll.sh
chmod +x exec-jekyll.sh
vagrant up

Update 4/16/2016 – If you don’t see

> ==> default: Running Jekyll!
> ==> default: Github does not allow user dependencies.
> ==> default: Configuration file: /srv/jekyll/_config.yml
> ==> default:             Source: /srv/jekyll
> ==> default:        Destination: /srv/jekyll/_site
> ==> default:       Generating...
> ==> default:                     done.
>

Then enter this: vagrant provision

For more details, see the next post in the series.

Blogging with VDJG: Part 1 - Vagrant, Docker & Jekyll

This blog is set up to be able to add and view new entries offline ( as text files ), and then push changes into a source repository to trigger live site updates ( as website files ). I use a Jekyll Docker container running in Vagrant to take the site from text files to HTML.

My process was inspired by a blogging process demonstrated by Boyd Boyd Hemphill at a devops / docker / cloud meetup, which he published on his blog

This series covers the process I set up, in detail. In the first part, I cover everything short of publishing it live. In the second part, I cover publishing it live, and in the third part, I cover what it looks like when I create a new blog entry.

I like to show all my work. But if you just want to get a blog up in a hurry with this method, I made a short cut!

( This post is currently in progress; there will be clean-up later. )

~/personal
➔ mkdir phusion-jekyll; cd phusion-jekyll

~/personal/phusion-jekyll
➔ git clone https://github.com/phusion/baseimage-docker.git
Cloning into 'baseimage-docker'...
remote: Counting objects: 1193, done.
remote: Total 1193 (delta 0), reused 0 (delta 0), pack-reused 1193
Receiving objects: 100% (1193/1193), 1.48 MiB | 1.57 MiB/s, done.
Resolving deltas: 100% (699/699), done.
Checking connectivity... done.

~/personal/phusion-jekyll
➔ cd baseimage-docker

personal/phusion-jekyll/baseimage-docker on master
➔ ls
CONTRIBUTING.md Makefile README_zh_tw.md install-tools.sh
Changelog.md README.md Vagrantfile test
LICENSE.txt README_ZH_cn_.md image tools

personal/phusion-jekyll/baseimage-docker on master
➔ vagrant up

Warning: The next line causes vagrant to allow running VM instance to access the files on your local machine. Know what you’re doing when you give any VM or container access to your local machine.

For the sake of convenience, I want a folder in the VM to directly reference my work folder (future github) folder, so I add this line:

config.vm.synced_folder "data", "/home/vagrant/data"

➔ tail -6 Vagrantfile
    config.vm.provision :shell, :inline => $script
  end

  config.vm.synced_folder "data", "/home/vagrant/data"

end

Then I create the data folder and restart the vagrant box:

personal/phusion-jekyll/baseimage-docker on master [!]
➔ mkdir data; vagrant halt; vagrant up

==> default: Attempting graceful shutdown of VM...

Bringing machine 'default' up with 'virtualbox' provider...
...

My new folder is at the top of this list:

==> default: Mounting shared folders...
default: /home/vagrant/data => /Users/jno/personal/phusion-jekyll/baseimage-docker/data
default: /vagrant/baseimage-docker => /Users/jno/personal/phusion-jekyll/baseimage-docker
default: /vagrant => /Users/jno/personal/phusion-jekyll/baseimage-docker

Next, I run the following in the vagrant session, to build the initial files:

cd data
docker run \
  --interactive \
  --label=jekyll \
  --publish 4000:4000 \
  --rm \ 
  --tty \
  --volume=$(pwd):/srv/jekyll 
  jekyll/jekyll:pages jekyll new . --force

The volume specification above is similar to the shared folder mount earlier, except for containers. At this time, this is considered more dangerous, by some. In this case, it’s pretty safe, as it only allows the docker container direct access to a path in the VM, and not your localhost.

I was going to include a screenshot here of what it should look like when the above command is run, but I spent the time making the short cut instead.

.. and create this file (phusion-jekyll/baseimage-docker/exec-jekyll.sh), to run the jekyll container:

cd /home/vagrant/data
docker stop jekyll_runtime 2> /dev/null
docker rm -v jekyll_runtime 2> /dev/null
docker run \
    --env FORCE_POLLING=true \
    --env JEKYLL_ENV=development \
    --env VERBOSE=true \
    --label=jekyll \
    --name=jekyll_runtime \
    --publish "0.0.0.0:4000:80" \
    --rm \
    --volume="$(pwd):/srv/jekyll" \
    jekyll/jekyll:pages jekyll build --watch

… and make the file executable:

➔ chmod +x exec-jekyll.sh

To make the webserver in the container accessible, and to execute my new script, I add these lines to the Vagrantfile that I edited before:

...

  config.vm.synced_folder "data", "/home/vagrant/data"
  config.vm.network :forwarded_port, guest: 4000, host: 4000
  config.vm.provision "shell", path: "exec-jekyll.sh"
end

vagrant provision runs the script:

personal/phusion-jekyll/baseimage-docker on master [!]
➔ vagrant provision
==> default: Running provisioner: shell...
        default: Running: /var/folders/9s/320v29913qs9j6kzxnqv7smclw01rh/T/vagrant-shell201
60302-97040-1s32frt.sh
==> default: stdin: is not a tty
==> default: jekyll_runtime
==> default: Github does not allow user dependencies.
==> default: Configuration file: /srv/jekyll/_config.yml
==> default: Source: /srv/jekyll
==> default: Destination: /srv/jekyll/_site
==> default: Generating...
==> default: done.
==> default: Auto-regeneration: enabled for '/srv/jekyll'

Now, I can browse to: http://localhost:4000, and click on the “Welcome to Jekyll” link.

This link was generated from data/_posts/[date]-welcome-to-jekyll.markdown

I switch to another terminal and edit the file locally:

---
layout: post
title: "Welcome to Jekyll!"
date: ... 
categories: jekyll update
---
You’ll find this post in your `_posts` directory. ...

I change the above to:

---
layout: post
title: "Welcome to Jekyll!"
date: ... 
categories: jekyll update
---
You’ll find this SAMPLE post in your `_posts` directory. ...

and when I save the file, I see activity in the previous terminal session:

...
==> default: done.
==> default: Auto-regeneration: enabled for '/srv/jekyll'
==> default: Regenerating: 1 file(s) changed at 2016-03-02 23:47:21

Finally, when I refresh the localhost:4000, it’s updated!

When I’m finished updating my site, I take the vagrant box down:

==> default:       Regenerating: 1 file(s) changed at 2016-03-03 15:00:13
==> default: ...done in 0.860794742 seconds.
^C==> default: Waiting for cleanup before exiting...
^C==> default: Exiting immediately, without cleanup!

personal/phusion-jekyll/baseimage-docker on master [!?]
➔ vagrant halt
==> default: Attempting graceful shutdown of VM...

personal/phusion-jekyll/baseimage-docker on master [!?]

That’s the process. Be sure to check out my shortcut for a handy script that does all the work for you!

I actually do a little more work to get the switchable theme in my static website. This work amounts to mangling the generated files with the use of a bash and a python script.

For the next blog in this series, I’ll post how to easily work github pages into this, and then my steps to create a new blog entry, after all the setup is done.

← Newer Page 1 of 2