Comments 44
Недавно столкнулся с тем, что ansible, как-то странно понимает секции include и block в шабонах. Приходилось использовать?
Сразу скажу, не копал глубоко.
Есть куча конфигов nginx с обшей частью, я попытался загнать общую часть в файлик, но не вышло. Что-то подобное в джанге было на урра.
{% set upstream_name = item.name + "_upstream" %}
{% set server_name = item.name + "-" + item.type + "-" + base_domain %}
{% set root_dir = build_dest + "/" + item.type + "/" + item.name + "/htdocs;" %}
Include нужен для того чтобы инклудить файлы с тасками в плебуках/ролях.
Block нужен что объединять группы тасков в блоки с некими общими условиями (when: something).
Тут вы пишите кусок jinja-шаблона. Теперь мне совсем не понятен контекст. :)
github.com/le9i0nx/ansible-rspamd/blob/master/templates/etc/rspamd/conf.d/default.conf.j2
код#{{ ansible_managed }}
{% if item.data is mapping %}
{% for key, value in item.data|dictsort %}
{% set tabs = [] %}
{% for i in tabs %}{{i}}{% endfor %}{{ key }} {
{% include 'nested_structure.j2' %}
{% for i in tabs %}{{i}}{% endfor %}}
{% endfor %}
{% endif %}
а теперь магия инклуд самого себя
github.com/le9i0nx/ansible-rspamd/blob/master/templates/etc/rspamd/conf.d/nested_structure.j2
код{% if value is mapping %}
{% set tabs = tabs + [' '] %}
{% for key, value in value|dictsort %}
{% if key == 'raw' %}
{% for listes in value %}
{% for i in tabs %}{{i}}{% endfor %}{{ listes }}
{% endfor %}
{% elif value is number %}
{% for i in tabs %}{{i}}{% endfor %}{{ key }} = {{ value }};
{% elif value is string %}
{% for i in tabs %}{{i}}{% endfor %}{{ key }} = "{{ value }}";
{% elif value is iterable %}
{% if value is mapping %}
{% for i in tabs %}{{i}}{% endfor %}{{ key }} {
{% include 'nested_structure.j2' %}
{% for i in tabs %}{{i}}{% endfor %}}
{% else %}
{% for listes in value %}
{% if listes is mapping %}
{% set value = listes %}
{% for i in tabs %}{{i}}{% endfor %}{{ key }} {
{% include 'nested_structure.j2' %}
{% for i in tabs %}{{i}}{% endfor %}}
{% else %}
{% for i in tabs %}{{i}}{% endfor %}{{ key }} = "{{ listes }}«1;
{% endif %}
{% endfor %}
{% endif %}
{% else %}
{% for i in tabs %}{{i}}{% endfor %}{{ key }} = {{ value }};
{% endif %}
{% endfor %}
{% endif %}
вообще некоторые вещи в шаблонах работают не ожидаемо
с чем приходится считатся
Есть определенные тонкости, но их понимание приходит со временем, после третьей, четвертой ревизии ваших ролей.
Поэтому у каждого свои «best practices» их нельзя получить и усвоить разом из какой-нибудь статейки.
К примеру, как делать не надо, потому что дебажить сложно, но это самый удобный способ передать в параметр servers
нужные данные в том виде, которая она ожидает, но чтобы это была другая переменная:
haproxy_backends:
- name: prometheus_api
balance: leastconn
mode: http
servers: |
[{% for host in prometheus_hosts %}
{{ '{' }}
'name': '{{ host.name }}',
'ip': '{{ host.ip }}',
'port': 9090,
'params': {{ host.params }},
'maxconn': 1000
{{ '}' }}
{% if not loop.last %},{% endif %}
{% endfor %}]
Сама переменная:
prometheus_hosts:
- name: prometheus1.example.com
ip: 10.54.254.43
params: "['check']"
- name: prometheus2.example.com
ip: 10.54.28.210
params: "['check', 'backup']"
Лучше всего этот костыль использовать на данных из setup типа ansible_fqdn. Делаешь setup для всех бэкендов и подставляешь их адреса сюда, миную лишнюю переменную.
Ну или про многие фильтры народ вообще не знает, типа default(omit), mandatory или combine.
В общем надо почаще заглядывать в документацию она обновляется с каждым релизом.
[defaults]
hash_behaviour = merge
Очень удобно.
Тоже перелазил с шефа и очень удивился стандартному поведению (replace
). Прописал себе merge
, но немного смущает документация:
We generally recommend not using this setting unless you think you have an absolute need for it, and playbooks in the official examples repos do not use this setting
1) rpm/deb-дистрибутивы имеют разные название пакетов, пути до конфигов
- include: {{ ansible_distribution }}.yml
Я выношу специфичные данные в отдельный файл.
2) разные сегменты сети имеют разные ntp, nameserver…
group_vars
- all
- dmz
# inventory
[dmz:children]
dmz_group1
А тут использую групповые переменные и inventory
Есть ли более красивое решение?
Установка/удаление ПО;
Конфигурирование ПО;
Деплой кода вашего ПО;
Stateless система под это дело совсем не подходит, поскольку нельзя делать откат ревизий, и, как следствие, нормальное A/B проходит мимо.
Кроме того, у них в гайдлайне написано, дескать: не делайте параметризированных ролей, лучше копипаста.
И получается, что сделать обычную роль для nginx с темплейтами и инклудами конфигов, которая в рамках одного inventory намазывается по разным серверам, — это целая, блин, задача с юнит-тестам, бл.
Создание/удаление контейнеров/виртуальных машин;
Создал, запустил, упал, перезапустил, упал. И так в цикле, пока apdex не просядит и мониторинг не начнёт орать, да? :-}
А стэктрейсы после запуска толстого плэйбука хотя бы на 50+ хостов смотреть? >____<
К примеру, когда в template неправильно указан аргумент src, а изменений много, и вносил их кто-то другой:
An exception occurred during task execution. The full traceback is:
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/ansible/executor/task_executor.py", line 124, in run
res = self._execute()
File "/usr/lib/python2.7/dist-packages/ansible/executor/task_executor.py", line 446, in _execute
result = self._handler.run(task_vars=variables)
File "/usr/lib/python2.7/dist-packages/ansible/plugins/action/template.py", line 80, in run
source = self._loader.path_dwim_relative(self._task._role._role_path, 'templates', source)
File "/usr/lib/python2.7/dist-packages/ansible/parsing/dataloader.py", line 236, in path_dwim_relative
if source.startswith('~') or source.startswith('/'):
AttributeError: 'NoneType' object has no attribute 'startswith'
fatal: [localhost]: FAILED! => {"failed": true, "msg": "Unexpected failure during module execution.", "stdout": ""}
есть желание хранить плейбуки в репозитории прямо рядом с кодом и с ним же бранчеваться. есть опыт такого дела? может ли ansible-playbook выполнять плейбук из определенного бранча? может плагины есть для этого какие…
сам пробовал гуглить, но все что вылезает касается модуля «git» который делает деплой уже непосредственно КОДА из какого-либо репо. а вот чтобы сам конфиг Ансибла… такого не нашел что то…
Тут можно разные подходы использовать. Можно сделать плейбук который будет обновлять сам Ansible и обновлять репо с плейбуками/ролями — дергать его по крону или как pre-task в Jenkins или аналогах.
У меня сейчас миграция с puppet на ansible, и комбинация -i и --limit очень помогает.
В нашем случае:
- Обилие говнокода на puppet, разгребать смысла нет. В текущем состоянии идет постоянное нарастание.
- Наличие центрального сервера и агентов. Что вместе с п1 ведет к серьезным тормозам. Например: запуск агентов был сначала раз в 25 минут, потом раз в 45, потом раз в час, потом раз в 2 часа. Agentless у ansible, считаем это плюсом. А наличие CI позволяет вполне заменять центральный сервер.
- Осознание излищней сложности puppet. Docker+ansible позволяют выкинуть 60% кода без рефакторинга.
- Очень удобная декомпозиция ролей. Соответсвенно всегда можно удобно и быстро выполнить малую роль.
Stateless система под это дело совсем не подходит, поскольку нельзя делать откат ревизий, и, как следствие, нормальное A/B проходит мимо.
Обоснуйте.
Кроме того, у них в гайдлайне написано, дескать: не делайте параметризированных ролей, лучше копипаста.
Что-то не припомню такого. Тыкните в док.
Создал, запустил, упал, перезапустил, упал. И так в цикле, пока apdex не просядит и мониторинг не начнёт орать, да? :-}
О чем это? Неудачные опыты?
А стэктрейсы после запуска толстого плэйбука хотя бы на 50+ хостов смотреть? >____<
К примеру, когда в template неправильно указан аргумент src, а изменений много, и вносил их кто-то другой:
При наличии рук не растущих из плеч и отсутствии привычки тестировать свой код можно добиться и более впечатляющих результатов.
Не советую использовать этот макрос, он включает в себя текущее время и поэтому ломает --check: при каждом прогоне task будет показываться как changed.
У меня при --check не было такой проблемы (ansible 2.0.1.0). Хотя в некоторых версиях думаю такое могло быть.
но у этой строки есть частный случай
когда два разных шаблона накатываются на один файл на сервере тогда будет постоянный changed даже если результат их работы одинаковый
и результат этой строки можно подправить переопределив его в /etc/ansible/ansible.cfg
ansible_managed = Ansible managed: modified on %Y-%m-%d %H:%M:%S
Что нужно сделать что-бы работала следующая схема по переменным различающихся по stages?
Групповые (общие) переменные
- group_vars/
- all/
- common
- secret
- dev/
- common
- secret
- stage/
- common
- secret
- prod/
- common
- secret
- all/
В Плейбуках пропивывате пути к файлам с переменными?
host01
host02
[stage]
host01
host02
[prod]
host01
host02
Очень важная фишка, зависимоти между ролями…
Надо использовать, тогда сами роли будут меньше и проще
Ansible с чего начать