Pull to refresh

Comments 106

UFO just landed and posted this here

Concentrated field experience — очень круто, спасибо!


Перспектива малого бизнеса

У нас полсотни серверов и десяток персоналок, и мы пока боимся добавлять vendor lock (даже open source) на критическом пути. Пробовали Ansible — для отчетов по оборудованию и софту — быстро научились (там всё более-менее процедурно). Для интеграции с нашей разнородной инфраструктурой пошло не очень, надо было много гуглить как делать идиоматически, либо делать всё процедурно и утонуть в этой лапше в конце. Ну и если что не так, то долго разбираться. Держать дополнительные знания в голове, когда еще до фига чего надо — тяжело.


Мы хорошо умеем настраивать Debian и сеть и писать на Bash & Python (пару десятков лет опыта у каждого), ну и программировать на "нормальных" языках (С++, Scala, Java, etc.). Ещё мы очень жадные не хотим делиться деньгами если можем сделать сами.


Поэтому пока что потихоньку подписываем своё небольшое JSON-driven самопальное на Python/Requests/Paramiko/CherryPy. Что не работает — выкидываем и переделываем с нуля. Пока неплохо получается, и декларативность с идемпотентностью в норме. Мы также приняли строгий закон делать change management как с кодом и ничего не хачить вручную — это было ключевым моментом.


Наверное мы тоже сдадимся когда вырастем еще, но у нас будет хорошая спецификация всего на JSON/Python и будет проще решить на что пересесть.


Как-то так.

А почему не тот же Fabric? Неужели писать свой велосипед выгоднее

Fabric это который библиотека на питоне? Просто не попался пока, посмотрю обязательно, спасибо за наводку!


Свой велосипед выгоднее/удобнее был пока что. Мы стараемся делать только самое самое необходимое пока растем и часто меняемся. Обычно сначала вообще делаем руками по чеклисту, чтобы отловить основные косяки, потом автоматизируем самым базовым способом, потом обобщаем если имеет смысл.

«Это не те SCM, которые вы ищете» (пасс руками по кругу).
Если я скажу, что Ansible — это как Fabric на стероидах, так понятнее будет? Ну и никто не мешает ровно тем же способом использовать Ansible: в качестве нормальной такой платформы.
Вооот! Ну наконец-то хоть кто-то озвучил самый логичный юзкейс! Для ансибла самое годное применение это быстрые развёртывания и быстрые же похороны без малейших попыток сопровождения.

Можете рассказать что вы имеете ввиду под "быстрые же похороны без малейших попыток сопровождения."? Что вы подразумеваете под сопровождением?

Был кейс прямо вот по слайду: разворачивали инфраструктуру Энсиблом, но довольно быстро упёрлись в предел применимости (началось всё с танцев вокруг zabbix-proxy) и очень больно мигрировали на Шефа. Но смигрировали-таки и не пожалели. Сопровождение — когда инстансов становится больше тысячи (bare metal) клиент/агент не просто нужен, а очень-преочень нужен.

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

Про «быстро похоронить»: когда я понял, что systemd понятнее наших ролей, а инвентори перевалил за третий килобайт и обзавёлся собственными README и TODO, мы с CTO сели и взгрустнули. Потом я показал тестовый стенд с Шефом.
Ни в коем случае не назову Chef серебряной пулей. Как минимум, он «странненький» в плане видимости функций. А ещё есть два способа подружить его с SELinux:
* отключить к чёртовой бабушке SELinux.
* совершенно непонятные танцы с capabilities и не только.

Кстати, мое мнение про решение для большого количества серверов: chef/puppet + ansible.


chef/puppet хорошо подходит для большой инфраструктуры. Можно с помощью chef/puppet устанавливать системные пакеты, пакеты, которые должны быть установлены на всех серверах, например zabbix-agent. Но chef/puppet не подходит для blue-green deployment, rolling update не используя kubernetes.


Аnsible не очень хорошо подходит для для большой инфраструктуры. Аnsible подходит для blue-green deployment, rolling update не используя kubernetes.

Вы предлагаете их сочетать и получить артефакты от всего и сразу?
получить артефакты от всего и сразу

Ошибки?

Скорее именно артефакты, потому что с точки зрения каждой из систем всё будет «just as planned», но в реальности будет вообще всё что угодно кроме ожидаемого результата.
И да, про идемпотентность в таком случае лучше даже и не вспоминать.

Можете привести пример?

Из собственного опыта, к счастью, не могу. Но умозрительная ситуация напрашивается сама:
Одновременное исполнение Энсиблом и Шефом любых операций с пакетным менеджером приведёт к блокировке у кого-то из них. А в случае с pip'ом, я даже не хочу себе представлять, что получится. Как такого добиться при рационалных настройках? Да запросто! Надо просто выключить хост на сутки и «очень вовремя» включить, чтобы Энсибл «дозвонился» именно тогда, когда шеф втянул новые конфиги и радостно приступил к исполнению.
Тут ИМХО первичен другой вопрос: вот мы по сути дублируем инструментарий, а чтобы что?

Я писал выше можно с помощью chef/puppet устанавливать системные пакеты. То есть установка пакетов только через yum/apt. Не думаю что будут проблемы запуске yum от puppet и от ansible. Просто будет подольше.


Используя chef/puppet + ansible можно устанавливать zabbix-agent на тысячи серверов и делать обновление продукта/бизнес-программы через blue-green deployment, rolling update не используя kubernetes.

Используя chef/puppet + ansible можно устанавливать zabbix-agent на тысячи серверов и делать обновление продукта/бизнес-программы через blue-green deployment, rolling update не используя kubernetes.

А без дублирования инструментария, получается, всё это нельзя?

Используя только chef/puppet сложно сделать обновление продукта/бизнес-программы через blue-green deployment, rolling update.


Используя только ansible сложно управлять тысячами серверов.

Это не дублирование инструментария, инструменты решают разную задачу, ansible хоть и пытается решить задачу менеджмента конфигураций, но решает её хуже на мой взгляд.
В задачах деплоймента приложения на хосты, не надо ставить пакеты. С этим прекрасно справятся puppet/chef. Зато выполнять в строгом порядке какие-то действия для rolling деплоймента приложения, при этом иметь доступ ко всем переменным и фактам всех хостов куда идет деплоймент — с этим уже лучше справятся ansible/bolt/choria.
То есть инструменты вполне совместимы, когда ты ими не решаешь одни и те же задачи.

