Recently I've found myself with several machines (home, client1, client2, etc) and got tired of setting up my bash environment, themes, and libs to run my development environments. To combat this, I thought I would give automating some things a try using a few of my favorite tools.
Ansible is an automation tool used to provision machines to be configured and ran in a very specific and reproducible way.
You might do things like:
- Configure a web server to run your application.
- Setup user accounts, folders, and permissions on a remote host.
- Deploy your application.
While containerization (Docker) has eliminated the need for Ansible for a lot of my use-cases, it's still a great tool if you ever find yourself wanting to run configuration/setup on a bunch of remote machines.
Think of it like declarative bash, configured in yaml.
A note on Ansible nomenclature
When working with Ansible you'll see things like role, playbook, group_vars, and such. A deep explanation of what those are and how to use them is outside the scope of this post, but you can think of it like this:
- a role is a collection of tasks and vars that produces a desired state.
- the inventory is a list of all hosts that Ansible can communicate with.
- a playbook will apply roles to your hosts defined in your inventory.
Check out my initial setup here.
At this stage in the repo, it has the following features:
- An init script that will install local dependencies (Brew, Ansible, Python)
- An Ansible role that sets up gitlab-runner
It starts here with the Makefile
PLAYBOOK_ARGS?="--diff" install: @sh ./scripts/init.sh install-galaxy: ansible-galaxy install -r requirements.yml provision: install-galaxy ansible-playbook mac.yml $(PLAYBOOK_ARGS) lint: ansible-lint mac.yml syntax: ansible-playbook mac.yml --syntax-check .PHONY: all install provision lint syntax
(Make is a great tool to use for running cross-platform tasks).
Running this will run the init script found in the scripts directory. This will setup your baseline dependencies; Homebrew, Python (for Ansible), and Ansible itself.
# /bin/bash set -e DIR="$(dirname "$(which "$0")")" source $DIR/scripts.sh # NOTE: this hasn't been done yet on a fresh machine, so use at your # own caution. Will update when this is run with a fresh OS install. # It also will only be tested on the latest version of Mac OSx, so # don't expect any support for the older OS distros. echo "\nChecking xcode and Homebrew..." # Update xcode if ! xcode-select -p; then echo "\n Installing xcode CLI tools" xcode-select --install fi # Homebrew if ! command_exists brew; then echo "\n Installing Homebrew" /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" fi # export PATH=/usr/local/bin:/usr/local/sbin:$PATH brew update > /dev/null brew doctor > /dev/null echo "\nChecking Brew and Brewfile..." brew --version brew bundle echo "\nChecking Python..." python3 --version echo "\nInstalling Ansible..." pip3 install -r requirements.txt > /dev/null echo "\nChecking Ansible..." if ! command_exists ansible; then echo "\n ERR: Ansible not installed." exit 1 fi ansible --version echo "\nDONE"
This will run Ansible itself, configuring your machine.
While I build this out I want to make sure I have some constraints in place to prevent creeping scope:
- Keep as few development dependencies on the host machine as possible.
- Keep the number of manual steps within reason.
- Don't go down authentication rabbit holes; e.g you will have to login yourself.
- Entire bash environment with dependencies in one click.
- Document any manual step and make it obvious when you must execute them.
The things I want to get setup next are:
- Pull my dot files from my dot file repo.
- Setup iTerm and my themes.
- Setup nvm, rbenv, php, and virtualenv.
- Setup my applications (VSCode, 1password, etc).