Ansible: playbooks and roles difference - ansible

I have 4 servers: production web, production db, staging web+db, development web+db (actually there are many dev servers, but they are used on localhosts using vagrant).
Config vars are different for these playbooks.
Actually I can use 4 playbooks, which include other yml files (nginx.yml, php.yml, mysql.yml), and I don't have to use roles.
Is it correct?
How should I organize my ansible files?

Ansible is flexile enough to work either way.
You can proceed with two aproaches
Define roles (i.e. production web, production db, staging web+db, development web+db) and under roles have tasks (nginx, php, mysql)
Define each module as role (i.e. nginx role, php role, mysql role) and then specify which roles are included in which playbook.
First way is better for cases that every php setup is different for every environment.
Second way is better for cases that all your php setups are the same, and it would be cumbersome to maintain 4 similar setup/config; you would write them once, and call them by their local variables.
Example of second one
./ansible-playbook roles/role1/tasks/production-web.yml -i hosts.yml
- name: playbook name
hosts: host1
sudo: yes
vars:
- php_version: 5.6.16
vars_files:
- "vars/local_vars"
pre_tasks:
- include: system-preparation.yml
- include: user-setup.yml
tasks:
- debug: msg="Installing and configuring PHP"
- include: php-setup.yml
- include: php-configuration.yml
post_tasks:
- include: health-check.yml
handlers:

Related

How to have multiple tasks under one role in Ansible?

I am setting up Ansible as a newbie. I would like to group a few tasks under an Nginx role.
See my folder structure
The only way I could get this to work is to use include statements in my playbooks... but that means I needed to start changing everything to relative paths since Ansible stopped being able to find things.
My playbook currently:
- name:
Install Nginx, Node, and Verdeccia
hosts:
all
remote_user:
root
tasks:
- include: ../roles/nginx/tasks/install.yml
- include: ../roles/nginx/tasks/create_node_config.yml
vars:
hostname: daz.com
How can I reference the sub task in the playbook to be something like
tasks:
- nginx.install
and still be within best practices.
Your use of roles so far is not in line with the norm or the idea of Ansible. From a purely technical point of view, it is quite possible that you have multiple task bundles in yml files that you include in the playbook.
If you want to include a specific task file from a role, you should better do this via the module include_role with the parameter tasks_from.
However, the workflow with roles usually looks different.
in the folder tasks should always be a file main.yml, this is called automatically, if simply the role is included, no matter over which way.
in this main.yml you can then add further control logic to include your yml files as required.
As it looks to me, for example, you always need to install, but depending on the use case you want to have different configurations.
create in your nginx role a file defaults/main.yml.
---
config_flavor: none
This initializes the config_flavor variable with the string none.
create in your nginx role a file tasks/main.yml.
---
- name: include installation process
include_tasks: install.yml
- name: configure node
include_tasks: create_node_config.yml
when: config_flavor == "node"
- name: configure symfony
include_tasks: create_symfony_config.yml
when: config_flavor == "symfony"
- name: configure wordpress
include_tasks: create_wordpress_config.yml
when: config_flavor == "wordpress"
The main.yml will be included by default when the role is applied.
This is where the installation is done first, then the proper configuration is done.
Which configuration should be done is defined by the variable config_flavor. In the listed example the values are node, symfony and wordpress. In all other cases the installation will be done, but no configuration (so in the default case with none).
include your role in the playbook as follows
---
- name: Install Nginx, Node, and Verdeccia
hosts: all
remote_user: root
vars:
hostname: daz.com
roles:
- role: nginx
config_flavor: node
At this point you can set the value for config_flavor. If you set wordpress instead, the tasks create_wordpress_config.yml will be included automatically, using the logic from tasks/main.yml.
You can find more about roles in the Ansible Docs.
There are many more possibilities and ways, you will get to know them in the course of your learning. Basically I would recommend you to read a lot in the Ansible docs and to use them as a reference book.
Please refer to bellow document. you can use "include_role" with "tasks_from" attribute. you don't need to provide full path of task files, Just file names.
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/include_role_module.html
Example:
- name: Run tasks/other.yaml instead of 'main'
ansible.builtin.include_role:
name: myrole
tasks_from: other