Ну, т.е. по-Вашему нет выгоды от использовании болта при наличии уже готовой экосистемы папета в компании?

Нет. bolt хорошо дополняет экосистему puppet. Более того, модули для puppet могут содержать tasks, которые можно использовать в plans(аналог плейбука) bolt'а. bolt умеет работать с puppetdb.
Он призван закрыть задачи, которые очень трудно решить puppet'ом либо их решение с помощью puppet не рационально.

Не согласен, поскольку ansible и puppet всё таки разные инструменты, и с определенными задачами puppet лучше справляется (менеджмент конфигураций), а с другими ansible (оркестрация/ad-hoc задачи). То вполне их можно безболезненно объединять. Более того, puppet как раз и предлагает это делать, правда вместо ansible предлагает использовать bolt. Но это по сути тот же ansible, только с DSL puppet'а и лучше встраивается в его экосистему.

chef и puppet

Пора закопать оба. Как минимум — из-за руби.


Аnsible не очень хорошо подходит для для большой инфраструктуры. Аnsible подходит для blue-green deployment, rolling update не используя kubernetes.

Смотри. Ты на chef и puppet можешь сделать то же самое. Придётся немного попрограммировать модули ) но это эквивалентно написанию сценариев (=плейбуков) ансибл. Но зато экосистема единая.

Золотые ваши слова. Я ведь теперь в кошмарах буду видеть инфраструктуру, в которой и Энсибл, и Шеф. Это не просто странно, а скорее даже debugging-driven debugging. К тому же бессмысленный и бесконечный.

Дело в том что в экосистеме puppet четко разделены задачи. 1) декларативное описание инфры — puppet, и оркестрация/ad-hoc задачи/другая автоматизация — bolt/choria. Вы просто не знакомы с таким подходом вот и всё. Замени puppet на chef, а bolt на ansible ничего не изменится, и получили решение тех же задач только с помощью chef + ansible вместо puppet + bolt. Совершенно нормальный подход

Смотри. Ты на chef и puppet можешь сделать то же самое. Придётся немного попрограммировать модули )

Мне кажется не получится. Но если у тебя получится, поделись опытом.

Про декларативную модель чуть подробней. Общий смысл в том, что мы не делаем какой-то процесс, мы не выполняем какие-то команды, а мы хотим привести систему в желаемое состояние.

декларативность там какая-то недостаточно декларативная ИМХО.


я не могу, например, сказать «на системе должны быть user1, user2 и всё», я могу сказать «добавь пользователя user1» и «удали пользователя user4». если в системе был кем-то заведён user5, то ansible никак об этом не узнает.
и так во всём — от списка репозиториев в sources.list до конфигов нжинкса в conf.d.


я не воспринимаю конфиги ансибла как декларативные, скорее они императивные с идемпотентностью.

Формально они, большинство из них, всё же деклариративные, просто не поддерживается "и всё". Только явное описание, что должно быть в системе и и явное описание чего не должно быть в ней. Что не описали — состояние неизвестно. Если вам это важно — опишите явно. И это разумный подход для подавляющего большинства случаев. Особенно с учётом последовательного выполнения.

edo1h


я не воспринимаю конфиги ансибла как декларативные, скорее они императивные с идемпотентностью

+ только не «конфиги», а «плейбуки»


я не могу, например, сказать «на системе должны быть user1, user2 и всё», я могу сказать «добавь пользователя user1» и «удали пользователя user4». если в системе был кем-то заведён user5, то ansible никак об этом не узнает.

По второму — да, не узнаёт, если явно это не прописать («получить список пользователей», «отфильтровать нужные», «создать недостающие», «шлепнуть лишние»). Но это беда любого SCM. И того, что система может вносить в себя изменения вне SCM (например, при установке пакетов). По идее решением мог быть интегрированная в саму операционную систему система управления конфигурацией. Пример как в NixOS. Но это не мейнстрим.
По первой части — ну, зависит от того, как модуль написан. Именно к модулю user претензий нет. Все стандартно state=present — проверяет есть ли юзер и если надо — создаёт. Аналогично со state=absent.

Но это беда любого SCM

Я бы так не сказал. Тот же пресловутый puppet знает о всех пользователях и других ресурсах в системе, даже если они не описаны. Это заложено в архитектуре провайдеров модулей, которые управляют этими ресурсами. Там обязательно реализуется метод — "получить все ресурсы данного типа".


Например ресурс user:


