Как стать автором
Обновить

Настраиваем любой Linux под себя одной командой

Системное администрирование *Программирование **nix *Разработка под Linux *DevOps *
Из песочницы

Иногда приходится настраивать различные *unix системы: персональные компьютеры, VPS, Raspberry Pi и так далее. Но когда их становится много, настраивать их становится всё сложнее и сложнее. Поэтому хочется автоматизировать этот процесс. В данной статье я расскажу как я решил подобную проблему, расскажу про некоторые существующие решения, а так же покажу магию bash!

Проблема

Приведём несколько часто встречающихся случаев, когда надо настроить linux под себя, то есть установить пакеты различными способами, настроить их (с помощью команд или изменяя конфиги).

  • VPS. Когда ты покупаешь облачный сервер, то он обычно пуст. Там почти всегда нет того что тебе нужно: docker, docker-compose, настроенного VPN или почтового сервера. Не для всего нужен k8s с возможностью резервации дополнительных мощностей, да и настройка подобной инфраструктуры занимает время.

  • Персональный компьютер, виртуальные машины. Если вы предпочитаете операционные системы на основе Linux, то вам наверняка не раз приходилось пробовать новые дистрибутивы и сборки. И со временем вы обрастаете полезным инструментарием для работы на них. Но если вы вдруг купите новое железо или друзья попросят поделится наработками? А может у вас навернулся SSD или вы потеряли рабочий ноутбук?

  • Установка и настройка одного и того же на различные дистрибутивы. Не все программы можно одинаково легко и безболезненно установить и настроить одновременно на Arch Linux и Debian. И если вы захотите перейти с Ubuntu на Arch Linux, то могут возникнуть сложности и большие

  • Сборка и установка пакетов из исходного кода. Не редко чтобы получить актуальную или конкретную версию программы нет иного способа, кроме как клонировать репозиторий, установить зависимости, собрать программу, установить её, а после настроить под себя. А иногда зависимости тоже необходимо собирать вручную. Это становится проблемой, когда весь этот процесс надо повторить на других машинах.

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

Пример такого скрипта на bash:

# Скачиваем скрипт-установщик
curl -fsSL https://get.docker.com -o get-docker.sh

# Устанавливаем докер
sudo sh get-docker.sh

# Удаляем скрипт-установщик
rm get-docker.sh

# Запускаем службу Docker
sudo systemctl enable --now docker

# Выдаём права текущему пользователю
sudo groupadd docker
sudo usermod -aG docker $USER

# Применяем права
newgrp docker

Скрипт простой и рабочий, хотя и не лишён недостатков, например, в плане безопасности.

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

Решения

Решают это проблему по разному. Приведу несколько интересных способов, что мне запомнились:

  1. Свой дистрибутив/ядро/сборка. Собрать собственный сборки на различный случаи жизни.

    Мнение: Трудоёмко и сложно в настройке и обновлении, но максимально стабильно и самый лучший способ кастомизации.

  2. Свой универсальный пакет. В пакеты можно встраивать и скрипты для конфигурации. Что мешает создать пакет mydesktop при установки который будет устанавливать и настраивать все ваши любимые программы.

    Мнение: Менее трудоёмко, чем свой дистрибутив, но требует для настройки CI/CD для выпуска пакетов. Удобен для обновления и миграций конфигурации множества машин.

  3. Скрипты на Python. С помощью таких библиотек как: Fabric, Invoke, Plumbum и subprocess.

    Мнение: гибкий способ, можно создать, например, универсальный пакетный менеджер, фасад для работы во всеми существующими. Но требует предварительной установки Python на машину (если ею не управляют через SSH).

  4. Написать скрипты на Bash.

    Мнение: самый простой способ - скопировать команды из терминала в файл, а после доставить через wget, SCP, curl куда угодно. Но не такой гибкий и с обновлениями есть проблемы.

Лично я попробовал все четыре способа. В итоге мне очень надоело постоянно что-то обновлять, тестировать, придумывать что-то сложное и гибкое - создание того самого универсального пакетного менеджера. И я написал простой сборщик скриптов на Bash

Идея

Допустим у нас есть 3 скрипта: install-docker.sh, install-wireshark.sh, install-tmux.sh.

Хотим создать из них 2 итоговых скрипта: desktop.sh и server.sh. В первый включить все существующие скрипты, а во второй только install-docker.sh и install-tmux.sh

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

