Ansible Multiple Application Role Approach

ansibledeployment

Just for a bit of background, I've worked with Puppet for 3 years and I understood it's architecture pretty well. Our company is refactoring our whole product basing it's architecture in microservices and is starting to use Continuous Integration/Deployment. I've used this opportunity to switch our configuration management to Ansible so I can use only one tool for both deployment and configuration/orchestration.

Our architecture will be totally based on AWS, with Live, Staging and 3 Integration/QA environments. Each microservice will have it's own separate deploy process and the Integration/QA envs will hold all applications in a single instance, while Live/Staging will have multiple instances and in some cases, different pools of instances per microservice.

My goal is to have a single Ansible configuration/deployment "repository" for all environments, using variables to parameterized the templates through the environments. This way we'll know we have a consistent configuration and deployment process through our whole development cycle.

What I'm having doubts right now is on how I approach the role creation for these multiple applications. I'm find this topic as well pretty hard to "google" since most posts I find is simple tutorials or single application deployment examples.

What I'm considering now is:

  1. Have separated roles for each "service" I need, such as nginx, java, logstash, etc, with each application configuration file inside it. In this way I keep roles reusability and avoid repeating myself when two or more apps use a pretty similar config file that can be made different via variables. I'll also have a deploy role with all deploy tasks in it. This is the approach I usually take when working with Puppet, but it can scatter configuration sometimes making it "hard" to find and add a couple cases when a change in one application config can impact another (mainly due to single templates serving more than one app).

  2. Have one role for microservice. This is easier to work with, since all configs and variables are in the same role, but I'll have to repeat tasks and configs for each microservice, and this makes me cringe a little.

The reason of this question is to measure how people that face the same problem deal with it, since it seems almost impossible to find reasonable answers about it through a google search and I have no friends/acquaintances that work with Ansible/multi app deploys.

Sorry if I was not clear enough/confusing, and thanks for every insight you can give me.

Best Answer

What I would do is to have roles for each system service that your application needs, a play and a role for each application/microservice, and group and/or host variables and role variables and defaults which define what to do.

I deploy a lot of PHP-based applications, so that looks a lot like this:

I'll have a play app_microservice.yml:

---
- hosts: app_microservice_servers
  roles:
    - nginx
    - mariadb
    - php-fpm
    - app_microservice

So I'll have a role roles/app_microservice which deploys the code. When I run this play, the nginx, mariadb and php-fpm prerequisites will be installed and configured first, if they haven't already been.

In addition to calling roles, a play can also run arbitrary tasks. Feel free to mix and match these if something is simple enough that a full role isn't called for.

This play also goes into all.yml along with every other play, so that I can occasionally do ansible-playbook all.yml. Remember that ansible doesn't guarantee idempotence like puppet tries to, so this is something you have to be careful of.

- include: app_microservice.yml

I use group variables to define things which are common to a group (though there are precious few of these that won't fit in the role variables or defaults instead), group all variables for global stuff, and host variables for anything that's unique to a host.

For instance, I give a unique MySQL root password to every host, but I have SSL ciphers and protocols defined in group_vars/all/main.yml so that, if they need to be changed, there is one source of truth for them.