Всем привет!
Мы продолжаем серию заметок, посвященных DevOps и по-прежнему ищем наиболее эффективные способы управления конфигурацией, не прекращая делиться опытом с сообществом хабра. В прошлых статьях мы рассматривали, как можно выстроить процесс управления конфигурацией Ansible с помощью Jenkins и Serverspec. А теперь по рекомендации в комментариях к одной из статей решили рассмотреть, как можно организовать процесс управления конфигурацией с помощью GitLab-CI.
Ansible-lint — это утилита для проверки корректности синтаксиса плейбука, стиля кода, которая может быть интегрирована в CI-сервис. В нашем случае, мы внедряем её в gitlab-ci, для проверки плейбуков на этапе принятия Merge-Request и выставления статуса проверок.
GitLab (GitLab Community Edition) — это opensource-проект, менеджер git-репозиториев, изначально разрабатывающийся как альтернатива платной, корпоративной версии github.
Установка GitLab CE описана в одной из наших прошлых статей.
Установка gitlab-ci-multirunner
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.rpm.sh | sudo bash
yum install gitlab-ci-multi-runner
Регистрация runner
gitlab-ci-multi-runner register
Далее — необходимо ответить на вопросы:
Running in system-mode.
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/ci):
http://domain.example.com/ci
Please enter the gitlab-ci token for this runner:
your_token
Please enter the gitlab-ci description for this runner:
[domain.example.com]:
Please enter the gitlab-ci tags for this runner (comma separated):
ansible
Registering runner... succeeded runner=
Please enter the executor: docker-ssh+machine, docker, docker-ssh, parallels, shell, ssh, virtualbox, docker+machine:
shell
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
Токен и URL можно взять со страницы настроек проекта.
Особенности настройки multi-runner.
Один раннер может обратаывать несколько проектов. Для того, чтоб один раннер обрабатывал всё подряд нужно просто зарегистрировать новый раннер, не указывая теги. Токен для shared-раннера нужно брать в Admin Area:
Можно пачку раннеров разнести по разным серверам.
И ещё: в gitlab, как и в Jenkins, есть такое понятие как теги.
Проект с тегом ansible, будет обрабатывать раннер, помеченный тегом ansible, к примеру. А для других проектов (без метки или с другой меткой) этот раннер работать не будет.
Также, в админке можно настроить соответствие раннера и проекта.
domain.example.com/admin/runners
Установка ansible-lint
ansible-lint можно установить через python-pip или из репозитория epel.
Первый способ:
Первым делом нужно установить python-pip, затем через него поставить ansible-lint:
sudo yum groupinstall @Development Tools
sudo yum install python-pip
sudo pip install --upgrade pip
sudo pip install ansible-lint
Второй способ
Всё просто: ставим epel-release и ставим ansible-lint через пакетный менеджер:
sudo yum install epel-release
sudo yum install ansible-lint
Настройка пайплайна.
Создадим в корне репозитория файл .gitlab-ci.yml (важно соблюдать количество пробелов, иначе будет ошибка, yaml такое не прощает, ага).
stages:
[два пробела]- test
test_job:
[два пробела]stage: test
[два пробела]script:
[четыре пробела]- ansible-lint *.yml
[два пробела]tags:
[четыре пробела]- ansible
stages — описываем стадии сборки проекта (обязательно)
stages:
- stagename
test_job — просто название джоба (может быть произвольным)
stage: test — описывает стадию test, которая указана выше, в секции stages (обязательно)
jobname:
stage: stagename
script — команда, которую выполняем для проведения теста в корне репозитория.
tags — метка для раннера
название стадии (stage: test) может быть произвольным (converge, pre-test, post-test, deploy, да как угодно).
название джоба (test_job) также может быть произвольным.
В GitLab есть встроенный линтер для пайплайнов. Проверить корректность синтаксиса пайплайна можно по URL domain.example.com/ci/lint
Вставляем пайплайн, жмём Validate.
При ошибке линтер будет ругаться и попытается ткнуть носом в ошибку.
(должно быть stages, а не stage)
Таким образом ansible-lint будет автоматически при каждом коммите проверять все плейбуки с расширением .yml из корня репозитория.
У нас в репозитории две роли
roles
+-- monit
L-- openssh
И два плейбука, накатывающих эти роли
+-- monit.yml
+-- openssh.yml
+-- README.md
L-- roles
openssh.yml
---
- hosts: all
user: ansible
become: yes
roles:
- openssh
monit.yml
---
- hosts: all
user: ansible
become: yes
roles:
- monit
Следовательно, проверяя плейбук, присваивающий роль — будет проверено всё содержимое роли:
roles/openssh/tasks/
+-- configure_iptables.yml
+-- configure_monitoring.yml
+-- configure_ssh.yml
L-- main.ym
roles/monit/tasks/
+-- configure_monit.yml
+-- configure_monit_checks.yml
+-- install_monit.yml
L-- main.yml
Теперь, при коммите ansible-lint будет запущен автоматически и проверит все наши роли, перечисленные в плейбуках.
Если попробовать что-нибудь закоммитить и перейти в веб-интерфейс (вкладка pipelines), то можно увидеть джоб в статусе failed.
Для того, чтоб отключить проверки lint'ом при пуше в репозиторий — достаточно вычистить в файле .gittab-ci.yml все стейджи, касающиеся запуска проверок ansible-lint.
Параметры проверки плейбуков также настраиваются:
?->$ ansible-lint --help
Usage: ansible-lint playbook.yml
Options:
--version show program's version number and exit
-h, --help show this help message and exit
-L list all the rules
-q quieter, although not silent output
-p parseable output in the format of pep8
-r RULESDIR specify one or more rules directories using one or
more -r arguments. Any -r flags override the default
rules in /usr/local/lib/python2.7/dist-
packages/ansiblelint/rules, unless -R is also used.
-R Use default rules in /usr/local/lib/python2.7/dist-
packages/ansiblelint/rules in addition to any extra
rules directories specified with -r. There is no need
to specify this if no -r flags are used
-t TAGS only check rules whose id/tags match these values
-T list all the tags
-v Increase verbosity level
-x SKIP_LIST only check rules whose id/tags do not match these
values
--nocolor disable colored output
--exclude=EXCLUDE_PATHS
path to directories or files to skip. This option is
repeatable.
?->$ ansible-lint -L
ANSIBLE0002: Trailing whitespace
There should not be any trailing whitespace
ANSIBLE0004: Git checkouts must contain explicit version
All version control checkouts must point to an explicit commit or tag, not just "latest"
ANSIBLE0005: Mercurial checkouts must contain explicit revision
All version control checkouts must point to an explicit commit or tag, not just "latest"
ANSIBLE0006: Using command rather than module
Executing a command when there is an Ansible module is generally a bad idea
ANSIBLE0007: Using command rather than an argument to e.g. file
Executing a command when there is are arguments to modules is generally a bad idea
ANSIBLE0008: Deprecated sudo
Instead of sudo/sudo_user, use become/become_user.
ANSIBLE0009: Octal file permissions must contain leading zero
Numeric file permissions without leading zero can behavein unexpected ways. See http://docs.ansible.com/ansible/file_module.html
ANSIBLE0010: Package installs should not use latest
Package installs should use state=present with or without a version
ANSIBLE0011: All tasks should be named
All tasks should have a distinct name for readability and for --start-at-task to work
ANSIBLE0012: Commands should not change things if nothing needs doing
Commands should either read information (and thus set changed_when) or not do something if it has already been done (using creates/removes) or only do it if another check has a particular result (when)
ANSIBLE0013: Use shell only when shell functionality is required
Shell should only be used when piping, redirecting or chaining commands (and Ansible would be preferred for some of those!)
ANSIBLE0014: Environment variables don't work as part of command
Environment variables should be passed to shell or command through environment argument
ANSIBLE0015: Using bare variables is deprecated
Using bare variables is deprecated. Update yourplaybooks so that the environment value uses the full variablesyntax ("{{your_variable}}").
Некоторые таски можно пропускать при проверке ( ansible-lint не очень любит модули command и shell, так как в идеологии ansible считается, что штатных core-модулей должно хватить практически для всех задач. На самом деле, это не всегда так ).
К примеру, у нас в роли встречается таск, использующий модуль command:
- name: Installing monit
command:
yum -y install monit
tags: monit
И если пролинтим плейбук с этой ролью, то ansible-lint сругнётся на то, что мы используем модуль command
?->$ ansible-lint monit.yml
[ANSIBLE0002] Trailing whitespace
monit.yml:7
- monit
[ANSIBLE0012] Commands should not change things if nothing needs doing
/tmp/ansible-lint/roles/monit/tasks/install_monit.yml:8
Task/Handler: Installing monit
[ANSIBLE0006] yum used in place of yum module
/tmp/ansible-lint/roles/monit/tasks/install_monit.yml:8
Task/Handler: Installing monit
Для того, чтобы этого избежать — можно пометить таск тегом skip_ansible_lint:
- name: Installing monit
command:
yum -y install monit
tags: monit,skip_ansible_lint
Теперь при прогоне lint'а по плейбуку он не будет ругаться на используемый модуль command:
?->$ ansible-lint monit.yml
[ANSIBLE0002] Trailing whitespace
monit.yml:7
- monit
Особенности Merge Request.
Забегая вперёд, пару слов о функционале проверок в MR.
По-умолчанию, merge-request может быть принят только в том случае, если проверка прошла успешно.
Отключить это можно в настройках проекта, в разделе Merge Requests:
Ansible-lint также можно запустить на локалхосте, не делая коммиты и не дожидаясь проверки CI-сервисом. Если у Вас на десктопе Linux или OS X — просто установите его к себе.
Примеры коммитов с ошибкой, как это выглядит в gitlab.
1. Открываем файл во встроенном редакторе GitLab:
2. Делаем изменения. К примеру, yaml очень чувствителен к пробелам, попробуем добавить лишний пробел в начале какой-нибудь строки:
Жмём Commit Changes, возвращаемся к изменённому файлу. Справа сверху появится пиктограмма со статусом проверки:
сейчас она в статусе Pending — так как проверка ещё не завершена.
Если ткнуть на пиктограмму — перейдем к статусу проверки нашего свежесделанного коммита:
Он сейчас в статусе Failed, так как мы умышленно допустили ошибку в синтаксисе.
Если ткнуть на пиктограмму Failed, то мы сможем увидеть результат работы ansible-lint:
Также, можно прилепить симпатичный баджик со статусом сборки в README.md
[![build status](http://domain.example.com/projectname/badges/master/build.svg)](http://domain.example.com/projectname/commits/master)
Взять его можно в настройках проекта, в разделе CI/CD Pipelines
Теперь статус проверки будет отображаться на главной странице проекта
Копипастим маркдаун и добавляем в README.md в корне проекта, коммитим, теперь статус проверки будет отображаться на главной странице проекта:
Зеленый / Passed — если проверка прошла успешна.
Красный / Failed — если проверка завершилась с ошибкой.
Также во вкладке Pipelines можно посмотреть статусы всех коммитов:
Таким образом, мы выстроили процесс контроля корректности синтаксиса при управлении конфигурацией.
Спасибо за внимание и всем удачной автоматизации!
Поделиться с друзьями