Desenvolvendo e testando funções compatíveis usando Molecule e Podman

Uma das principais vantagens da plataforma de automação Red Hat Ansible é que sua linguagem de automação pode ser lida não apenas por alguns gurus, mas também por quase todos os envolvidos em TI. Portanto, qualquer especialista pode contribuir para a automação, o que facilita muito a organização da interação entre as equipes e a implementação da automação no nível da cultura corporativa.







No entanto, com tanta massa de pessoas envolvidas, é muito importante testar tudo minuciosamente. Ao desenvolver o conteúdo do Ansible, como manuais, funções ou coleções, é altamente recomendável que você teste tudo em um ambiente de teste antes de lançar para a produção. O objetivo deste teste é ter certeza de que tudo está funcionando como deveria, para evitar surpresas desagradáveis ​​em sistemas de "produção".



Testar conteúdo de automação é complicado porque requer a implantação de uma infraestrutura de teste dedicada e a configuração de condições de teste para garantir que os próprios testes sejam relevantes. Molecule é uma estrutura de teste abrangente que o ajuda a desenvolver e testar funções Ansible para que você possa se concentrar no desenvolvimento de automação sem se distrair com o gerenciamento de sua infraestrutura de teste.



É assim que está declarado na documentação do projeto:



"O Molecule foi projetado para ajudar a desenvolver e testar as funções do Ansible e promove uma abordagem que resulta em funções bem escritas, fáceis de entender e manter."


O Molecule permite que você teste uma função em várias instâncias de destino para testá-la em uma variedade de sistemas operacionais e ambientes de virtualização. Sem ele, para cada uma dessas combinações, você teria que criar e manter um ambiente de teste separado, configurar conexões para testar instâncias e reverter para seu estado original antes de cada teste. O Molecule faz tudo por você, de forma automatizada e reproduzível.



Nesta série de duas partes, mostraremos como usar o Molecule para desenvolver e testar funções de Ansible. Na primeira parte, veremos como instalar e configurar o Molecule, na segunda, desenvolver funções com ele.



Se a função fizer parte de uma coleção, use esta abordagem para desenvolver e testar a unidade. No próximo artigo, mostraremos como usar o Molecule para executar testes integrados em coleções.



Molecule usa drivers para fornecer instâncias de destino em uma variedade de tecnologias, incluindo contêineres Linux, máquinas virtuais e provedores de nuvem. Por padrão, ele vem com três drivers pré-instalados: Docker e Podman para contêineres, bem como um driver Delegado para criar integrações personalizadas. Os drivers para outros provedores são fornecidos pela comunidade de desenvolvimento do projeto.



Neste post estaremos usando o driver Podmanpara desenvolver e testar uma nova função usando contêineres Linux. O Podman é um mecanismo de contêiner leve para Linux, não precisa de um daemon em execução e permite que contêineres sem raiz sejam executados, o que é bom para a segurança.



Usando o Molecule com o driver Podman, iremos desenvolver e testar uma nova função Ansible do zero que implanta um aplicativo da web baseado em um servidor da web Apache e deve ser executado no Red Hat Enterprise Linux (RHEL) 8 ou Ubuntu 20.04.



Estamos analisando um cenário típico em que uma função deve funcionar em diferentes versões do sistema operacional. Usando contêineres Podman e Linux, podemos criar várias instâncias para testar a função em diferentes versões do sistema operacional. Por causa de sua leveza, os contêineres permitem que você itere rapidamente por meio da funcionalidade de uma função durante o desenvolvimento. O uso de contêineres para funções de teste é aplicável nesta situação, uma vez que a função configura apenas instâncias do Linux em execução. Para testar em outros sistemas de destino ou infraestruturas de nuvem, você pode usar o driver delegado ou outros drivers fornecidos pela comunidade.



O que nós precisamos



Para os exemplos neste artigo, você precisa de uma máquina Linux física ou virtual com Python 3 e Podman instalados (estamos usando RHEL 8.2). O Podman também teve que ser configurado para executar contêineres sem raiz. A instalação do Podman está além do escopo deste artigo, consulte a documentação oficial para obter informações relacionadas . A instalação do Podman no RHEL 8 também é abordada na documentação do contêiner RHEL 8 .



Vamos começar



O Molecule foi projetado como um pacote Python e, portanto, é instalado via pip. A primeira etapa é criar um ambiente Python dedicado e instalar nosso Molecule nele:



$ mkdir molecule-blog
$ cd molecule-blog
$ python3 -m venv molecule-venv
$ source molecule-venv/bin/activate
(molecule-venv) $ pip install "molecule[lint]"


