Ускоренное импортозамещение или как разворачивать Linux-дистрибутив БЕЗ помощи SCCM в распределённой корпоративной сети

Kate

Administrator
Команда форума
Опять в интернете кто-то неправ! Натолкнулся недавно на статью и даже сначала ужасно огорчился. И один из комментариев в самую точку — зачем насиловать пингвина виндой? Разумеется, это негодование шуточное. На самом деле — это инсталляция с помощью стороннего dhcp/bootp-сервера, а то что он на windows, так это другой вопрос — у кого и что было, кто и чем умеет пользоваться. Ребята, молодцы! По крайней мере, движутся в правильном направлении. А вот насколько это проще без инфраструктуры Windows, мы сейчас и посмотрим.
Разумеется, установка образов используя виндовую инфраструктуру мне не нравится и поэтому я по шагам опишу (и разовью) один из стандартных методов.

Процесс инсталляции с локального носителя в значительно утрированном виде выглядит следующим образом: груб — монтирует минимальную файловую систему initrd и грузит ядро, ядро запускает процесс init (systemd), который, в свою очередь, запускает инсталлятор. У RedHat — это anaconda, у Debian/Ubuntu — он называется debian-installer, и далее начинается процесс установки. Я буду описывать более родную мне анаконду, а значит — это отечественные дистрибутивы ROSA и REDOS.

Загрузились. Анаконда рисует нам экраны с различными вопросами — временная зона, параметры сети, какой набор софта поставить, пользователей заводим/пароли им назначаем, как разбить диски и т.д. Когда вопросы закончатся, начинается инсталляция и мы можем спокойно идти пить чай (в молодости пили пиво). Далее одна перезагрузка и машина готова, единственное — её надо уже шлифовать под пользователя. Переносить данные, почту, ставить нестандартный софт, минимальное обучение и т.д.

Коллаж из инсталляционных скриншотов. Не соответствуют реальной последовательности установки и вроде как даже от разных версий
Коллаж из инсталляционных скриншотов. Не соответствуют реальной последовательности установки и вроде как даже от разных версий

Пока всё совпадает с процессом установки Windows, по крайней мере, тем, который я ещё застал и который иногда наблюдаю у коллег. Здесь меня могут поправить и я согласен, что знания мои в этой области мизерные. Но обращаю внимание, что статья о процессе установки линукса и винду — мы больше троллить не будем.

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

Итак, мы впервые установили «эталонную» машину. Заходим в каталог пользователя root и видим файл anaconda-ks.cfg

Содержимое anaconda-ks для примера:

#version=DEVEL
# System authorization information
auth --enableshadow --passalgo=sha512
# Use CDROM installation media
cdrom
# Use graphical install
graphical
# Run the Setup Agent on first boot
firstboot --enable
ignoredisk --only-use=sda
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us','ru' --switch='grp:alt_shift_toggle'
# System language
lang ru_RU.UTF-8

# Network information
network --bootproto=dhcp --device=eno1 --ipv6=auto --no-activate
network --hostname=localhost.localdomain

# Root password
rootpw --iscrypted $6$K2i9HR45ptnHOg4U$MflacVttGoh333/L52RHz8fwn4pnOgRJES2/eGa9MWU6bxF7PQPZscYGDTk8BVe0IIIB8JyQay1yFb8wmbAI.1
# System services
services --enabled="chronyd"
# System timezone
timezone Europe/Moscow --isUtc
user --groups=wheel --name=test --password=$6$0Rl333j/K/qIsR1Y$L.Qnf9ppQVJbo8tkOkbNNmKNJrSAbvioJIfmqR6vG24vXSqBqrK4365I8Vwoj416AyXWsur1OguUgvocCFWYo1 --iscrypted --g
# X Window System configuration information
xconfig --startxonboot
# System bootloader configuration
bootloader --location=none
autopart --type=lvm
# Partition clearing information
clearpart --none --initlabel

%packages
@^mate-desktop-environment
@base
@core
@desktop-debugging
@dial-up
@directory-client
@fonts
@guest-agents
@guest-desktop-agents
@input-methods
@internet-browser
@java-platform
@mate-desktop
@multimedia
@network-file-system-client
@networkmanager-submodules
@print-client
@rosa-utils
@x11
chrony

%end

%addon com_redhat_kdump --disable --reserve-mb='auto'

%end

%anaconda
pwpolicy root --minlen=6 --minquality=50 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=50 --notstrict --nochanges --notempty
pwpolicy luks --minlen=6 --minquality=50 --notstrict --nochanges --notempty
%end


Когда мы устанавливали систему — все наши ответы были записаны в данный файл kickstart. Этот файл можно взять и передать при установке на следующем компьютере в параметрах инсталлятору и тогда мы получим почти полную копию данной системы. Под выражением «почти полная» я подразумеваю, что будет идентичный набор программного обеспечения, сетевые адреса, пользователи и пароли и т.д., а всё, что уникально для машины — UUID дисков, размеры партиций, зависящие от физического объёма диска и т.д. будут свои.

