Hướng dẫn: cách kiểm tra vai trò ansible và tìm hiểu các vấn đề trước khi sản xuất

Xin chào tất cả mọi người!

Tôi làm kỹ sư DevOps trong dịch vụ đặt phòng khách sạn. Ostrovok.ru. Trong bài viết này, tôi muốn nói về kinh nghiệm của chúng tôi trong việc thử nghiệm vai trò ansible.

Tại Ostrovok.ru, chúng tôi sử dụng ansible làm trình quản lý cấu hình. Gần đây, chúng tôi nảy sinh nhu cầu thử nghiệm các vai trò, nhưng hóa ra, không có nhiều công cụ cho việc này - phổ biến nhất có lẽ là khung Molecule, vì vậy chúng tôi quyết định sử dụng nó. Nhưng hóa ra tài liệu của anh ta im lặng về nhiều cạm bẫy. Chúng tôi không thể tìm thấy một hướng dẫn đầy đủ chi tiết bằng tiếng Nga, vì vậy chúng tôi quyết định viết bài báo này.

Hướng dẫn: cách kiểm tra vai trò ansible và tìm hiểu các vấn đề trước khi sản xuất

Phân tử

phân tử - một khuôn khổ để giúp kiểm tra vai trò ansible.

Mô tả đơn giản: Phân tử tạo một phiên bản trên nền tảng mà bạn chỉ định (đám mây, máy ảo, bộ chứa; để biết thêm chi tiết, hãy xem phần Người lái xe), chạy vai trò của bạn trên đó, sau đó chạy thử nghiệm và xóa phiên bản. Trong trường hợp không thực hiện được một trong các bước, Molecule sẽ thông báo cho bạn về điều đó.

Bây giờ nhiều hơn.

Một chút lý thuyết

Hãy xem xét hai thực thể chính của Phân tử: Kịch bản và Trình điều khiển.

Kịch bản

Kịch bản chứa một mô tả về cái gì, ở đâu, như thế nào và theo trình tự nào sẽ được thực hiện. Một vai trò có thể có nhiều tập lệnh và mỗi tập lệnh là một thư mục dọc theo đường dẫn <role>/molecule/<scenario>, chứa các mô tả về các hành động cần thiết cho thử nghiệm. Tập lệnh phải được bao gồm default, sẽ được tạo tự động nếu bạn khởi tạo vai trò bằng Phân tử. Tên của các tập lệnh sau tùy thuộc vào bạn.

Trình tự các hành động thử nghiệm trong một tập lệnh được gọi là ma trận, và theo mặc định nó là:

(Các bước có nhãn ?, được bỏ qua theo mặc định nếu người dùng không chỉ định)

  • lint - chạy linters. Theo mặc định được sử dụng yamllint и flake8,
  • destroy - xóa các phiên bản từ lần khởi chạy cuối cùng của Phân tử (nếu có),
  • dependency? - cài đặt phụ thuộc ansible của vai trò được thử nghiệm,
  • syntax - kiểm tra cú pháp của vai trò bằng cách sử dụng ansible-playbook --syntax-check,
  • create - tạo một ví dụ,
  • prepare? - chuẩn bị ví dụ; ví dụ: kiểm tra/cài đặt python2
  • converge — ra mắt playbook đang được thử nghiệm,
  • idempotence - khởi động lại playbook cho bài kiểm tra idempotency,
  • side_effect? - hành động không liên quan trực tiếp đến vai trò, nhưng cần thiết cho các bài kiểm tra,
  • verify - chạy thử nghiệm cấu hình kết quả bằng cách sử dụng testinfra(mặc định) /goss/inspec,
  • cleanup? - (trong các phiên bản mới) - đại khái là "làm sạch" cơ sở hạ tầng bên ngoài bị ảnh hưởng bởi Phân tử,
  • destroy - Xóa một thể hiện.

Trình tự này áp dụng cho hầu hết các trường hợp, nhưng có thể thay đổi nếu cần thiết.

