Instrucións: como probar roles ansibles e descubrir problemas antes da produción

Ola a todos!

Traballo como enxeñeiro de DevOps nun servizo de reservas de hoteis. Ostrovok.ru. Neste artigo, quero falar da nosa experiencia na proba de roles ansibles.

En Ostrovok.ru, usamos ansible como xestor de configuración. Recentemente, chegamos á necesidade de probar papeis, pero como se viu, non hai tantas ferramentas para iso - o máis popular, quizais, é o marco Molecule, polo que decidimos usalo. Pero resultou que a súa documentación cala sobre moitas trampas. Non puidemos atopar un manual suficientemente detallado en ruso, polo que decidimos escribir este artigo.

Instrucións: como probar roles ansibles e descubrir problemas antes da produción

Molécula

Molécula - un marco para axudar a probar roles ansibles.

Descrición simplificada: a molécula crea unha instancia na plataforma que especifique (nube, máquina virtual, contedor; para máis detalles, consulte a sección Chofer), executa o seu rol nel, despois executa probas e elimina a instancia. En caso de falla nalgún dos pasos, a Molécula informarao.

Agora máis.

Un pouco de teoría

Considere dúas entidades clave da Molécula: Escenario e Controlador.

Escenario

O guión contén unha descrición de que, onde, como e en que secuencia se realizará. Un rol pode ter varios scripts, e cada un é un directorio ao longo do camiño <role>/molecule/<scenario>, que contén descricións das accións necesarias para a proba. Debe incluírse o guión default, que se creará automaticamente se inicializa o rol cunha Molécula. Os nomes dos seguintes guións dependen de ti.

Chámase a secuencia de accións de proba nun script matriz, e por defecto é:

(Pasos etiquetados ?, omitido por defecto se non o especifica o usuario)

  • lint - correndo linters. Por defecto utilízanse yamllint и flake8,
  • destroy - eliminando instancias do último lanzamento da Molecule (se hai),
  • dependency? — instalación da dependencia ansible do papel probado,
  • syntax - Comprobar a sintaxe do rol utilizando ansible-playbook --syntax-check,
  • create - creación dunha instancia,
  • prepare? - preparación da instancia; por exemplo, comprobar/instalar python2
  • converge — lanzamento do libro de xogos que se está a probar,
  • idempotence - reiniciar o manual para a proba de idempotencia,
  • side_effect? - accións non directamente relacionadas co papel, pero necesarias para probas,
  • verify - Realización de probas da configuración resultante utilizando testinfra(predeterminado) /goss/inspec,
  • cleanup? - (en novas versións) - grosso modo, "limpar" a infraestrutura externa afectada pola Molécula,
  • destroy - Eliminar unha instancia.

Esta secuencia abarca a maioría dos casos, pero pódese cambiar se é necesario.

Cada un dos pasos anteriores pódese executar por separado molecule <command>. Pero debe entenderse que para cada comando cli pode haber a súa propia secuencia de accións, que pode descubrir executando molecule matrix <command>. Por exemplo, ao executar o comando converge (execución do libro de xogos en proba), realizaranse as seguintes accións:

$ molecule matrix converge
...
└── default         # название сценария
    ├── dependency  # установка зависимостей
    ├── create      # создание инстанса
    ├── prepare     # преднастройка инстанса
    └── converge    # прогон плейбука

A secuencia destas accións pódese editar. Se algo da lista xa está feito, omitirase. O estado actual, así como a configuración das instancias, Molecule almacena no directorio $TMPDIR/molecule/<role>/<scenario>.

Engade pasos con ? pode describir as accións desexadas no formato ansible-playbook e facer o nome do ficheiro segundo o paso: prepare.yml/side_effect.yml. Agarda estes ficheiros A molécula estará no cartafol do script.

Chofer

Un controlador é unha entidade onde se crean instancias de proba.
A lista de controladores estándar para os que Molecule ten modelos preparados é a seguinte: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

