说明:生产前如何测试角色并找出问题

大家好!


我在酒店预订服务Ostrovok.ru中担任DevOps工程师。 在本文中,我想谈谈我们在测试角色扮演方面的经验。


在Ostrovok.ru,我们使用ansible作为配置管理器。 最近,我们提出了测试角色的需求,但事实证明,没有足够的工具可用于此目的-最受欢迎的也许是Molecule框架,因此我们决定使用它。 但是事实证明,他的文档对许多陷阱保持沉默。 我们找不到俄文的足够详细的指南,因此我们决定写这篇文章。



分子


分子 -帮助测试难胜任角色的框架。


简化描述:分子在您指定的平台(云,虚拟机,容器;有关更多详细信息,请参见“ 驱动程序”部分)上创建实例,在其上运行您的角色,然后运行测试并删除该实例。 如果其中一个步骤失败,分子将通知您。


现在更详细。


一点理论


考虑分子的两个关键实体:场景和驱动程序。


情境


该脚本包含将执行的内容,位置,方式和顺序的描述。 一个角色可以具有多个脚本,每个脚本都位于路径<role>/molecule/<scenario> ,其中包含测试所需动作的描述。 必须存在default脚本,如果您使用Molecule初始化角色,则会自动创建该脚本。 您可以自行选择以下方案的名称。


脚本中的测试序列称为matrix ,默认情况下如下:


(如果用户未描述,则默认情况下会跳过标有?步骤)


  • lint -运行短绒lint 。 默认情况下,使用yamllintflake8
  • destroy -从上一次分子发射中删除实例(如果有的话),
  • dependency ? -安装受测角色的ansible依赖性,
  • syntax -使用ansible-playbook --syntax-check角色的语法,
  • create -创建一个实例,
  • prepare ? -实例的准备; 例如检查/安装python2
  • converge -推出经过测试的剧本,
  • idempotence -重新启动剧本进行幂等性测试,
  • side_effect吗? -与角色没有直接关系,但对于测试是必需的动作,
  • verify -使用testinfra (默认)/ inspec / inspec对结果配置进行测试,
  • cleanup ? -(在新版本中)-粗略地说,“清洗”受分子影响的外部基础设施,
  • destroy -删除实例。

此顺序适用于大多数情况,但是您可以根据需要进行更改。


以上每个步骤都可以使用molecule <command>单独运行。 但是值得了解的是,对于每个这样的cli命令,通过执行molecule matrix <command> ,您可能都可以识别出一系列动作。 例如,当您运行converge命令(运行经过测试的剧本)时,将执行以下操作:


 $ molecule matrix converge ... └── default #   ├── dependency #   ├── create #   ├── prepare #   └── converge #   

这些动作的顺序可以编辑。 如果列表中的内容已经完成,则将被跳过。 当前状态以及实例配置存储在$TMPDIR/molecule/<role>/<scenario>目录中。


?添加步骤 您可以用ansible-playbook格式描述所需的操作,然后按照以下步骤创建文件名: side_effect.yml / side_effect.yml 。 分子将等待脚本文件夹中的这些文件。


司机


驱动程序是创建测试实例的实体。
分子已准备好模板的标准驱动程序如下:Azure,Docker,EC2,GCE,LXC,LXD,OpenStack,Vagrant,Delegated。


在大多数情况下,模板是脚本文件夹中的create.ymldestroy.yml ,分别描述了实例的创建和删除。
Docker和Vagrant例外,因为在没有上述文件的情况下可以与其模块进行交互。


值得强调一下Delegated驱动程序,因为如果在文件中使用它来创建和删除实例,则仅描述了实例的配置,其余的应由工程师描述。


默认驱动程序是Docker。


现在我们转向实践并考虑那里的其他功能。


开始使用


作为“ hello world”,我们测试了安装nginx的简单作用。 我们将选择docker作为驱动程序-我认为它已安装在大多数人中(请记住docker是默认驱动程序)。


准备virtualenv并在其中安装molecule


 > pip install virtualenv > virtualenv -p `which python2` venv > source venv/bin/activate > pip install molecule docker # molecule  ansible  ; docker   

