Когда нужно массово переустановить ОС на компьютерах в корпоративной сети, мы привыкли использовать System Center Configuration Manager (SCCM) и все хорошо, если речь идёт про Windows, но с Linux немного все сложнее, т.к. нет готовых инструментов в SCCM.

К счастью, SCCM удобный и гибкий инструмент, чтобы решить любую задачу по переустановке ОС. Если у вас инсталляция SCCM не распределённая, где все ПК находятся в одной сети, то вам подойдёт вот эта статья для установки ОС Linux с сетевой папки.

Если у вас распределённая инсталляция SCCM, где много Distribution Point в отдалённых локациях (с «небыстрыми» каналами связи), а установку нужно проводить на 100 ПК одновременно, то с сетевой папки сделать это сложно. Именно эту задачу нам понадобилось решить, попутно улучшив и автоматизировав способ, описанный выше (идея взята из упомянутой статьи и доработана, спасибо fisher51 и моим коллегам, кто помогал).

Итак, приступим.

Создаём виртуалку с минимальным диском, это важно, т.к. от размера будет зависеть размер итогового образа (для Xubuntu достаточно 9Gb). Устанавливаем Xubuntu (для примера), выбирая стандартное разделение дисков:

Разбивка диска
Разбивка диска

Как видно на скриншоте, у нас один диск 9Gb со стандартной разбивкой, где /dev/sda1 – загрузочная партиция (FAT32), /dev/sda2 – логический диск, /dev/sda5 – партиция самого Linux (ext4).

Далее настраиваете операционную систему, как вам нужно, например, в корпоративной среде можно сразу прописать настройки прокси (PAC файл), временную зону и т.д.

Образ можно снять либо на подключённый дополнительный диск, либо подключить сетевой. В последнем случае нам понадобится ещё она компонента:

apt install cifs-utils

Мы помним, что диск у нас уменьшен для минимизации размера образа, но после его разворачивания на обычных компьютерах, где диск более 9Gb, нам нужно его автоматически расширить без привлечения администратора. Также в виде автоматизации можно сделать ввод в домен при запуске системы, либо запуск любых других скриптов, но этот вопрос подробно рассматривать не буду, оставлю для специалистов.

Итак, делаем автоматизацию расширения диска при первом запуске системы.
Создаём/изменяем в директории /etc файл rc.local - это конфиг службы rc-local, которая будет запускаться при запуске системы и стартовать наш/и скрипт/ы.

sudo nano /etc/rc.local

Листинг rc.local

#!/bin/sh -e
exec /usr/sbin/res1.sh
exit 0

где: #!/bin/sh -e - запуск консоли, exec /usr/sbin/res1.sh – запуск скрипта res1.sh
Через команду exec сюда можно дописывать и другие скрипты, главное не забывать их отсюда удалять, иначе они будут запускаться при каждом запуске (хотя это тоже полезно, но не в моем случае).

Делаем этот файл исполняемым chmod +x /etc/rc.local

Создаём в директории /usr/sbin/ файл, называем, например, res1.sh

sudo nano /usr/sbin/res1.sh

Листинг res1.sh

echo -e "resizepart\n2\nYes\n100%\nresizepart\n5\nYes\n100%\nquit" | parted /dev/sda ---pretend-input-tty
echo 1 > /sys/block/sda/device/rescan
resize2fs /dev/sda5
sed -i '/res1.sh/d' /etc/rc.local
rm -f /usr/sbin/res1.sh
reboot

где:
1 строчка – передаём через конвейерный input команду для утилиты parted выполняем resizepart 2 на 100% диска и resizepart 5 на 100% , т.е. раздвигаем логическую и основную партицию linux до 100% диска;
2 строчка – делает обновление информации о диске;
3 строчка – расширяется файловая до конца диска;
4 строчка – удаление строчки запуска скрипта из службы rc.local;
5 строчка – удаление скрипта
res1.sh;
6 строчка – перезагрузка.

Делаем этот файл исполняемым: chmod +x /usr/sbin/res1.sh

Я буду снимать образ на сетевой диск, следовательно, подключим его:

mkdir /mnt/image
mount.cifs //имя_сервера/имя_сетевой_папки /mnt/image -o user=имя_пользователя,pass=пароль      

Теперь запустим снятие образа на добавленную сетевую папку.

dd if=/dev/sda of=/mnt/image/sda.dd.img bs=8M

где:
if- указываем с какого диска снимаем копию;
of – указываем куда копируем образ;
bs- размер блока чтения 8Мб.

В итоге на сетевой папке у нас лежит образ sda.dd.img размером 9Gb, сжимаем его архиватором 7z, в Zip-файл sda.dd.zip (при выборе максимального сжатия у меня файл получился 2.14 Gb, при минимальном быстром сжатии 2.22 Gb что в целом очень хорошо).