Na maioría dos casos, os modelos son ficheiros create.yml и destroy.yml no cartafol do script que describe a creación e eliminación dunha instancia, respectivamente.
As excepcións son Docker e Vagrant, xa que as interaccións cos seus módulos poden producirse sen os ficheiros mencionados.

Cabe destacar o controlador Delegado, xa que se se usa nos ficheiros para crear e eliminar unha instancia, só se describe o traballo coa configuración de instancias, o resto debería ser descrito polo enxeñeiro.

O controlador predeterminado é Docker.

Agora pasemos á práctica e consideremos máis características alí.

introdución

Como un "hola mundo", imos probar un simple rol de instalación de nginx. Imos escoller docker como controlador: creo que a maioría de vós o tédes instalado (e recordade que docker é o controlador predeterminado).

Preparar virtualenv e instalar nel molecule:

> pip install virtualenv
> virtualenv -p `which python2` venv
> source venv/bin/activate
> pip install molecule docker  # molecule установит ansible как зависимость; docker для драйвера

O seguinte paso é inicializar o novo rol.
A inicialización dun novo rol, así como dun novo script, realízase mediante o comando molecule init <params>:

> molecule init role -r nginx
--> Initializing new role nginx...
Initialized role in <path>/nginx successfully.
> cd nginx
> tree -L 1
.
├── README.md
├── defaults
├── handlers
├── meta
├── molecule
├── tasks
└── vars

6 directories, 1 file

Resultou un típico papel ansible. Ademais, todas as interaccións coas moléculas CLI fanse desde a raíz do papel.

Vexamos o que hai no directorio de roles:

> tree molecule/default/
molecule/default/
├── Dockerfile.j2  # Jinja-шаблон для Dockerfile
├── INSTALL.rst.   # Немного информации об установке зависимостей сценария
├── molecule.yml   # Файл конфигурации
├── playbook.yml   # Плейбук запуска роли
└── tests          # Директория с тестами стадии verify
    └── test_default.py

1 directory, 6 files

Imos analizar a configuración molecule/default/molecule.yml (substitúe só a imaxe docker):

---
dependency:
  name: galaxy
driver:
  name: docker
lint:
  name: yamllint
platforms:
  - name: instance
    image: centos:7
provisioner:
  name: ansible
  lint:
    name: ansible-lint
scenario:
  name: default
verifier:
  name: testinfra
  lint:
    name: flake8

dependencia

Esta sección describe a fonte das dependencias.

Opcións posibles: galaxia, dourado, cuncha.

Shell é só un shell de comandos que se usa no caso de que galaxia e gilt non cobren as túas necesidades.

Non estarei aquí por moito tempo, é suficientemente descrito en documentación.

condutor

O nome do condutor. O noso é docker.

pelusa

O linter é yamllint.

As opcións útiles nesta parte da configuración son a posibilidade de especificar un ficheiro de configuración para yamllint, reenviar variables de ambiente ou desactivar o linter:

lint:
  name: yamllint
  options:
    config-file: foo/bar
  env:
    FOO: bar
  enabled: False

plataformas

Describe a configuración das instancias.
No caso de docker como controlador, a Molécula iterouse nesta sección e cada elemento da lista está dispoñible en Dockerfile.j2 como variable item.

No caso de condutor que o requira create.yml и destroy.yml, a sección está dispoñible nelas como molecule_yml.platforms, e as iteracións sobre el xa se describen nestes ficheiros.

Dado que Molecule proporciona control de instancias aos módulos ansibles, a lista de opcións posibles tamén se debe buscar alí. Para docker, por exemplo, úsase o módulo docker_container_module. Podes atopar os módulos que se usan noutros controladores documentación.

Así como exemplos do uso de varios controladores pódense atopar nas probas da propia Molécula.

Substitúe aquí centos: 7 en ubuntu.

provedor

