Estructurar Cloud Deployment Manager para su uso a gran escala

Cuando el sistema "Infraestructura como código" sobrepasa el ejemplo de "Hello World" sin planificación, el código tiende a desestructurarse. Las configuraciones no planificadas están codificadas. La capacidad de mantenimiento se reduce drásticamente.

Utiliza este documento, junto con el ejemplo de código adjunto, para estructurar Cloud Deployment Manager de manera más eficiente y a gran escala.

Además, aplica la convención de nombres y las recomendaciones internas en todos tus equipos. Este documento está diseñado para un público técnicamente avanzado y se da por sentado que tienes un conocimiento básico de Python, la infraestructura de Google Cloud Platform (GCP), Cloud Deployment Manager y, en general, la infraestructura como código.

Antes de comenzar

Varios entornos con una sola base de código

Para implementaciones grandes con más de una docena de recursos, las recomendaciones estándares requieren que utilices una cantidad significativa de propiedades externas (parámetros de configuración), a fin de que puedas evitar la codificación de las strings y la lógica para crear plantillas genéricas. Muchas de estas propiedades están parcialmente duplicadas debido a entornos similares como, por ejemplo, un entorno de desarrollo, prueba o producción, y servicios similares. Por ejemplo, todos los servicios estándares se ejecutan en una pila LAMP similar. Seguir estas recomendaciones da como resultado un gran conjunto de propiedades de configuración con una gran cantidad de duplicaciones que pueden ser difíciles de mantener, lo que aumenta la posibilidad de que tenga lugar un error humano.

La siguiente tabla es una muestra de código para ilustrar las diferencias entre una configuración jerárquica y una configuración única por implementación. La tabla destaca una duplicación común en una configuración única. Mediante la configuración jerárquica, la tabla muestra cómo mover las secciones repetidas a un nivel más alto en la jerarquía para evitar la repetición y disminuir las posibilidades de que tenga lugar un error humano.

Plantilla Configuración jerárquica sin redundancia Configuración única con redundancia

project_config.py

config = \ {'ProjectId': 'qwerty123456', 'ProjectOwner': 'Bob', 'ProjectAbbrevation': 'SNP'}

N/A

frontend_config.py

config = {'ServiceName': 'frontend'}

config = \ {'ProjectId': 'qwerty123456', 'ProjectOwner': ''Bob'', 'ProjectAbbrevation': 'SNP', 'ServiceName': 'frontend'}

backend_config.py

config = {'ServiceName': 'backend'}

config = \ {'ProjectId': 'qwerty123456', 'ProjectOwner': ''Bob'', 'ProjectAbbrevation': 'SNP', 'ServiceName': 'backend'}

db_config.py

config = {'ServiceName': 'db'}

config = \ {'ProjectId': 'qwerty123456', 'ProjectOwner': ''Bob'', 'ProjectAbbrevation': 'SNP', 'ServiceName': 'db'}

Para manejar mejor una base de código grande, utiliza un diseño jerárquico estructurado con una combinación en cascada de propiedades de configuración. Para hacerlo, utiliza varios archivos para la configuración, en lugar de solo uno. Además, trabaja con funciones auxiliares y comparte parte de la base de código en toda la organización.

El ejemplo de código que se adjunta a este documento, Organization_with_departments, contiene una base de código con una estructura predefinida, pero personalizable, una secuencia de comandos auxiliar para combinar configuraciones, funciones auxiliares para asignar nombres, y un conjunto completo de configuraciones de ejemplo. Puedes encontrar este ejemplo funcional en el repositorio de muestras de GitHub de Cloud Deployment Manager.

La estructuración y la organización en cascada del código de manera jerárquica ofrecen varios beneficios:

  • Cuando divides la configuración en varios archivos, mejoras la estructura y la legibilidad de las propiedades. También puedes evitar su duplicación.
  • Diseñas la combinación jerárquica para que los valores se coloquen en cascada de una manera lógica, lo que permite crear archivos de configuración de nivel superior que son reutilizables en todos los proyectos o los componentes.
  • Defines cada propiedad solo una vez (aparte de reemplazar), lo que evita la necesidad de tratar con espacios de nombres en los nombres de propiedades.
  • Las plantillas no necesitan conocer el entorno real porque la configuración adecuada se carga según las variables correspondientes.