Скрытый текст
$ puppet resource user
user { '_apt':
  ensure             => 'present',
  gid                => 65534,
  home               => '/nonexistent',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 104,
}
user { 'bin':
  ensure             => 'present',
  comment            => 'bin',
  gid                => 2,
  home               => '/bin',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 2,
}
user { 'daemon':
  ensure             => 'present',
  comment            => 'daemon',
  gid                => 1,
  home               => '/usr/sbin',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 1,
}
user { 'dnsmasq':
  ensure             => 'present',
  comment            => 'dnsmasq,,,',
  gid                => 65534,
  home               => '/var/lib/misc',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 107,
}
user { 'games':
  ensure             => 'present',
  comment            => 'games',
  gid                => 60,
  home               => '/usr/games',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 5,
}
user { 'gnats':
  ensure             => 'present',
  comment            => 'Gnats Bug-Reporting System (admin)',
  gid                => 41,
  home               => '/var/lib/gnats',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 41,
}
user { 'irc':
  ensure             => 'present',
  comment            => 'ircd',
  gid                => 39,
  home               => '/var/run/ircd',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 39,
}
user { 'landscape':
  ensure             => 'present',
  gid                => 112,
  home               => '/var/lib/landscape',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 108,
}
user { 'list':
  ensure             => 'present',
  comment            => 'Mailing List Manager',
  gid                => 38,
  home               => '/var/list',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 38,
}
user { 'lp':
  ensure             => 'present',
  comment            => 'lp',
  gid                => 7,
  home               => '/var/spool/lpd',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 7,
}
user { 'lxd':
  ensure             => 'present',
  gid                => 65534,
  home               => '/var/lib/lxd/',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/bin/false',
  uid                => 105,
}
user { 'mail':
  ensure             => 'present',
  comment            => 'mail',
  gid                => 8,
  home               => '/var/mail',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 8,
}
user { 'man':
  ensure             => 'present',
  comment            => 'man',
  gid                => 12,
  home               => '/var/cache/man',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 6,
}
user { 'messagebus':
  ensure             => 'present',
  gid                => 107,
  home               => '/nonexistent',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 103,
}
user { 'news':
  ensure             => 'present',
  comment            => 'news',
  gid                => 9,
  home               => '/var/spool/news',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 9,
}
user { 'nginx':
  ensure             => 'present',
  comment            => 'nginx user,,,',
  gid                => 119,
  home               => '/nonexistent',
  password           => '!',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/bin/false',
  uid                => 115,
}
user { 'nobody':
  ensure             => 'present',
  comment            => 'nobody',
  gid                => 65534,
  home               => '/nonexistent',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 65534,
}
user { 'ntp':
  ensure             => 'present',
  gid                => 114,
  home               => '/nonexistent',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 111,
}
user { 'pollinate':
  ensure             => 'present',
  gid                => 1,
  home               => '/var/cache/pollinate',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/bin/false',
  uid                => 110,
}
user { 'postfix':
  ensure             => 'present',
  gid                => 117,
  home               => '/var/spool/postfix',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 113,
}
user { 'proxy':
  ensure             => 'present',
  comment            => 'proxy',
  gid                => 13,
  home               => '/bin',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 13,
}
user { 'root':
  ensure             => 'present',
  comment            => 'root',
  gid                => 0,
  groups             => ['ssh-allow-login'],
  home               => '/root',
  password           => '!',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/bin/bash',
  uid                => 0,
}
user { 'sshd':
  ensure             => 'present',
  gid                => 65534,
  home               => '/run/sshd',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 109,
}
user { 'statd':
  ensure             => 'present',
  gid                => 65534,
  home               => '/var/lib/nfs',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 114,
}
user { 'sync':
  ensure             => 'present',
  comment            => 'sync',
  gid                => 65534,
  home               => '/bin',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/bin/sync',
  uid                => 4,
}
user { 'sys':
  ensure             => 'present',
  comment            => 'sys',
  gid                => 3,
  home               => '/dev',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 3,
}
user { 'syslog':
  ensure             => 'present',
  gid                => 106,
  groups             => ['adm', 'projects'],
  home               => '/home/syslog',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/bin/false',
  uid                => 102,
}
user { 'systemd-network':
  ensure             => 'present',
  comment            => 'systemd Network Management,,,',
  gid                => 102,
  home               => '/run/systemd/netif',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 100,
}
user { 'systemd-resolve':
  ensure             => 'present',
  comment            => 'systemd Resolver,,,',
  gid                => 103,
  home               => '/run/systemd/resolve',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 101,
}
user { 'uucp':
  ensure             => 'present',
  comment            => 'uucp',
  gid                => 10,
  home               => '/var/spool/uucp',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 10,
}
user { 'uuidd':
  ensure             => 'present',
  gid                => 110,
  home               => '/run/uuidd',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 106,
}
user { 'www-data':
  ensure             => 'present',
  comment            => 'www-data',
  gid                => 33,
  home               => '/var/www',
  password           => '*',
  password_max_age   => 99999,
  password_min_age   => 0,
  password_warn_days => 7,
  shell              => '/usr/sbin/nologin',
  uid                => 33,
}

И получается задача:


я не могу, например, сказать «на системе должны быть user1, user2 и всё», я могу сказать «добавь пользователя user1» и «удали пользователя user4». если в системе был кем-то заведён user5, то ansible никак об этом не узнает.

Решается так:


  user {'user1':
      ensure => present,
  }
  user {'user2':
      ensure => present,
  }
  resources {'user':
      purge => true,
      unless_system_user => true, # Чтобы не удалить системных пользователей
  }

То есть в puppet очень просто можно сказать — удали все ресурсы какого-то типа, которые не описаны, поскольку он знает о всех ресурсах которыми управляет в системе. Конечно с пакетами в системе я бы так не советовал делать.


в ansible декларативность там какая-то недостаточно декларативная ИМХО.

Да, я тоже так считаю. ansible императивный, поскольку просто выполняет таски как скрипт, каждую по очереди. Например:


tasks:
  - file:
      path: /tmp/test
      state: absent
  - file:
      path: /tmp/test
      state: directory

Приведет к тому, что директория /tmp/test будет создана. А если поменять местами, то она будет удалена.


В puppet такое невозможно. Такая запись приведет к ошибке дубликата ресурсов. Поскольку не может быть одного ресурса с двумя состояниями:


file {'/tmp/test':
    ensure => absent,
}
file {'/tmp/test':
    ensure => directory,
}

Это будет ошибка: Error: Evaluation Error: Error while evaluating a Resource Statement, Duplicate declaration: File[/tmp/test] is already declared at (file: /root/1.pp, line: 1); cannot redeclare (file: /root/1.pp, line: 4) (file: /root/1.pp, line: 4, column: 1) on node


И без разницы, в какой последовательности их написать. И даже если попробовать схитрить и сделать так:


file {'id2':
    path   => '/tmp/test',
    ensure => directory,
}
file {'id1':
    path   => '/tmp/test',
    ensure => absent,
}

То это все равно приведет к ошибке дубликата: Error: Evaluation Error: Error while evaluating a Resource Statement, Cannot alias File[id2] to ["/tmp/test"] at (file: /root/1.pp, line: 5); resource ["File", "/tmp/test"] already declared (file: /root/1.pp, line: 1) (file: /root/1.pp, line: 5, column: 1) on node test


То есть puppet более честен в плане декларативности чем ansible. Поэтому именно с задачей управления конфигурациями как мне кажется он лучше справляется. Но эти инструменты можно комбинировать. ansible отлично справляется с другими задачами, с которыми puppet справляется хуже.