"Provedor" - unha entidade que xestiona instancias. No caso de Molecule, isto é ansible, o soporte para outros non está previsto, polo que esta sección pódese chamar configuración estendida ansible cunha advertencia.
Aquí podedes especificar moitas cousas, destacarei os puntos principais, na miña opinión:

  • libros de xogos: pode especificar que libros de xogos deben usarse en determinadas etapas.

provisioner:
  name: ansible
  playbooks:
    create: create.yml
    destroy: ../default/destroy.yml
    converge: playbook.yml
    side_effect: side_effect.yml
    cleanup: cleanup.yml

provisioner:
  name: ansible
  config_options:
    defaults:
      fact_caching: jsonfile
    ssh_connection:
      scp_if_ssh: True

provisioner:
  name: ansible  
  connection_options:
    ansible_ssh_common_args: "-o 'UserKnownHostsFile=/dev/null' -o 'ForwardAgent=yes'"

  • opcións: Opcións de Ansible e variables de ambiente

provisioner:
  name: ansible  
  options:
    vvv: true
    diff: true
  env:
    FOO: BAR

escenario

Nome e descrición das secuencias de guións.
Pode cambiar a matriz de acción predeterminada de calquera comando engadindo a chave <command>_sequence e como valor para iso definindo a lista de pasos que precisamos.
Digamos que queremos cambiar a secuencia de accións ao executar o comando run playbook: molecule converge

# изначально:
# - dependency
# - create
# - prepare
# - converge
scenario:
  name: default
  converge_sequence:
    - create
    - converge

verificador

Configurar un marco para as probas e un linter para el. O linter predeterminado é testinfra и flake8. As opcións posibles son as mesmas que as anteriores:

