IPXE Kickstart安装CentOS的方法

这些年IDC物理机装机的大法也在不断衍进,从最早的手动装一堆tftp/dhcp/syslinux/httpd,到cobbler的一统江湖,到现在的dnsmasq轻量级安装,nocps安装,一直在不断进化着。

因为cobbler实在太重,不得不专门起一个kvm虚机来运行,完全不喜欢啊。所以一直也在研究终极安装服务器的大法。

折腾服务器无数回,找出了个自己比较喜欢的方式。

首先介绍一下背景知识:

  • PXE 可以通过网络给计算机安装操作系统。 PXE协议大致上结合了DHCP和TFTP。

  • gPXE gPXE是PXE的一个开源实现(更早的实现是Etherboot)。通过gPXE能让网卡直接支持网络启动,而不依赖于网卡自带的PXE固件。同时相比PXE,gPXE支持更多的协议。 传统的PXE只能通过TFTP进行传输,而gPXE支持HTTP,iSCSI和ATA over Ethernet(AoE),甚至支持wifi链接。

  • iPXE iPXE表示 it doesn’t PXE。iPXE是gPXE的原班人马写的(他们从Etherboot开始),作为官方的gPXE的替代品。 gPXE扩展的功能在iPXE中都得到支持。 之所以不再使用gPXE是由于存在版权纠纷,iPXE从2010年4月开始,基于同一个代码库开始开发。

  • PXELINUX Syslinux是一个优秀的系统启动加载器(bootloader),可引导自硬盘、光盘、和通过PXE的网络启动。 PXELINUX派生自Syslinux,用来使支持PXE的网卡从网络引导启动Linux。PXELINUX程序不是烧在网卡里,而是存储在TFTP服务器上。

  • Chainloading iPXE 可以把iPXE当作固件刷进计算机网卡的ROM里替换掉自带的PXE,但更为常见的是通过chainloading的方式进入iPXE。

有点晕是吧,总结一下,pxe包含了gpxe/ipxe/pxelinux,ipxe是最新的,gpxe/ipxe/pxelinux可以通过chain的方式顶替网卡原生的pxe。

推荐的装机方式:

客户机启动网卡自带的固件pxe,然后去服务器拉一个gpxe/ipxe,然后启动这个gpxe/ipxe,再去服务器拉具体的启动文件,这种就是chain方式了。我们就可以用到http/iscsi/wifi等各种先进方式启动了。

我们第一步先要准备一个gpxe的boot文件。

解释一下,文件后缀有.pxe/.kpxe/.kkpxe,这是个递进关系,.pxe是最原生的网卡驱动,.kpxe包含了调用原生网卡的UNDI驱动(无网卡驱动),.kkpxe更进一步,包含了UNDI+PXE原生网卡的驱动。

当然选择.kpxe了,我们的目的就是通过这个ipxe调用原生网卡上的驱动即可,如果是你自己要烧网卡的bootroom片子,就得选择所有驱动了。

这样我们会得到一个 gpxe-1.0.1-undionly.kpxe 的文件,保存备用。

然后我们来设置Dnsmasq:

 1log-dhcp
 2
 3dhcp-no-override
 4
 5enable-tftp  
 6tftp-root = /tftpboot
 7
 8dhcp-range=tftp,172.16.36.100,172.16.36.105
 9
10dhcp-match=gpxe,175  
11dhcp-boot=net:#gpxe,gpxe-1.0.1-undionly.kpxe,gxe/bootserver,172.16.36.1  
12dhcp-boot=http://172.16.8.1/ks/boot.txt  

注意:gpxe-1.0.1-undionly.kpxe是放在/tftpboot/gpxe/之下的

上面有很多玄机,dhcp-range是随便设一个地址池,因为最终实际是gpxe来决定地址,所以第一次dhcp得到的地址反而不重要了。dhcp-no-override一定要有,否则gpxe有bug,无法启动。

其次匹配gpxe,凡是175的都是gpxe,为什么要匹配呢?看下面,有两个dhcp-boot启动选项,#pxe,#表示不是,这行意思是:不是gpxe启动的话用/tftp/gpxe/gpxe-1.0.1-undionly.kpxe来启动,dhcp的server是172.16.36.1。第二行如果是gpxe启动的话,就chain到[http://172.16.8.1/ks/boot.txt]去启动