Далее создаём сетевую папку, доступную по всей сети компании, с правами подключения под определённым аккаунтом. В папку выкладываем скрипт SetupLinux.ps1, который будет запускать в Task Sequence с определёнными параметрами.

[CmdletBinding()]
Param(
    [Parameter( Mandatory = $true, Position = 0 )]
    [ValidateSet( 'ShowProgressLinuxInstall', 'StartShowProgressLinuxInstall', 'CreatePartition', 'SetVariable', 'ShowProgressLinuxDownload', 'StartShowProgressLinuxDownload' )]
    [String]$Worktype
)

function Main ( $Worktype ) {
    switch ( $Worktype ) {
        'CreatePartition'   {
            $HardDisk = Get-Disk -Number 0
            $HardDiskSize = $HardDisk.Size
            if ($HardDiskSize -lt 20Gb) {
                Write-Host "Small disk, Exit" , $HardDiskSize
                Exit 1
            }
            Get-Disk -Number 0 | Where-Object PartitionStyle -EQ 'RAW' | Initialize-Disk
            Write-Host "Initialize Disk complete"
            #Start-Sleep -Seconds 5
            Get-Disk -Number 0 | Clear-Disk -RemoveData -RemoveOEM -Confirm:$false
            Write-Host "Clear Disk complete"
            #Start-Sleep -Seconds 5
            Get-Disk -Number 0 | Where-Object PartitionStyle -EQ 'RAW' | Initialize-Disk
            #Start-Sleep -Seconds 5
            Write-Host "Initialize Disk complete"
            $Offset = $HardDiskSize-5Gb-10Mb
            $NewPartition = Get-Disk -Number 0 | New-Partition -Size 5Gb -Offset $Offset -DriveLetter C
            #Start-Sleep -Seconds 5
            Write-Host "Create Partition complete"
            Format-Volume -FileSystem NTFS -Force -Partition $NewPartition
            #Start-Sleep -Seconds 5
            Write-Host "Format Partition Disk complete"
        }

        'StartShowProgressLinuxInstall' {
            Start-Process -WindowStyle Hidden -FilePath "powershell.exe" -ArgumentList "-WindowStyle Hidden -NoProfile -nologo -ExecutionPolicy Bypass -File T:\SetupLinux.ps1 -Worktype ShowProgressLinuxInstall"
            Exit
        }

        'ShowProgressLinuxInstall' {
            $TsProgressUI = New-Object -ComObject Microsoft.SMS.TsProgressUI
            $TotalProgressCount = (Get-Item C:\_SMSTaskSequence\Packages\MVI00424\sda.dd.zip).Length
            $CountAttempts = 10
            while ($CountAttempts -gt 0) {
                Start-Sleep -Seconds 5
                $CountAttempts = $CountAttempts - 1
                while (Get-WmiObject -Class win32_process -Filter {name = '7z.exe'}) {
                    $ProgressCount = (Get-WmiObject -Class win32_process -Filter {name = '7z.exe'}).ReadTransferCount
                    $Procent = $ProgressCount / $TotalProgressCount * 100
                    $TsProgressUI.ShowTSProgress("","","","Linux Install ($([math]::Round($Procent))% complete)",$Procent,100)
                    Start-Sleep -Seconds 5
                }
            }
        }

        'StartShowProgressLinuxDownload' {
            Start-Process -WindowStyle Hidden -FilePath "powershell.exe" -ArgumentList "-WindowStyle Hidden -NoProfile -nologo -ExecutionPolicy Bypass -File T:\SetupLinux.ps1 -Worktype ShowProgressLinuxDownload"
            Exit
        }
        
        'ShowProgressLinuxDownload' {
            $TsProgressUI = New-Object -ComObject Microsoft.SMS.TsProgressUI
            $CountAttempts = 10
            while ($CountAttempts -gt 0) {
                Start-Sleep -Seconds 5
                $CountAttempts = $CountAttempts - 1
                while (Get-WmiObject -Class win32_process -Filter {name = 'OSDDownloadContent.exe'}) {
                    $ProgressCount = (Get-WmiObject -Class win32_process -Filter {name = 'OSDDownloadContent.exe'}).ReadTransferCount
                    $TotalProgressCount = (Get-WmiObject -Class win32_process -Filter {name = 'OSDDownloadContent.exe'}).WriteTransferCount
                    if ($ProgressCount -gt 1048576) {
                        $Procent = $ProgressCount / $TotalProgressCount * 100
                        $TsProgressUI.ShowTSProgress("","","","Download Linux Package ($([math]::Round($Procent))% complete)",$Procent,100)
                    }
                    Start-Sleep -Seconds 5
                }
            }
        }

        'SetVariable' {
            Get-Disk -Number 0 | Update-Disk
            Get-Disk -Number 0 | Get-Partition | Where-Object -FilterScript {$_.Type -eq "FAT32"} | Set-Partition -NewDriveLetter C
            $TSEnvironment = New-Object -ComObject Microsoft.SMS.TSEnvironment
            $config = [PSCustomObject]@{
                OSDComputerName = $TSEnvironment.Value("OSDComputerName")
                IN_DOMAIN = $TSEnvironment.Value("IN_DOMAIN")
            }
            Out-File -FilePath C:\config.json -InputObject ($config | ConvertTo-Json) -Encoding utf8
        } 

    }

}
                                                                                                                                                                                                                                 
