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

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

Время на прочтение5 мин
Количество просмотров28K

Иногда приходится настраивать различные *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, Ansible и 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!

P.S.

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

Теги:
Хабы:
Всего голосов 20: ↑4 и ↓16-11
Комментарии30

Публикации

Истории

Работа

Ближайшие события

19 августа – 20 октября
RuCode.Финал. Чемпионат по алгоритмическому программированию и ИИ
МоскваНижний НовгородЕкатеринбургСтавропольНовосибрискКалининградПермьВладивостокЧитаКраснорскТомскИжевскПетрозаводскКазаньКурскТюменьВолгоградУфаМурманскБишкекСочиУльяновскСаратовИркутскДолгопрудныйОнлайн
24 – 25 октября
One Day Offer для AQA Engineer и Developers
Онлайн
25 октября
Конференция по росту продуктов EGC’24
МоскваОнлайн
26 октября
ProIT Network Fest
Санкт-Петербург
7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань