Plantilla de balanceador de carga Ansible para múltiples centros de datos

Plantilla de balanceador de carga Ansible para múltiples centros de datos

Estoy migrando la gestión de una configuración de varios centros de datos existente a Ansible, pero no estoy seguro de cuál es la mejor manera de modelarlo, ya que soy nuevo en esto.

Tengo tres centros de datos D1, D2 y D3. En cada uno, la misma configuración se repite de forma idéntica:

  • Unequilibrador de carga nginx(lb.D[n]) vinculado a una IP pública
  • Dosservidores de aplicaciones(como[1-2].D[n]) que reciben tráfico únicamente del balanceador de carga local
  • Un esclavo (solo lectura)servidor de base de datos(db.D[n]) desde el cual leen ambos servidores de aplicaciones.

El archivo de hosts que creé hasta ahora se parece a esto:

# DC1 -----------
[dc_1_webservers]
10.43.0.10

[dc_1_appservers]
10.43.0.20
10.43.0.21

[dc_1_dbservers]
10.43.0.30

[dc_1:children]
dc_1_webservers
dc_1_appservers
dc_1_dbservers

# DC2 -----------
[dc_2_webservers]
10.43.10.10

[dc_2_appservers]
10.43.10.20
10.43.10.21

[dc_2_dbservers]
10.43.10.30

[dc_2:children]
dc_2_webservers
dc_2_appservers
dc_2_dbservers

# DC3 -----------
[dc_3_webservers]
10.43.20.10

[dc_3_appservers]
10.43.20.20
10.43.20.21

[dc_3_dbservers]
10.43.20.30

[dc_3:children]
dc_3_webservers
dc_3_appservers
dc_3_dbservers

[webservers:children]
dc_1_webservers
dc_2_webservers
dc_3_webservers

[appservers:children]
dc_1_appservers
dc_2_appservers
dc_3_appservers

He dejado deliberadamente solo direcciones IP aquí porque me gustaría entender cómo funcionaría una solución Ansible pura, en lugar de recurrir a DNS.

El problema es completar correctamente el proxy inverso de nginx en sentido ascendente, de modo quesolo se agregan los servidores de aplicaciones locales para cada DCcuando se ejecuta la función nginx y la plantilla del archivo de configuración se copia en la máquina del equilibrador de carga. En particular, ¿es posible hacer algo como esto?

# file /etc/nginx/sites-enabled/loadbalancer.conf in lb.D[n] (i.e. lb.D2)
 upstream backend  {
 # Iterate over the app servers in the current data center (i.e. D2)
 {% for host in [datacenters][current_datacenter][appservers] %}
     # Add each local app server IP to the load balancing pool 
     # (i.e. 10.43.10.20 and 10.43.10.21 for DC2)
     server {{ hostvars[host]['ansible_eth0']['ipv4']['address'] }};
 {% endfor %}
 }

Por un lado, no estoy seguro de que el archivo hosts tenga completamente sentido (¿debería agregar variables a las entradas individuales? En la configuración actual no puedo hacer algo como [dc][3][appservers], aunque no estoy seguro). ahí está la solución).

¡Muchas gracias!

EDITAR 1:

La estructura del libro de jugadas es la siguiente:

main.yml
hosts
vars.yml
servers/
    webservers.yml
    appservers.yml
roles/
   base/
     files/
       ssh/
       newrelic/
     tasks/
       main.yml
     handlers/
       main.yml
   webserver/
     files/
       ssl_certs/
     templates/
       nginx/
          loadbalancer.j2
     tasks/
       main.yml
     handlers/
       main.yml
   appserver/
     files/
       pip/
         requirements.txt
     templates/
       supervisor/
          gunicorn.j2
     tasks/
        main.yml
     handlers/
        main.yml

El punto de entrada de main.yml tiene solo dos líneas:

---
- include: servers/webservers.yml
- include: servers/appservers.yml

webservers.yml recopila datos sobre servidores de aplicaciones (pensé que sería necesario para lograr mi objetivo, aunque todavía no estoy completamente seguro de cómo), y luego primero invoca una función base que simplemente instala algunas claves SSH compartidas, enlaces NewRelic y otros cosas que son comunes a todas las máquinas en nuestra nube, luego invoca la función real del servidor web.

---
- name: Gather data about appservers
  hosts:  appservers
  gather_facts: yes
  tasks:
    - debug: Gather Facts

- name: Configure all frontend web servers
  hosts: webservers
  sudo: yes
  roles:
    - { role: base }
    - { role: webserver }

Dicha función de "servidor web" instala nginx, copia los certificados SSL y finalmente copia la plantilla de configuración nginx de jinja2.

 - name: Install nginx configuration file.
    template: src=files/loadbalancer.j2 dest=/etc/nginx/sites-available/{{ project_name }} backup=yes

Respuesta1

Puedes utilizarvariables mágicas group_namesy groupsbuscar grupos definidos en su inventario:

---
- hosts: webservers
  vars:
    dcs: [dc_1, dc_2, dc_3]
  tasks:
  - debug:
      msg: |
        upstream backend {
        {%- for dc in dcs %}
        {%-   if dc in group_names %}
        {%-     for host in groups[dc+'_appservers'] %}
        server {{host}};
        {%-     endfor %}
        {%-   endif %}
        {%- endfor %}
        }

Este manual le dará el siguiente resultado.

TASK: [debug ]     **************************************************************** 
ok: [10.43.0.10] => {
    "msg": "upstream backend { server 10.43.0.20; server 10.43.0.21;}"
}
ok: [10.43.10.10] => {
    "msg": "upstream backend { server 10.43.10.20; server 10.43.10.21;}"
}
ok: [10.43.20.10] => {
    "msg": "upstream backend { server 10.43.20.20; server 10.43.20.21;}"
}

Cambie server {{host}};según sea necesario.

información relacionada