Estructura la base de código de manera jerárquica

Una implementación de Cloud Deployment Manager contiene una configuración YAML o un archivo de esquema, junto con varios archivos de Python. De manera conjunta, estos archivos forman la base de código de una implementación. Los archivos de Python pueden servir para propósitos diferentes. Puedes usar los archivos de Python como plantillas de configuración, como archivos de código general (clases auxiliares), o como archivos de código que almacenan propiedades de configuración.

Para estructurar la base de código de manera jerárquica, utiliza algunos archivos de Python como archivos de configuración, en lugar del archivo de configuración estándar. Este enfoque te brinda mayor flexibilidad que vincular la implementación a un solo archivo yaml.

Trata a la infraestructura como un código real

Un principio importante para el código limpio es No te repitas (DRY). Define todo solo una vez. Este enfoque hace que la base de código sea más limpio, más fácil de revisar y validar, y más fácil de mantener porque, cuando una propiedad debe modificarse en solo un lugar, el riesgo de error humano disminuye.

Para una base de código más ligera con archivos de configuración más pequeños y una duplicación mínima, utiliza estos lineamientos para estructurar las configuraciones a fin de seguir el principio DRY.

Organizaciones, departamentos, entornos y módulos

Los principios fundamentales para estructurar la base de código de forma limpia y jerárquica se utilizarán en organizaciones, departamentos, entornos y módulos. Estos principios son opcionales y prolongables. Para obtener un diagrama de la jerarquía de la base de código de ejemplo, que sigue estos principios, consulta la jerarquía de configuración.

En el siguiente diagrama, un módulo se implementa en un entorno. La combinación de configuración selecciona los archivos de configuración apropiados en cada nivel según el contexto en el que se utiliza. También define automáticamente el sistema y el departamento.

Un módulo implementado en un entorno

En la siguiente lista, los números representan el orden de reemplazo:

  1. Propiedades organizativas

    Este es el nivel más alto en la estructura. En este nivel, puedes almacenar propiedades de configuración como, por ejemplo, organization_name, organization_abbreviation, que puedes utilizar en la convención de nombres, y las funciones auxiliares que deseas compartir y aplicar a todos los equipos.

  2. Propiedades de los departamentos

    Las organizaciones contienen departamentos, si tienes departamentos en tu estructura. En el archivo de configuración de cada departamento, comparte propiedades que no utilicen otros departamentos, por ejemplo, department_name, cost_center.

  3. Propiedades de los sistemas (proyectos)

    En cada departamento existen sistemas. Un sistema es una pila de software bien definida, por ejemplo, la plataforma de comercio electrónico. No es un proyecto de GCP, sino un ecosistema de servicios en funcionamiento.

    En el nivel de sistema, el equipo tiene mucha más autonomía que en los niveles superiores. Aquí, puedes definir funciones auxiliares (por ejemplo, project_name_generator(), instance_name_generator(), instance_label_generator()) para los parámetros en todo el equipo y el sistema (por ejemplo, system_name, default_instance_size, naming_prefix).

  4. Propiedades de los entornos

    Es probable que el sistema tenga varios entornos, como Dev, Test o Prod y, de manera opcional, QA y Staging, que son bastante similares entre sí. Lo ideal sería que utilicen la misma base de código y se diferencien únicamente en el nivel de configuración. En el nivel de entorno, puedes reemplazar propiedades como, por ejemplo, default_instance_size para las configuraciones Prod y QA.

  5. Propiedades de los módulos

    Si el sistema es grande, divídelo en varios módulos, en lugar de mantener un bloque monolítico grande. Por ejemplo, puedes pasar las herramientas de redes y la seguridad principales a bloques separados. También puedes separar las capas de backend, frontend y base de datos en módulos independientes. O, los módulos son plantillas que desarrollan terceros en las que puedes agregar solamente la configuración apropiada. En el nivel de módulo, puedes definir propiedades que sean relevantes únicamente para los módulos particulares, lo que incluye propiedades diseñadas para reemplazar propiedades heredades en el nivel de sistema. Los niveles de entorno y módulo son divisiones paralelas en un sistema, pero los módulos siguen los entornos en el proceso de combinación.

  6. Propiedades de los módulos específicas de los entornos

    Algunas de las propiedades del módulo también pueden depender del entorno, por ejemplo, tamaños de instancias, imágenes, extremos. Las propiedades de los módulos específicas de los entornos son el nivel más específico y el último punto de la combinación en cascada para reemplazar el valor definido previamente.