Mỗi bước trên có thể được chạy riêng với molecule <command>. Nhưng cần hiểu rằng đối với mỗi lệnh cli như vậy có thể có chuỗi hành động riêng mà bạn có thể tìm ra bằng cách thực hiện molecule matrix <command>. Ví dụ, khi chạy lệnh converge (chạy playbook đang được kiểm tra), các hành động sau sẽ được thực hiện:

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

Trình tự của các hành động này có thể được chỉnh sửa. Nếu một cái gì đó từ danh sách đã được thực hiện, nó sẽ bị bỏ qua. Trạng thái hiện tại cũng như config của các instance thì Molecule lưu trong thư mục $TMPDIR/molecule/<role>/<scenario>.

Thêm các bước với ? bạn có thể mô tả các hành động mong muốn ở định dạng ansible-playbook và đặt tên tệp theo bước: prepare.yml/side_effect.yml. Mong đợi các tệp này Phân tử sẽ nằm trong thư mục tập lệnh.

Người lái xe

Trình điều khiển là một thực thể nơi các phiên bản thử nghiệm được tạo.
Danh sách các trình điều khiển tiêu chuẩn mà Molecule có sẵn các mẫu như sau: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.

Trong hầu hết các trường hợp, các mẫu là các tệp create.yml и destroy.yml trong thư mục script mô tả việc tạo và xóa một phiên bản tương ứng.
Các trường hợp ngoại lệ là Docker và Vagrant, vì tương tác với các mô-đun của chúng có thể xảy ra mà không có các tệp nói trên.

Cần làm nổi bật trình điều khiển được ủy quyền, vì nếu nó được sử dụng trong các tệp để tạo và xóa một phiên bản, thì chỉ hoạt động với cấu hình của các phiên bản được mô tả, phần còn lại sẽ do kỹ sư mô tả.

Trình điều khiển mặc định là Docker.

Bây giờ hãy chuyển sang thực hành và xem xét các tính năng khác ở đó.

Bắt đầu

Với tư cách là "xin chào thế giới", hãy thử nghiệm vai trò cài đặt nginx đơn giản. Chúng tôi sẽ chọn docker làm trình điều khiển - Tôi nghĩ rằng hầu hết các bạn đã cài đặt nó (và hãy nhớ rằng docker là trình điều khiển mặc định).

Chuẩn bị virtualenv và cài đặt trong đó molecule:

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

Bước tiếp theo là khởi tạo vai trò mới.
Khởi tạo vai trò mới, cũng như tập lệnh mới, được thực hiện bằng lệnh 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

Nó hóa ra là một vai trò ansible điển hình. Hơn nữa, tất cả các tương tác với Phân tử CLI đều được thực hiện từ gốc của vai trò.

Hãy xem có gì trong thư mục vai trò:

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

1 directory, 6 files