Инсталляцию с данным файлом производим следующим образом:

  1. Копируем файл на носитель, с которого будем грузиться и ставить систему — на флешку, т.к. мне кажется, остальные варианты уже неактуальны.
  2. При загрузке в меню grub на строчке с пунктом меню для установки системы, нажимаем «e» и проваливаемся в редактирование пункта.
  3. В строчку, начинающуюся на linux — добавляем параметр inst.ks=anaconda-ks.cfg.
  4. Продолжаем загрузку. «Ctrl+x».

Теперь инсталлятор прочитает файл anaconda-ks.cfg и пропустит все экраны с вопросами. По сути, пока получили грамотное клонирование, но не достигли цели минимизации последующего ручного труда при доводке системы.

Следующий этап. Читаем документацию по синтаксису kickstart-файла (на английском, на русском). Всё очень и очень просто. Например, параметры сети меняются в одной строчке, указываются имя и пароль (хэш) локального пользователя, по набору софта — подключаем/отключаем как группами, так и индивидуально. Уже сразу (сейчас) можно нарисовать кучу файлов для каждой машины, закидать их на флешку и при установке только обозначать требуемый конфиг. Можно попробовать, но мы пойдём дальше.

Кстати, ручное создание kickstart дело весьма полезное, особенно на начальном этапе, но и соответствующие инструменты автоматизации имеются, как для создания оного (system-config-kickstart — объявлен deprecated :) ), так и для проверки — ksvalidator. А также RedHat имеет особенный сервис Kickstart generator, к которому нам доступ не получить, да и не очень-то хотелось.

_bq5nc-ypweugheoarp5x26v0-g.jpeg


Держать уникальные конфиги на флешках — идея так себе. По сути, хоть в «энтерпрайзе» рабочие места и стремятся к типовым конфигурациям, но их (рабочих мест) иногда реально много и править, а потом раскладывать конфиги по всему вороху флешек становится утомительно. Значит, мы приходим к централизованному хранению конфигурационных файлов.
Сказано — сделано. Все свои kickstart-файлы разместили в каталог веб-сервера, процесс загрузки меняем минимально. Указываем параметр:

inst.ks=http://192.168.0.2/anaconda-ks-192.168.2.31.cfg
Здесь я условно написал уникальное имя конфига для нашей машины

Замечаем, что в качестве источника kickstart-файла указан сетевой ресурс. Делаем вывод, что у нас есть сеть, а как она может быть, если ip-адрес мы указываем в самом kickstart-файле?

И, разумеется, эта ситуация уже была продумана и решена. Вот пример для указания статического адреса, параметры для которого мы вписываем аналогично тому, как указывали сценарий для inst.ks:

ip=192.168.2.31::10.32.2.29:24:linux2:eno1:none


Для dhcp проще, читаем самостоятельно. С самого начала не указал, но, может, вы обратили внимание, что вся статья заточена под статическую адресацию, ибо в моём «энтерпрайзе» это только так, но вы легко можете сделать поправку под свою инфраструктуру. Также обращаю внимание, что ip-адрес в процессе инсталляции, и ip-адрес, который будет после установки системы — можно делать разными, т.е. всю установку производить в выделенном сегменте, а потом отдавать компьютеры пользователям на их реальные рабочие места и в совершенно других сетевых сегментах.

Мысль летит дальше, и нам уже неинтересно лепить конфигурацию для отдельных машин. Хочется, чтобы всё делалось самостоятельно. Напрягаемся сами (или напрягаем ближайшего программиста) и делаем простейшую (в зависимости от потребностей) динамическую страничку для формирования kickstart-файла. Контент собирается в зависимости от параметров в запросе или IP-адреса обратившегося.

Мой вариант скрипта:
Как писал выше, адресация только статика (рай для безопасников), а локалок, мелко порубленных на сегменты, достаточно много. По большому счёту мне необходимо только задать параметры сети — адрес, маска, шлюз, адреса dns-серверов.
Параметры для всех сегментов сети находятся в файле networks.csv примерно такого вида:

192.168.0.0/24;192.168.0.1;192.168.0.3,192.168.0.2;DMZ
192.168.1.0/25;192.168.1.1;192.168.0.3,192.168.0.2;Пользователи 1
192.168.1.128/25;192.168.1.129;192.168.0.3,192.168.0.2;Принтеры
192.168.2.48/28;192.168.2.49;8.8.8.8,192.168.0.3;VIP
...


Первое поле — сетка с префиксом, второе — шлюз, третье — адреса dns-серверов, четвёртое поле — комментарий.

Сам веб-сервер — практически однострочник на python, который можно держать в чистом виде или спрятать за балансировщиком. Используем лёгкий python веб-фреймворк: Bottle

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from bottle import route, run, template
import ipaddress
import glob

# получение конфигурационного файла configFile для хоста с адресом ipAddr
@route('/<configFile>/<ipAddr>')
def index(configFile, ipAddr):