Observe que estamos instalando o Molecule com a opção "lint" para que o pip também forneça as ferramentas "yamllint" e "ansible-lint", o que nos permitirá usar o Molecule para analisar estaticamente o código de função em relação aos padrões de codificação Ansible.



A instalação baixa todas as dependências necessárias da Internet, incluindo Ansible. Agora vamos ver o que instalamos:



$ molecule --version
molecule 3.0.4
   ansible==2.9.10 python==3.6


Bem, é hora de usar o comando "molécula" para inicializar a nova função do Ansible.



Inicializando uma nova função Ansible



De modo geral, ao desenvolver um novo papel Ansible, ele é inicializado com o comando "ansible-galaxy role init", mas usaremos o comando "molécula". Isso nos dará a mesma estrutura de funções do comando "ansible-galaxy", bem como um código básico para a execução de testes do Molecule.



Por padrão, o Molecule usa o driver Docker para executar testes. Como queremos usar o podman em vez disso, ao inicializar a função com o comando "molécula", devemos especificar o driver apropriado usando a opção "--driver-name = podman".



Volte para o diretório "molecule-blog" e inicialize a nova função "mywebapp" com o seguinte comando:



$ molecule init role mywebapp --driver-name=podman
--> Initializing new role mywebapp...
Initialized role in /home/ricardo/molecule-blog/mywebapp successfully.


O Molecule cria nossa estrutura de funções na pasta "mywebapp". Mude para esta pasta e veja o que ela contém:



$ cd mywebapp
$ tree
.
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── molecule
│   └── default
│       ├── converge.yml
│       ├── INSTALL.rst
│       ├── molecule.yml
│       └── verify.yml
├── README.md
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml
 
10 directories, 12 files


O Molecule coloca seus arquivos de configuração no subdiretório "molécula". Ao inicializar uma nova função, apenas um script aparece aqui, denominado "padrão". Posteriormente, você pode adicionar seus scripts aqui para testar várias condições. Neste artigo, usaremos apenas o script "padrão".



Vamos verificar a configuração básica no arquivo "molecule / default / molecule.yml":



$ cat molecule/default/molecule.yml 
---
dependency:
  name: galaxy
driver:
  name: podman
platforms:
  - name: instance
    image: docker.io/pycontribs/centos:7
    pre_build_image: true
provisioner:
  name: ansible
verifier:
  name: ansible


Como solicitamos, este arquivo informa que o driver Podman é usado para testes. É aqui que se define a plataforma padrão para a instância de teste, através da imagem do container "docker.io/pycontribs/centos:7", que mudaremos mais tarde.



Ao contrário do Molecule v2, o Molecule v3 não define um linter padrão. Portanto, vamos abrir o arquivo de configuração "molécula / padrão / molécula.yml" e adicionar a configuração do lint no final:



$ vi molecule/default/molecule.yml
...
verifier:
  name: ansible
lint: |
  set -e
  yamllint .
  ansible-lint .


Salve e feche o arquivo e execute o comando "molecule lint" na pasta raiz do nosso projeto para executar o linter em todo o projeto:



$ molecule lint


Obtemos alguns erros na saída, pois o arquivo "meta / main.yml" não contém alguns valores obrigatórios. Vamos corrigir isso: edite o arquivo "meta / main.yml", adicione "autor", "empresa", "licença", "plataformas" e remova a linha em branco no final. Para ser breve, dispensaremos os comentários e, em seguida, nosso "meta / main.yaml" ficará assim:



$ vi meta/main.yml
galaxy_info:
  author: Ricardo Gerardi
  description: Mywebapp role deploys a sample web app 
  company: Red Hat 
 
  license: MIT 
 
  min_ansible_version: 2.9
 
  platforms:
  - name: rhel
    versions:
    - 8 
  - name: ubuntu
    versions:
    - 20.04
 
  galaxy_tags: []
 
dependencies: []


Vamos executar o linter no projeto novamente e garantir que não haja mais erros.



$ molecule lint
--> Test matrix
    
└── default
    ├── dependency
    └── lint
    
--> Scenario: 'default'
--> Action: 'dependency'
Skipping, missing the requirements file.
Skipping, missing the requirements file.
--> Scenario: 'default'
--> Action: 'lint'
--> Executing: set -e
yamllint .
ansible-lint . 


Então, nosso papel é inicializado e a configuração básica da molécula também está no lugar. Agora vamos criar uma instância de teste.



Crie uma instância de teste



Por padrão, Molecule define apenas uma instância, que é chamada de "instância" e é criada a partir da imagem "Centos: 7". Nossa função, se você se lembra, deve funcionar no RHEL 8 e no Ubuntu 20.04. Além disso, como ele executa o servidor da web Apache como um serviço do sistema, precisamos de uma imagem de contêiner com "systemd" habilitado.