How can you deploy a web application onto one of many web servers using Ansible?

I suspect I'm going about this in the wrong way, but I want to use Ansible to install one of a set of web servers and then install a web app on top of that. I'm having a hard time figuring out what the roles should look like and, in particular, what the app role should depend on.
I can have roles for each of the web servers, but then it seems like I'd have to have a role per app-webserver pair. There doesn't seem to be a way to have the app depend on any web server, or use a variable to specify the dependent role based on my attempts at using one in meta/main.yml.
Alternatively, I can have a generic webserver role that itself installs one of the supported webservers, but I'm not sure how that should work and I've been enable to find an example to refer to.
Perhaps I'm thinking about this the wrong way. Is duplication the only way to go about this? (I simplified the problem somewhat for brevity, in actuality I also have multiple databases that can be used, so the combinations would be m*n app-webserver-db triplets.)
You can use groups of groups in your inventory. Create a main group webservers, and subgroups for every application server (geronimo, jetty, and so on) :
[webservers:children]
geronimo
glassfish
jetty
wildfly
[geronimo]
srv1
[glassfish]
srv2
[jetty]
srv3
[wildfly]
srv4
And then install appropriate application server according to the containing subgroup. And finally install application on every webservers :
---
- hosts: geronimo
roles:
- geronimo_role
- hosts: glassfish
roles:
- glassfish_role
- hosts: jetty
roles:
- jetty_role
- hosts: wildfly
roles:
- wildfly_role
- hosts: webservers
roles:
- application_role
I'm not sure to fully understand your problem. But it seems that you can solve this by organizing your inventory properly.
[webservers]
srv1
srv2
srv3
srv4
[application1]
srv1
[application2]
srv2
[application3]
srv3
[application4]
srv4
You can configure all webservers at once, and then install each application on the appropriate webserver.
---
- hosts: webservers
roles:
- webserver_role
- hosts: application1
roles:
- application1_role
- hosts: application2
roles:
- application2_role
- hosts: application3
roles:
- application3_role
- hosts: application4
roles:
- application4_role
webserver_role would install and configure the common stuff, while application1_role, application2_role, application3_role and application4_role would install and configure application specific stuff.

Run Ansible role without running dependencies defined in the role's meta

I have a role wp-vhost that has one role it depends on:
// roles/wp-vhost/meta/main.yml
---
dependencies:
- { role: nginx }
Each time I run wp-vhost, the nginx role will also run. I understand that this is fine and it's a desired behavior.
However, during my local development, time is unnecessarily lost on running the nginx role, when I want to run only the tasks defined in wp-vhosts since I know that nginx had run before and set-up the necessary environment for wp-vhost.
Is there a way to execute a playbook with roles, without executing roles' dependencies?
The way I would do this is to use Ansible tags and apply them to your "wp-vhost" specific code.
Assuming your wp-vhost role's main playbook is in main.yml, a good pattern is to spin out the actual tasks into a sub-playbook called something like wp-vhost.yml, included from main.yml, so the non-nginx code gets a tag that doesn't get applied to the nginx role. In this case:
- include: wp-vhost.yml
tags: wp-vhost
In order to use a tag for every chunk of Ansible code (whether an included tasks file or a role), try writing every role mentioned in dependencies like this:
- role: nginx
tags: nginx
When in testing mode, you can run just the wp-vhost specific parts like this:
$ ansible-playbook --tags wp-vhost main.yml
Or you can run the whole playbook including any dependencies like this - default is to run everything ignoring tags:
$ ansible-playbook main.yml
This makes it easy to quickly run just parts of a complex set of cascading roles and include files when testing, and also use the wp-vhost role normally in other roles' dependencies.
Impact on role structure
Careful use of tags doesn't affect role structure or use at all, and you would typically use tags only for testing.
For more complex roles, it's common to structure the tasks into separate files in any case, keeping the main.yml simple, like this:
- name: Set up base OS
include: base_os.yml
tags: base_os
- name: Ensure logs are rotated
include: logrotate.yml
tags: logrotate
- name: Create users and groups
include: users_groups.yml
tags: users_groups
Solution without include files
If you don't want to change the wp-vhosts use of include files, you would need to use blocks in the playbook (Ansible 2.0+):
- hosts: all
roles:
- role: nginx
tags: nginx
tasks:
- block:
- debug: msg=hello
- someaction: ...
tags: wp-vhosts
Note that the final tags: is aligned with the block: so applies to all tasks in that block. This is cleaner than splitting the playbook into multiple plays.
Non-tag alternative
You can use a when: condition on the role invocation in the wp-vhost role dependencies, and define a variable such as debug_mode to control this. However, such debug/test logic will clutter your codebase compared to defining a tag per role invocation or task file.

