Jeff Geerling, автор большого количества ролей на Ansible Galaxy, в связи с коронавирусом выложил книги Ansible for DevOps и Ansible for Kubernetes бесплатно. Можно будет скачивать и все последующие обновления.
https://www.jeffgeerling.com/blog/2020/you-can-get-my-devops-books-free-rest-month
#ansible #kubernetes
https://www.jeffgeerling.com/blog/2020/you-can-get-my-devops-books-free-rest-month
#ansible #kubernetes
Знания из серии "ходил мимо 100 раз и вдруг нежданчик"
Сегодня узнал что оказывается нельзя параметризировать просто так имена тасков в ансибле, например того же хендлера
Ansible task names need to be defined as "global vars" (vars which are defined via a method which creates only a single variable no matter how many hosts reference that variable later). Inventory variables don't satisfy that because inventory, by definition, defines variables for individual hosts. If you wish to parameterize the handler name, you could set it via an extra var at ansible-playbook invocation.
#ansible
Сегодня узнал что оказывается нельзя параметризировать просто так имена тасков в ансибле, например того же хендлера
name: restart {{ service }}
- просто так незя сделать. А вот почему:Ansible task names need to be defined as "global vars" (vars which are defined via a method which creates only a single variable no matter how many hosts reference that variable later). Inventory variables don't satisfy that because inventory, by definition, defines variables for individual hosts. If you wish to parameterize the handler name, you could set it via an extra var at ansible-playbook invocation.
#ansible
извлекаем значение из переменной в ansible
случай довольно "тяжелый", тут бы в пору в дурку звонить, но понадобилось мне извлечь в переменную несколько значений из словаря, который в массиве, который в словаре, который в массиве. и сделать это всё по конкретным именам ключей, а вывод воплотить в конкретно оформленную строку. в общем наслаждайтесь.
Дано(для простоты оставлены только нужные для селекта ключи):
случай довольно "тяжелый", тут бы в пору в дурку звонить, но понадобилось мне извлечь в переменную несколько значений из словаря, который в массиве, который в словаре, который в массиве. и сделать это всё по конкретным именам ключей, а вывод воплотить в конкретно оформленную строку. в общем наслаждайтесь.
Дано(для простоты оставлены только нужные для селекта ключи):
user_list:Нужно получить:
- name: core
ssh_keys:
- name: main
type: "ecdsa-sha2-nistp256"
value: "AAAA..."
pubkey: "ecdsa-sha2-nistp256 AAAA....."Как это в итоге получилось, для переменной в hostvars:
pubkey: "{% set core_main_ssh_params =#ansible #jinja #дичь
user_list |
selectattr('name', 'equalto', 'core') |
sum(attribute='ssh_keys', start=[]) |
selectattr('name', 'equalto', 'main') |
list | first -%}
{{ core_main_ssh_params.type }} {{ core_main_ssh_params.value }}"
Конфиг prometheus сервера с хостами из consul шаблонизированный в jinja
consul_services - переменная получаемая таском:
#consul #ansible #prometheus #jinja
global:
scrape_interval: 10s
scrape_timeout: 10s
remote_write:
- queue_config:
max_samples_per_send: 10000
max_shards: 30
url: {{ remote_write_url }}
rule_files:
{% for rulefile in (lookup('fileglob', '*.rules')).split(',') %}
- /etc/prometheus/{{ rulefile | basename }}
{% endfor %}
alerting:
alertmanagers:
- static_configs:
- targets:
{% for host in groups[alertmanager_group] %}
- {{ hostvars[host]['ansible_default_ipv4']['address'] }}:9093
{% endfor %}
{% set service_list=[] %}
{%- for k,v in consul_services.json.items() %}
{{ service_list.append(v.Service) }}
{%- endfor %}
scrape_configs:
{% for service in service_list | unique %}
- job_name: {{ service }}
consul_sd_configs:
{% for tag in ['env1','env2','env3'] %}
- server: {{ consul_url | replace("http://", "") }}
tags: [ {{ tag }} ]
services: [ {{ service }} ]
{% endfor %}
{% endfor %}
consul_services - переменная получаемая таском:
- name: Fetch consul services
uri:
url: "{{ consul_url }}/v1/agent/services?filter=prometheus+in+Tags"
body: json
register: consul_services
changed_when: false
check_mode: no
#consul #ansible #prometheus #jinja
Вооооот. А еще я наклепал лабу по linux hardening... По большей части это компиляция из известных ресурсов, моего там практически нет. В целом это выглядит как чистый хахреднинг, но на самом деле он лежит в разделе про ansible, потому что тут довольно неплохие задачи которые позволят прокачать свои умения в этом продукте. Так шо объединяем приятное с полезным - инфраструктура как код и сесурити, шобы злобный хацкер не майнил бетховенов на вашем железе!
https://github.com/bykvaadm/OS/tree/master/devops/ansible/lab4
#linux #hardening #security #ansible
https://github.com/bykvaadm/OS/tree/master/devops/ansible/lab4
#linux #hardening #security #ansible
GitHub
OS/devops/ansible/lab4 at master · bykvaadm/OS
Contribute to bykvaadm/OS development by creating an account on GitHub.
Собрал стенд для обучения работы с hashicorp vault
Разворачивается через вагрант на локальных вм. Поднимается куб кластер в котором поднимается HA версия vault с бекендом на HA etcd.
НА - это не на, а аббревиатура. написано большими буквами потому что я не помню как пишется high availabilпыр-пыр-пыр. etcd используется вместо консула потому что почему бы и нет. разница в бэкенде не существенна при обучении работы с vault. (ну на самом деле, потому что консул в кубе можно развернуть только один кластер, а это значит что мы отдаем его только под секреты - ведь не шарить же его еще с кем-то если мы там храним секреты, а в данном случае кажется избыточным поднимать консул, ведь если у вас будет 20 нод, вы получите 20 реплик консула (так написан чарт), а у etcd по-прежнему останется 3. )
В данном репозитории ТОЛЬКО сам стенд. материалы для обучения продаются, как говорится, отдельно =)
https://github.com/bykvaadm/vault-on-kubernetes-stand
#virtualbox
#vagrant
#ansible
#kubernetes
#helm
#docker
#etcd
#ingress
#hashicorp
#vault
#обучение
З.Ы. поделились аналогичным стендом, на компоузах и с консулом. https://github.com/temalovepizza/vaultstuff
Разворачивается через вагрант на локальных вм. Поднимается куб кластер в котором поднимается HA версия vault с бекендом на HA etcd.
НА - это не на, а аббревиатура. написано большими буквами потому что я не помню как пишется high availabilпыр-пыр-пыр. etcd используется вместо консула потому что почему бы и нет. разница в бэкенде не существенна при обучении работы с vault. (ну на самом деле, потому что консул в кубе можно развернуть только один кластер, а это значит что мы отдаем его только под секреты - ведь не шарить же его еще с кем-то если мы там храним секреты, а в данном случае кажется избыточным поднимать консул, ведь если у вас будет 20 нод, вы получите 20 реплик консула (так написан чарт), а у etcd по-прежнему останется 3. )
В данном репозитории ТОЛЬКО сам стенд. материалы для обучения продаются, как говорится, отдельно =)
https://github.com/bykvaadm/vault-on-kubernetes-stand
#virtualbox
#vagrant
#ansible
#kubernetes
#helm
#docker
#etcd
#ingress
#hashicorp
#vault
#обучение
З.Ы. поделились аналогичным стендом, на компоузах и с консулом. https://github.com/temalovepizza/vaultstuff
GitHub
GitHub - bykvaadm/vault-on-kubernetes-stand
Contribute to bykvaadm/vault-on-kubernetes-stand development by creating an account on GitHub.
Используем несколько паролей в ansible-vault
Данный пост родился благодаря тому что документация ansible на этот счет нихрена не очевидна и мне пришлось потратить заметное количество времени на то чтобы сделать эту примитивную задачу, а именно - получить возможность использовать несколько разных паролей для разграничения доступа к sensitive data в ansible.
Дисклаймер: это мой личный путь, я описываю свой личный кейс, не надо писать в комментах "КОКОКО это не сработает при таких-то и таких-то условиях".
1) сохраняем файлы с паролями, например ~/.vault_prod ~/.vault_dev
2) рассказываем об этом ansible и помещаем, например, в .zshrc
3) шифруем
- текст: ansible-vault encrypt_string TEXT --encrypt-vault-id prod
- файл: ansible-vault encrypt --encrypt-vault-id dev /path/to/file
4) расшифруем
При расшифровке (выкатке на сервера) указывать id не нужно - ансибл последовательно перебирает все указанные в ANSIBLE_VAULT_IDENTITY_LIST файлы и расшифровывает
#ansible
Данный пост родился благодаря тому что документация ansible на этот счет нихрена не очевидна и мне пришлось потратить заметное количество времени на то чтобы сделать эту примитивную задачу, а именно - получить возможность использовать несколько разных паролей для разграничения доступа к sensitive data в ansible.
Дисклаймер: это мой личный путь, я описываю свой личный кейс, не надо писать в комментах "КОКОКО это не сработает при таких-то и таких-то условиях".
1) сохраняем файлы с паролями, например ~/.vault_prod ~/.vault_dev
2) рассказываем об этом ansible и помещаем, например, в .zshrc
export ANSIBLE_VAULT_IDENTITY_LIST=prod@~/.vault_prod, dev@~/.vault_dev
3) шифруем
- текст: ansible-vault encrypt_string TEXT --encrypt-vault-id prod
- файл: ansible-vault encrypt --encrypt-vault-id dev /path/to/file
4) расшифруем
При расшифровке (выкатке на сервера) указывать id не нужно - ансибл последовательно перебирает все указанные в ANSIBLE_VAULT_IDENTITY_LIST файлы и расшифровывает
#ansible
о структуре ansible репозитория (часть 1)
Казалось бы тема не сильно сложная, бери беспрактис от ансибла и работай - никаких проблем. Однакож есть несколько моментов, которые они не учитывают:
1. по любым примерам показывается что, мол, храните плейбуки в корне папки ансибла и всё ок. ну вот вам для примера 3 ямлика, красиво же.
2. кросс-инвентарные переменные. правда, я вроде не плохо гуглю, но на оффдоках не нашел ничего похожего.
В чем же проблема №1? а в том, что когда у вас несколько инвентарей, и вы пишете плейбуки которые по смыслу делают одно и то же но в разных инвентарях, вам их надо либо делать строго одинаковыми и в конечном итоге получать один файл (с возможными доработками в виде условий, которые в обычной жизни нахрен не нужны), либо делать несколько файлов для каждого инвентаря. Оба варианта очевидно в конечном итоге приводят к не очень хорошим результатам. В первом случае - это какая-то не нужная логика, которая усложняет поддержку и использование плейбука, а во втором случае у нас просто множится количество файлов. В моем опыте оказалась ситуация когда у коллег удавалось писать "абсолютный" плейбук для своих задач, но это им просто повезло - если ты пишешь плейбук для тестовой и для продовой инфры, сервера по сути одни и те же и способы ввыкладки сервиса тоже. а значит это по сути один и тот же инвентарь, который разделен логически на тест и прод. А вот мне повезло не так сильно и нужно было писать плейбуки под создание сервиса как на своих железках (которые мы можем приготовить как угодно) так и в облаке, а также на "территории" легасёвой инфраструктуры клиента. В таком случае сами понимате сделать 1 плейбук на всё невозможно. Стали рождаться плейбуки вида rolename_inventory_azaza, rolename_inventory_ololo, rolename_inventory_pururum итп. Ситуацию осложняло то, что не все придерживались практики (я никого не виню - не было никакой договорённости) указывать имя инвентаря в имени плейбука.
В конечном итоге ситуация пришла к тому, что в корневом каталоге у нас оказались порядка 50 плейбуков, вперемешку со служебными файлами - gitlab-ci, Dockerfile, ansible.cfg, ansible-lint итп итп. Лично мне стало уже просто неудобно этим оперировать репозиторием. Не критично, не тяжело или как-то сложно, а именно неудобно. плейбуки перестали помещаться в один столбец в pycharm, а понять из названия сразу к какому инвентарю относится плейбук стало тоже непонятно - нужно было заходить внутрь, смотреть группу по которой катался плейбук, грепать ее по инвентарям... короче гемор! При этом в текущем состоянии репозиторий не то чтобы был плох, нет, им вполне можно было пользоваться, но я понимал, что команда у нас растет, а репозиторию меньше года и что дальше будет только хуже. В итоге назрел план небольшой революции и перекроя репозитория. конечный результат - после истории №2.
#ansible
Казалось бы тема не сильно сложная, бери беспрактис от ансибла и работай - никаких проблем. Однакож есть несколько моментов, которые они не учитывают:
1. по любым примерам показывается что, мол, храните плейбуки в корне папки ансибла и всё ок. ну вот вам для примера 3 ямлика, красиво же.
2. кросс-инвентарные переменные. правда, я вроде не плохо гуглю, но на оффдоках не нашел ничего похожего.
В чем же проблема №1? а в том, что когда у вас несколько инвентарей, и вы пишете плейбуки которые по смыслу делают одно и то же но в разных инвентарях, вам их надо либо делать строго одинаковыми и в конечном итоге получать один файл (с возможными доработками в виде условий, которые в обычной жизни нахрен не нужны), либо делать несколько файлов для каждого инвентаря. Оба варианта очевидно в конечном итоге приводят к не очень хорошим результатам. В первом случае - это какая-то не нужная логика, которая усложняет поддержку и использование плейбука, а во втором случае у нас просто множится количество файлов. В моем опыте оказалась ситуация когда у коллег удавалось писать "абсолютный" плейбук для своих задач, но это им просто повезло - если ты пишешь плейбук для тестовой и для продовой инфры, сервера по сути одни и те же и способы ввыкладки сервиса тоже. а значит это по сути один и тот же инвентарь, который разделен логически на тест и прод. А вот мне повезло не так сильно и нужно было писать плейбуки под создание сервиса как на своих железках (которые мы можем приготовить как угодно) так и в облаке, а также на "территории" легасёвой инфраструктуры клиента. В таком случае сами понимате сделать 1 плейбук на всё невозможно. Стали рождаться плейбуки вида rolename_inventory_azaza, rolename_inventory_ololo, rolename_inventory_pururum итп. Ситуацию осложняло то, что не все придерживались практики (я никого не виню - не было никакой договорённости) указывать имя инвентаря в имени плейбука.
В конечном итоге ситуация пришла к тому, что в корневом каталоге у нас оказались порядка 50 плейбуков, вперемешку со служебными файлами - gitlab-ci, Dockerfile, ansible.cfg, ansible-lint итп итп. Лично мне стало уже просто неудобно этим оперировать репозиторием. Не критично, не тяжело или как-то сложно, а именно неудобно. плейбуки перестали помещаться в один столбец в pycharm, а понять из названия сразу к какому инвентарю относится плейбук стало тоже непонятно - нужно было заходить внутрь, смотреть группу по которой катался плейбук, грепать ее по инвентарям... короче гемор! При этом в текущем состоянии репозиторий не то чтобы был плох, нет, им вполне можно было пользоваться, но я понимал, что команда у нас растет, а репозиторию меньше года и что дальше будет только хуже. В итоге назрел план небольшой революции и перекроя репозитория. конечный результат - после истории №2.
#ansible
о структуре ansible репозитория (часть 2)
Проблема №2: кросс инвентарные переменные. А вот это нужно для того чтобы можно было из любого инвентаря воспользоваться нужной общей переменной. Например вы создаете виртуалку и хотите чтобы после ее разворота можно было сразу обратиться по доменному имени. Вы добавляете роль управления днс именами в плейбук... а как авторизоваться? как хороший пацан вы написали универсальную роль и не захардкодили в ней параметр с токеном. Или другой пример - база данных пользователей, если вы катаете их ансиблом (хейтеры, отстаньте), то чтобы катать их на разные инвентари и не дублировать, нужно либо иметь один плейбук который будет только что и делать что настраивать пользователей и вы будете запускать его с лимитами по нужным хостам..... ну, да, звучит ужасно. Либо - хранить где-то снаружи ямл с ключами и хешами юзеров. Общие ссл сертификаты. адрес консула. Ну и итд итп, это много где используется. С самого начала такой файл был организован как group_vars/all.yml в корне ансибла. По сути этой бы проблемы не было, если бы не способ решения первого пункта. Для справки как это вообще работало: запускаемый плейбук читает свою директорию. и у него нет никаких проблем залезть в соседнюю с ним папку group_vars и забрать all.yaml а потом сходить в inventory/i_name/ и там прочитать group_vars, host_vars... и так мы получали все нужные переменные при запуске....
А теперь к решению. Для того чтобы сделать красиво я рассмотрел вариант убрать все плейбуки по инвентарям в папку playbooks/i_name. Сказано - сделано. и в этот момент мгновенно перестали работать роли и кросс-инвентарные переменные. Решение вопроса было осуществлено с помощью симлинка. т.е. мы взяли и слинковали в каждом инвентаре кросс-инвентарный файл с переменными. а в ansible.cfg нужно добавить вот эти строки:
А конечная структура вышла вот такой:
Остается до сих пор проблема того, что в нашем кросс-инвентарном файле может быть довольно много переменных. На текущий момент в качестве решения я думаю о том чтобы сделать symlink кросс-платформенных переменных не на файл global.yml, а на директорию, all -> all. в директори можно хранить множество разделенных по смыслу файлов и все они будут подсасываться во время работы. а файл специфичных для инвентаря переменных вынести по классике в group_vars/all.yml. Но это - тема для будущей революции =)
#ansible
Проблема №2: кросс инвентарные переменные. А вот это нужно для того чтобы можно было из любого инвентаря воспользоваться нужной общей переменной. Например вы создаете виртуалку и хотите чтобы после ее разворота можно было сразу обратиться по доменному имени. Вы добавляете роль управления днс именами в плейбук... а как авторизоваться? как хороший пацан вы написали универсальную роль и не захардкодили в ней параметр с токеном. Или другой пример - база данных пользователей, если вы катаете их ансиблом (хейтеры, отстаньте), то чтобы катать их на разные инвентари и не дублировать, нужно либо иметь один плейбук который будет только что и делать что настраивать пользователей и вы будете запускать его с лимитами по нужным хостам..... ну, да, звучит ужасно. Либо - хранить где-то снаружи ямл с ключами и хешами юзеров. Общие ссл сертификаты. адрес консула. Ну и итд итп, это много где используется. С самого начала такой файл был организован как group_vars/all.yml в корне ансибла. По сути этой бы проблемы не было, если бы не способ решения первого пункта. Для справки как это вообще работало: запускаемый плейбук читает свою директорию. и у него нет никаких проблем залезть в соседнюю с ним папку group_vars и забрать all.yaml а потом сходить в inventory/i_name/ и там прочитать group_vars, host_vars... и так мы получали все нужные переменные при запуске....
А теперь к решению. Для того чтобы сделать красиво я рассмотрел вариант убрать все плейбуки по инвентарям в папку playbooks/i_name. Сказано - сделано. и в этот момент мгновенно перестали работать роли и кросс-инвентарные переменные. Решение вопроса было осуществлено с помощью симлинка. т.е. мы взяли и слинковали в каждом инвентаре кросс-инвентарный файл с переменными. а в ansible.cfg нужно добавить вот эти строки:
[defaults]добавление ~/.ansible/roles нужно для того чтобы подцеплялись galaxy роли.
roles_path = roles:~/.ansible/roles:/etc/ansible/roles
А конечная структура вышла вот такой:
.Запуск плейбука осуществляется из директории с ансиблом такой командой:
├── inventories
│ ├── global.yml
│ ├── inventory1
│ │ ├── group_vars
│ │ │ ├── all
│ │ │ │ ├── global.yml -> ../../../global.yml
│ │ │ │ └── local.yml
│ │ │ ├── group1.yml
│ │ │ ├── ...
│ │ │ └── groupN.yml
│ │ ├── host_vars
│ │ │ ├── host1.yml
│ │ │ ├── ...
│ │ │ └── hostN.yml
│ │ └── hosts
│ └── inventory2
│ ├── group_vars
│ │ ├── all
│ │ │ ├── global.yml -> ../../../global.yml
│ │ │ └── local.yml
│ │ ├── group1.yml
│ │ ├── ...
│ │ └── groupN.yml
│ ├── host_vars
│ │ ├── host1.yml
│ │ ├── ...
│ │ └── hostN.yml
│ └── hosts
├── playbooks
│ ├── inventory1
│ │ ├── play1.yml
│ │ ├── ...
│ │ └── playN.yml
│ └── inventory2
│ ├── play1.yml
│ ├── ...
│ └── playN.yml
├── roles
│ ├── role1
│ ├── ...
│ └── roleN
├── ansible.cfg
├── tabpy.yml
├── test.yaml
├── wireguard.yml
└── zookeeper.yml
ansible-playbook -i inventories/inventory1/hosts playbooks/inventory1/play1.yml -bD [--tags, ...]Строка полностью влезает в консоль и не переносится на вторую, что вполне сохраняет удобство. Кроме того такой подход к хранению плейбуков является обратно-совместимым. вы можете оставить часть плейбуков в корневой директории.
Остается до сих пор проблема того, что в нашем кросс-инвентарном файле может быть довольно много переменных. На текущий момент в качестве решения я думаю о том чтобы сделать symlink кросс-платформенных переменных не на файл global.yml, а на директорию, all -> all. в директори можно хранить множество разделенных по смыслу файлов и все они будут подсасываться во время работы. а файл специфичных для инвентаря переменных вынести по классике в group_vars/all.yml. Но это - тема для будущей революции =)
#ansible
Делаем резервные копии postgres на s3 (minio)
В гисте приложен кусочек плейбука ansible который настраивает резервное копирование через mc клиент. скрипт умеет выгружать в bucket по-отдельности каждую базу из списка, оценивать размер и время совершения последнего копирования каждой базы и отдавать эту информацию в формате prometheus, а также подчищать из s3 устаревшие копии.
https://gist.github.com/bykvaadm/434a4eef5392528c9c0e4788937301bc
#postgres
#docker
#patroni
#ansible
#minio
#prometheus
В гисте приложен кусочек плейбука ansible который настраивает резервное копирование через mc клиент. скрипт умеет выгружать в bucket по-отдельности каждую базу из списка, оценивать размер и время совершения последнего копирования каждой базы и отдавать эту информацию в формате prometheus, а также подчищать из s3 устаревшие копии.
https://gist.github.com/bykvaadm/434a4eef5392528c9c0e4788937301bc
#postgres
#docker
#patroni
#ansible
#minio
#prometheus
Gist
Postgres patron backup on Minio with prometheus monitoring
Postgres patron backup on Minio with prometheus monitoring - README.md
Когда нужно ролью ansible положить некоторое количество файлов, можно это сделать методом создания директорий, а потом каждый файл класть по-отдельности. Но это подход, который не слишком-то удобен и требует переписывать каждый раз код. Для того чтобы автоматизировать этот процесс можно пользоваться фильтрами with_filetree\fileglob:
первый таск создаст все директории с учетом вложенных, какие бы не были в files/www, а второй таск положит все файлы какие бы там не были, сохраняя расположение файлов в дереве каталогов.
#ansible
- name: ensure www dirs
file:
path: "/var/www/{{ item.path }}"
state: directory
owner: root
group: root
mode: 0755
with_filetree:
- files/www
when: item.state == 'directory'
- name: ensure apple files
copy:
src: "{{ item.src }}"
dest: "/var/{{ item.src | regex_search('www/(vhost1|vhost2)/.*') }}"
with_filetree:
- files/www
when: item.state == 'file'
первый таск создаст все директории с учетом вложенных, какие бы не были в files/www, а второй таск положит все файлы какие бы там не были, сохраняя расположение файлов в дереве каталогов.
#ansible
Еще в догонку по ансиблу - о булевых выражениях. Сейчас будет ооочень очевидная вещь, но True и true - это разные вещи. Почему-то раньше я дико тупил и все мои булевые проверки были такими:
хотя на самом деле всё очень просто. true - строка. True\False - bool.
поэтому объявляем переменную мы так:
и проверку делаем так:
#ansible #очевидное
{% if anyvar | bool %}
или
when: anyvar | bool
или еще хуже
when: anyvar | bool == "true"
хотя на самом деле всё очень просто. true - строка. True\False - bool.
поэтому объявляем переменную мы так:
anyvar: True
и проверку делаем так:
when: anyvar
{% if anyvar %}
#ansible #очевидное