A Red Hat tem uma imagem de base universal oficial para RHEL 8 com "systemd" habilitado:



• registry.access.redhat.com/ubi8/ubi-init



Não há imagem oficial "systemd" para Ubuntu, então usaremos uma imagem mantida por Jeff Geerling (Jeff Geerling) da comunidade Ansible:



• geerlingguy / docker-ubuntu2004-ansible



Para obter instâncias com "systemd", vamos editar o arquivo de configuração "molecule / default / molecule.yml" removendo a instância "centos: 7" dele e adicionando duas novas instâncias:



$ vi molecule/default/molecule.yml
---
dependency:
  name: galaxy
driver:
  name: podman
platforms:
  - name: rhel8
    image: registry.access.redhat.com/ubi8/ubi-init
    tmpfs:
      - /run
      - /tmp
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    capabilities:
      - SYS_ADMIN
    command: "/usr/sbin/init"
    pre_build_image: true
  - name: ubuntu
    image: geerlingguy/docker-ubuntu2004-ansible
    tmpfs:
      - /run
      - /tmp
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    capabilities:
      - SYS_ADMIN
    command: "/lib/systemd/systemd"
    pre_build_image: true
provisioner:
  name: ansible
verifier:
  name: ansible
lint: |
  set -e
  yamllint .
  ansible-lint .


Com estes parâmetros montamos para cada instância o sistema de arquivos temporário "/ run" e "/ tmp", bem como o volume "cgroup". Além disso, incluímos a função "SYS_ADMIN", necessária para executar contêineres com Systemd.



Se você fizer tudo de forma inteligente e executar este exemplo em uma máquina RHEL 8 com SELinux habilitado, então você também precisa definir o parâmetro booleano "container_manage_cgroup" como verdadeiro para que os contêineres possam executar o Systemd (consulte a documentação do RHEL 8 para mais detalhes ):



sudo setsebool -P container_manage_cgroup 1


O Molecule usa o Ansible Playbook para inicializar essas instâncias. Vamos alterar e adicionar os parâmetros de inicialização, modificando o dicionário "provisioner" no arquivo de configuração "molecule / default / molecule.yml".



Ele aceita as mesmas opções de configuração especificadas no arquivo de configuração "ansible.cfg". Por exemplo, vamos atualizar a configuração do provisionador adicionando uma seção "padrões". Defina o interpretador Python como "auto_silent" para desativar os avisos. Vamos incluir os plug-ins de retorno de chamada "profile_tasks", "timer" e "yaml" para que as informações do criador de perfil sejam incluídas na saída do Playbook. Por fim, adicione a seção "ssh_connection" e desative o pipelining SSH, pois não funciona com o Podman:



provisioner:
  name: ansible
  config_options:
    defaults:
      interpreter_python: auto_silent
      callback_whitelist: profile_tasks, timer, yaml
    ssh_connection:
      pipelining: false


Vamos salvar este arquivo e criar uma instância com o comando "molecule create" do diretório raiz de nossa função:



$ molecule create


Molecule irá executar um playbook init e criar ambas as nossas instâncias. Vamos verificá-los com o comando "lista de moléculas":



$ molecule list
Instance Name    Driver Name    Provisioner Name    Scenario Name    Created    Converged
---------------  -------------  ------------------  ---------------  ---------  -----------
rhel8            podman         ansible             default          true       false
ubuntu           podman         ansible             default          true       false


Também vamos verificar se os dois contêineres estão em execução no Podman:



$ podman ps
CONTAINER ID  IMAGE                                                   COMMAND               CREATED             STATUS                 PORTS  NAMES
2e2f14eaa37b  docker.io/geerlingguy/docker-ubuntu2004-ansible:latest  /lib/systemd/syst...  About a minute ago  Up About a minute ago         ubuntu
2ce0a0ea8692  registry.access.redhat.com/ubi8/ubi-init:latest         /usr/sbin/init        About a minute ago  Up About a minute ago         rhel8


Ao desenvolver uma função, o Molecule usa instâncias em execução para testá-la. Se o teste falhar ou algum erro levar a alterações irreversíveis, por causa das quais tudo tem que ser reiniciado, você pode matar essas instâncias a qualquer momento com o comando "Destruir molécula" e criá-las novamente com o comando "Criar molécula".



Conclusão



Se você está impaciente e deseja se aprofundar no tópico de desenvolvimento e teste de funções ou no tópico de automação Ansible, recomendamos os seguintes recursos:






All Articles