Ansible group sets of servers into 'apps' - ansible

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.

Related

Is there an ansible strategy that takes host groups into account?

We use an inventory file and ansible. We have many micro services and sometimes we have different instances for internal and external use. AFAIK, the builtin ansible strategies (free, host_pinned, serial) ignore the groups. Is there a strategy that works like host_pinned but on a per group basis?
Example inventory:
[my-service-external]
my-external-hosts[01:57].example.com
[my-service-internal]
my-internal-hosts[1:3].example.com
[my-service:children]
my-service-external
my-service-internal
Example playbook.yml:
---
- name: ping
hosts: my-service
strategy: host_pinned
serial:
- 1
- "30%"
tasks:
- name: ping
ansible.builtin.ping:
If this playbook would do something that would actually impact the service, like restarting some application server, all internal hosts would go down at pretty much the same time and possibly cause an outage.

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.

Ansible group variable evaluation with local actions

I have an an Ansible playbook that includes a role for creating some Azure cloud resources. Group variables are used to set parameters for the creation of those resources. An inventory file contains multiple groups which reference that play as a descendant node.
The problem is that since the target is localhost for running the cloud actions, all the group variables are picked up at once. Here is the inventory:
[cloud:children]
cloud_instance_a
cloud_instance_b
[cloud_instance_a:children]
azure_infrastructure
[cloud_instance_b:children]
azure_infrastructure
[azure_infrastructure]
127.0.0.1 ansible_connection=local ansible_python_interpreter=python
The playbook contains an azure_infrastructure play that references the actual role to be run.
What happens is that this role is run twice against localhost, but each time the group variables from cloud_instance_a and cloud_instance_b have both been loaded. I want it to run twice, but with cloud_instance_a variables loaded the first time, and cloud_instance_b variables loaded the second.
Is there anyway to do this? In essence, I'm looking for a pseudo-host for localhost that makes it think these are different targets. The only way I've been able to workaround this is to create two different inventories.
It's a bit hard to guess how you playbook look like, anyway...
Keep in mind that inventory host/group variables are host-bound, so any host always have only one set of inventory variables (variables defined in different groups overwrite each other).
If you want to execute some tasks or plays on your control machine, you can use connection: local for plays or local_action: for tasks.
For example, for this hosts file:
[group1]
server1
[group2]
server2
[group1:vars]
testvar=aaa
[group2:vars]
testvar=zzz
You can do this:
- hosts: group1:group2
connection: local
tasks:
- name: provision
azure: ...
- hosts: group1:group2
tasks:
- name: install things
apk: ...
Or this:
- hosts: group1:group2
gather_facts: no
tasks:
- name: provision
local_action: azure: ...
- name: gather facts
setup:
- name: install things
apk:
In this examples testvar=aaa for server1 and testvar=zzz for server2.
Still azure action is executed from control host.
In the second example you should turn off fact gathering and call setup manually to prevent Ansible from connecting to possibly unprovisioned servers.

Ansible: What would be the preferred way of running several tasks on different groups?

Let's say we have 3 services and 5 servers and
Service 1 should run on all servers.
Service 2 should run on server 1, 2 and 3.
Service 3 should run on server 4 and 5.
I could think of a few dirty ways to accomplish that, but I'd like to know what the best-practice for that scenario would be.
I was thinking that it might be a good idea to first define a group for each service that specifies the hosts that it should be deployed on in the inventory file:
[service-1]
server-[01:05]
[service-2]
server-[01:03]
[service-3]
server-[04:05]
To get the services on the target machines I would use copy or template.
And for actually starting services I found this.
But how would I make the services start on only those machines that they are supposed to run on?
I guess I could create multiple playbooks to achieve that, but I would really prefer to put everything into one playbook.
A playbook can have multiple plays. Therefore you indeed can use those groups to archive your goal and still only have one playbook:
- name: Setup service 1
hosts: service-1
tasks/roles: ...
- name: Setup service 2
hosts: service-2
tasks/roles: ...
- name: Setup service 3
hosts: service-3
tasks/roles: ...
Alternatively you can filter you roles/tasks with conditions like so:
- name: Setup all service
hosts: all
roles:
- role: service1
when: "'service-1' in group_names"
- role: service2
when: "'service-2' in group_names"
- role: service3
when: "'service-3' in group_names"
group_names is a magic variable and holds all the groups the current host belongs to.

Ansible: playbooks and roles difference

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:

Resources