呵呵,如果不这么设置,就用一行的话:

1dhcp-boot=gpxe-1.0.1-undionly.kpxe,gxe/bootserver,172.16.36.1  

就会陷入死循环,首先pxe启动,抓了个gpxe,gpxe又启动抓了个gpxe,又抓gpxe,循环往复没玩没了。所以必须标记gpxe,并跳出这个循环。

我们在172.16.8.1上面建立/centos7的yum安装源,同时建立/ks目录。准备boot.txt,boot2.php,boot3.php,centos7.ks四个文件,下面一个一个解释:

首先是boot.txt

1cat boot.txt  
2#!gpxe
3
4chain http://172.16.8.1/ks/boot2.php?uuid=\${uuid}&mac=\${mac}&busid=\${busid}&ip=\${ip}&hostname=\${hostname:uristring}&serial=\${serial:uristring}&asset=\${asset:uristring}&manufacturer=\${manufacturer:uristring}&product=\${product:uristring}

大家看上面,boot.txt是个gpxe脚本,实际是让gpxe向boot2.php传输了一些数据过来,有机器的uuid/mac/busid/hostname/serial/product等等。给个具体的例子,从access.log看到实际发过来的请求如下:

1"GET /ks/boot2.php?uuid=%5C44454c4c-5600-1054-8042-b1c04f433532&mac=%5Cec%3Af4%3Abb%3Ad9%3A96%3A40&busid=%5C01%3A80%3A86%3A15%3A21&ip=%5C172.16.36.100&hostname=%5C&serial=%5C1VTBC52&asset=%5C&manufacturer=%5CDell%20Inc.&product=%5CPowerEdge%20R730 HTTP/1.0" 200 46 "-" "gPXE/1.0.1" "-"

看上面,有很多信息,网卡的物理地址,还有serial,对应dell就是svc tag号,还有机器类别PowerEdge R730,这是个好东西啊。

我们购买机器的时候肯定有序列号,上架到机房的时候,可以让idc抄下来机柜和序列号,然后我们让网管规划好ip,再这里就可以利用serial来确定机器应该按哪个模板安装。

再看模板文件,centos7.ks

 1#version=DEVEL
 2auth --enableshadow --passalgo=sha512  
 3url --url=http://172.16.8.1/centos7  
 4text  
 5firstboot --enable  
 6ignoredisk --only-use=sda  
 7keyboard --vckeymap=us --xlayouts='us'  
 8lang en_US.UTF-8  
 9selinux --disabled
10
11services --enabled="chronyd"
12
13network  --bootproto=static --device=em1 --noipv6 --nodns --onboot=yes --gateway={gateway} --ip={ip} --nameserver=172.16.8.1 --netmask={netmask}  
14network  --bootproto=dhcp --device=em2 --noipv6 --nodns --onboot=no  
15network  --bootproto=dhcp --device=em3 --noipv6 --nodns --onboot=no  
16network  --bootproto=dhcp --device=em4 --noipv6 --nodns --onboot=no  
17network  --hostname={hostname}
18
19#grub-crypt --sha-512
20rootpw --iscrypted $6$0Y.SH935/jvt0X.D$lCte9H/KiFeGbTGrrcuXGZXmnq3Rk4Crz8nAvCgH.Pf2SNmoUdh.g5WGWJqtVO4QTyqvnXc/6FyVjptWIaM4w1  
21timezone Asia/Shanghai --isUtc
22
23bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=sda  
24clearpart --all --drives=sda
25
26part /boot --fstype ext4 --size=500 --ondisk=/dev/sda  
27part swap --size=8192 --ondisk=/dev/sda  
28part / --fstype ext4 --size=1024 --grow --ondisk=/dev/sda
29
30%packages
31@compat-libraries
32@core
33wget  
34net-tools  
35chrony  
36bridge-utils  
37%end
38
39%post
40yum -y erase NetworkManager  
41cat <<EOF >/etc/sysconfig/network-scripts/ifcfg-br0  
42DEVICE=br0  
43TYPE=Bridge  
44BOOTPROTO=static  
45ONBOOT=yes  
46IPADDR={ip}  
47NETMASK={netmask}  
48GATEWAY={gateway}  
49EOF  
50cat <<EOF > /etc/modprobe.d/bonding.conf  
51alias bond0 bonding  
52BONDING_OPTS="miimon=100 mode=1 primary=em1"  
53EOF  
54cat <<EOF > /etc/sysconfig/network-scripts/ifcfg-bond0  
55DEVICE=bond0  
56ONBOOT=yes  
57USERCTL=no  
58BRIDGE=br0  
59EOF  
60cat <<EOF > /etc/sysconfig/network-scripts/ifcfg-em1  
61DEVICE=em1  
62USERCTL=no  
63ONBOOT=yes  
64MASTER=bond0  
65SLAVE=yes  
66BRIDGE="br0"  
67EOF  
68cat <<EOF > /etc/sysconfig/network-scripts/ifcfg-em2  
69DEVICE=em2  
70USERCTL=no  
71ONBOOT=yes  
72MASTER=bond0  
73SLAVE=yes  
74BRIDGE="br0"  
75EOF  
76%end
77
78reboot  