. Main $Worktype

Далее переходим в SCCM и создаём пакет.

Файлы пакета SCCM
Файлы пакета SCCM

В пакете у нас должны быть:

  • 7z.dll , 7z.exe - программа 7z, чтобы распаковать архив (достаточно этих файлов);

  • ddrelease64.exe – утилита DD под Windows, берем отсюда, там есть 32- и 64-битная версия (я использую 64-битную, т.к. у меня boot образ x64);

  • sda.dd.zip – собственно сам файл архива;

  • install.cmd – пакетный файл установки.

Листинг install.cmd:

@echo off
cd C:_SMSTaskSequence\Packages\XXX00424
7z.exe e -so sda.dd.zip | ddrelease64.exe of=\?\Device\Harddisk0\Partition0 bs=8M

где:
XXX00424 – код текущего пакета, из которого производится запуск;

C 3 строчкой поясню, распаковываем через 7z в консоль (параметр -so) файл sda.dd.zip. Далее передаём поток утилите ddrelease64.exe и сразу записываем его на диск \\?\Device\Harddisk0\Partition0 блоком 8Mb.

Далее пакет распространяем на Distribution Point’ы.

Теперь создадим загрузочный Task Sequence

Выбираем Create a new custom task sequence, нажимаем далее.

Выбираем 64-битный загрузочный образ, нажимаем далее.

Добавляем шаг 1: перезагрузка, если при запуске задания введён неправильный пароль (защита от «дурака»).

Шаг 1-Properties
Шаг 1-Properties
Шаг 1 - Options
Шаг 1 - Options

Добавляем шаг 2: подключаем сетевую папку, доступную под определённым аккаунтом по всей сети, в которой лежит скрипт SetupLinux.ps1 (описанный выше).

Добавляем шаг 3: запуск PowerShell скрипта с параметром -WorkType CreatePartition для инициализации, очистки диска и создания временной NTFS партиции для загрузки образа.

Добавляем шаг 4: запуск PowerShell скрипта с параметром -WorkType StartShowProgressLinuxDownload для отображения прогресса скачки образа.

Добавляем шаг 5: скачивание пакета SCCM на созданный временный диск NTFS

Добавляем шаг 6: запуск PowerShell скрипта с параметром -WorkType StartShowProgressLinuxInstall для отображения прогресса установки образа.

Добавляем шаг 7: запуск командного файла install.cmd из скачанного на временный диск пакета SCCM.

Добавляем шаг 8: запуск PowerShell скрипта с параметром  -WorkType SetVariable, в этом шаге на диске, куда уже записали Linux, находим загрузочный диск с FAT32 для сохранения JSON файла с параметрами Task Sequence. Через него можно передать переменные имя компьютера OSDComputerName, нужно ли вводить ПК Linux в домен IN_DOMAIN, либо любые другие параметры. На эту партицию также можно положить любые скрипты, которые вы хотите запустить при запуске ОС Linux.

Далее добавляем Deployment для Task Sequence, указываем необходимые переменные.

Далее загружаемся по сети PXE и наслаждаемся установкой Linux из SCCM за 5-7 мин.

В итоге получилась заливка ОС Linux и партиция раздвинута до конца диска 40gb.

Чтобы убедится, что мы передали файл конфига из SCCM в Linux, подключим временно партицию /dev/sda1, командой  mount /dev/sda1 /mnt/cm

Параметры, переданные через JSON из Task Sequence:

Вот и все, наслаждаемся работой Linux в корпоративной сети.