Ansible: swarm role or two roles?

I want to follow best practices for ansible and use roles that match the features.
How to organize roles that have same commons but different usage? Let me explain this on an example of installing docker swarm.
Docker swarm may be installed as a _master_ or as a _node_. Currently I have the swarm role. It has main.yml with tasks for both master and a node. Only by variables I determine if tasks is for a master, or for a node.
I dont like this. Instead of having variables, I would like to use hosts lists and say?
serverA is swarm_master
serverB, serverC... is swarm_node
This means I need two different roles, right? One for swarm_master and one for swarm_node. How I am going to share the same installation of swarm between these two roles?
You can use:
Hosts:
[swarm-master]
serverA
[swarm-nodes]
serverB
serverC
Playbook:
---
- hosts: swarm-master, swarm-nodes
roles:
- role: swarm
is_master: "{{ 'swarm-master' in group_names }}"
I think it's easier to understand the playbook, when you assign role parameters/variables when applying role.
It will be hard to guess for others that your role somewhere inside checks some variables.
To logically structure you tasks inside role, you may use conditional includes.
./roles/swarm/task/main.yml:
- include: docker_common.yml
- include: swarm_master.yml
when: is_master
- include: swarm_node.yml
when: not is_master

Ansible group sets of servers into 'apps'

I have a script that setups all the servers. Now trying to figure out a good way to configure them to talk to each other. e.g. Configure the application server to talk to a particular database server.
Test app 1
db01
app01
app02
mem01
Test app 2
db02
app03
mem02
The only thing I could come up with a role that takes the servers as params but I dislike that I have to also specify the hosts twice.
- name: Test app 1
hosts: [db01, app01, app02, mem01]
roles:
- {role: app, db: db01, ap: [app01, app02], mem: mem01}
How organized is your inventory file?
Looking at what you posted, this might be a good inventory file organization for you:
[testapp1-dbServers]
db01
[testapp1-appServers]
app01
app02
[testapp1-memServers]
mem01
[testapp2-dbServers]
db02
[testapp2-appServers]
app03
[testapp2-memServers]
mem02
[testapp1:children]
testapp1-dbServers
testapp1-appServers
testapp1-memServers
[testapp2:children]
testapp2-dbServers
testapp2-appServers
testapp2-memServers
[dbServers:children]
testapp1-dbServers
testapp2-dbServers
[appServers:children]
testapp1-appServers
testapp2-appServers
[memServers:children]
testapp1-memServers
testapp2-memServers
This might be overkill if you have no plans to increase the number of servers in any of the first 6 buckets, but it allows you to do things like group_vars files (individual ones for some or all groupings - testapp1, testapp2, dbServers, etc) and clean up your playbook file:
- name: Test app 1
hosts: testapp1 (all vars passed via group_vars file)
roles:
- generic_server_setup
- name: DB Server setup
hosts: dbServers (all vars passed via group_vars file)
roles:
- install_postgres
- other_db_things
The final thing that will help you the most can be found here.
Specifically, getting access to all the groups the current host is in and all the hosts in a group.
QUICK FIX: If you want to sacrifice some organization because you aren't worried about scaling and are not annoyed by the same information being in multiple locations, just add the relevant hosts as vars to testapp1 and testapp2 files under group_vars.

Resources