Реализовать на bash это достаточно просто:

#!/usr/bin/env bash

cat install-wireshark.sh >> desktop.sh
cat install-tmux.sh >> desktop.sh
cat install-docker.sh >> desktop.sh

cat install-tmux.sh >> server.sh
cat install-docker.sh >> server.sh

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

Создадим папку scripts и все скрипты будем хранить там:

mkdir scripts

mv install-docker.sh scripts/docker.sh
mv install-tmux.sh scripts/tmux.sh
mv install-wireshark.sh scripts/wireshark.sh

Теперь составим список всех скриптов в папке, чтобы всегда можно было добавить что-нибудь ещё и добавим список для выбора (whiptail) для наглядности:

# Выясняем абсолютный путь до текущего скрипта
SCRIPTPATH="$(
	cd "$(dirname "$0")" >/dev/null 2>&1
	pwd -P
)"

# Указываем путь до папки со скриптами
SCRIPTS_DIRECTORY=$SCRIPTPATH/scripts

# Инициализиуем переменную со списком для checklist
_checklist=

# Цикл по всем скриптам в папке
for i in $SCRIPTS_DIRECTORY/*.sh; do
    [ -e "$i" ] || continue
    script_name=$(basename "$i")

    _checklist+="$script_name $script_name off "
done

# Checklist
OUTPUT=$(whiptail --checklist "Please pick one" 10 60 4 $_checklist 3>&2 2>&1 1>&3)
Результат
Результат

Абсолютный путь до исполняемого скрипта SCRIPTPATH необходим если скрипт будет запускаться из произвольного места.

Осталось только выделенные скрипты собрать в один:

output_script=$SCRIPTPATH/output.sh

for select_script_name in $OUTPUT; do
    # Убираем ковычки:
		select_script_name="${select_script_name%\"}"
		select_script_name="${select_script_name#\"}"
    # Собираем скрипты
    cat $SCRIPTS_DIRECTORY/$select_script_name >> $output_script
done

Таким образом мы получили простой скрипт для сборки скриптов для установки и настройки.

Итоговый код
#!/usr/bin/env bash

# Выясняем абсолютный путь до текущего скрипта
SCRIPTPATH="$(
	cd "$(dirname "$0")" >/dev/null 2>&1
	pwd -P
)"

# Указываем путь до папки со скриптами
SCRIPTS_DIRECTORY=$SCRIPTPATH/scripts

# Инициализиуем переменную со списком для checklist
_checklist=

# Цикл по всем скриптам в папке
for i in $SCRIPTS_DIRECTORY/*.sh; do
    [ -e "$i" ] || continue
    script_name=$(basename "$i")

    _checklist+="$script_name $script_name off "
done

# Checklist
OUTPUT=$(whiptail --checklist "Please pick one" 10 60 4 $_checklist 3>&2 2>&1 1>&3)


output_script=$SCRIPTPATH/output.sh

for select_script_name in $OUTPUT; do
    # Убираем ковычки:
		select_script_name="${select_script_name%\"}"
		select_script_name="${select_script_name#\"}"
    # Собираем скрипты
    cat $SCRIPTS_DIRECTORY/$select_script_name >> $output_script
done

Заключение

Но простого скрипта для слияния нескольких файлов - этого недостаточно, чтобы это было полезно для повседневной жизни. Вот что ещё предстоит реализовать для этого:

  1. Зависимости из других скриптов. Например, чтобы использовать скрипт install-docker-compose.sh для начала надо использовать install-docker.sh.

  2. Пользовательский интерфейс: CLI и/или TUI.

  3. Логирование и работа с исключениями

  4. Скрипты могут работать по разному для различных систем. Поэтому скрипты, как минимум, должны знать:

    • Какие в системе установлены пакетные менеджеры

    • Какой дистрибутив используется

    • Какие установлены WM и DE

    • Версия ядра

  5. Возможность в итоговый скрипт запаковывать дополнительные файлы (например, конфигурационные файлы)

  6. Способы публикации созданных конфигурационных скриптов и доставки на устройства

  7. Тестирование проекта

Если вам интересно как это всё можно реализовать на чистом bash, то можете написать комментарии, что конкретно вам больше всего интересно. А так же можете посмотреть что в итоге у меня вышло: Oh my Linux!

Теги:
Хабы:
Всего голосов 15: ↑3 и ↓12 -9
Просмотры 6.8K
Комментарии Комментарии 8