Но в эпоху иммутбл инфры, облаков. Когда есть контейнеры, packer, pulumi, terraform, AWS Cloud Development Kit, k8s, nomad и т.д. Наверное вообще не имеет смысла сидеть и сравнивать все эти инструменты (ansible/puppet/chef/solt), так как они потихоньку уходят на задний план.

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

это не решает проблему гоночек, в случае, если этим ресурсом пытается управлять какая-то еще другая система. Пример — iptables правила в случае использования docker/любого vpn. Удачи это описать бесконфликтно и чтоб надежно работало.


То есть puppet более честен в плане декларативности чем ansible.

еще проблема, что нужно не только состояние ("куда мы идем?"), а порядок действий ("как мы туда придем?"). И в том же паппете это делается, но через боль (например, нам обязательно нужно установить пакет А до пакета Б — вот потому что это так работает, есть альтернативы — например, пересобрать пакеты самому и всю логику реализовата в post-inst, но я бы не сказал, что они радикально лучше)


Но в эпоху иммутбл инфры, облаков. Когда есть контейнеры, packer, pulumi, terraform, AWS Cloud Development Kit, k8s, nomad и т.д. Наверное вообще не имеет смысла сидеть и сравнивать все эти инструменты (ansible/puppet/chef/solt), так как они потихоньку уходят на задний план.

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

это не решает проблему гоночек, в случае, если этим ресурсом пытается управлять какая-то еще другая система. Пример — iptables правила в случае использования docker/любого vpn. Удачи это описать бесконфликтно и чтоб надежно работало.

Никакой проблемы нет, я это делаю через puppet. Поскольку puppet знает о всех правилах iptables, ты можешь игнорировать правила docker/vpn/k8s. В результате он накатит правила которые ты описал, не тронет правила docker/vpn/k8s и удалит правила которые кто-то добавил вручную.


еще проблема, что нужно не только состояние ("куда мы идем?"), а порядок действий ("как мы туда придем?"). И в том же паппете это делается, но через боль (например, нам обязательно нужно установить пакет А до пакета Б — вот потому что это так работает, есть альтернативы — например, пересобрать пакеты самому и всю логику реализовата в post-inst, но я бы не сказал, что они радикально лучше)

Да, это так. Поскольку puppet декларативен, то нужно стараться описать конечное состояние. А вот если ты пытаешься им делать "как мы туда придем?" то будет беда скорее всего. Поэтому это делается только если ну очень надо. Но это про более сложные истории чем установить пакет А до пакета Б, поскольку зависимости как раз он умеет без проблем:


package {'p1':}
package {'p2':
  require => Package['p1']
}

"как мы туда придем?" — а для такого обычно и используют ansible, а в экосистеме puppet обычно для такого используют bolt, но можно и ansible.

Да, это так. Поскольку puppet декларативен, то нужно стараться описать конечное состояние. А вот если ты пытаешься им делать "как мы туда придем?" то будет беда скорее всего. Поэтому это делается только если ну очень надо. Но это про более сложные истории чем установить пакет А до пакета Б, поскольку зависимости как раз он умеет без проблем:

