2. About me
● Linux system automation engineer
○ Passionate about automation, configuration management and monitoring
○ 10+ years of professional experience (3y Puppet, 1y+ Ansible)
○ Creator and contributor of many Open Source projects (Ansible, Android, Collectd, Gentoo, …)
○ https://github.com/jtyr
● Worked in
○ Scientific environment (CERN1
)
○ E-commerce (Lastminute.com2
, ProtonMail3
)
○ HFT trading (RGM Advisors2
, Pico Trading3
, Thomson Reuters2
)
○ Public sector (Ministry of Justice3
)
○ https://uk.linkedin.com/in/jirityr
[1] Quattor
[2] Puppet
[2] Ansible
3. About automation
● Minimize or reduce human intervention
○ Faster
○ Less error prone
○ Reproducible
● It doesn’t take people’s job, it just frees up their hands to do something more
interesting
● Requires wide set of skills (infra, sysadmin, dev, architecture, management, ...)
4. ● It’s not a role or a team
● It’s not about tools
● It’s a CULTURAL MOVEMENT
● The goal is to “establish better communication between dev and ops people and
allow them to work together to deliver better quality of product to the end user in
faster and more reliable way”
● Common attributes are communication, collaboration, knowledge sharing,
automation, testing, monitoring, ...
● Automate everything (provisioning, building, testing, deployment, ...)
● Share sense for responsibility
● Think open-source (quality, documentation, contribution)
DevOps
5. Ansible best practices
● Write logic into roles instead of in the playbook
○ Playbook only instantiate roles → fewer changes in the playbook
● Write atomic roles for better reusability
○ For example: Do not mix configuration of Nginx, Logstash into the same role (use separate well
parameterized roles instead)
● Keep each role in a separate Git repo
○ Access, tagging, prevent conflicts
● Use defaults instead of vars to provide parameters for the role
○ Use vars only to override the defaults in the dependant role
● Indent by 2 or 4 spaces instead of tabs
● Don’t use one-line Ansible params, use pure YAML syntax instead:
debug:
msg: Hello world!
debug: msg="Hello world"
6. Ansible pattern #1 - Single Playbook
● All plays in single playbook (site.yaml)
● Every machine belongs to one play only
○ All other plays are skipped
● Play only loads roles
○ No tasks
○ All parameters in vars_files or in wapper roles
● Roles configurable via hierarchical variables
○ Inspired by Hiera
○ More flexible than Hiera (variable number of levels per play)
7. Ansible pattern #1 - Single Playbook
- name: App1 server play
# Play specific for certain hosts/groups
hosts: ~^myapp1hostd{2}$
# Hiera-like variable overriding
vars_files:
# Global settings
- vars/global/main.yaml
# Allow to override Global settings for App1
- vars/apps/app1/main.yaml
# Allow to override Global and App1 settings on per-host
- ["vars/hosts/{{ inventory_hostname }}.yaml", "vars/ hosts/nonexisting.yaml"]
roles:
# Standard Operational Environment role (in every play)
- soe
# Role or wrapper role
- app1
9. Ansible pattern #2 - Config Encoders
● Problem:
○ It’s difficult to develop an Ansible role with an universal configuration
○ There are many Ansible roles which do the same but have different parametrization
○ Users end up cloning roles and adding their modifications
■ Often not contributed back to the original role
■ Sometimes not merged by the original author
○ That creates fragmentation with still no perfect Ansible role (can not configure everything)
● Solution:
○ Describe the configuration file in YAML format and use Jinja2 filters to convert it to other
configuration formats
○ Supported formats: Apache, Erlang, HAProxy, INI, JSON, Logstash, Nginx, TOML, XML and YAML
○ Will submit PR to Ansible Core
13. ● Problem:
○ We got multiple environments (e.g. DEV, QA, STG, PROD)
○ Each environment is configured by many Ansible roles
○ We want to shift configuration from lower to higher environments in controlled manner
■ Be able to change each of the role in lower environments without affecting higher
environments
■ Deploy new machines in each environment with the same configuration like the other
machines in that environment
Ansible pattern #3 - CD for configuration management
DEV QA STG PROD
Role 1 t22 t10 t5 t3
Role 2 t19 t16 t11 t7
14. ● Solution - Android repo script
○ Management tool built on top of Git
○ Automates parts of the Android development workflow
○ Download files from multiple repositories into one local working directory using manifest file
○ Integrates with Gerrit - code review system
○ Works for management of any source code (Java, Ansible, Puppet, ...)
○ For development it's more flexible than ansible-galaxy
Ansible pattern #3 - CD for configuration management
<manifest>
<remote name="jtyr-github" fetch="https://github.com/jtyr" />
<default remote="jtyr-github" revision="master" sync-j="4" />
<project name="ansible-test_playbook" path="." revision="master" />
<project name="ansible-test_role1" path="roles/role1" revision="refs/tags/t1" />
<project name="ansible-test_role2" path="roles/role2" revision="b2d50df" />
</manifest>
15. Ansible pattern #3 - CD for configuration management
● To create Ansible environments is as simple as:
○ Get repo script
mkdir ~/bin
curl -s https://gerrit.googlesource.com/git-repo/+/stable/repo?format=TEXT | base64 -d >~/bin/repo
chmod +x ~/bin/repo
echo 'export PATH="$PATH:$HOME/bin"' >> ~/.bashrc
○ Build all environments
for ENV in dev qa stg prd; do
mkdir -p ~/ansible/env/$ENV
cd ~/ansible/env/$ENV
repo init -u http://url.to/your/ansible-manifest.git -b $ENV
repo sync --no-clone-bundle
done
● More specific example follows...
16. ● Let's create multiple environments containing one playbook and couple of roles
mkdir -p /tmp/ansible/{envs,repos/ansible-{manifest,site.git,role{1,2}.git/tasks}}
● Create simple Ansible playbook and inventory file and turn it into Git repo
cd /tmp/ansible/repos/ansible-site.git
echo -e '.reponroles' > .gitignore
echo -e "---nn- name: First playn hosts: alln roles:n - role1n - role2" >site.yaml
echo "localhost ansible_python_interpreter=/usr/bin/python2 ansible_connection=local" >hosts
sed -i 's/xC2xA0/ /g' site.yaml;git init; git add -A; git commit -m "Initial commit"
rm -fr ./*; mv ./.git/* ./; rm -fr ./.git; git config --boolcore.bare true
● Create Ansible roles and turn them into Git repos
for ROLE in 1 2; do cd /tmp/ansible/repos/ansible-role$ROLE.git; echo -e "---nn- name: Task from Role 2n
debug:n msg: Hello from Role $ROLE" > tasks/main.yaml; sed -i 's/xC2xA0/ /g' tasks/main.yaml;git init; git
add -A; git commit -m "Initial commit"; done
● Create some role commits and tag them
for ROLE in 1 2; do cd /tmp/ansible/repos/ansible-role$ROLE.git; if [[ $ROLE == 1 ]]; then TAGS=22; else
TAGS=19; fi; for TAG in $(seq $TAGS); do sed -r -i "s/(msg:Hello from Role [0-9]).*/1 - tag t$TAG/" tasks/main.
yaml; git commit -am "Tag $TAG"; git tag t$TAG; done; sed -i 's/Hello/Hi/' tasks/main.yaml; git commit -am "One more
commit"; rm -fr ./*; mv ./.git/* ./; rm -fr ./.git; git config --boolcore.bare true; done
Ansible pattern #3 - CD for configuration management
17. Ansible pattern #3 - CD for configuration management
● Create Android manifest file for all environments (as per the table 4 slides back)
cd /tmp/ansible/repos/ansible-manifest
git init
for N in master,master,master dev,refs/tags/t22,refs/tags/t19 qa,refs/tags/t10,refs/tags/t16 stg,refs/tags/t5
refs/tags/t11 prd,refs/tags/t3,refs/tags/t7; do IFS=',' read -r -a A <<< $N; git checkout -b ${A[0]}; echo -e '<?xm
version="1.0" encoding="UTF-8"?>nn<manifest>n <remote name="local" fetch="/tmp/ansible/repos" />nn <default
remote="local" revision="master" sync-j="4" />nn <project name="ansible-site" path="." revision="master" />n
<project name="ansible-role1" path="roles/role1" revision="'${A[1]}'" />n <project name="ansible-role2" path="
roles/role2" revision="'${A[2]}'" />n</manifest>' >default.xml; git add -A; git commit -m "Adding manifest for
${A[0]} env"; done
● Initialize all environments
for ENV in master dev qa stg prd; do mkdir -p /tmp/ansible/envs/$ENV; cd /tmp/ansible/envs/$ENV;repo init -u
/tmp/ansible/repos/ansible-manifest -b $ENV;repo sync --no-clone-bundle; done
● Initialize the development environment (switch to the main branch for all projects)
cd /tmp/ansible/envs/master
repo forall -p -c 'git checkout $(git branch -avv | grep "remotes/m/master" | sed "s,.*/,,")'
● Go to any of the environments and try to run the Ansible playbook
ansible-playbook -i hosts site.yaml
18. Ansible pattern #3 - CD for configuration management
● Useful Android repo commands:
# Show all possible repo commands
repo help --all
# List all projects
repo list
# Show status of all projects (show which files have been modified)
repo status
# Show changes across all projects
repo diff
# Run command across all projects
repo forall -p -c 'git add -A; git commit -m "My change"; git push'
# Sync only particular project(s)
repo sync my_project
19. Conclusion
● Single Playbook enables hierarchical parametrization
● Config Encoders support to create Ansible roles with universal and very dynamic
configuration
● Android repo script allows to build multiple Ansible environments with different
role versions facilitating CD for CM