Hãy cùng phân tích cấu hình molecule/default/molecule.yml (chỉ thay thế hình ảnh 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

phụ thuộc

Phần này mô tả nguồn gốc của sự phụ thuộc.

Quan trọng: thiên hà, áp dụng, vỏ bọc.

Shell chỉ là một shell lệnh được sử dụng trong trường hợp galaxy và gilt không đáp ứng nhu cầu của bạn.

Tôi sẽ không ở đây trong một thời gian dài, nó được mô tả trong tài liệu.

trình điều khiển

Tên của người lái xe. Của chúng tôi là docker.

xơ vải

Kẻ nói dối là yamllint.

Các tùy chọn hữu ích trong phần cấu hình này là khả năng chỉ định tệp cấu hình cho yamllint, chuyển tiếp các biến môi trường hoặc vô hiệu hóa kẻ nói dối:

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

nền tảng

Mô tả cấu hình của các thể hiện.
Trong trường hợp docker làm trình điều khiển, Phân tử được lặp lại trong phần này và mỗi phần tử của danh sách có sẵn trong Dockerfile.j2 như một biến item.

Trong trường hợp người lái xe yêu cầu create.yml и destroy.yml, phần có sẵn trong chúng như molecule_yml.platformsvà các lần lặp lại nó đã được mô tả trong các tệp này.

Vì Phân tử cung cấp quyền kiểm soát các phiên bản cho các mô-đun ansible, nên bạn cũng nên tìm kiếm danh sách các cài đặt khả thi ở đó. Ví dụ, đối với docker, mô-đun được sử dụng docker_container_module. Những mô-đun được sử dụng trong trình điều khiển khác có thể được tìm thấy trong tài liệu.

Cũng như các ví dụ về việc sử dụng các trình điều khiển khác nhau có thể được tìm thấy trong các bài kiểm tra của chính Phân tử.

Thay thế ở đây xu:7 trên ubuntu.

người cung cấp

"Nhà cung cấp" - một thực thể quản lý các phiên bản. Trong trường hợp của Molecule, đây là ansible, hỗ trợ cho những người khác không được lên kế hoạch, vì vậy phần này có thể được gọi là cấu hình mở rộng ansible với một lời cảnh báo.
Ở đây bạn có thể chỉ định rất nhiều thứ, theo ý kiến ​​​​của tôi, tôi sẽ nhấn mạnh những điểm chính:

  • sách chơi: bạn có thể chỉ định playbook nào sẽ được sử dụng ở các giai đoạn nhất định.

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'"

  • lựa chọn: Tùy chọn Ansible và biến môi trường

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

kịch bản

Tên và mô tả các chuỗi kịch bản.
Bạn có thể thay đổi ma trận hành động mặc định của bất kỳ lệnh nào bằng cách thêm phím <command>_sequence và như một giá trị cho nó bằng cách xác định danh sách các bước chúng ta cần.
Giả sử chúng ta muốn thay đổi chuỗi hành động khi chạy lệnh playbook run: molecule converge

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

kiểm định

Thiết lập một khuôn khổ cho các bài kiểm tra và một kẻ nói dối về nó. Kẻ nói dối mặc định là testinfra и flake8. Các tùy chọn có thể giống như trên:

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

Hãy trở lại với vai trò của chúng ta. Hãy chỉnh sửa tập tin tasks/main.yml đến loại này:

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

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

Và thêm các bài kiểm tra vào 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")

Xong, nó chỉ còn lại để chạy (từ thư mục gốc của vai trò, hãy để tôi nhắc bạn):

> molecule test

Ống xả dài dưới cánh lướt gió:

--> 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

Vai trò đơn giản của chúng tôi đã được thử nghiệm mà không gặp vấn đề gì.
Điều đáng ghi nhớ là nếu có vấn đề trong quá trình làm việc molecule test, thì nếu bạn không thay đổi trình tự mặc định, thì Phân tử sẽ xóa phiên bản.

Các lệnh sau rất hữu ích cho việc gỡ lỗi:

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

Vai trò hiện tại

Thêm tập lệnh mới vào vai trò hiện có là từ thư mục vai trò với các lệnh sau:

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

Trong trường hợp đây là kịch bản đầu tiên trong vai trò, thì tham số -s có thể được bỏ qua vì nó sẽ tạo ra một kịch bản default.

Kết luận

Như bạn có thể thấy, Phân tử không phức tạp lắm và bằng cách sử dụng các mẫu của riêng bạn, việc triển khai một tập lệnh mới có thể được rút gọn thành việc chỉnh sửa các biến trong sách hướng dẫn tạo và xóa phiên bản. Phân tử này tích hợp liền mạch với các hệ thống CI, cho phép bạn tăng tốc độ phát triển bằng cách giảm thời gian kiểm tra sách giải trí theo cách thủ công.

Cám ơn vì sự quan tâm của bạn. Nếu bạn có kinh nghiệm kiểm tra các vai trò ansible và nó không liên quan đến Phân tử, hãy cho chúng tôi biết về điều đó trong các nhận xét!

Nguồn: www.habr.com

Thêm một lời nhận xét