Clase auxiliar para combinar configuraciones

La clase config_merger es una clase auxiliar que carga automáticamente los archivos de configuración adecuados y combina su contenido en un solo diccionario.

Para utilizar la clase config_merger, debes utilizar la siguiente información:

  • El nombre del módulo.
  • El contexto global, que contiene el nombre del entorno.

Llamar a la función estática ConfigContext muestra el diccionario de configuración combinado.

En el siguiente código se muestra cómo utilizar esta clase:

  • El module = "frontend" especifica el contexto, los archivos de propiedades que se cargan.
  • El entorno se selecciona automáticamente en context.properties["envName"].
  • La configuración global.

    cc = config_merger.ConfigContext(context.properties, module)
    
    print cc.configs['ServiceName']
    

En segundo plano, esta clase auxiliar tiene que alinearse con las estructuras de configuración, cargar todos los niveles en el orden correcto y reemplazar los valores de configuración adecuados. Para cambiar los niveles o el orden de reemplazo, modifica la clase de combinación de configuración.

En el uso diario y de rutina, normalmente no necesitarás tocar esta clase. Por lo general, edita las plantillas y los archivos de configuración adecuados y, a continuación, utiliza el diccionario de salida con todas las configuraciones.

La base de código de ejemplo contiene los siguientes tres archivos de configuración codificados:

  • org_config.py
  • department_config.py
  • system_config.py

Puedes crear los archivos de configuración de la organización y del departamento como vínculos simbólicos durante el inicio del repositorio. Estos archivos pueden residir en un repositorio de código separado, ya que este no forma lógicamente parte de la base de código del equipo del proyecto, pero se comparte en toda la organización y el departamento.

La combinación de configuración también busca archivos que coincidan con los niveles restantes de la estructura:

  • envs/[environment name].py
  • [environment name]/[module name].py
  • modules/[module name].py

Archivo de configuración

Cloud Deployment Manager utiliza un archivo de configuración, que es un archivo único para una implementación específica. No se puede compartir en todas las implementaciones.

Cuando utilizas la clase config-merger, las propiedades de configuración se separan completamente de este archivo de configuración porque no lo estás utilizando. En su lugar, utilizas una colección de archivos de Python, que te brinda mucha más flexibilidad en una implementación. Estos archivos también pueden compartirse en todas las implementaciones.

Cualquier archivo de Python puede contener variables, lo que te permite almacenar la configuración de una manera estructurada, pero distribuida. El mejor enfoque es utilizar diccionarios con una estructura acordada. La combinación de configuración busca un diccionario denominado configs en cada archivo de la cadena de combinación. Esas configs separadas se combinan en una sola.

Durante la combinación, cuando una propiedad con la misma ruta y el mismo nombre aparece en los diccionarios varias veces, la combinación de configuración reemplaza esa propiedad. En algunos casos, este comportamiento es útil, como cuando un valor específico del contexto reemplaza un valor predeterminado. Sin embargo, existen muchos otros casos en los que deseas evitar el reemplazo de la propiedad. Para evitar el reemplazo de una propiedad, agrega un espacio de nombres separado para que sea único. En el siguiente ejemplo, agrega un espacio de nombres; para ello, crea un nivel adicional en el diccionario de configuración, lo que crea un subdirectorio.

    config ={
            'Zip_code': '1234'
            'Count': '3'
            'project_module':{
                 'admin': 'Joe',
          }
    }

    config ={
            'Zip_code': '5555'
            'Count': '5'
            'project_module_prod':{
                 'admin': 'Steve',
          }
    }
    