下一步是初始化一个新角色。
新的角色以及新场景的molecule init <params>是使用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 

结果是一个典型的角色。 此外,与CLI分子的所有交互都是从角色的根源开始的。


让我们看看角色目录中的内容:


 > tree molecule/default/ molecule/default/ ├── Dockerfile.j2 # Jinja-  Dockerfile ├── INSTALL.rst. #       ├── molecule.yml #   ├── playbook.yml #    └── tests #     verify └── test_default.py 1 directory, 6 files 

让我们分析一下molecule/default/molecule.yml配置(我们将仅替换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 

依赖


本节描述了依赖项的来源。


可能的选项: 银河系镀金面 ,外壳。


外壳程序只是命令外壳程序,如果银河和镀金不满足您的需求,则可以使用该外壳程序。


我不会在这里停留很长时间,在文档中对此进行了足够的描述


司机


驱动程序的名称。 我们有这个码头工人。


皮棉


作为短绒,使用yamllint。


在配置的这一部分中,有用的选项是为yamllint指定配置文件,转发环境变量或禁用linter的功能:


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

平台


描述实例的配置。
如果将docker作为驱动程序,则在此部分上迭代Molecule,并且Dockerfile.j2中的每个列表项Dockerfile.j2作为item变量使用。


对于destroy.yml create.ymldestroy.yml的驱动程序,该部分在它们中的名称为destroy.yml ,这些文件中已经描述了该版本。


由于Molecule为ansible模块提供了实例控制,因此必须在此处查找可能的设置列表。 例如,对于docker ,使用docker_container_module模块。 可以在文档中找到其他驱动程序中使用了哪些模块。


在分子本身的测试中也可以找到使用各种驱动程序的示例。


替换centos:此处ubuntu上的 7


供应者


“提供者”是控制实例的实体。 在分子的情况下,这是ansible的,没有计划为他人提供支持,因此可以保留保留地将其扩展配置为ansible。
在这里,您可以指定很多东西,我认为主要是重要的时刻:


  • 剧本 :您可以指定在某些阶段应使用的剧本。

 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 

  • connection_options连接参数

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

  • options :Ansible选项和环境变量

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

情景


脚本序列的名称和描述。
您可以<command>_sequence添加<command>_sequence并确定我们需要作为其值的步骤列表来更改<command>_sequence的默认操作矩阵。
假设我们要在运行playbook run命令时更改操作顺序: molecule converge


 # : # - dependency # - create # - prepare # - converge scenario: name: default converge_sequence: - create - converge 

验证者


设置测试框架和测试框架。 默认情况下, testinfraflake8用作flake8 。 可能的选项与上述类似:


 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 

让我们回到我们的角色。 编辑tasks/main.yml ,如下所示:


 --- - name: Install nginx apt: name: nginx state: present - name: Start nginx service: name: nginx state: started 

并将测试添加到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") 

完成后,它仅能运行(我提醒您从角色的根源开始):


 > molecule test 

扰流板下的长排气口:
 --> 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 

我们的简单角色经过了测试,没有任何问题。
值得记住的是,如果在molecule test的操作过程中出现问题,那么如果您没有更改标准序列,则分子将删除该实例。


以下命令对于调试很有用:


 > molecule --debug <command> # debug info.      . > molecule converge #      . > molecule login #    . > molecule --help #   . 

现有角色


使用以下命令从角色目录向现有角色添加新脚本:


 #     > molecule init scenarion --help #    > molecule init scenario -r <role_name> -s <scenario_name> 

如果这是该角色中的第一个脚本,则-s可以省略,因为将创建default脚本。


结论


如您所见,Molecule并不是很复杂,并且在使用自己的模板时,可以减少新脚本的部署,以编辑剧本中的变量来创建和删除实例。 该分子与CI系统无缝集成,可通过减少手动测试剧本所需的时间来提高开发速度。


谢谢您的关注。 如果您有测试角色的经验,并且与分子无关,请在评论中告诉我们!

Source: https://habr.com/ru/post/zh-CN448136/


All Articles