Enfoque de sistema para las variables en Ansible

estilo de código ansible devops

¡Ey! Mi nombre es Denis Kalyuzhni Trabajo como ingeniero en el departamento de automatización de procesos de desarrollo. Todos los días, se implementan nuevas compilaciones de aplicaciones en cientos de servidores de campaña. Y en este artículo comparto mi experiencia de usar Ansible para estos fines.

Esta guía ofrece una forma de organizar las variables en una implementación. Esta guía está diseñada para aquellos que ya usan roles en sus libros de jugadas y leen Mejores prácticaspero se encuentra con problemas similares:

  • Habiendo encontrado una variable en el código, es imposible entender de inmediato de qué es responsable;
  • Hay varios roles y las variables deben asociarse con un valor, pero no funciona;
  • Tener dificultad para explicar a los demás cómo funciona la lógica de las variables en sus libros de jugadas

Nos encontramos con estos problemas en proyectos de nuestra empresa, como resultado de lo cual llegamos a las reglas para dar formato a las variables en nuestros libros de jugadas, que en cierta medida resolvieron estos problemas.

Enfoque de sistema para las variables en Ansible

Variables en roles

Una función es un objeto de sistema de implementación independiente. Como cualquier objeto del sistema, debe tener una interfaz para interactuar con el resto del sistema. Las variables de rol son una interfaz de este tipo.

Tomemos, por ejemplo, el papel api, que instala una aplicación Java en el servidor. ¿Qué variables tiene?

Enfoque de sistema para las variables en Ansible

Las variables de rol se pueden dividir en 2 tipos por tipo:

1. Свойства
    a) независимые от среды
    б) зависимые от среды
2. Связи
    a) слушатели 
    б) запросы внутри системы
    в) запросы в среду

Propiedades variables son variables que definen el comportamiento de un rol.

Variables de consulta son variables cuyo valor se utiliza para designar recursos externos al rol.

Oyentes variables son variables cuyo valor se utiliza para formar variables de consulta.

Por otro lado, 1a, 2a, 2b son variables que no dependen del entorno (hierro, recursos externos, etc.) y se pueden rellenar con valores por defecto en el rol defaults. Sin embargo, variables como 1.b y 2.c no se pueden llenar con valores que no sean 'ejemplo', ya que cambiarán de soporte a soporte dependiendo del entorno.

Estilo de código

  • El nombre de la variable debe comenzar con el nombre del rol. Esto facilitará averiguar en el futuro de qué rol es la variable y de qué es responsable.
  • Al usar variables en roles, debe asegurarse de seguir el principio de encapsulación y usar variables definidas en el rol mismo o en los roles de los que depende el actual.
  • Evite usar diccionarios para variables. Ansible no le permite anular convenientemente valores individuales en un diccionario.

    Un ejemplo de una mala variable:

    myrole_user:
        login: admin
        password: admin

    Aquí, el inicio de sesión es la variable mediana y la contraseña es la variable dependiente. Pero
    dado que se combinan en un diccionario, deberá especificarlo en su totalidad
    Siempre. Lo cual es muy inconveniente. Mejor de esta forma:

    myrole_user_login: admin
    myrole_user_password: admin

Variables en los manuales de implementación

Al compilar un libro de jugadas de implementación (en adelante, un libro de jugadas), nos adherimos a la regla de que debe colocarse en un repositorio separado. Al igual que los roles: cada uno en su propio repositorio de git. Esto le permite darse cuenta de que los roles y el libro de jugadas son diferentes objetos independientes del sistema de implementación, y los cambios en un objeto no deberían afectar el funcionamiento del otro. Esto se logra cambiando los valores predeterminados de las variables.

Al compilar un libro de jugadas, para resumir, es posible anular los valores predeterminados de las variables de rol en dos lugares: en las variables del libro de jugadas y en las variables de inventario.

mydeploy                        # Каталог деплоя
├── deploy.yml                  # Плейбук деплоя
├── group_vars                  # Каталог переменных плейбука
│   ├── all.yml                 # Файл для переменных связи всей системы
│   └── myapi.yml               # Файл переменных свойств группы myapi
└── inventories                 #
    └── prod                    # Каталог окружения prod
        ├── prod.ini            # Инвентори файл
        └── group_vars          # Каталог для переменных инвентори
            └── myapi           #
                ├── vars.yml    # Средозависимые переменные группы myapi
                └── vault.yml   # Секреты (всегда средозависимы) *

* - Variables y bóvedas