Clases auxiliares y convenciones de nombres

Las convenciones de nombres son la mejor manera de mantener bajo control la infraestructura de Cloud Deployment Manager. No deseas ver ningún nombre vago y genérico como, por ejemplo, my project o test instance.

El siguiente ejemplo es una convención de nombres en toda la organización para las instancias:

def getInstanceName(self, name):
return self.configs['Org_level_configs']['Org_Short_Name'] + '-' +
    self.configs['Department_level_configs']['Department_Short_Name'] + '-' +
    self.configs['Systen_short_name'] + '-'+
    name + '-'+
    self.configs["envName"]

Proporcionar una función auxiliar facilita la asignación de nombre a cada instancia según la convención acordada. También simplifica la revisión del código porque ningún nombre de instancia proviene de ningún otro lugar que no sea esta función. La función recoge automáticamente nombres de configuraciones de nivel superior. Este enfoque ayuda a evitar entradas innecesarias.

Puedes aplicar estas convenciones de nombres a la mayoría de los recursos de GCP y a las etiquetas. Las funciones más complejas pueden incluso generar un conjunto de etiquetas predeterminadas.

Estructura de carpeta de la base de código de ejemplo

La estructura de carpeta de la base de código de ejemplo es flexible y personalizable. Sin embargo, está parcialmente codificada para la combinación de configuración y el archivo de esquema de Cloud Deployment Manager, lo que significa que si realizas una modificación, debes reflejar estos cambios en la combinación de configuración y los archivos de esquema.

├── global
│   ├── configs
│   └── helper
└── systems
    └── my_ecom_system
        ├── configs
        │   ├── dev
        │   ├── envs
        │   ├── modules
        │   ├── prod
        │   └── test
        ├── helper
        └── templates
    

La carpeta global contiene archivos que se comparten en diferentes equipos de proyectos. Por cuestiones de simplicidad, la carpeta de configuración contiene la configuración de la organización y todos los archivos de configuración de los departamentos. En este ejemplo, no hay ninguna clase auxiliar independiente para los departamentos. Puedes agregar cualquier clase auxiliar a nivel de organización o sistema.

La carpeta global puede residir en un repositorio de Git separado. Puedes hacer referencia a sus archivos en los sistemas individuales. También puedes utilizar vínculos simbólicos, pero podrían crear confusión o interrupciones en determinados sistemas operativos.

├── configs
│   ├── Department_Data_config.py
│   ├── Department_Finance_config.py
│   ├── Department_RandD_config.py
│   └── org_config.py
└── helper
    ├── config_merger.py
    └── naming_helper.py

La carpeta de sistemas contiene uno o más sistemas diferentes. Los sistemas están separados entre sí, y no comparten configuraciones.

├── configs
│   ├── dev
│   ├── envs
│   ├── modules
│   ├── prod
│   └── test
├── helper
└── templates

La carpeta de configuración contiene todos los archivos de configuración que son exclusivos de este sistema, y también hace referencia a las configuraciones globales mediante vínculos simbólicos.

├── department_config.py -> ../../../global/configs/Department_Data_config.py
├── org_config.py -> ../../../global/configs/org_config.py
├── system_config.py
├── dev
│   ├── frontend.py
│   └── project.py
├── prod
│   ├── frontend.py
│   └── project.py
├── test
│   ├── frontend.py
│   └── project.py
├── envs
│   ├── dev.py
│   ├── prod.py
│   └── test.py
└── modules
    ├── frontend.py
    └── project.py

Org_config.py:

config ={
        'Org_level_configs':{
                'Org_Name': 'Sample Inc.',
                'Org_Short_Name': 'sampl',
                'HQ_Address': {
                                'City': 'London',
                                'Country': 'UK'
                }
        }
}

En la carpeta auxiliar, puedes agregar más clases auxiliares y hacer referencia a las clases globales.

├── config_merger.py -> ../../../global/helper/config_merger.py
└── naming_helper.py -> ../../../global/helper/naming_helper.py

En la carpeta de plantillas, puedes almacenar las plantillas de Cloud Deployment Manager o hacer referencia a tales plantillas. Los vínculos simbólicos también funcionan aquí.