verifier:
  name: testinfra
  additional_files_or_dirs:
    - ../path/to/test_1.py
    - ../path/to/test_2.py
    - ../path/to/directory/*
  options:
    n: 1
  enabled: False
  env:
    FOO: bar
  lint:
    name: flake8
    options:
      benchmark: True
    enabled: False
    env:
      FOO: bar

Volvamos ao noso papel. Imos editar o ficheiro tasks/main.yml a este tipo:

---
- name: Install nginx
  apt:
    name: nginx
    state: present

- name: Start nginx
  service:
    name: nginx
    state: started

E engadir probas a molecule/default/tests/test_default.py

def test_nginx_is_installed(host):
    nginx = host.package("nginx")
    assert nginx.is_installed

def test_nginx_running_and_enabled(host):
    nginx = host.service("nginx")
    assert nginx.is_running
    assert nginx.is_enabled

def test_nginx_config(host):
    host.run("nginx -t")

Feito, só queda correr (desde a raíz do papel, permíteme lembralo):

> molecule test

Escape longo baixo o alerón:

--> Validating schema <path>/nginx/molecule/default/molecule.yml.
Validation completed successfully.
--> Test matrix

└── default
    ├── lint
    ├── destroy
    ├── dependency
    ├── syntax
    ├── create
    ├── prepare
    ├── converge
    ├── idempotence
    ├── side_effect
    ├── verify
    └── destroy

--> Scenario: 'default'
--> Action: 'lint'
--> Executing Yamllint on files found in <path>/nginx/...
Lint completed successfully.
--> Executing Flake8 on files found in <path>/nginx/molecule/default/tests/...
Lint completed successfully.
--> Executing Ansible Lint on <path>/nginx/molecule/default/playbook.yml...
Lint completed successfully.
--> Scenario: 'default'
--> Action: 'destroy'

    PLAY [Destroy] *****************************************************************

    TASK [Destroy molecule instance(s)] ********************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Wait for instance(s) deletion to complete] *******************************
    ok: [localhost] => (item=None)
    ok: [localhost]

    TASK [Delete docker network(s)] ************************************************

    PLAY RECAP *********************************************************************
    localhost                  : ok=2    changed=1    unreachable=0    failed=0

--> Scenario: 'default'
--> Action: 'dependency'
Skipping, missing the requirements file.
--> Scenario: 'default'
--> Action: 'syntax'

    playbook: <path>/nginx/molecule/default/playbook.yml

--> Scenario: 'default'
--> Action: 'create'

    PLAY [Create] ******************************************************************

    TASK [Log into a Docker registry] **********************************************
    skipping: [localhost] => (item=None)

    TASK [Create Dockerfiles from image names] *************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Discover local Docker images] ********************************************
    ok: [localhost] => (item=None)
    ok: [localhost]

    TASK [Build an Ansible compatible image] ***************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Create docker network(s)] ************************************************

    TASK [Create molecule instance(s)] *********************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Wait for instance(s) creation to complete] *******************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    PLAY RECAP *********************************************************************
    localhost                  : ok=5    changed=4    unreachable=0    failed=0

--> Scenario: 'default'
--> Action: 'prepare'
Skipping, prepare playbook not configured.
--> Scenario: 'default'
--> Action: 'converge'

    PLAY [Converge] ****************************************************************

    TASK [Gathering Facts] *********************************************************
    ok: [instance]

    TASK [nginx : Install nginx] ***************************************************
    changed: [instance]

    TASK [nginx : Start nginx] *****************************************************
    changed: [instance]

    PLAY RECAP *********************************************************************
    instance                   : ok=3    changed=2    unreachable=0    failed=0

--> Scenario: 'default'
--> Action: 'idempotence'
Idempotence completed successfully.
--> Scenario: 'default'
--> Action: 'side_effect'
Skipping, side effect playbook not configured.
--> Scenario: 'default'
--> Action: 'verify'
--> Executing Testinfra tests found in <path>/nginx/molecule/default/tests/...
    ============================= test session starts ==============================
    platform darwin -- Python 2.7.15, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
    rootdir: <path>/nginx/molecule/default, inifile:
    plugins: testinfra-1.16.0
collected 4 items

    tests/test_default.py ....                                               [100%]

    ========================== 4 passed in 27.23 seconds ===========================
Verifier completed successfully.
--> Scenario: 'default'
--> Action: 'destroy'

    PLAY [Destroy] *****************************************************************

    TASK [Destroy molecule instance(s)] ********************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Wait for instance(s) deletion to complete] *******************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Delete docker network(s)] ************************************************

    PLAY RECAP *********************************************************************
    localhost                  : ok=2    changed=2    unreachable=0    failed=0

O noso sinxelo papel foi probado sen problemas.
Paga a pena lembrar que se hai problemas durante o traballo molecule test, entón se non cambiou a secuencia predeterminada, a Molécula eliminará a instancia.

Os seguintes comandos son útiles para a depuración:

> molecule --debug <command> # debug info. При обычном запуске Молекула скрывает логи.
> molecule converge          # Оставляет инстанс после прогона тестируемой роли.
> molecule login             # Зайти в созданный инстанс.
> molecule --help            # Полный список команд.

Papel existente

Engadir un novo script a un rol existente é dende o directorio de roles cos seguintes comandos:

# полный список доступных параметров
> molecule init scenarion --help
# создание нового сценария
> molecule init scenario -r <role_name> -s <scenario_name>

No caso de que este sexa o primeiro escenario no papel, entón o parámetro -s pódese omitir xa que creará un script default.

Conclusión

Como podes ver, a Molecule non é moi complexa e, usando os teus propios modelos, a implantación dun novo script pódese reducir a editar variables nos cadernos de creación e eliminación de instancias. A molécula intégrase perfectamente cos sistemas CI, o que lle permite aumentar a velocidade de desenvolvemento reducindo o tempo para a proba manual dos libros de xogo.

Grazas pola súa atención. Se tes experiencia en probar roles ansibles e non está relacionado coa Molécula, fálanos nos comentarios!

Fonte: www.habr.com

Engadir un comentario