Sparka igång en server med Kickstart

02 July, 2019

Jag gillar att testa nya funktioner, programvaror och annat som kräver en server för ändamålet. Då jag kör VMware:s ESXi hemma så kan jag närhelst jag vill sparka igång en ny virtuell maskin. Då jag gör detta hyfsat ofta bestämde jag mig för att automatisera det hela så långt som möjligt.

Det finns både kommersiella och gratis alternativ för att uppnå vad jag egentligen ville göra, nämligen att automatisera installationen av CentOS 7 så långt det bara var möjligt. Givetvis kan man via VMwares egna VRealize automatisera skapandet av den virtuella maskinen och sedan skjuta in operativsystemet från en på förhand skapad mall, men det kändes som det var lite väl mycket jobb för att göra något som egentligen är ganska enkelt.

Funktionen jag använder kallas kort och gott “Kickstart” och den är inbyggd i Red Hat Enterprise Linux och därmed också i CentOS version 7 som jag använder för det mesta (även om jag börjat bygga mer och mer på FreeBSD, men det är ett ämne för en kommande bloggpost).

Kickstart är enkelt: en dator på ett subnät, exempelvis 10.10.10.0/24, startar upp och istället för att försöka starta från en inbyggd hårddisk, CD-ROM-skiva, floppy eller vad man nu tänker att denna dator ska starta från. Denna dator kan vara antingen virtuell eller fysisk, det spelar ingen roll. Funktionen datorn använder för att starta kallas PXE (Preboot Execution Environment) och den gör på många sätt exakt samma sak som vad gamla TFTP (Trivial FTP) gjorde vilket är detta: datorn skriker ut medelst en broadcast på det lokala subnätet att den efterfrågar en fil.

Med TFTP fick man, om man exempelvis skulle starta en Sun-maskin via detta protokoll, döpa filen som skulle serveras via TFTP till datorns MAC-adress för att rätt maskin skulle “plocka upp” rätt fil.

I fallet PXE är använder man bland annat TFTP och DHCP i kombination utan att behöva döpa en fil till ett visst namn. Det är nämligen lite smartare än så.

Datorn startar upp och via PXE försöker den få en IP-adress via DHCP. När denna adress tilldelas så skickas också adressen till en bootserver med i samma paket och därefter kan datorns BIOS begära en PXE-fil som innehåller grundläggande information för att installationen ska hoppa igång. I denna fil talar man om hur uppstartsmenyn ska se ut, var Linuxkärnan ska hämtas från och vilket protokoll som ska användas, och så vidare.

Min fil (/var/lib/tftpboot/pxelinux.cfg/default) ser ut så här:

default menu.c32
prompt 0
timeout 10
MENU TITLE joacim.net PXE Menu
LABEL centos7_x64
MENU LABEL CentOS 7_X64
KERNEL /networkboot/vmlinuz
APPEND initrd=/networkboot/initrd.img inst.repo=ftp://10.10.10.113/pub ks=ftp://10.10.10.113/pub/centos7.cfg

