Ansible basics
Ansible tips¶
Below are some tips on using Ansible if you are unfamiliar with it. These are not best practices but will point you in the right direction and give you an idea of how things work.
Installing packages¶
Ansible allows you to use yum, apt or whatever else you need. However, this is not useful if you are going to reuse roles or playbook tasks. If you want to make sure that you will be able to install something across different Linux distributions, then you can use the following. This example is for installing varnish:
- name: install varnish
package:
name: varnish
state: latest
Change lines in files¶
Take a look at this from ansible's own documentation
known hosts¶
Very useful to have this in your playbook for when you need to add known hosts. This could be when cloning a new repo for example. It saves you from having to add extra bits to your tasks. Below is an example of adding github and bitbucket. You would change the user to whatever makes sense to you.
- name: Add github and bitbucket to jekins known hosts
lineinfile:
dest: "home/user/.ssh/known_hosts"
create: yes
state: present
line: "{{ lookup('pipe', 'ssh-keyscan -t rsa {{ item.domain }}') }}"
regexp: "{{ item.regex }}"
with_items:
- { domain: 'github.com', regex: '^github\\.com'}
- { domain: 'bitbucket.org', regex: '^bitbucket\\.org'}
Bash scripts¶
Ansible is capable of running bash scripts and you can add a task to do so wherever you want in a playbook.
Here is an example below of a playbook with a run the Bash script task:
tasks:
- name: Copy and Execute the script
script: "bash file name or location"
Bash script causes Ansible to stop running and shows that there is an error.¶
When I was working with a bash script, Ansible did not like the script at all despite it actually being fine for its intended purpose. If you find that your bash script is not at fault but want Ansible to use it and keep on going with the rest of the playbook, we can simply change the above task to the following:
tasks:
- name: Copy and Execute the script
script: "bash file name or location"
ignore_errors: yes
Run tasks before any roles or tasks (pre tasks)¶
If you need to run some tasks before anything else in your playbook (you might refer to these as dependencies) then we would put These under "pre_tasks" like I have in the example below. Take note of the packages and the command as these are a pretty common requirements for some tasks.
---
- hosts: all
pre_tasks:
- name: install libselinux-python
become: yes
package:
name: libselinux-python
state: present
- name: Install pexpect
become: yes
command: pip install pexpect
PHP and Ansible¶
Use these roles
ansible-galaxy install geerlingguy.php
Make sure you have the right repo as well. Do your research and use one of the following depending on the OS
epel
ansible-galaxy install geerlingguy.repo-epel
or
remi
ansible-galaxy install geerlingguy.repo-remi
variables to use:
php_enablerepo: "the repo you are using above"
php_version: "version of php you want"
php_packages_state: "latest"
php_packages:
- list
- packages
- like
- this
Ansible Lint¶
sudo pip install ansible-lint
ansible-lint playbook-main.yml
Viewing Vaulted Passwords¶
If you want to view a vaulted password, you can do this (for example):
ansible localhost -m debug -a 'var=rmq_admin_pass'
If "geerlingguy.php : Ensure PHP packages are installed." fails at all in your playbook then you will not have php installed correctly. Don't ignore this task failing.
Paths in playbooks¶
If you want a reliable abs path, you should use the {{ playbook_dir }}
variable, which behaves like __DIR__
in PHP.
For example - playbooks are in a subfolder and we want to access files in the project root:
- name: Install Galaxy Roles in the requirements.yml file
local_action:
command ansible-galaxy install -r {{ playbook_dir }}/../requirements.yml --roles-path {{ playbook_dir }}/../roles
Run a command as a playbook task.¶
tasks:
- name: do the command
command: "the terminal command you want"
You may be better off using shell
if you want to do bash things, e.g
tasks:
- name: Remove any none git folders from the roles directory. We assume that if it is a git repo, its being developed on locally and should not be removed.
shell: find roles -mindepth 1 -maxdepth 1 -type d '!' -exec test -e '{}/.git' ';' -print | xargs rm -rf
Copying over files.¶
For a lot of the above packages it's also good to copy over configuration files that you know you will need. Simply create a configuration file, fill it with everything you need and use the following module to copy it across. Below is an example for php.ini
- name: Create php.ini
template: src=templates/php/php.ini dest=//etc/php.ini`
Install ansible role¶
To install a role we can use the following command:
ansible-galaxy install "ansible.role" -p
useful ansible roles: geerlingguy.php geerlingguy.nginx geerlingguy
SSH Keys with Ansible¶
The following tasks will create SSH keys
tasks:
- name: Generate /etc/ssh/ RSA host key
command : ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -C "" -N ""
creates: /etc/ssh/ssh_host_rsa_key
- name: Generate /etc/ssh/ DSA host key
command : ssh-keygen -q -t dsa -f /etc/ssh/ssh_host_dsa_key -C "" -N ""
creates: /etc/ssh/ssh_host_dsa_key
- name: Generate /etc/ssh/ ECDSA host key
command : ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -C "" -N ""
creates: /etc/ssh/ssh_host_ecdsa_key
'''
Bitbucket and Ansible¶
Below is an example of cloning a bitbucket repo. I will mention this now to save confusion, if you do not have the "accept_hostkey: true" like you can see below, you will not be able to clone from a repo for the first time from what I have seen so far.
- name: cloning the repo into the directory we just created
git:
repo: "project_repo_url"
dest: "destination of where the repo is going"
accept_hostkey: true
key_file: "location of key file"
become: true
become_user: "user"
ssh key variables¶
When it comes to writing out variables in your variable file or in the playbook itself, you need to be aware of how to write it out for it to work. The following is how I have done this:
ssh-key: |
-----BEGIN RSA PRIVATE KEY-----
somelongkeythatwithloadsofmultiplelinesforyou
fjioefiejfjeoifjioejfiejfjeofjejfojefjoejffjd
doepojdejdjejdjeidpjdjpdjwopdjwpedjpwdjwopjdo
-----END RSA PRIVATE KEY-----
Debug Output¶
To be able to better read Ansible output it is a good idea to set the correct plugin callback in your ansible.cfg
file.
Below the [defaults]
area add the following:
[defaults]
...
stdout_callback = yaml
bin_ansible_callbacks = true
...
This will make your error output display in a much more readable state - errors will no longer be output on the same line and wrap across your terminal.
Variables in Ansible¶
Ansible gives you a few options when it comes to Variables. We explore these below.
User prompts¶
You can set variables with user prompts. This is very useful for when information is not going to be the same when you use the playbook again. This could be a password for a ssh key for example which you can see below:
vars_prompt:
- name: "pass"
prompt: "Password for SSH Key?"
tasks:
- name: Generate /etc/ssh/ RSA host key
command : ssh-keygen -q -t rsa -f /home/ec/.ssh/id_rsa/ssh_host_rsa_key -N "{{ pass }}"
Automatically respond to prompts¶
To automate things we have to respond to promps that will come our way. Ansible can automatically respond to prompts for you which makes things nice and easy.
Below is an example of this.
Chdir = the directory for the command to be executed in.
expect = this is what we need to put in the playbook for prompt responses.
command = The command that will be executed responses = this is where we place the exact phrase that the terminal would normally ask you. In this case the terminal prompt was going to be "Password for 'https://edmondscommerce@bitbucket.org" I then followed this with ' on both sides. The answer below is a variable set earlier in the playbook by the user as passwords should not be stored anywhere.
- name: pull snippets library
chdir: /opt/Projects
expect:
command: git clone https://edmondscommerce@bitbucket.org/edmondscommerce/snippets-library.git
responses:
(?i)Password for 'https://edmondscommerce@bitbucket.org': '{ password }'
Example of variables and roles¶
When you use roles in your playbook you need to sometimes give them extra information. The way I have done it so far is to do the following:
---
- hosts: all
become: true
vars:
php_enablerepo: "remi-php70,epel"
roles:
- geerlingguy.php
In the above example I have read what variables are available in the README file of the role and have placed them in he playbook using vars:
. I was able to select a repo so that I could install a specific version of php. Although this is how I have done it it's worth mentioning that I have read you can also point your playbook to a file with all of your variables in it instead using
vars_files
- /vars/external_vars.yml
Debugging¶
Pass in -vvv
when running ansible-playbook
to get much more details about what is going on, eg:
[root@host ansible-project]# ansible-playbook plays/playbook-installLxcOnContainerHost.yml -vvv
ansible-playbook 2.7.5
config file = /vagrant/ansible-project/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /bin/ansible-playbook
python version = 2.7.5 (default, Oct 30 2018, 23:45:53) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]
Using /vagrant/ansible-project/ansible.cfg as config file
/vagrant/ansible-project/hosts.ini did not meet host_list requirements, check plugin documentation if this is unexpected
/vagrant/ansible-project/hosts.ini did not meet script requirements, check plugin documentation if this is unexpected
/vagrant/ansible-project/hosts.ini did not meet yaml requirements, check plugin documentation if this is unexpected
Parsed /vagrant/ansible-project/hosts.ini inventory source with ini plugin
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/centos/install.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/centos/remove.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/fedora/install.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/fedora/install-dnf.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/fedora/install-yum.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/fedora/remove.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/fedora/remove-dnf.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/fedora/remove-yum.yml
Researching the server¶
When we are going to build a server based on one that already exists, we need to do some research in order to make sure we replicate what we can. What you may notice is that it can be hard to get the exact specific version of something, for example, a server may have php 7.0.23 but you are installing 7.0.24. As long as the 7.0.2 part is there then it should be ok. Every package is different though and the above is an example.
Some of the main packages we need to look into are:
php¶
To look at php version simply type
php -v
to find out php modules
yum list installed | grep php
or
php -m
Mysql¶
mysql -v
make sure to read the output as mysql does not just have different version numbers. For example, mysql percona.
\q
to quit when you have read the version.
Varnish¶
varnish requires the following command
varnishd -V
that's a capital V unlike the previous commands.
nginx¶
nginx
-v will tell you what you need to know.