ip = ipaddress.ip_address(ipAddr.decode('utf-8'))
net0 = ipaddress.ip_network(u'10.0.0.0/8')

# находим сеть с наибольшим префиксом
for n in ipdb.keys():
if ip in n:
if net0.prefixlen < n.prefixlen: net0 = n

if net0.prefixlen == 8: return '' # сеть в нашей базе отсутствует

return template(configFile, ip=str(ip), mask=str(net0.netmask), gw=ipdb[net0]['gw'], ns=ipdb[net0]['ns'])

# получение пречня конфигурационных файлов
@route('/list')
def show_configs():

cfgList = '<pre>\n';

for cfgFileName in glob.glob('*.cfg'):
cfgList += cfgFileName + '\n'

return cfgList

if __name__ == '__main__':

# загрузка базы сетей
ipdb = {}
with open("networks.csv") as ipdbFile:
for line in ipdbFile:
(network, gw, ns, comment) = line.strip().split(";")
ipdb[ipaddress.ip_network(network)] = { 'gw': gw, 'ns': ns }

# запуск сервера
run(host='127.0.0.1', port=8891)


Ну и набор конфигурационных файлов, в которых надо в двойных фигурных скобках указать изменяемые параметры (собственный шаблонизатор bottle в деле). Например, строчки с параметрами сети в моих конфигах выглядят так:

network --bootproto=static --device=eno1 --ip={{ip}} --netmask={{mask}} --gateway={{gw}} --nameserver={{ns}} --ipv6=auto --activate --hostname=lnx1


Как этим пользоваться? При установке указываем путь к файлу:

inst.ks=http://192.168.0.2:8891/new.cfg/192.168.2.31


где new.cfg — конфигурационный файл, а 192.168.2.31 — ip-адрес нашей будущей машины.

Также можно глянуть, какие kickstart-файлы находятся на сервере. Просто с любой машины зайти браузером на http://192.168.0.2/list.

Данный «сервер» применяйте исключительно в учебных целях! Ибо безопасность здесь отсутствует.

Студентам дарю идею: можно сделать неплохой диплом, развив подобный сервис — с блэкджеком с генератором kickstart-файлов, упорядоченным хранением и отдачей их по сети. Аналогичный сервис RedHat предоставляет это за плату (предположительно, т.к. проверить не могу).

Итак, вроде написано много, а результат, кажется, пока не очень заметен и значим. На самом деле — уже сейчас мы можем написать инструкцию на половинку листочка А4 и отправить её в самый далёкий сегмент нашей распределённой сети. Специально обученный персонал скачивает iso-файл с сервера производителя нашей отечественной ОС (либо с внутренних ресурсов), подготавливает флешку(и) и запускает инсталляцию по нашему сценарию, хоть на полусотне машин одновременно. Причём из инфраструктуры достаточно только одного легковесного веб-сервера на всю корпоративную сеть!

Осталась фаза некоего тюнинга системы. Здесь, несложно — только обозначу, а дальше сами. Как правило, админы делают некий скрипт, который вручную запускают на свежеустановленной системе. В этом скрипте обычно прописаны все необходимые действия в виде установки сертификатов, ssh-ключей, какой-либо дополнительный софт, подключение/отключение репозиториев, правил фаервола, задания в крон и прочее.

Для таких нужд в kickstart имеются две секции — %pre и %post. Секция %pre выполняется до установки. Здесь корректируем работу самого инсталлятора — например, можно изменить параметры разбивки диска в зависимости от его размера, завести какие-нибудь переменные для подстановки их значений в kickstart. У меня эта секция всегда пустая и познания чисто теоретические — пытайте как угодно, ничего не выдам :)

Секция %post — вот что нам нужно. Посудите сами: система установлена, chroot в неё сделан, сеть доступна, все системные конфиги сформированы, имеется полный комплект консольных утилит, права на выполнение рутовые. Вдобавок, саму скриптовую часть можно писать как на баше, так и на питоне.

Что тут пишем? Да всё, что перечислял выше:

  • скачиваем и раскладываем сертификаты, запускаем update-ca-trust,
  • заводим необходимых пользователей, скачиваем и раскладываем конфиги в sudoers.d,
  • распихиваем по всем щелям ssh-сертификаты (authorized_keys),
  • скачиваем дополнительные файлы — например, наполняем /etc/skel (man pam_mkhomedir),
  • разрешаем/запрещаем сервисы и сразу конфиги им правим,
  • ограничиваем информационные потоки (файрвол настраиваем),
  • и прочие полезные мероприятия, всё это в любом порядке и в любых количествах.

При написании секции %post обращаю особое внимание на /etc/skel/* — это те файлы, которые система скопирует в домашний каталог пользователя при его первом входе. Так как у линукса нет реестра и сопутствующих ему проблем, то необходимые текстовые конфиги (например, профили firefox, thunderbird) можно также генерировать индивидуально, на этапе инсталляции. Пример %post своих конфигов — не покажу.

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

 
Сверху