DySprozin aka xjmjk
DySprozin aka xjmjk
974 просмотров4 комментариев

Быстрая и надежная настройка Репки — Ansible

Disclaimer
В настоящей статье автор крупными мазками даёт общее представление об Ansible — что это за зверь и как его готовить, чтобы по этой и следующим статьям (если они будут) любой мог хоть сколько-нибудь осмысленно реализовать у себя описанную автоматизацию. Это не полноценная статья про Ansible, так что гуру DevOps и прочих IaC-ов могут выдыхать :-)

Водная часть
Пожалуй, первоначальная настройка Репки, как и любой другой железки — самая ответственная часть. Она же самая муторная. Без должной автоматизации, работа превращается в рутину, а малейшая ошибка, опечатка, забытый конфиг могут всплыть уже потом, когда готовое устройство на базе одноплатника начало глючить «непонятно почему» и «проще снести и поставить заново». Особенно, когда оно уже уехало к заказчику, да.

Ну и сама идея — нажать кнопочку и идти пить кофе заняться в это время чем-то более полезным весьма привлекает. Какие варианты автоматизации? Можно, конечно, не заморачиваться, а просто написать bash-скрипт, который построчно выполнит все команды: установит нужный софт, внесет правки в конфиги и так далее.

В целом этот вариант рабочий — до первого сбоя в середине выполнения, который никогда не стоит сбрасывать со счетов: ошибка сети, перебой в питании, случайный кот… И вот уже скрипт превращается в тыкву, ведь без соответствующих оберток и проверок повторный его запуск будет спотыкаться буквально на всём: повторное создание папки, изменение конфигов по шаблону, распаковка архивов... да и просто удаление файлов может пойти не по плану. А если вдруг нужно запустить скрипт на десятке Репок (кстати, а вы знали, что кластер из Репок — это грядка?)…

Это всё я веду к тому, что гораздо надёжней использовать Ansible — этот инструмент не только включает в себя большинство необходимых проверок, которые исключают повторное выполнение уже выполненных задач (тасков), но и его банально проще читать, в отличие от каши, в которую рано или поздно скатится любой bash-скрипт.

Установка Ansible
Практика показала, что ставить Ansible непосредственно на Репке — процесс долгий, муторный и, в конечном итоге, бессмысленный. Тем более в рамках данной статьи — мы предполагаем, что изначально wifi-доступа к Репке нет или он очень нестабилен. Потому устанавливать Ansible будем на домашний (рабочий) компьютер и выполнять с него же (сегодня локально, а дальше — на Репке с использованием ssh).

Установку будем производить на Ubuntu 22.04, но в целом она стандартна для любой *nix машины. «Ой, а у меня Windows!», — ну… вы сами выбрали этот путь :-) Поищите решение в Яндексе (на самом деле, как бывший виндузятник, я просто вам завидую, винда классная!).

При установке мы будем использовать виртуальное окружение, потому что если есть способ не захламлять основную систему, то лучше не захламлять (ваш КЭП).

Поставим python3-venv (а заодно sshpass, чтобы была возможность из ansible локально вводить sudo-пароль, если он у вас есть):

apt-get install -y python3-venv sshpass

Дальнейшая настройка на всех ОС должна быть похожа.

Создадим виртуальное окружение:

python3 -m venv ~/.venv/ansible/

Активируем его:

source ~/.venv/ansible/bin/activate

В случае успеха должно появиться слово ansible в скобках:

Рис. 1. Окружение (ansible) активировано

Получилось? Отлично! Запомните или запишите где-то эту команду — она будет пригождаться каждый раз, когда вы захотите использовать Ansible снова. Кстати, мы его до сих пор не поставили, исправляемся:

pip install ansible

Теперь ненадолго отвлечёмся — запишем на SD-карточку свежий образ РепкаОС 1.0.14 (от 06.10.23), плейбук тестировался только на нем. Описывать по десятому кругу одни и те же шаги по заливке оси не вижу смысла, так что сразу к делу:

sudo dd if=~/Downloads/arm64_ubuntu_20.04.6_desktop_06.10.23_1GHz.img of=/dev/XXX bs=1M status=progress iflag=direct oflag=direct 

Логично, что вместо ~/Downloads надо указать свою директорию, а вместо /dev/XXX — свою карту памяти. После записи, как правило, автоматом открывается директория с папкой. Ее обычно спешат тут же закрыть, а карточку отмонтировать. Но сейчас не тот случай. Для дальнейшей работы карточка должна быть примонтирована (т. е. в Репку пока не вставляем), а так же должен быть известен путь монтирования. Например, на Ubuntu он выглядит примерно так:

/media/sysadmin/6142818e-d23c-4d3d-9efb-072818e2818e

Теперь склонируйте себе в отдельную папку репозиторий с Ansible-ролями (пока роль всего одна, да и вообще автор как бы намекает, что ему не помешал бы на официальном гитфлике Репки репозиторий для юзера xjmjk, а пока качайте с нашего сервера).

git clone https://git.1qq.su/repka-pi-pub/ansible-roles.git repka-ansible-roles

Теперь заходим в repka-ansible-roles, внутри такое вот (или похожее) дерево:

Рис. 2. Дерево Ansible-роли

Нас тут сейчас интересует подпапка vars, точнее, ее отсутствие. Связано это с тем, что в ней хранятся переменные, которые могут содержать пароли, а потому в гите им быть… кхм… не желательно :-)

mkdir roles/repka_init/vars/

Далее создайте файл roles/repka_init/vars/main.yml со следующим содержимым:

main_dir: /media/sysadmin/6142818e-d23c-4d3d-9efb-072818e2818e
wpa_ssid: MY-WI-FI
wpa_psk: my-wifi-password

Пожалуй, будем лишним пояснять, что первая строчка это путь к примонтированной папке, вторая и третья строчка — это wifi-сеть и пароль к ней.

Наконец, перед запуском пробежимся по главному файлу:

roles/repka_init/tasks/main.yml

- name: Add wifi interface configuration
  copy:
    content: |
      allow-hotplug wlan0
      auto wlan0
      iface wlan0 inet dhcp
      wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
    dest: "{{ main_dir }}/etc/network/interfaces.d/wlan0"

- name: Add wpa_supplicant.conf
  copy:
    content: |
       ctrl_interface=DIR=/var/run/wpa_supplicant_wlan0_custom GROUP=netdev
       update_config=1
       country=RU
       p2p_disabled=1
       network={
               ssid="{{wpa_ssid}}"
               psk="{{wpa_psk}}"
       }
    dest: "{{ main_dir }}/etc/wpa_supplicant/wpa_supplicant.conf"
    mode: '0600'

- name: Fix bug in the /etc/wpa_supplicant/functions.sh
  lineinfile:
    path: "{{ main_dir }}/etc/wpa_supplicant/functions.sh"
    regexp: 'echo "\$WPA_SUP_PNAME: \$@" >/dev/stderr'
    line: 'echo "$WPA_SUP_PNAME: $@" >> /var/log/wpa_supplicant_err.log'

- name: Disable ipv6
  lineinfile:
    path: "{{ main_dir }}/etc/sysctl.conf"
    line: 'net.ipv6.conf.all.disable_ipv6 = 1'
    create: yes

- name: Add 'TimeoutSec=900'
  ini_file:
    dest: "{{ item }}"
    section: "Service"
    option: "TimeoutSec"
    value: 900
  with_items:
    - "{{ main_dir }}/lib/systemd/system/wpa_supplicant-wired@.service"
    - "{{ main_dir }}/lib/systemd/system/wpa_supplicant.service"
    - "{{ main_dir }}/lib/systemd/system/wpa_supplicant-nl80211@.service"
    - "{{ main_dir }}/lib/systemd/system/wpa_supplicant@.service"

      
- name: blue led off and bash_init script
  lineinfile:
    path: "{{ main_dir }}/etc/crontab"
    line: "@reboot root  /bin/bash -c 'echo 0 > /sys/class/leds/rbs\\:red\\:status/brightness ; cat /boot/poweroff_flag || /bin/bash /boot/bash_init.sh'"

- name: Add init bash script
  copy:
    content: |
      #!/bin/bash
      /usr/bin/systemctl daemon-reload
      touch /boot/poweroff_flag
      poweroff
    dest: "{{ main_dir }}/boot/bash_init.sh"

#- name: Comment line in fstab
#  replace:
#    path: "{{ main_dir }}/etc/fstab"
#    regexp: '^(.*tmpfs\s+/tmp\s+tmpfs\s+defaults\s+0\s+0.*)$'
#    replace: '#\1'

Для тех, кто видит ansible первый раз, поясню. Выше приведен плейбук, а точнее часть плейбука — таски, т. е. задачи, которые сервер будет выполнять. Каждая задача начинается с «- name: ...». Впрочем, подробный разбор ansible, как было замечено, выходит за рамки настоящей статьи, тут просто быстро пробежимся, за что именно отвечает каждый шаг.

- name: Add wifi interface configuration

Создаст файл конфига wifi /etc/network/interfaces.d/wlan0 с указанием конфига wpa_supplicant.conf. Там же указывается, что будет использоваться dhcp — вы можете поправить на свой вкус, главное, не забывайте соблюдать количество отступов.

- name: Add wpa_supplicant.conf

Создаст, собственно, сам файл конфига wpa_supplicant.conf с логином, паролем, регионом и т. д.