La diferencia es que las variables del libro de jugadas siempre se usan cuando se llaman libros de jugadas ubicados en el mismo nivel. Esto significa que estas variables son excelentes para cambiar los valores predeterminados de variables que no dependen del entorno. Por el contrario, las variables de inventario solo se utilizarán para un entorno particular, lo que es ideal para las variables específicas del entorno.

Es importante tener en cuenta que la prioridad de las variables no le permitirá redefinir las variables primero en las variables del libro de jugadas y luego por separado en el mismo inventario.

Esto significa que ya en esta etapa debe decidir si la variable depende del entorno o no y colocarla en el lugar correcto.

Por ejemplo, en un proyecto, la variable responsable de habilitar SSL dependió del entorno durante mucho tiempo, ya que no pudimos habilitar SSL por razones fuera de nuestro control en uno de los stands. Después de que solucionamos este problema, se volvió independiente del medio y pasó a las variables del libro de jugadas.

Variables de propiedad para grupos

Expandamos nuestro modelo en la Figura 1 agregando 2 grupos de servidores con una aplicación Java diferente, pero con configuraciones diferentes.

Enfoque de sistema para las variables en Ansible

Imagine cómo se verá el libro de jugadas en este caso:

- hosts: myapi
  roles:
    - api

- hosts: bbauth
  roles:
    - auth

- hosts: ghauth
  roles:
    - auth

Tenemos tres grupos en el libro de jugadas, por lo que se recomienda crear tantos archivos de grupo en las variables de inventario group_vars como en las variables del libro de jugadas a la vez. Un archivo de grupo en este caso es la descripción de un componente de su aplicación en el libro de jugadas. Cuando abre el archivo de grupo en las variables del libro de jugadas, inmediatamente ve todas las diferencias con respecto al comportamiento predeterminado de los roles asignados al grupo. En variables de inventario: diferencias en el comportamiento de los grupos de stand a stand.

Estilo de código

  • Trate de no usar variables host_vars en absoluto, ya que no describen el sistema, sino solo un caso especial, que a la larga generará preguntas: "¿Por qué este host es diferente del resto?", cuya respuesta es no siempre es fácil de encontrar.

Vincular variables

Sin embargo, se trata de variables de propiedad, pero ¿qué pasa con las variables de enlace?
Su diferencia es que deben tener el mismo valor en diferentes grupos.

Al principio había Идея usa una construcción monstruosa de la forma:
hostvars[groups['bbauth'][0]]['auth_bind_port'], pero fue inmediatamente abandonado
porque tiene defectos. Primero, el volumen. En segundo lugar, la dependencia de un huésped específico en el grupo. En tercer lugar, es necesario recopilar datos de todos los hosts antes de comenzar la implementación, si no queremos obtener un error de variable indefinida.

Como resultado, se decidió utilizar variables de enlace.

Vincular variables son variables que pertenecen al libro de jugadas y son necesarias para vincular objetos del sistema.

Las variables de enlace se rellenan en las variables generales del sistema group_vars/all/vars y se forman eliminando todas las variables de escucha de cada grupo y agregando el nombre del grupo del que se eliminó la escucha al comienzo de la variable.

Así, se asegura la uniformidad y la no intersección de nombres.

Intentemos vincular variables del ejemplo anterior:

Enfoque de sistema para las variables en Ansible

Imagina que tenemos variables que dependen unas de otras:

# roles/api/defaults:
# Переменная запроса
api_auth1_address: "http://example.com:80"
api_auth2_address: "http://example2.com:80"

# roles/auth/defaults:
# Переменная слушатель
auth_bind_port: "20000"

Pongámoslo en variables comunes group_vars/all/vars todos los oyentes y agregue el nombre del grupo al nombre:

# group_vars/all/vars
bbauth_auth_bind_port: "20000"
ghauth_auth_bind_port: "30000"

# group_vars/bbauth/vars
auth_bind_port: "{{ bbauth_auth_bind_port }}"

# group_vars/ghauth/vars
auth_bind_port: "{{ ghauth_auth_bind_port }}"

# group_vars/myapi/vars
api_auth1_address: "http://{{ bbauth_auth_service_name }}:{{ bbauth_auth_bind_port }}"
api_auth2_address: "http://{{ ghauth_auth_service_name }}:{{ ghauth_auth_bind_port }}"

Ahora, cambiando el valor del conector, estaremos seguros de que la solicitud irá al mismo puerto.

Estilo de código

  • Dado que las funciones y los grupos son objetos del sistema diferentes, deben tener nombres diferentes para que las variables de enlace muestren con precisión que pertenecen a un grupo de servidores específico y no a una función en el sistema.