├── project_creation -> ../../../../../../examples/v2/project_creation
└── simple_frontend.py

Utilizar la base de código de ejemplo

La mejor manera de comenzar a aplicar esta práctica jerárquica como base de tu infraestructura como código es clonar la base de código de ejemplo y copiar el contenido de la carpeta hierarchical_configuration.

  1. Verifica el repositorio de ejemplo.

    git clone https://github.com/GoogleCloudPlatform/deploymentmanager-samples.git
    cd deploymentmanager-samples/community/hierarchical_configuration/Organization_with_departments/systems/my_ecom_system
    gcloud config set deployment_manager/glob_imports True
    
  2. Para configurar el sistema, utiliza los siguientes vínculos simbólicos para hacer referencia a los archivos globales en el contexto local.

    ln -sf ../../../global/helper/config_merger.py helper/config_merger.py
    ln -sf ../../../global/helper/naming_helper.py helper/naming_helper.py
    ln -sf ../../../global/configs/org_config.py configs/org_config.py
    
  3. Selecciona el departamento apropiado en la lista global.

        ln -sf ../../../global/configs/Department_Data_config.py  configs/department_config.py
    
  4. Para establecer el contexto de entorno correcto, utiliza la marca --properties para especificar la propiedad envName. Esta propiedad te permite ejecutar el mismo código orientado a entornos diferentes con el mismo comando. [MY-PROJECT-ID] representa el ID del proyecto de tu propio proyecto de GCP.

    [MY-PROJECT-ID]
    gcloud deployment-manager deployments create hierarchy-org-example-dev
    --template env_demo_project.py --properties=envName:dev
    gcloud deployment-manager deployments create hierarchy-org-example-test
    --template env_demo_project.py --properties=envName:test
    gcloud deployment-manager deployments create hierarchy-org-example-prod
    --template env_demo_project.py --properties=envName:prod
    

Recomendaciones

Aquí se recopilan algunas recomendaciones adicionales para ayudarte a estructurar el código de manera jerárquica.

Archivos de esquema

En el archivo de esquema, es un requisito de Cloud Deployment Manager enumerar cada archivo que utilices de cualquier manera durante la implementación. Agregar una carpeta completa hace que el código sea más corto y más genérico.

  • Clases auxiliares:

    • path: helper/*.py
  • Archivos de configuración:

    • path: configs/*.py
    • path: configs/*/*.py
  • Importaciones masivas (estilo glob):

    gcloud config set deployment_manager/glob_imports True
    
  • Varias implementaciones

    Se recomienda que el sistema contenga varias implementaciones, lo que significa que van a utilizar los mismos conjuntos de configuraciones, incluso si son módulos diferentes, por ejemplo, herramientas de redes, firewalls, backend, frontend. Es posible que necesites acceder al resultado de estas implementaciones desde otra implementación. Puedes consultar el resultado de la implementación una vez que esté listo y se guarde en la carpeta de configuraciones. Puedes agregar estos archivos de configuración durante el proceso de combinación.

    Los comandos gcloud deployment-manager admiten los vínculos simbólicos, y los archivos vinculados se cargan correctamente. Sin embargo, los vínculos simbólicos no se admiten en todos los SO.

    Jerarquía de configuración

    En el siguiente diagrama se incluye una descripción general de los niveles diferentes y sus relaciones. Cada rectángulo representa un archivo de propiedad, como lo indica el nombre del archivo en rojo.

    Jerarquía de configuración con niveles diferentes y sus relaciones destacadas.

    Orden de combinación adaptado al contexto

    La combinación de configuración selecciona los archivos de configuración apropiados en cada nivel según el contexto dentro del cual se utiliza cada archivo. El contexto es un módulo que implementas en un entorno. Este contexto define el sistema y el departamento de forma automática.

    En el siguiente diagrama, los números representan el orden de reemplazo en la jerarquía:

    Diagrama del orden de reemplazo

    Pasos siguientes

    ¿Te ha resultado útil esta página? Enviar comentarios:

    Enviar comentarios sobre...

    Documentación de Cloud Deployment Manager