PXE Booting x86_64 UEFI Clients with Dnsmasq
using UEFI PXE booting to install linux on up boards
Update: Naturally, the day after I get this up and running, Red Hat announces that Atomic Host will be supplanted by Container Linux, so all of this stuff that’s specific to Atomic is effectively deprecated. I’ll be starting over with Container Linux.
I have a little Intel NUC box I use as a server. This is how I configured it to get the Up Boards to boot and install Fedora Atomic.
TODO: make these into ansible playbooks
Firewalld Changes
For Dnsmasq to work, I need a zone for my k8s hosts and I need to open DNS, DHCP, and TFTP:
# DHCP is broadcast, so it isn't useful to add it to a zone. If I had multiple interfaces,
# I would restrict it to one
firewall-cmd --permanent --add-service=dhcp
firewall-cmd --permanent --new-zone=k8s
firewall-cmd --permanent --zone=k8s --add-source=10.0.0.0/24
firewall-cmd --permanent --zone=k8s --add-service=dns
firewall-cmd --permanent --zone=k8s --add-service=http
firewall-cmd --permanent --zone=k8s --add-service=syslog
firewall-cmd --permanent --zone=k8s --add-service=tftp
firewall-cmd --permanent --zone=k8s --add-port=68/udp
# pick up the config changes
firewall-cmd --reload
Dnsmasq Setup
TFTP
mkdir -p /var/lib/tftpboot
cp /boot/efi/EFI/fedora/{shim,grubx64}.efi /var/lib/tftpboot/
Config
port=0
user=dnsmasq
group=dnsmasq
# DHCP pool setup
dhcp-range=10.0.0.151,10.0.0.200,12h
dhcp-option=option:router,10.0.0.1
# Static mappings
dhcp-host=cc:00:ff:ff:ee:ea,10.0.0.101,k8s-master01,infinite
dhcp-host=cc:00:ff:ff:ee:eb,10.0.0.102,k8s-master02,infinite
dhcp-host=cc:00:ff:ff:ee:ec,10.0.0.104,k8s-n01,infinite
dhcp-host=cc:00:ff:ff:ee:ed,10.0.0.105,k8s-n02,infinite
dhcp-host=cc:00:ff:ff:ee:ee,10.0.0.106,k8s-n03,infinite
dhcp-match=set:efi-x86_64,option:client-arch,7
dhcp-boot=tag:efi-x86_64,shim.efi
# TFTP Server setup
enable-tftp
tftp-root=/var/lib/tftpboot
log-dhcp
conf-dir=/etc/dnsmasq.d,.rpmnew,.rpmsave,.rpmorig
Atomic Setup
PXE Boot
nginx
We need a web server to serve up the kickstart and install.img files:
dnf install -y nginx
mkdir -p /srv/http/{fedora,kickstart}
semanage fcontext -a -t httpd_sys_content_t "/srv/http(/.*)?"
restorecon -Rv /srv/http/
cat <<EOF > /etc/nginx/default.d/fedora.conf
location /fedora {
alias /srv/http/fedora;
autoindex on;
autoindex_exact_size off;
}
EOF
cat <<EOF > /etc/nginx/default.d/kickstart.conf
location /kickstart {
alias /srv/http/kickstart;
autoindex on;
autoindex_exact_size off;
}
EOF
Install Files
kernel, initrd, install image, etc.
Now set up the files needed for kickstarting the boxes:
curl -OL https://download.fedoraproject.org/pub/alt/atomic/stable/Fedora-Atomic-28-20180425.0/AtomicHost/x86_64/iso/Fedora-AtomicHost-ostree-x86_64-28-20180425.0.iso
mount -t iso9660 -o loop Fedora-AtomicHost-ostree-x86_64-28-20180425.0.iso /mnt
mkdir -p /srv/http/fedora/28/atomic
rsync -a /mnt/images /srv/http/fedora/28/atomic/
mkdir -p /var/lib/tftpboot/fedora/28
cp /mnt/images/pxeboot/{vmlinuz,initrd.img} /var/lib/tftpboot/fedora/28/
grub
cat <<EOF > /var/lib/tftpboot/grub.cfg
set default="0"
function load_video {
insmod efi_gop
insmod efi_uga
insmod video_bochs
insmod video_cirrus
insmod all_video
}
load_video
set gfxpayload=keep
insmod gzio
insmod part_gpt
insmod ext2
set timeout=10
### END /etc/grub.d/00_header ###
### BEGIN /etc/grub.d/10_linux ###
menuentry 'Install Fedora 28 Atomic Host' --class fedora --class gnu-linux --class gnu --class os {
linuxefi fedora/28/atomic/vmlinuz inst.stage2=http://10.0.0.10/fedora/28/atomic/ ip=dhcp inst.ks=http://10.0.0.10/kickstart/atomic-ks.cfg inst.cmdline inst.sshd
initrdefi fedora/28/atomic/initrd.img
}
EOF
kickstart profiles
TODO: this needs to vary per-host to set up the static networking configuration correctly, but the thought of installing something heavyweight like Cobbler or Foreman is… unappealing. I think the right move is to just implement like a 20-line template rendering web server in golang or python.
cat <<EOF > /srv/http/kickstart/atomic-ks.cfg
text
install
reboot
sshpw --username root --plaintext installpw
auth --enableshadow --passalgo=sha512
ostreesetup --nogpg --osname="fedora-atomic" --remote="fedora-atomic" --url="file:///ostree/repo" --ref="fedora/28/x86_64/atomic-host"
ignoredisk --only-use=mmcblk0
keyboard us
lang en_US.UTF-8
network --bootproto=static --device=enp2s0 --ip=10.0.0.104 --netmask=255.255.255.0 --hostname=k8s-n01.ressman.org --gateway=10.0.0.1 --nameserver 10.0.0.1
logging --host 10.0.0.10 --level debug
rootpw --iscrypted PASSWORD_CRYPT
timezone America/Chicago --isUtc
user --groups=wheel --name=atomic --password=PASSWORD_CRYPT --iscrypted --gecos="Atomic User"
sshkey --username root "SSH_KEY_1"
sshkey --username atomic "SSH_KEY_2"
bootloader --location=mbr --boot-drive=mmcblk0
clearpart --all --initlabel --drives=mmcblk0
autopart --noswap --fstype="xfs"
%post --erroronfail
rm -f /etc/ostree/remotes.d/fedora-atomic.conf
ostree remote add --set=gpgkeypath=/etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-28-primary fedora-atomic https://kojipkgs.fedoraproject.org/atomic/repo
cp /etc/skel/.bash* /root
%end
EOF
OSTree
This was a little more complicated since I’m still learning about Atomic, but the goal here is to have a periodically updating local copy of the ostree repo for all nodes to update against.