Som synes är nästa steg för servern att hämta filen centos7.cfg via FTP (ks=ftp://...). På samma FTP-server ligger också hela repot för CentOS 7 (inst.repo). Filen centos7.cfg är ganska lång och kanske inte helt självförklarande men här komner ett försök:

firewall --disabled
install
url --url="ftp://10.10.10.113/pub/"
rootpw --iscrypted $1$ywI.eO8s$YNZ50c4X6MIG21Lovjn9f0
auth useshadow passalgo=sha512
text
firstboot disable
keyboard sv-latin1
lang en_US
selinux disabled

I denna första del stänger vi av brandväggen, säger att det är en installation som ska göras och var installationsfilerna finns. Vi sätter ett root-lösenord som läggs in i krypterad form i denna fil, säger åt installationsprogrammet att köras i textläge, sätter svensk tangentbordslayout, engelska som systemspråk och stänger av SELinux.

logging level=info
eula --agreed
logging --host=10.10.10.115
timezone Europe/Stockholm --ntpservers=ntp.joacimmelin.se
bootloader location=mbr
clearpart --all --initlabel
part swap --asprimary --fstype="swap" --size=2048
part /boot --fstype=ext4 --size=4096
part / --fstype=ext4 --size=16384
%packages
@^minimal
open-vm-tools
nano
nfs-utils
wget
@core
%end

I detta andra steg sätter vi loggningsnivå och vilken server vi vill skicka loggarna till (i mitt fall min syslog-server), vi ställer in att klockan ska synkroniseras mot min NTP-server, hur bootloadern ska skrivas, hur stor swapfil servern ska ha, hur stor bootpartitionen ska vara och hur stor root-partitionen ska vara. Här kan man givetvis lägga in andra partitioner som /var eller /home om man vill det - så länge den totala storleken för samtliga partitioner inte överstiger ytan på den fysiska eller virtuella hårddisk servern har att tillgå.

%addon com_redhat_kdump --disable --reserve-mb='auto'
%end
%post --log=/root/ks-post.log
mv /etc/rc.d/rc.local /etc/rc.d/rc.local.old
wget http://kickstart01.joacimmelin.se/rc.local -O /etc/rc.d/rc.local
systemctl enable rc-local
wget http://kickstart01.joacimmelin.se/zabbix_agentd.conf -O /etc/zabbix_agentd.conf
wget http://kickstart01.joacimmelin.se/zabbix_agentd.psk -O /etc/zabbix_agentd.psk
wget http://kickstart01.joacimmelin.se/CentOS-Base.repo -O /etc/yum.repos.d/CentOS-Base.repo
wget http://kickstart01.joacimmelin.se/afterinstall.sh -O /etc/afterinstall.sh
wget http://kickstart01.joacimmelin.se/selinux/config -O /etc/selinux/config
wget http://kickstart01.joacimmelin.se/selinux/ifcfg-ens192.example -O /etc/sysconfig/network-scripts/ifcfg-ens192.example
wget http://kickstart01.joacimmelin.se/main.cf -O /etc/postfix/main.cf
wget http://kickstart01.joacimmelin.se/bacula-fd.conf -O /etc/bacula/bacula-fd.conf
wget http://kickstart01.joacimmelin.se/bconsole.conf -O /etc/bacula/bconsole.conf
chmod 755 /etc/afterinstall.sh
chown root:root /etc/afterinstall.sh
mkdir /root/.ssh
wget http://kickstart01.joacimmelin.se/authorized_keys -O /root/.ssh/authorized_keys
chmod +x /etc/rc.d/rc.local
mkdir -p /bacula/restore
chown -R bacula:bacula /bacula
chmod -R 700 /bacula
%end
reboot --eject

I detta tredje steg händer en del intressanta saker som är special för min installation. För att få Kickstart att köra ett script när servern startar om efter installationen är klar så ska man enligt dokumentationen kunna köra detta i avsnittet %post men det fungerar inte riktigt. I CentOS 6 fungeade det däremot utmärkt, så jag tvingas göra en fuling där jag som synes först döper om /etc/rc.d/rc.local tillfälligt. Därefter hämtar jag hem en egen version av /etc/rc.d/rc.local som placeras på rätt plats.

Vad som sedan följer är en rad filer som laddas ner och placeras på rätt ställe. Bland dessa finns konfigurationsfilerna för övervakningssystemet Zabbix, en egen /etc/yum.repos.d/CentOS-Base.repo som hämtar sina filer från min egna spegling av CentOS 7-repot, en konfigurationsfil för SELinux, Postfix samt backupsystemet Bacula. Jag sätter fulla rättigheter och ägare på filen /etc/afterinstall.sh och slutligen laddar jag ner SSH-nycklarna så jag kan logga in från min bastion-server utan att slå in något lösenord.

Lite kataloger skapas för Bacula och därefter får /etc/rc.d/rc.local korrekta rättigheter för att exekveras. I denna fil anropar jag sedan filen /etc/afterinstall.sh som vi diskuterar härnäst i denna bloggpost:

wget http://kickstart01.joacimmelin.se/resolv.conf
cd /root
rpm -ivh http://kickstart01.joacimmelin.se/zabbix-release-3.0-1.el7.noarch.rpm
yum install epel-release -y
yum install deltarpm -y
yum install zabbix-agent -y
yum install bacula-client -y
yum install net-tools -y
yum install telnet -y
yum install figlet -y
figlet ${HOSTNAME%%.*} > /etc/motd
mv /etc/zabbix_agentd.conf /etc/zabbix/
mv /etc/zabbix_agentd.psk /etc/zabbix/
mv /etc/bacula-fd.conf /etc/bacula/
mv /etc/bconsole.conf /etc/bacula/
systemctl start zabbix-agent
systemctl enable zabbix-agent
mkdir /backup
echo "stor03.joacimmelin.se:/backup2 /backup nfs defaults 0 0" >> /etc/fstab
yum update -y
chmod -x /etc/rc.d/rc.local
reboot

Då tar vi det från början. Vi tankar hem en egen /etc/resolv.conf och lägger in. Man kan givetvis fråga sig varför jag inte bara sätter DNS:erna i filen för nätverkskonfigurationen men det är för att min /etc/resolv.conf ser ut så här:

search joacimmelin.se
options rotate
options timeout:1
nameserver 10.10.10.134
nameserver 10.10.10.169

Med en fil som ser ut som ovan kommer klienten försöka anropa den sekundära DNS:en efter en sekund om den första inte svarar. Dessa inställningar går mig veterligen inte att sätta via konfigurationsfilen för nätverkskortet i CentOS 7.

Hur som helst, åter till den andra filen i kickstart-kedjan. Jag laddar ner klienten för Zabbix, därefter lägger jag till epel-repot, lägger in deltarpm-paketet (väldigt trevligt då det endast installerar skillnaderna mellan det gamla och det nya paketet vilket går snabbare och sparar bandbredd. Därefter installerar jag Zabbix-agenten, Bacula-klienten, net-tools-paketet, telnet och slutligen figlet som därefter pangar in serverns värdnamn i filen /etc/motd. Detta är i sig ganska onödigt i dagsläget då den kommer skjuta in värdnamnet localhost i /etc/motd men jag har lagt in det redan nu för att irritera mig tillräckligt mycket för att bygga tidigare steg där jag via ett enkelt webbgränssnitt kan skapa grundkonfigurationen och sätta värdnamn och IP-adress och sådant redan innan servern är installerad. Det vore också trevligt att automatiskt skjuta in servern i Bacula för backuper samt i Zabbix för övervakning.

Räkna med att jag kommer blogga om detta här.

Jag flyttar Zabbix konfiguratonsfiler på plats, skapar katalogen /backup som sedan monteras upp via nfs och jag lägger in raderna för detta i /etc/fstab. Slutligen kör jag en total uppdatering av alla paket, slår av exekveringsflaggan på /etc/rc.d/rc.local som annars skulle köra samma fil en gång till och till sist startas servern om.

Det jag måste göra manuellt efter detta är att sätta serverns värdnamn i /etc/hostname, konfigurera dess IP-adress, subnätmask och gateway slutligen lägga in servern i mina lokala DNS:er. Sen är det bara att köra på. Den initiala konfigurationen i VMware innefattar att skapa den virtuella servern med val av operativsystem, ställa in RAM och hårddiskyta och slutligen “slå på strömmen” på maskinen. Inte så blodigt egentligen men det vore trevligt att kunna automatisera även det ovanstående (se nedan).

När jag började titta på detta så utgick jag från denna guide som jag varmt rekommenderar. Sen är det bara att börja gräva i Red Hat:s dokumentation för Kickstart för att hitta roliga saker att lägga in.

Uppdatering För de som liksom jag tycker det är på tok för jobbigt att sitta och klicka fram en ny VM varje gång den ska skapas så finns det tack och lov script som andra redan hackat ihop. Detta är ett bra exempel - notera dock att du behöver justera följande rader så de passar just din miljö. Här är mina ändringar och/eller tillägg. Notera att dessa alltså är anpassade för ESXi 6.5 (detta gör att jag satt config.version och virtualHW.version till de värden som står nedan) där jag kör med VmxNet3-adaptern i ett nätverk som heter “VM Network” (standardnamnet). Det är CentOS 7 i 64-bitarsversion som körs:

config.version = "8"
virtualHW.version = "13"
vcpu.hotadd = "TRUE"
mem.hotadd = "TRUE"
ethernet0.virtualDev = "vmxnet3"
ethernet0.networkName = "VM Network"
guestOS = "centos7-64"

Lycka till!