注意上面,{ip}、{netmask}、{gateway}、{hostname}是待定的。

然后看看boot2.php:

 1<?php  
 2$dns='172.16.8.1';
 3$base7='http://172.16.8.1/centos7';
 4$ks7='http://172.16.8.1/ks/boot3.php';
 5
 6echo "#!gpxe\n";
 7
 8
 9switch ($_REQUEST['mac']) {
10
11  case '\ec:f4:bb:d9:96:40':
12    $ip="172.16.36.2:172.16.37.254:255.255.254.0:myhost-16-36-2";
13    $ipa=explode(':',$ip);
14    echo "ifopen net0\n";
15    echo "set net0/ip $ipa[0]\n";
16    echo "set net0/netmask $ipa[2]\n";
17    echo "set net0/gateway $ipa[1]\n";
18    echo "set net0/dns $dns\n";
19    echo "set base-url $base7\n";
20    echo "kernel \${base-url}/images/pxeboot/vmlinuz\n";
21    echo "imgargs vmlinuz inst.ks=$ks7?file=centos7.ks&ip=$ipa[0]&mask=$ipa[2]&gateway=$ipa[1]&hostname=$ipa[3] ksdevice=bootif inst.vnc inst.vncpassword=xxxxxxxx inst.sshd\n";
22    echo "initrd \${base-url}/images/pxeboot/initrd.img\n"; 
23    echo "boot\n";
24    break;
25
26  case '00:11:22:33:44:55':
27    # boot from iSCSI
28    echo "set initiator-iqn iqn.2007-08.com.example.initiator:initiator\n";
29    # see http://ipxe.org/sanuri for the syntax
30    echo "sanboot iscsi:san.example.com:6:3260:0:iqn.2007-08.com.example.san:sometarget\n";
31    break;
32
33  case '\00:77:21🆎cd:ee':
34    # boot boot.salstar.sk's super cool boot menu      
35    echo "chain http://boot.salstar.sk\n";
36    break;
37
38  default:
39    # exit iPXE and let machine go on with BIOS boot sequence
40    echo "exit\n";
41    break;
42}
43
44?> 

注意上面,我们是通过网卡的物理地址来判断模板的,用svc tag号更好。

第四个文件:boot3.php

 1<?php
 2
 3$origin_str = file_get_contents($_REQUEST['file']);
 4
 5$update_str = str_replace("{ip}", $_REQUEST['ip'], $origin_str);
 6$update_str = str_replace('{netmask}', $_REQUEST['mask'], $update_str);
 7$update_str = str_replace('{gateway}', $_REQUEST['gateway'], $update_str);
 8$update_str = str_replace('{hostname}', $_REQUEST['hostname'], $update_str);
 9
10echo $update_str;  
11?>

boot3.php的功能就是替换掉模板文件里的ip等,然后返回一个正确的ks文件。

这下就完美了,我们基本就需要修改ks下的boot2.php和centos7.ks,就可以控制远程安装了。

dhcp和tftp,就用dnsmasq和那一个gxpe就够了,省了大事了。

还有更好玩的: 网卡原生pxe–>gpxe–>pxelinux.0

大家尽情想象吧。


Kickstart安装脚本中如何同时配置bridge和bond
用IPXE启动个Ubuntu桌面
comments powered by Disqus