Archivos de entorno

Los roles pueden usar archivos que difieren de un entorno a otro.

Los certificados SSL son un ejemplo de tales archivos. Guárdalos como texto
en una variable no es muy conveniente. Pero es conveniente almacenar la ruta hacia ellos dentro de una variable.

Por ejemplo, usamos la variable api_ssl_key_file: "/path/to/file".

Dado que es obvio que el certificado clave cambiará de un entorno a otro, esta es una variable dependiente del entorno, lo que significa que debe ubicarse en el archivo
group_vars/myapi/vars inventario de variables, y contienen el valor 'por ejemplo'.

La forma más conveniente en este caso es colocar el archivo clave en el repositorio del libro de jugadas a lo largo de la ruta
files/prod/certs/myapi.key, entonces el valor de la variable será:
api_ssl_key_file: "prod/certs/myapi.key". La conveniencia radica en el hecho de que las personas responsables de implementar el sistema en un stand en particular también tienen su propio lugar dedicado en el repositorio para almacenar sus archivos. Al mismo tiempo, sigue siendo posible especificar la ruta absoluta al certificado en el servidor, en caso de que otro sistema proporcione los certificados.

Múltiples soportes en un entorno

A menudo existe la necesidad de desplegar varios soportes casi idénticos en el mismo entorno con diferencias mínimas. En este caso, dividimos las variables dependientes del entorno en las que no cambian dentro de este entorno y las que sí lo hacen. Y sacamos este último directamente en los archivos de inventario. Después de esta manipulación, es posible crear otro inventario directamente en el directorio del entorno.

Reutilizará el inventario group_vars y también podrá redefinir algunas variables directamente por sí mismo.

La estructura de directorio final para el proyecto de implementación:

mydeploy                        # Каталог деплоя
├── deploy.yml                  # Плейбук деплоя
├── files                       # Каталог для файлов деплоя
│   ├── prod                    # Католог для средозависимых файлов стенда prod
│   │   └── certs               # 
│   │       └── myapi.key       #
│   └── test1                   # Каталог для средозависимых файлов стенда test1
├── group_vars                  # Каталог переменных плейбука
│   ├── all.yml                 # Файл для переменных связи всей системы
│   ├── myapi.yml               # Файл переменных свойств группы myapi
│   ├── bbauth.yml              # 
│   └── ghauth.yml              #
└── inventories                 #
    ├── prod                    # Каталог окружения prod
    │   ├── group_vars          # Каталог для переменных инвентори
    │   │   ├── myapi           #
    │   │   │   ├── vars.yml    # Средозависимые переменные группы myapi
    │   │   │   └── vault.yml   # Секреты (всегда средозависимы)
    │   │   ├── bbauth          # 
    │   │   │   ├── vars.yml    #
    │   │   │   └── vault.yml   #
    │   │   └── ghauth          #
    │   │       ├── vars.yml    #
    │   │       └── vault.yml   #
    │   └── prod.ini            # Инвентори стенда prod
    └── test                    # Каталог окружения test
        ├── group_vars          #
        │   ├── myapi           #
        │   │   ├── vars.yml    #
        │   │   └── vault.yml   #
        │   ├── bbauth          #
        │   │   ├── vars.yml    #
        │   │   └── vault.yml   #
        │   └── ghauth          #
        │       ├── vars.yml    #
        │       └── vault.yml   #
        ├── test1.ini           # Инвентори стенда test1 в среде test
        └── test2.ini           # Инвентори стенда test2 в среде test

Resumiendo

Después de organizar las variables de acuerdo con el artículo: cada archivo con variables es responsable de una tarea específica. Y dado que el archivo tiene ciertas tareas, se hizo posible asignar una persona responsable de la corrección de cada archivo. Por ejemplo, el desarrollador de la implementación del sistema se vuelve responsable del correcto llenado de las variables del libro de jugadas, mientras que el administrador, cuyo soporte se describe en el inventario, es directamente responsable del llenado del inventario de variables.

Los roles se convirtieron en una unidad de desarrollo independiente con su propia interfaz, lo que permitió al desarrollador de roles desarrollar funciones en lugar de adaptar el rol para que se ajuste al sistema. Este problema era especialmente cierto para los roles comunes de todos los sistemas en una campaña.

Los administradores del sistema ya no necesitan comprender el código de implementación. Todo lo que se requiere de ellos para una implementación exitosa es completar los archivos de variables de entorno.

Literatura

  1. Документация

autor

Kalyuzhni Denis Alexandrovich

Fuente: habr.com

Añadir un comentario