- name: Fix bug in the /etc/wpa_supplicant/functions.sh

Костыль, чтобы wpa_supplicant не ругался на /dev/stderr , а писал ошибки в отдельный файл /var/log/wpa_supplicant_err.log

- name: Disable ipv6

Отключаем ipv6 — обычно он больше мешает.

- name: Add 'TimeoutSec=900'

Добавляем во все конфиги сервисов wpa_supplicant дополнительный timeout.

- name: blue led off and bash_init script

Добавляем в крон таску, которая:

  • выключает синий светодиод
  • проверяет наличие файла /boot/poweroff_flag (см. следующую таску)
  • если файла нет, то запускает bash_init.sh

- name: Add init bash script

Создаст сам скрипт bash_init.sh , который:

  • перезагрузит конфиги: /usr/bin/systemctl daemon-reload
  • создаст файл poweroff_flag (чтобы этот скрипт больше не выполнялся): touch /boot/poweroff_flag
  • выключит репку: poweroff

Последний пункт оказался очень удобен: больше не надо подключать монитор, чтобы проверить, запустилась ли репка, прошла ли инициализация и т. д. Если репка выключилась через некоторое время после первого запуска, то с вероятностью 99% всё прошло успешно, можно включить репку заново и проверить подключение по wifi.

Ну вот и всё, кажется… А, нет, еще осталась таска:

- name: Comment line in fstab

Я эту таску специально закомментил, потому что она вредная :-) Отключает в fstab монтирование папки /tmp в оперативку, что может быть актуально, как временное решение. Делать на страх и риск, по заверениям знающих людей, постоянная запись в /tmp убивает SD-карту на раз.

Теперь точно всё. Файл в папке vars создали? Сейчас вы находитесь в папке repka-ansible-roles? Слово ansible в скобках не пропало? Если пропало, то сделайте снова «source ...» (см. выше). Готовы? Поехали:

ansible-playbook --ask-become-pass repka_init.yml

Результат должен быть примерно таким:

Рис 3. Успешный успех

Поздравляю :-) Безопасно извлеките SD-карту теперь питание компьютера можно отключить. Теперь вставляете ее в Репку, включаете и ждёте, пока она сама выключится. Дождались? Теперь подайте заново питание и через пару минут можно пробоваться подключаться по wifi — должно получиться.

Enjoy, за сим всё! =)


Комментарии (4)

Для участия в обсуждении вы должны быть авторизованным пользователем
admin
admin  

Статья просто огонь! Спасибо!
Про то, что кластер из Репок это уже грядка и про случайного кота очень улыбнуло :-)

Михаил  

после ввода команды
ansible-playbook --ask-become-pass repka_init.yml
выводит:
BECOME password:

какой пароль вводить? 123?

ввожу пароль 123 и вот что выдает:
это правильно?

(ansible) user@mbk:~/repka-ansible-roles $ ansible-playbook --ask-become-pass repka_init.yml
BECOME password:
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the
implicit localhost does not match 'all'

PLAY [localhost] ***************************************************************************

TASK [Gathering Facts] *********************************************************************
ok: [localhost]

TASK [repka_init : Add wifi interface configuration] ***************************************
fatal: [localhost]: FAILED! => {"msg": "Failed to get information on remote file (/media/user/93eafb14-0568-40ea-a1e8-0ab1907ef5ee/etc/network/interfaces.d/wlan0): Structure needs cleaning"}

PLAY RECAP *********************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

DySprozin aka xjmjk
DySprozin aka xjmjk  

fatal: [localhost]: FAILED! => {"msg": "Failed to get information on remote file (/media/user/93eafb14-0568-40ea-a1e8-0ab1907ef5ee/etc/network/interfaces.d/wlan0): Structure needs cleaning"}

вот тут ошибка ) в конфиге надо прописать путь к sd-карте

из статьи:

Для дальнейшей работы карточка должна
 быть примонтирована (т. е. в Репку пока не 
вставляем), а так же должен быть известен 
путь монтирования. Например, на Ubuntu он 
выглядит примерно так:

/media/sysadmin/6142818e-d23c-4d3d-9efb-072818e2818e
Михаил  

было прописано в файле roles/repka_init/vars/main.yml

main_dir: /media/user/93eafb14-0568-40ea-a1e8-0ab1907ef5ee
wpa_ssid: DIR-825-FA14
wpa_psk: 79320863

в каком файле? который в tasks или который в vars?

"Теперь ненадолго отвлечёмся — запишем на SD-карточку свежий образ РепкаОС 1.0.14 (от 06.10.23), плейбук тестировался только на нем. "

а я использую образ от 1.12.2023(arm64_ubuntu_20.04.6_desktop_01.12.23_ver-1.4.img)
может из за этого?

Новые посты

Навигация

ВойтиРегистрацияТемы