Удачи вам в ваших экспериментах.

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


  1. ky0
    08.06.2022 12:35

    Выглядит сложновато по сравнению с конфигом в 20 строчек в Терраформе, разворачивающим всё нужное из шаблона.


    1. sarksiov79 Автор
      08.06.2022 12:40
      +3

      Терраформ применим, на виртуалках в ЦОДе, а тут задача кучу виндовых тачек перезалить на обычных ПК.


      1. ky0
        08.06.2022 12:48
        +1

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


      1. dbax
        08.06.2022 15:19

        ansible?


  1. onegreyonewhite
    08.06.2022 13:18
    +4

    А чем Cobbler не подошёл? Он ещё и репы в себе может держать (и обновлять), установка и настройка через кикстарт и подобные. Тот же Ubuntu MAAS тоже можно, но это больше про сервера. Зачем насиловать форточками пингвина?


    1. sarksiov79 Автор
      08.06.2022 14:18

      Ну если делать вообще с нуля, то им тоже можно, вариантов много, тут накинул.

      Но если уже в сети развернут SCCM с DP, зачем переделывать PXE точки?

      В схеме с SCCM, можно будет ставить оба вида операционок, кому-то форточки, а кому-то пингвинов.


      1. Cruz_Castillo
        08.06.2022 18:00

        Коллега, а не пробовали классический автоматизированный сценарий "обновления" ОС (что раньше описывался в методике BDD - Business Desktop Deployment как Zero Touch Installation)? Сбор данных/пользовательских файлов (Windows, USMT без шифрования, в сеть); ребут (WPE), форматирование, образ (Linux); восстановление данных (из сети). PXE не нужен, начало процесса - SCCM client. К тому, что массовые миграции из одной точки с Windows на Linux не за горами.


        1. sarksiov79 Автор
          08.06.2022 18:03

          Для Windows использовали, но для Linux нет, хотя проблемы не вижу, сценарий примерно такой же.


  1. Alexrook
    08.06.2022 13:43
    +1

    Можете пояснить, если мы меняем одну зарубежную ОС на другую зарубежную ОС, при чем здесь термин «Импортозамещение»?


    1. sarksiov79 Автор
      08.06.2022 14:22
      +1

      У меня был кейс с xubuntu, но таким же способом можно ставить любой дистрибутив Linux, хоть Альт.


      1. Kagato_by
        08.06.2022 20:29

        Альт внезапно перестал быть зарубежным потому что кто-то внутри страны его собирает из чужих сорсов?


    1. Francyz
      08.06.2022 15:03
      +2

      Раз уж на то пошло, то и SCCM нужно будет скоро импортозамещать, так что статья актуальна до поры до времени.


  1. amarao
    08.06.2022 14:34
    +4

    У линукса есть масса интересных решений для разворачивания бареметалла. Начиная от скромных pxe-серверов с которых можно "забутиться и раскатать" и заканчивая боевыми мультитенантными ironic'ами.

    Количество прогресс-баров и окошек в этой штуке меня сильно напрягло. так же как и количество винды. Может, лучше, без всё-таки?

    С точки же зрения разворачивания серверов - доставка образа - это относительно сложная, но ограниченная задача. Вот финальное конфигурирование (сеть, имя, ssh-ключи, пользователи) - это куда более тонко. (подсказка Cloud Init, datasource=NoCloud).


    1. sarksiov79 Автор
      08.06.2022 18:09

      Решений согласен масса, тут описан метод, если в компании уже есть большая инфраструктура SCCM. Кончено, специально его ставить, для это задачи не нужно.


  1. AAT666
    08.06.2022 17:58
    +1

    Спасибо большое за инструкцию! Оччччень пригодится вскорости!

    Но судя по всему - все данные пользовател-я(ей) (как в профилях, так и просто на разделах диска) надо как-то куда-то заранее сохранить ?..


    1. sarksiov79 Автор
      08.06.2022 18:06

      Коллега выше в комментариях написал, можно прикрутить USMT и сохранить данные.


      1. AAT666
        08.06.2022 20:03

        Ну, "прикручивать" ничего не надо - MECM умеет это делать "из коробки", как по hardlink - так и в точку миграции... Интересовал, именно, момент переноса данных. Но, я так понял, это не входило в Вашу задачу... Но опыт - очень интересный! Благодарю еще раз!


  1. alef13
    08.06.2022 22:19
    +1

    вот что бывает когда поручают импортозамещение любителям винды :) не в обиду, но действительно - есть штатные средства развёртывания и намного удобнее и проще чем раскатка образа, который потом ещё допиливать и допиливать. И полагаю что это будет традиционно мышкой в сессии vnc с обязательным присутствием пользователя


  1. polar_yogi
    09.06.2022 14:44

    >Через команду exec сюда можно дописывать и другие скрипты,
    Я, возможно, зануда... Нет, не так.
    Я знаю, что я зануда, но команда exec запускает выполнение программы, заменяя родительский процесс, поэтому все команды после первого exec выполнены не будут.