Ansible с чего начать

    В последние пару лет я все чаще использую Ansible для решения практически любых задач связанных с автоматизацией, будь то конфигурирование, резервное копирование или деплой проектов. Не смотря на то, что система очень хорошо документирована, я думаю смогу добавить немного полезной информации для тех кто еще только начинает пользоваться Ansible. Для начала я хотел бы рассказать об основных вещах, таких как структура проекта в котором будут содержаться плейбуки, роли, переменные, шаблоны и файлы необходимые для автоматизации развертывания серверов, кода и всего другого, что можно сделать с помощью Ansible.

    Итак, Ansible это очень гибкий и легкий инструмент для написания сценариев автоматизации любой сложности. Вы можете описать в нем как простое окружение разработчика так сложную структуру крупного проекта с несколькими окружениями (dev/stage/prod).

    Как мне видится с Ansible можно решать следующие задачи:

    • Установка/удаление ПО;
    • Конфигурирование ПО;
    • Создание/удаление пользователей;
    • Контроль пользовательских паролей/ключей;
    • Создание/удаление контейнеров/виртуальных машин;
    • Деплой кода вашего ПО;
    • Запуск различных скриптов/тестов.

    Пара замечаний для тех кто еще не знаком с Ansible:
    — Прежде чем приступить к написанию плейбуков/ролей вам нужно почитать документацию Ansible-playbook, Ansible-role и научиться понимать YAML-syntax (это очень просто);
    — Также стоит сразу сказать, что лучше вести разработку в git-репозитории, поэтому не поленитесь обзавестись аккаунтом на github или заведите локальный git-repo (mercurial, svn, etc). Если вы еще не научились пользоваться git, то сейчас самое время.

    На мой взгляд, Ansible гораздо проще и легче для «усвоения» чем puppet и chef (мне доводилось использовать и то и другое) хоть это и немного разные продукты. После того как вы ознакомились с введением и заглянули в Module Index, вы уже можете начинать писать плейбуки которые заметно облегчат вам жизнь.

    Пример плейбука для распространения вашего ssh pub-key на серверы:
    # file: keys.yml
    ---
    - hosts: app-servers
      tasks:
      - name: Set up authorized_keys for the backup user # Всегда указывайте подробные имена для тасков, так будет вам проще читать вывод и понятнее для коллег что вы хотите здесь сделать.
        authorized_key: user=backup key="{{ item }}"
        with_file:
        - keys/backup.pub
    ...

    ansible-playbook playbooks/keys.yml

    Это все понятно, но что дальше?

    Расширенная структура проекта

    Если хотите описывать структуру более или менее сложного проекта с n-tier архитектурой, стоит сразу определиться со списком групп хостов по ролям и на основании этого прикинуть какие задачи должны быть общими для всех хостов (например подключение репозиториев, создание пользователей и т.д.), а какие частные (конфигурирование nginx, mysql, создние python venv и т.д.) и исходя из этого начинать писать роли начиная с базовой общей роли постепенно переходя к частным.

    Расширенная структура проекта может включать в себя:
    • Переменные (общие и частные);
    • Плейбуки (сценарии);
    • Роли (структурированные плейбуки);
    • Списки групп хостов (inventory).

    Список групп хостов (inventory)

    Если вы хотите иметь несколько окружений то придется завести несколько файлов inventory, по умолчанию (в deb-пакете) в конфиге ansible.cfg используется файл hosts (/etc/ansible/hosts). Путь к inventory не обязательно прописывать в конфиге можно задавать разные файлы с ключом -i.

    Чтобы логика описанная в ваших ролях или плейбуках работала одинаково на разных окружениях заводите группы с одинаковыми именами для всех окружений, например:

    Production inventory
    # file: production
    
    [app-servers:children]
    app-php-servers
    app-python-servers
    
    [app-php-servers]
    appserv-01.example.com
    appserv-03.example.com
    
    [app-python-servers]
    appserv-02.example.com
    appserv-04.example.com
    
    [db-servers]
    dbserv-[01:02].example.com
    
    [cdn]
    cdn-[01:03].example.com
    
    [app-servers:vars]
    env=PROD
    ansible_ssh_user=admin
    

    Develop inventory
    # file: develop
    
    [app-servers:children]
    app-php-servers
    app-python-servers
    
    [app-php-servers]
    appserv-01.dev.example.com
    appserv-03.dev.example.com
    
    [app-python-servers]
    appserv-02.dev.example.com
    appserv-04.dev.example.com
    
    [db-servers]
    dbserv-[01:02].dev.example.com
    
    [cdn]
    cdn-[01:02].dev.example.com
    
    [app-servers:vars]
    env=DEV
    ansible_ssh_user=admin
    

    Как видно из примера, группы могут включать в себя другие группы, а также можно объявлять общие переменные прямо в inventory.

    Переменные

    Структура директорий может выглядеть следующим образом:
    ansible/
    # Групповые (общие) переменные
     - group_vars/
              - all/
                - common
                - secret  
              - dev/
                - common
                - secret    
              - stage/
                - common
                - secret
              - prod/
                - common
                - secret
    # Переменные отдельных хостов (частные) 
     - host_vars/
             - appserv-01.example.com/
                - common
                - secret
             - dbserv-01.example.com/
                - common
                - secret
             - cdn-01.example.com/
                - common
                - secret
    

    Каждая группа и каждый хост могут иметь набор переменных в разных файлах (например common, secret).Названия файлов в директориях здесь не приципиальны, главное чтобы имя директории совпадало с именами (группы или хоста) в соответствующем inventory. Заводить директорию для группы или единичного хоста не обязательно, можно просто создать файл и записать в нем все необходимые переменные. Но если вы хотите хранить пароли в шифрованном виде (не хеши, а именно пароли), отдельно от общих переменных, то стоит завести описанную выше структуру, об этом я расскажу ниже. 

    Шифрование переменных с Ansible-vault
    Ansible-vault утилита для шифрования(default AES256) файлов групповых или хостовых переменных и в принципе любых файлов в которых вы хотите хранить секретные переменные (пароли, ключи и т.д.). Таким образом, вы сможете хранить в репозитории (даже в публичном, хотя это всё же не желательно) любые данные и не переживать за их безопасность.

    Пользовательские пароли имеет смысл хранить в групповых файлах (group_vars) по имени группы или как all если у вас на всех окружениях одни и те же юзеры.

    В описанной выше структуре я указывал файлы secret в которых и предполагается хранить шифрованные переменные.

    Зашифровать файл:
    ansible-vault encrypt host_vars/cdn-01.example.com/secret

    Отредактировать зашифрованный файл:
    ansible-vault edit host_vars/cdn-01.example.com/secret

    Показать зашифрованный файл:
    ansible-vault view host_vars/cdn-01.example.com/secret

    Конечно, чтобы шифровать и расшифровывать файлы нужен будет достаточно длинный ключ и хранить его нужно в надежном месте (например KeePass). Чтобы автоматически расшифровывать файлы во время запуска (runtime) плейбуков нужно будет указывать ключ --vault-password-file либо задавать путь к файлу через конфиг ansible.cfg, в этом случае также нужно будет позаботиться о сохранности ключа и выставить ему нужные права (0400). Ну и конечно не стоит его хранить в репозитории вместе с зашифрованными файлами.

    Плейбуки

    Все действия (tasks) которые вы хотите выполнить можно записывать в плейбуки (если их скажем не больше десятка и вы не используете файлы и шаблоны) в остальных случаях стоит использовать роли.

    В плейбуке как минимум должны быть указаны:
    — Целевая группа хостов (hosts) здесь можно задавать исключения по маске ( — hosts: app-servers:!app-04.*), либо несколько групп через двоеточие ( -hosts: db-servers:cdn);
    — Действия (tasks) или роли (roles).
    Дополнительно можно указать:
    — Пользователя для ssh-connect (remote_user);
    — Пользователя sudo (become_user);
    — Использование повышения привилегий (become: True/False);
    — Переменные (vars)
    — Файлы переменных (vars_files)
    —  Количество одновременных коннектов (serial), если выставить 1 — то будет происходить последовательное выполнение плейбука по одному хосту за раз.

    Роли

    Роль представляет собой структурированный плейбук содержащий набор (как и минимум) тасков (task), и дополнительно — обрабработчиков событий (handler), переменных (defaults), файлов (files), шаблонов (templates),  а также описание и зависимости (meta).

    Структура роли Deploy
    - deploy/
       - defaults/
          - main.yml
       - files/
          - maintenance.html
       - handlers/
          - main.yml
       - meta/
          - main.yml
       - tasks/
          - deploy.yml
          - main.yml
          - migrations.yml
          - tests.yml
       - templates/
          - app_config.j2

    Файл с переменными по умолчанию:
    # file: deploy/defaults/main.yml
    ---
    branch_name: master
    mysql_host: localhost
    ...

    Здесь очень удобно задавать какие-то общие вещи, например по умолчанию хост для БД localhost, а group_vars/host_vars вы можете задавать нужные хосты для соответствующих окружений.

    Файл с обработчиками событий
    # file: deploy/handlers/main.yml
    ---
    - name: reload uwsgi
      service: name=uwsgi state=reloaded
    - name: flush cache
      shell: redis-cli flushall
    ...

    В обработчиках можно указывать абсолютно любые действия которые необходимо выполнять после тех или иных тасков, будь то выкладка нового кода или изменение конфига.

    Файл с описанием тасков
    # file: deploy/tasks/main.yml
    ---
    - include: deploy.yml
      tags:
        - common
        - deploy
    - include: migrations.yml
      tags:
        - common
        - migrations
    - include: pytasks.yml
      when: "'app-python-servers' in group_names"
      tags:
        - common
        - pytasks
    - include: tests.yml
      tags:
        - tests
    ...

    Можно задавать жесткие условия для выполнения некоторых тасков. В примере выше я задал условие:
    when: "'app-python-servers' in group_names"

    что означает, что таск будет выполняться только для хостов которые состоят в группе app_python-servers.

    Я практически всегда использую теги для декомпозирования крупных ролей. В примере роли выше я задал общий тег «common» для первых двух тасков и отдельный тег для tests для последнего таска. Если мне нужно выполнить только первые два таска (т.е. выкатить код) я запускаю плйбук с ключом --tags common (или --skip-tags tests):
    ansible-playbook -i develop playbooks/deploy.yml --tags common

    затем, можно запустить тесты отдельно (обычно они долго выполняются) просто задаю --tags tests:
    ansible-playbook -i develop playbooks/deploy.yml --tags tests

    Шаблоны
    В качестве шаблонизатора Ansible использует jinja2 со всеми его прелестями. Пример простого конфига uwsgi в виде ini файла с переменными:
    # {{ ansible_managed }}
    
    [uwsgi]
    
    chdir = {{ app_dir }}/{{ app_name }}
    home = {{ app_dir }}/{{ app_name }}/env
    
    master = True
    
    module = {{ app_name }}.wsgi:application
    
    chmod-socket = 660
    
    uid = {{ web_user }}
    gid = {{ web_user }}
    
    processes = 8
    
    listen = 256
    
    max-requests = 100
    
    buffer-size = 16384
    
    vacuum = true
    
    env DJANGO_SETTINGS_MODULE = {{ env }}.settings
    
    {% if env is defined and env == DEV %}
    # Enable logging 
    req-logger = file:/{{ logs_dir }}/{{ app_name }}/reqlog
    logger = file:/{{ logs_dir }}/{{ app_name }}/errlog
    {% endif %}
    

    Можно использовать любые приемы jinja2 в сочетании с переменными Ansible. Например:
    — Задавать строки только хост состоит в той или иной группе (либо задать строки только для определенного хоста) и при этом использовать loop:
    # file: iptables.j2
    ...
    {% if (groups['cdn'] is defined and inventory_hostname in groups['cdn']) %}
    # Allows HTTP and HTTPS connections from anywhere
    {% for port in webs_ports %}
    -A INPUT -p tcp -m tcp --dport {{ port }} -j ACCEPT
    {% endfor %}
    {% endif %}
    ...

    Зависимости

    Под зависимостями здесь подразумеваются другие роли которые необходимо выполнить перед тем как выполнять вашу конечную роль, в формате — { role: role_name, var_name: value }, например:
    # file: deploy/meta/main.yml
    ---
    dependencies:
    - { role: base, apt_repo: us }

    Указав все необходимые зависимости для конечной роли (например app-servers) вы можете создать всего один плейбук в котором достаточно будет указать целевую группу хостов и роль.  И этого будет достаточно чтобы поддерживать систему в консистентном состоянии, запуская например плейбук по крону. Если нужно обновить какие-то определенные конфиги по месту, то вам придут на помощь теги.

    Если вы хотите делать периодические билды и контролировать их выполнение или просто дать «кнопку» разработчикам, могу порекомендовать плагин Ansible для Jenkins подключив который вы сможете задавать в тасках Jenkins пути до playbook, inventory, а также tags и extra-vars.

    Что дальше?

    Описаная в статье структура не претендует на звание эталонной или универсальной, но наверняка подойдет для большинства случаев. Вы можете использовать её как отправную точку. В процессе написания собственных ролей вы найдете лучший и более удобный для вас способ описания инфраструктуры которую вы строите. Главное не пытайтесь все усложнять, чем проще вы пишите и чем понятнее ваши плейбуки для других тем лучше.

    Держите открытой вкладку с официальной документацией по Ansible, она постоянно дополняется по мере развития проекта. Я до сих пор нахожу в ней новые и интересные для себя вещи.

    В этой статье я рассказал не все что хотел, есть мысли и идеи еще на одну-две заметки. Если вас интересуют определенные вопросы пишите их комментариях или мне на почту, я постараюсь ответить и возможно учесть ваши пожелания при написании следующей статьи.

    UPD:
    Полезный пример разделения окружений (production/staging) здесь. Спасибо shuron за ссылку.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 44

      0

      Недавно столкнулся с тем, что ansible, как-то странно понимает секции include и block в шабонах. Приходилось использовать?

        0
        include вместе с block пока не использовал (block — относительно новая директива, в 2.0 появилась). А в чем странность?
          0

          Сразу скажу, не копал глубоко.
          Есть куча конфигов 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;" %}
            0
            Вы говорили про странности с include и block.
            Include нужен для того чтобы инклудить файлы с тасками в плебуках/ролях.
            Block нужен что объединять группы тасков в блоки с некими общими условиями (when: something).
            Тут вы пишите кусок jinja-шаблона. Теперь мне совсем не понятен контекст. :)
              0

              Я про include/block в контексте jinja, а не yaml.

                0
                Include/Block работают в контексте тасков плейбука/роли.
                  0

                  Еще раз. Я не про include в коде yaml, а в коде шаблона. То есть если я приведенный выше кусок вынесу в инклюд, я ничего не получу.

                    0
                    Я понял. :) Ответ выше. В jinja свои директивы, include/block там не будут работать.
                      0

                      Именно. То есть получается, все плюшки jinja там толком не поиспользовать.

              0
              В Django свой шаблонизатор не совместимый с Jinja
                0

                Разве? ну возможно. Хотя вроде jinja тянет в зависимостях. А потом обертывает в свои врапперы. Утверждать не буду, проверять лень. :)

            –1
            мой пример include в шаблоне
            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 %}

            вообще некоторые вещи в шаблонах работают не ожидаемо
            с чем приходится считатся
              0
              Too many ifs! :)
              Спрячте текст под спойлер плиз.
                0

                Спасибо :) завтра вкурю полноценно

              +4
              Ох, если бы я не знал уже Ансибла, меня бы эта статья только запутала. Ансибл очень очень простой, а вот написание приличного playbook'а на нём — груда best practices и приёмов, которые совершенно неочевидно вытекают из документации по ansible. И вот именно эту штуку «за пределами документации» никто не хочет рассказывать.
                +2
                Ну на самом деле за пределами документации сейчас уже не так и много всего.
                Есть определенные тонкости, но их понимание приходит со временем, после третьей, четвертой ревизии ваших ролей.
                Поэтому у каждого свои «best practices» их нельзя получить и усвоить разом из какой-нибудь статейки.
                  0
                  я незнаю ansible, и когда я вижу комментарий что мне нужно 3-4 раза переписать, я так подозреваю чуть ли не половину, и только после этого мне будет удобно и хорошо им пользоватся, то как то желание изучать его пропадает
                    0
                    «К сожалению», любой программный продукт нужно постоянно доделывать, допиливать и т.д.
                    Если вы не готовы, что либо поддерживать и дорабатывать, то вам нечего делать в ИТ.
                  +1
                  За два года почти ежедневной работы с ним накопился нехилый опыт прикручивания костылей и использования хитрых способов. Я бы статью написал, только есть одна проблема — для меня все это теперь кажется очевидным и не понятно о чем есть интерес у других почитать.
                    +1

                    К примеру, как делать не надо, потому что дебажить сложно, но это самый удобный способ передать в параметр 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 для всех бэкендов и подставляешь их адреса сюда, миную лишнюю переменную.

                      0

                      Ну или про многие фильтры народ вообще не знает, типа default(omit), mandatory или combine.

                        +2
                        В основном не знают (если это так) те, кто начинал осваивать ansible с более ранних версий. Например, я сравнительно недавно узнал про default(omit) хотя он появился в 1.8, а combine появился в 2.0.
                        В общем надо почаще заглядывать в документацию она обновляется с каждым релизом.
                          0
                          Что касается combine, у меня по старой привычке с chef'а стоит

                          [defaults]
                          hash_behaviour = merge


                          Очень удобно.
                            0

                            Тоже перелазил с шефа и очень удивился стандартному поведению (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
                              0
                              Ну мало ли чего они там рекомендуют. Дефолтный merge облегчает жизнь сильно. А официальные плейбуки я не использую. Предпочитаю писать всё самому.
                      0
                      У меня с ansible было несколько организационных проблем и я не уверен, что решил их правильно.

                      1) rpm/deb-дистрибутивы имеют разные название пакетов, пути до конфигов

                      - include: {{ ansible_distribution }}.yml
                      

                      Я выношу специфичные данные в отдельный файл.

                      2) разные сегменты сети имеют разные ntp, nameserver…

                      group_vars
                        - all
                        - dmz
                      

                      # inventory
                      [dmz:children]
                      dmz_group1
                      

                      А тут использую групповые переменные и inventory

                      Есть ли более красивое решение?
                        0
                        1) Нормально (хотя это не очень хорошо если вам приходится следить за зоопарком разных дистрибутивов).
                        2) Это тоже нормально, от этого не всегда можно уйти.
                        0
                        Установка/удаление ПО;
                        Конфигурирование ПО;
                        Деплой кода вашего ПО;

                        Stateless система под это дело совсем не подходит, поскольку нельзя делать откат ревизий, и, как следствие, нормальное A/B проходит мимо.
                        Кроме того, у них в гайдлайне написано, дескать: не делайте параметризированных ролей, лучше копипаста.
                        И получается, что сделать обычную роль для nginx с темплейтами и инклудами конфигов, которая в рамках одного inventory намазывается по разным серверам, — это целая, блин, задача с юнит-тестам, бл.

                        Создание/удаление контейнеров/виртуальных машин;

                        Создал, запустил, упал, перезапустил, упал. И так в цикле, пока apdex не просядит и мониторинг не начнёт орать, да? :-}

                        А стэктрейсы после запуска толстого плэйбука хотя бы на 50+ хостов смотреть? >____<

                        К примеру, когда в template неправильно указан аргумент src, а изменений много, и вносил их кто-то другой:
                        output -vvvv
                        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": ""}
                        

                          0
                          спасибо за материал! насчет "-i " мысль интересная. сам пока использую --limit вместо этого

                          есть желание хранить плейбуки в репозитории прямо рядом с кодом и с ним же бранчеваться. есть опыт такого дела? может ли ansible-playbook выполнять плейбук из определенного бранча? может плагины есть для этого какие…

                          сам пробовал гуглить, но все что вылезает касается модуля «git» который делает деплой уже непосредственно КОДА из какого-либо репо. а вот чтобы сам конфиг Ансибла… такого не нашел что то…
                            0
                            Я храню роли в отдельном репо. Смешивать с кодом (Python/PHP) я не стал бы, смысла нет (если только вы не упираетесь в какие-то ограничения).
                            Тут можно разные подходы использовать. Можно сделать плейбук который будет обновлять сам Ansible и обновлять репо с плейбуками/ролями — дергать его по крону или как pre-task в Jenkins или аналогах.
                              0

                              У меня сейчас миграция с puppet на ansible, и комбинация -i и --limit очень помогает.

                                0
                                а чем обусловлена такая миграция, если не секрет?
                                  0

                                  В нашем случае:


                                  1. Обилие говнокода на puppet, разгребать смысла нет. В текущем состоянии идет постоянное нарастание.
                                  2. Наличие центрального сервера и агентов. Что вместе с п1 ведет к серьезным тормозам. Например: запуск агентов был сначала раз в 25 минут, потом раз в 45, потом раз в час, потом раз в 2 часа. Agentless у ansible, считаем это плюсом. А наличие CI позволяет вполне заменять центральный сервер.
                                  3. Осознание излищней сложности puppet. Docker+ansible позволяют выкинуть 60% кода без рефакторинга.
                                  4. Очень удобная декомпозиция ролей. Соответсвенно всегда можно удобно и быстро выполнить малую роль.
                              0
                              Stateless система под это дело совсем не подходит, поскольку нельзя делать откат ревизий, и, как следствие, нормальное A/B проходит мимо.

                              Обоснуйте.

                              Кроме того, у них в гайдлайне написано, дескать: не делайте параметризированных ролей, лучше копипаста.

                              Что-то не припомню такого. Тыкните в док.

                              Создал, запустил, упал, перезапустил, упал. И так в цикле, пока apdex не просядит и мониторинг не начнёт орать, да? :-}

                              О чем это? Неудачные опыты?

                              А стэктрейсы после запуска толстого плэйбука хотя бы на 50+ хостов смотреть? >____<

                              К примеру, когда в template неправильно указан аргумент src, а изменений много, и вносил их кто-то другой:

                              При наличии рук не растущих из плеч и отсутствии привычки тестировать свой код можно добиться и более впечатляющих результатов.
                                0
                                # {{ ansible_managed }}

                                Не советую использовать этот макрос, он включает в себя текущее время и поэтому ломает --check: при каждом прогоне task будет показываться как changed.
                                  0
                                  Это не совсем правда. Дата задается, но меняется только если шаблон изменился.
                                  У меня при --check не было такой проблемы (ansible 2.0.1.0). Хотя в некоторых версиях думаю такое могло быть.
                                    0
                                    + если результат шаблона изменился
                                    но у этой строки есть частный случай
                                    когда два разных шаблона накатываются на один файл на сервере тогда будет постоянный changed даже если результат их работы одинаковый
                                    и результат этой строки можно подправить переопределив его в /etc/ansible/ansible.cfg
                                    ansible_managed = Ansible managed: modified on %Y-%m-%d %H:%M:%S
                                      0
                                      Давно не проверял, хорошо, если починили. Хотя в документации по-прежнему пишут: «Note that if using this feature, and there is a date in the string, the template will be reported changed each time as the date is updated.»
                                    0

                                    Что нужно сделать что-бы работала следующая схема по переменным различающихся по stages?


                                    Групповые (общие) переменные
                                    • group_vars/
                                      • all/
                                        • common
                                        • secret
                                      • dev/
                                        • common
                                        • secret
                                      • stage/
                                        • common
                                        • secret
                                      • prod/
                                        • common
                                        • secret

                                    В Плейбуках пропивывате пути к файлам с переменными?

                                      0
                                      Эта схема будет работать автоматически, если в файле inventory (hosts) будут соответствующие группы (dev/stage/prod). В плейбуках при этом можно ничего специально не прописывать.
                                      hosts
                                      [dev]
                                      host01
                                      host02

                                      [stage]
                                      host01
                                      host02

                                      [prod]
                                      host01
                                      host02
                                        0
                                        Точно…

                                        Вот теперь вспомнил почему я сделал по другому
                                        я не хотел перемешивать окружения
                                        и поэтому у меня выглядит так как описано тут:

                                        http://toja.io/using-host-and-group-vars-files-in-ansible/

                                      0

                                      Очень важная фишка, зависимоти между ролями…
                                      Надо использовать, тогда сами роли будут меньше и проще

                                        0
                                        Хорошая статья! Я изредка использую Ansible, когда настраиваю новый сервер/VPS. Но так как я использую его редко, то мой Ansible-проект сейчас похож на кашу. Статья помогла мне понять один из способов хорошей организации Ansible-проекта, теперь займусь рефакторингом :) Автору спасибо!
                                          0

                                          Спасибо за статью.
                                          Еще один подход к разделению энвайроментов.


                                          На счет тегов. Избыточные теги тоже зло. На мой взгляд (когда применяется бездумно) нарушает KISS и YAGNI.
                                          По этому поводу можно подробней почитать здесь

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                          Самое читаемое