нам stage puppet приходилось для этого использоваться. require как в сниппете было недостаточно (

stage и anchor использовались для этого да. Обычно это говорит о том, что надо рефакторить код из-за большого количества связей ресурсов между разными классами, или наоборот, некоторые ресурсы в текущем классе выделять в отдельный.
Рекомендуется выставлять связи между классами, а не ресурсами которые зависят от ресурсов другого класса.


Типо такого:


  Class['proxysql::prerequisites']
  -> Class['proxysql::repo']
  -> Class['proxysql::install']
  -> Class['proxysql::config']
  -> Class['proxysql::service']
  -> Class['proxysql::admin_credentials']
  -> Class['proxysql::reload_config']
  -> Class['proxysql::configure']

  Class['proxysql::install']
  ~> Class['proxysql::service']

С puppet проблема — он очень сложный. Думаю из-за этого не популярен.

С puppet проблема — он очень сложный. Думаю из-за этого не популярен.

а что бы такое обзорное почитать чтобы понять нужно ли оно мне?


очень смущает, что ansible стал стандартом de-facto, многие переходят с puppet/chef/etc на ansible, и мало кто в другую сторону.

Мне кажется нет смысла. Сейчас потихоньку от этих инструментов отказываются или сильно минимизируют их использование в пользу иммутбл инфры. А всякие сложные вещи реализуют на языках программирования. Например операторы для k8s пишут на golang, также установщики самого k8s пишут часто на golang (rke,pke).
Всё меньше и меньше мест, где применяют ansible/solt/puppet/chef. Поэтому начинать переходить на какой-то из них из другого в этом списке, наверное нет смысла.

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

имеет смысл, если инфра, например, на бареметал… и кубера того же не превидится в обозримом будущем, но я бы все равно смотрел в сторону MAAS/Tinkerbell и прочих методов автоматизации и предоставления metal-as-a-service и дальнейшей immutable infra даже поверх железа

UFO just landed and posted this here

Ну вот terraform похож не много на puppet и страдает как мне кажется. Появились неплохие конкуренты: pulumi и AWS Cloud Development Kit.


А порой хочется какую-то задачу просто решить через ansible чем решать ее сложно terraform'ом. Вот например ребята из skyeng так и сделали для задачи управления github'ом: https://habr.com/ru/company/skyeng/blog/516192/

UFO just landed and posted this here
UFO just landed and posted this here

Отличие принципиальное. puppet знает о всех ресурсах, независимо от того описаны они в коде или нет, ansible знает только что описано в коде, а точнее знает только о тасках которые требуется выполнить.


purge => true — это не функционал модуля user. Таким же образом можно сделать например с пользователями mysql:


    resources {'Mysql_user':
         purge => true,
    }

Или базами clickhouse


    resources { 'Clickhouse_database':
        purge => true,
    }

Тип ресурса и в каком модуле он реализован — не играет роли.
Это архитектура инструмента. Когда пишешь модуль, ты обязан реализовать некоторые методы, в том числе и метод — "достать все ресурсы для этого модуля". puppet получает с мастера все ресурсы, потом смотрит какие есть ресурсы на хосте, смотрит разницу и старается привести ресурсы на хосте к описанным на мастере — если огрублять.


Но это выглядит явно не как достоинство puppet.

Это честная декларативность. Один и тот же ресурс не может иметь два состояния одновременно. Если же может, то это не декларативность. Плохо это или хорошо — зависит от ситуации. Как по мне, именно для управления конфигурациями — это хорошо, а для всяких ad-hoc задач — неудобно, тут лучше взять более императивные инструменты, например ansible.

Как по мне, именно для управления конфигурациями — это хорошо, а для всяких ad-hoc задач — неудобно, тут лучше взять более императивные инструменты, например ansible.

именно так, не могу не согласиться. И поэтому я буду утверждать, что ansible — это не SCM. Ни разу. Но может использоваться для настройки окружения.

UFO just landed and posted this here

В плане реализации модуля, а точнее провайдера в нем, тоже достаточно принципиальное. В puppet ты реализуешь несколько методов создать/изменить/удалить ресурс + получить список всех ресурсов. В ansible тоже нечто похожее, но принципиально отличаются архитектура и механика как это работает.


puppet получает список описанных ресурсов с мастера и получает список ресурсов хоста. Сравнивает, видит разницу, и выполняет методы провайдера модуля, чтобы привести ресурсы на хосте к тому виду, как они описаны на мастере. В твоем модуле эту механику реализовывать не требуется, такое поведение тебе гарантирует сам puppet. То есть в описанных мной примерах, если указано:


  resources { 'Clickhouse_database':
        purge => true,
    }

То puppet просто применит метод "удалить ресурс" из твоего провайдера модуля, ко всем базам clickhouse что он видит на хосте, кроме тех что описаны в puppet коде. Тебе со стороны провайдера модуля не надо реализовывать само это сравнение ресурсов, puppet это делает сам. В провайдере модуля только методы изменить аттрибут/аттрибуты ресурса/удалить ресурс/создать ресурс/получить все ресурсы и всё.


В случае с ansible такой механики насколько я знаю нет. Для выполнения task'а он копирует код модуля на хост, и запускает его. Вроде область его видимости текущий task и его свойства, этот код ничего не знает о других task'ах описанных в текущем play или других task'ов которые описаны в play других playbook'ов. Также всю эту механику: сравнить список текущих ресурсов и их свойств на хосте, со всеми tasks и их свойствами во всех playbook'ах, что будут применены к хосту, надо будет делать самому, причем в пределах выполнения каждого task такого типа, что будет очень затратно в плане скорости выполнения как минимум. Я не знаю возможно ли в ansible в пределах выполнения task модулем достать список всех тасков, которые также будут применены к хосту для сравнения со списком ресурсов которые уже есть на хосте, чтобы не удалить лишние ресурсы, но это придется делать самому + это затратная операция, чем больше таких task'ов, тем больше код будет делать одно и тоже для каждого такого типа task.


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


Ну и разница в декларативности также остается. Puppet более декларативен, в нем ты описываешь состояние, а task'и на как в ansible.

UFO just landed and posted this here

факты это другой механизм, он с данным вопросом не связан. Речь о механизме работы именно с ресурсами в терминах puppet и task'ами в терминах ansible.


Стандартный модуль user в ansible делает что-то с одним пользователем в одном task'e насколько я с ним знаком:


- name: 'user johnd'
  user:
    name: johnd
    comment: John Doe
    uid: 1040
    group: admin

Наверняка можно написать модуль, которому передается массив пользователей со свойствами и пусть он будет удалять всех пользователей, что нет в этом списке. Но таким модулем невозможно нормально пользоваться. Так как сразу получим проблему при использовании нескольких task в разных плеях и плейбуках, которые используют такой модуль или же если мы тащим к себе какой-то плейбук в котором используется стандартный модуль user. Наш модуль будет просто напросто удалять всех других пользователей, которые определены стандартным модулем user или же они определены в других task'ах нашим же модулем.


В puppet же, без разницы где и сколько раз ты объявил ресурс user и в каких классах или где-то еще. Всё это в итоге вместе со всеми другими ресурсами попадет на агент в виде json, и агент всё сделает. Для этого не требуется писать какой-то свой специальный модуль user, со своей специальной логикой.

UFO just landed and posted this here
Нет, не получим никакой проблемы. С чего вдруг?

Я возможно не понял о чём идет речь. Но вы же сами писали что нужно написать свой модуль + использовать только один task с ним:


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

Какой модуль ansible имеется в виду? Можете привести пример решения задачи: "нужно чтобы на хосте были пользователи user1, user2, при этом любые другие не системные пользователи (то есть с uid > 1000), которые не объявлены в task'ах модуля user удалялись."


Да, потому что его уже написали.

Я еще раз повторю — это не часть логики конкретного модуля puppet. Никто не пишет эту логику в модулях puppet, она заложена в агенте. У него такой принцип работы, реализовывать это разработчику модуля не требуется. Вы почему-то каждый раз упускаете это из виду. У puppet архитектура другая совсем. Никто его "уже не написал". Эту логику написал разработчики puppet, а не разработчики его модулей.


Итого вы говорите принципиальных отличий нет. Но для реализации
аналогичного в ansible предлагаете:


  • Написать свой кастомный модуль
  • Использовать task такого модуля только один раз, так как если его вызывать несколько раз с разными параметрами — это выстрел по ногам. Да и в целом такой модуль не юзабелен, и вызовет больше проблем чем пользы.

В puppet это заложено архитектурно. Для этого не надо реализовывать специальную логику в его модулях и писать кастомные модули для такой логики. Нет ограничений на один ресурс(task в ansible). Можно объявлять ресурсы модуля вообще в разных местах, в puppet агент они прилетят все вместе в одном json. Вменяемо, насколько я понимаю, в ansible это не реализовать, в виду другой архитектуры.


Это и есть принципиальные отличия.

UFO just landed and posted this here
но добиться этого вполне возможно при желании

Переписать все модули ansible и использовать для таких модулей всего один task — это нерабочее решение, и его невозможно использовать адекватно. И по юзабельности и функционалу оно все равно уступает тому, что есть в puppet из коробки.


Нет принципиальных архитектурных блокеров.

Есть. Я уже выше достаточно подробно рассказал какие.


Это будет точной копией юзер модуля паппета и таким же юзабельным как он.

Нет не будет. В puppet я могу использовать модуль user в куче классов одновременно в любых вариациях. В ansible я могу такое делать со стандартным модулем user тоже, но с ограничением о котором мы говорим, а в предложенной вами реализации модуля я смогу использовать только один раз task в одном месте. Это далеко не тоже самое, что в puppet.


Зачем вам вызывать модуль, создающих юзеров, несколько раз с разными параметерами?

Чтобы создать разных пользователей. Я могу в puppet иметь разные классы, один для настройки ssh сервер который создает пользователя, другой для mysql, который тоже создает пользователя, третий для nginx с созданием пользователя. И их переиспользовать как угодно. Тоже самое я могу делать и со стандартным модулем user в ansible, правда с ограничением о котором мы как раз говорим. А предложенный вами способ заставит вынести создание пользователей из всех этих ролей в отдельный task, и каждый раз когда я хочу переиспользовать одну из таких ролей мне нужно будет добавлять такой task для модуля user отдельно и согласовывать его с другими ролями.
А если учесть что мы перепишем все модули, как вы предлагаете, то таких единичных task'ов и параметров к ним будет настолько много, что любое изменение в ролях или удаление/добавление ролей будет адово сложным.

UFO just landed and posted this here
Или не использовать purge как вы делаете это в паппете? Впрочем это уже все усложнение и придумывание новых условий.

Так изначальный тред про purge и декларативность. О каких новых условиях идет речь? Напомню о постановке задачи edo1h:


я не могу, например, сказать «на системе должны быть user1, user2 и всё», я могу сказать «добавь пользователя user1» и «удали пользователя user4». если в системе был кем-то заведён user5, то ansible никак об этом не узнает.
и так во всём — от списка репозиториев в sources.list до конфигов нжинкса в conf.d.
я не воспринимаю конфиги ансибла как декларативные, скорее они императивные с идемпотентностью.

Поэтому ваше высказывание про придумывание новых условий — неправда.


Зачем вам переписывать все модули? Не нужно использовать только один таск, зачем вы придумываете?

Тогда лучше объясните что вы предлагаете для реализации задачи, а лучше с примером — я вас к сожалению не понял.


Нет, никакие из них не архитектурные

Архитектурные различия между puppet и ansible значительные. ansible выполняет список tasks по порядку, puppet совсем действует по другому, я уже не однократно описывал как. Именно поэтому в ansible хуже с декларативностью и есть большие проблемы с нормальной реализацией purge.


всего лишь некоторый легко восполняемый функционал уже встроен в паппет, и который легко можно реализовать в ансибл

Нет, это неправда к сожалению.

UFO just landed and posted this here
Обычно делается как-то концентрированно.

Обычно по ролям разбросано. Системные и прикладные аккаунты в соотвествующих ролях. Сконцентрировано разве что
персональные аккаунты для админов операторов и то проблемы с группами могут быть.

Можете привести пример решения задачи: «нужно чтобы на хосте были пользователи user1, user2, при этом любые другие не системные пользователи (то есть с uid > 1000), которые не объявлены в task'ах модуля user удалялись.»
а зачем такое нужно? Какой реальный use case?

Дело не в юзерах. Дело в том, что это типовая задача:


  1. получить список контейнеров, оставить только те, которые описаны в [манифесте|плейбуке] и привести их к определенному состоянию. Остальное — шлепнуть
  2. то же самое с правилами iptables
  3. то же самое с файлами
  4. то же самое с пользователями

    N. your option
Ну спорные задачи. Если ансибл ничего не знает о каких то контейнерах/пользователях/файлах/объектах — то возможно не стоит их удалять. Вижу очень много подводных камней в такой парадигме. Возможно для каких то специфических задач оно и нужно, но у меня, например, не возникало подобных за все время использования ansible (2+ года)
Если ансибл ничего не знает о каких то контейнерах/пользователях/файлах/объектах — то возможно не стоит их удалять.

если ансибл ничего не знает, например, о правилах айпитейблз, то легко можно получить дублирование правил, а это не хорошо. Я просто привел пример.


то возможно не стоит их удалять.

Почему? Предположим, у Вас каталог с конфигурацией vhost nginx. И админ туда зашел своими грязными руками и что-то поменял. Или обновление накатило дополнительный конфигурационный файл. А мы хотим, чтобы структура каталогов /etc/nginx была ровно такая, как мы ее задумали.


А если, например, мы управляем файлами конфигураций в ролях? Бр… какой-то ад начинается (ладно, можно просто так не делать и "не пытаться хотеть странного")

UFO just landed and posted this here
Ну спорные задачи

А мне кажется логично. Если я описал в системе управления конфигурациями как должна выглядеть директория /etc/nginx/conf.d и конфигурации в ней, я ожидаю что система будет всегда делать её такой, какой я описал. А если кто-то что-то там поменял, например добавил файл, то естественно это уже не то что я описал в коде, поэтому файл должен быть удалён. Более того, такой лишний файл конфигурации может сломать всю конфигурацию nginx, поэтому от системы управления конфигурациями я ожидаю больших гарантий того, как она за этим следит.


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

Если я описал в системе управления конфигурациями как должна выглядеть директория /etc/nginx/conf.d и конфигурации в ней, я ожидаю что система будет всегда делать её такой, какой я описал
если прям нужно такое, хотя не понимаю зачем — никто не мешает сначала удалить все файлы, а потом проверить нужные. Да лишний шаг, но зато ты точно знаешь что ты делаешь и что хочешь получить.

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

это костыль. Потому что проверка+удаление+приведение должны делать за один шаг, иначе есть высокая вероятность, что система будет в каком-то неконсистентном состоянии


Решение в puppet выглядит ружъем, которое рано или поздно выстрелит. И будет больно, имхо

я так не считаю. Хочешь (и нужно) — используешь, не хочешь — не используешь

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

Это плохое решение и оно не общее для любых типов ресурсов. Аналогичное с правилами iptables или правами к базе приведет к ужасным последствиям. Да и каждый раз удалять все файлы при применении конфигурации это дичь. Если ничего не поменялось, то не надо это менять, а в таком решении мы получим статус о changed task'ах — при любых прогонах. Опять скрипты вместо управления конфигурациями.

Это плохое решение и оно не общее для любых типов ресурсов.
и не должно быть общим для разных ресурсов, имхо

а в таком решении мы получим статус о changed task'ах — при любых прогонах
это да, но не критично

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

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


и не должно быть общим для разных ресурсов

Если писать свои костыли для очистки, конечно не должно.


никаких скриптов

Угу, оно и видно. Вместо ресурсов такси, вместо графа зависимостей, копирование кода на хост и выполнение его по порядку. Упала какая-то таска, handler не выполнился. Обычный императивный скрипт на мой взгляд, хоть и оформлен в yaml формате. Но в этом одновременно и приемущество ansible на задачах не про управление конфигурациями.

потому что я в том же модуле ансибла узнаю обо всех ресурсах

нет


Вся разница в том, что в puppet это must, в Ansible по желанию.

да

UFO just landed and posted this here

Ровно потому что модуль не может опираться на «факты» для понимания того — нужно ли применять некое действие или нет. Т.е. факты — это хорошо, для понимания стартовых условий, в которых был применён плейбук (ну, не знаю — там хостнейм, айпи адрес и прочее). Но Вы же сами пишете, что никакой защиты от дурака нет и получается, что в процессе выполнения play факты могут разъехаться с реальностью. Ну, либо необходимо тогда факты обновлять после каждого вызова любого модуля ансибла, но мы бы чокнулись это делать (быстродействие и так не фонтан)

UFO just landed and posted this here
Информацию прекрасно можно собрать и в самом модуле перед тем как что-то делать.

но к фактам, простите, это имеет отношения чуть менее, чем никакого

Так нам же нужно не просто собрать информацию о ресурсах на хосте. Нам еще нужно знать какие task этого же модуля на этом хост прилетят. Иначе мы не сможем построить список того, что мы хотим получить, и сравнить со списком того что есть на хосте, а затем привести хост к тому что хотим получить.


А иначе мы просто будем сравнивать только текущий task с тем что есть на хосте, и так каждый такой task. Что и происходит в ansible.

UFO just landed and posted this here

на самом деле нет, они перед глазами у админа, а не перед глазами у ансибла, т.к. конкретные таски могут быть скипнуты по условиям выполнения предыдущих тасок...

Насколько я знаком с ansible. Он для выполнения task'а, копирует код модуля на хост и выполняет его, и так с каждым task такого модуля. Область видимости модуля один task и его свойства. Поправьте если я не прав.


Но опять же это детали. В puppet, при разработке модуля, тебе вообще не надо думать об области видимости модуля, и решать связанные с этим задачи для реализации удаления ресурсов. puppet это делает сам, сравнивая список всех ресурсов(task в терминах ansible) описанных на мастере для этого хоста, с тем что есть в этом хосте. Поэтому у тебя не болит голова о том, как реализовать purge для ресурсов, которые не описаны — оно само.

UFO just landed and posted this here
Не правы. Есть контекст плейбука и данных с прошлых запусков если они кешируются.

Контекст текущего плейбука, а других плейбуков, которые тоже будут применены к этому хосту? Прошлые запуски не помогут узнать, что у нас появились новые task'и для модуля в другом playbook'e. Хочется посмотреть примеры на ansible, которые это используют для того чтобы удалять с хоста ресурсы, которые не под управлением ansible.


я, честно говоря, не вижу от чего тут может болеть голова

Ну это довольно не тривиальная вещь на мой взгляд. И требует большой работы. Например выше вы предложили ограничить использование модуля одним task'ом — что накладывает очень много ограничений на удобство использования такого модуля.


хочешь пиши модуль чтобы был декларативным

Не совсем понял что значит декларативность модуля. Так как модули/провайдеры выполняют как раз императивные действия, как в ansible так и в puppet. От модулей ansible/провайдеров puppet мы требуем идемпотентности как правило.


Ну вот конструкция:


tasks:
  - file:
      path: /tmp/test
      state: absent
  - file:
      path: /tmp/test
      state: directory

Не декларативна, поскольку тут один и тот же объект имеет два разных состояния. Как я понял вы предлагаете переписать модуль file на свой custom_file и делать что-то вроде:


tasks:
  - custom_file:
      - path: /tmp/test
        state: absent
      - path: /tmp/test
        state: directory
      - path: /etc/nginx
        state: directory

И уже в модуле custom_file проверять path и таким образом гарантировать декларативность и выдавать ошибку при одинаковых path. Но на мой вкус это сделает ansible просто не юзабельным, придется вытаскивать все task с использованием модуля file из всех ролей, и описать это все отдельно одним task'ом — что ужасно и не юзабельно плюс сильно ухудшит возможность переиспользования.


В придачу с другими фишками ансибла у тебя свобода

Аналогичная свобода есть в любой другой реализации SCM.

UFO just landed and posted this here
Нет, будущее ансибл не предсказывает и это не нужно.

Текущее выполнение task'ов, которых не было в предыдущем запуске, это не будущее, а настоящее.


Использование purge одним таском, а не модуля.

Как при выполнении task purge, узнать о всех task'ах которые применятся к хосту, чтобы удалить только то, что не описано в плейбуках?


Нет, я такого не предлагал. Для чего вы это делаете? Какая ваша конечная цель?

Тогда я не понял вас, каким образом вы предлагаете обеспечить декларативность? Конечная цель сделать описание декларативным, и сделать так, чтобы все что не подконтрольно ansible удалялось для указанного типа модуля

Тогда я не понял вас, каким образом вы предлагаете обеспечить декларативность? Конечная цель сделать описание декларативным, и сделать так, чтобы все что не подконтрольно ansible удалялось для указанного типа модуля

задачу написания идемпотентных (не декларативных!) плейбуков, очевидно, ансибл перекладывает на плечи разработчика (администратора) плейбуков. Соответственно, в случае плейбуков, которые занимаются какими-то операционными вещами — эта идемпотентность не нужна. В случае плейбуков, которые реализуют использование ansible как SCM средства — нужна. Поди разберись! Но т.к. сам инструмент по сути является инструментом "simple IT automation", то такие вопросы и возникают.

UFO just landed and posted this here
Зачем вы удаляете и создаете ту же директорию?

это просто демонстрация того, что ансибл — это не декларативный инструмент. Это инструмент, который последовательно выполняет таски. Баш на стероидах, ч.т.д. Для использования в качестве SCM не годится, но если он хочется, то можно.

UFO just landed and posted this here

зачем, если salt/puppet/chef это все умеют из коробки?
Сколько нужно обмазывать ансибл, чтобы им можно было начать пользоваться?
Ну, я уж не говорю о том, что по возможности нужно съезжать на IaC + immutable infra

UFO just landed and posted this here

Перефразирую — ансибл не нужно устанавливать, он с неба спускается? Не нужно, чтобы целевая система имела тот же python-интерпретатор правильной версии?


Что значит «из коробки»?

то и значит. Посмотрите архитектуру указанных систем, задачи, которые они решают, и как они эти задачи решают.


Я только за IaC + immutable infra, но не вижу тут никаких противоречий.

Tower/AWX к этому никакого отношения не имеет. Он просто запускалка плейбуков. Не более.

UFO just landed and posted this here
Нет, с ансиблом это не пройдет

Ну это печально что тут сказать. Из всех ролей вытаскивать task'и определенного модуля, чтобы реализовать хоть какой-то purge — сильно неудобное в поддержке решение и оно совсем не будет работать как в puppet. Так как puppet просто применяет absent ко всем ресурсам которые не описаны, ansible так не может сделать принципиально.


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


Либо давайте пример такой task'и purge. Я вангую там будет очередной костыль в виде shell скрипта или в лучшем случае отдельный модуль, который удаляет ресурсы, отсутствующие в контексте play, но эти решения оба плохи, так как такие ресурсы должны управляться родным модулем и удалятся его средствами через absent.


Также такое решение ужасно с точки зрения надежности. Легко забыть и добавить task в какую-нибудь роль, а потом обнаружить что результат выполнения такого таска будет удален или не удален, зависит от порядка выполнения, что очередной раз нам показывает императивную природу ansible.


Поэтому "можно реализовать" — это лукавство. Можно, но с кучей ограничений, таких что пользоваться таким решением просто невозможно. Причина этих ограничений: другая архитектура, слабая декларативность, императивная природа инструмента. Это принципиальные отличия.


Зачем вы удаляете и создаете ту же директорию?

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


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


Не вижу смысла дальше дискутировать, пока тред не превратился в демагогию окончательно.

Один и тот же ресурс не может иметь два состояния одновременно. Если же может, то это не декларативность.

Это просто разная декларативность. Декларация полного конечного состояния системы после полного применения единого по сути конфига и декларация состояния системы после применения одного плэя.

декларация состояния системы после применения одного плэя.

Нет. Это не декларация. Как минимум потому что ансибл не оперирует термином «ресурс», а именно, что модули. И вы полностью (как в обычном программировании) полагаетесь на… side-effects. Немного спасает, что бОльшая часть модулей написана правильно и умеет в идемпотентность, но в первую очередь — это желаемое свойство самого плейбука. Которое достигается тем, что он будет особым способом написан.
Был уже пример про


- file:
path: /tmp/test
state: absent
- file:
path: /tmp/test
state: directory
декларация состояния системы после применения одного плэя

Не одного play, а одного task по идее, в одном play нет декларативности, поскольку там несколько task'ов могут описать один и тот же объект с разными состояниями. Если бы была декларативность на уровне одного play, то это уже было бы неплохо.


На мой взгляд декларативность не может применяться к одному объекту с одним действием/описанием над ним. Например:


a = 10

Конечно такая конструкция всегда декларативна, в любом языке, пока она не превратится в такую:


a = 10
...
...
a = 12

Декларативность это как раз про декларацию полного состояния, как это делает terraform например.

UFO just landed and posted this here
никакие другие репозитории он не удалял

а должен?

Потому что вы не сказали ему это сделать.


Файлы довольно уникальный тип ресурса для puppet. Так как файлов в системе очень много, и не очень эффективно их загонять все в ресурсы и знать обо всех, поэтому puppet с ними работает не много иначе. Но тем не менее, задача с source.list решается так:


Если используется /etc/apt/sources.list.d:


file {'/etc/apt/sources.list.d':
  ensure  => directory,
  recurse => true,
  purge   => true,
}

Если используется модуль apt. То нужно классу apt об этом сказать:


class {'apt':
    purge => {
        'sources.list'   => true,
        'sources.list.d' => true,
        'preferences'    => true,
        'preferences.d'  => true,
        'apt.conf.d'     => true,
    }
}

На самом деле он внутри это делает также передавая свойство purge в ресурсе файл. С конфигами nginx решается аналогично.

Коллеги, добавил опрос. Прошу проголосовать.

мне кажется, «нет» нужно поделить на «нет, оно не нужно» и «нет, но хотелось бы иметь такую возможность»

Добавил. Но сбросить результаты опроса похоже не получится.

и переголосовать нельзя )

UFO just landed and posted this here

тем, что это не терраформ? У терраформа вполне конкретная задача — управление инфраструктурными объектами, а не настройка конкретных серверов...

UFO just landed and posted this here

terraform всё таки позиционируется на провижионе инфраструктуры, а не управлении софтом на серверах. О чём честно пишут в доках:


Terraform is not a configuration management tool

контекст:


Configuration management tools install and manage software on a machine that already exists. Terraform is not a configuration management tool, and it allows existing tooling to focus on their strengths: bootstrapping and initializing resources.


Terraform focuses on the higher-level abstraction of the datacenter and associated services, while allowing you to use configuration management tools on individual systems. It also aims to bring the same benefits of codification of your system configuration to infrastructure management.


If you are using traditional configuration management within your compute instances, you can use Terraform to configure bootstrapping software like cloud-init to activate your configuration management software on first system boot.


И советуют совмещать эти инструменты, если нужно.

Sign up to leave a comment.

Articles

Change theme settings