这些年IDC装机的大法也在不断衍进,从最早的自己手动装一堆tftp/dhcp/syslinux/httpd,到cobbler的一统江湖,到现在的dnsmasq轻量级安装,一直在变化。
因为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文件,之所以用gpxe是因为可以在网站直接生成boot文件,省的编译了。
在线生成gpxe文件的网站:
http://rom-o-matic.net/gpxe/gpxe-1.0.1/contrib/rom-o-matic/
我们选2个地方即可:
- Choose an output format:[PXE bootstrap loader keep [Keep PXE stack method 1] (.kpxe)]
- Choose a NIC type:[undionly]
然后下载文件即可。
解释一下,文件后缀有.pxe/.kpxe/.kkpxe,这是个递进关系,.pxe是最原生的网卡驱动,.kpxe包含了调用原生网卡的UNDI驱动(无网卡驱动),.kkpxe更进一步,包含了UNDI+PXE原生网卡的驱动。
当然选择.kpxe了,这就直接导致第二个选项选undionly即可,我们的目的就是通过这个gpxe调用原生网卡上的驱动即可,如果是你自己要烧网卡的bootroom片子,就得选择所有驱动了。
这样我们会得到一个 gpxe-1.0.1-undionly.kpxe 的文件,保存备用。
然后我们来设置Dnsmasq:
log-dhcp
dhcp-no-override
enable-tftp
tftp-root = /tftpboot
dhcp-range=tftp,172.16.36.100,172.16.36.105
dhcp-match=gpxe,175
dhcp-boot=net:#gpxe,gpxe-1.0.1-undionly.kpxe,gxe/bootserver,172.16.36.1
dhcp-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]去启动
呵呵,如果不这么设置,就用一行的话:
dhcp-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
cat boot.txt
#!gpxe
chain 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看到实际发过来的请求如下:
"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
#version=DEVEL
auth --enableshadow --passalgo=sha512
url --url=http://172.16.8.1/centos7
text
firstboot --enable
ignoredisk --only-use=sda
keyboard --vckeymap=us --xlayouts='us'
lang en_US.UTF-8
selinux --disabled
services --enabled="chronyd"
network --bootproto=static --device=em1 --noipv6 --nodns --onboot=yes --gateway={gateway} --ip={ip} --nameserver=172.16.8.1 --netmask={netmask}
network --bootproto=dhcp --device=em2 --noipv6 --nodns --onboot=no
network --bootproto=dhcp --device=em3 --noipv6 --nodns --onboot=no
network --bootproto=dhcp --device=em4 --noipv6 --nodns --onboot=no
network --hostname={hostname}
#grub-crypt --sha-512
# root pass is password
rootpw --iscrypted $6$0Y.SH935/jvt0X.D$lCte9H/KiFeGbTGrrcuXGZXmnq3Rk4Crz8nAvCgH.Pf2SNmoUdh.g5WGWJqtVO4QTyqvnXc/6FyVjptWIaM4w1
timezone Asia/Shanghai --isUtc
bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=sda
clearpart --all --drives=sda
part /boot --fstype ext4 --size=500 --ondisk=/dev/sda
part swap --size=8192 --ondisk=/dev/sda
part / --fstype ext4 --size=1024 --grow --ondisk=/dev/sda
%packages
@compat-libraries
@core
wget
net-tools
chrony
bridge-utils
%end
%post
yum -y erase NetworkManager
cat <<EOF >/etc/sysconfig/network-scripts/ifcfg-br0
DEVICE=br0
TYPE=Bridge
BOOTPROTO=static
ONBOOT=yes
IPADDR={ip}
NETMASK={netmask}
GATEWAY={gateway}
EOF
cat <<EOF > /etc/modprobe.d/bonding.conf
alias bond0 bonding
BONDING_OPTS="miimon=100 mode=1 primary=em1"
EOF
cat <<EOF > /etc/sysconfig/network-scripts/ifcfg-bond0
DEVICE=bond0
ONBOOT=yes
USERCTL=no
BRIDGE=br0
EOF
cat <<EOF > /etc/sysconfig/network-scripts/ifcfg-em1
DEVICE=em1
USERCTL=no
ONBOOT=yes
MASTER=bond0
SLAVE=yes
BRIDGE="br0"
EOF
cat <<EOF > /etc/sysconfig/network-scripts/ifcfg-em2
DEVICE=em2
USERCTL=no
ONBOOT=yes
MASTER=bond0
SLAVE=yes
BRIDGE="br0"
EOF
%end
reboot
注意上面,{ip}、{netmask}、{gateway}、{hostname}是待定的。
然后看看boot2.php:
<?php
$dns='172.16.8.1';
$base7='http://172.16.8.1/centos7';
$ks7='http://172.16.8.1/ks/boot3.php';
echo "#!gpxe\n";
switch ($_REQUEST['mac']) {
case '\ec:f4:bb:d9:96:40':
$ip="172.16.36.2:172.16.37.254:255.255.254.0:myhost-16-36-2";
$ipa=explode(':',$ip);
echo "ifopen net0\n";
echo "set net0/ip $ipa[0]\n";
echo "set net0/netmask $ipa[2]\n";
echo "set net0/gateway $ipa[1]\n";
echo "set net0/dns $dns\n";
echo "set base-url $base7\n";
echo "kernel \${base-url}/images/pxeboot/vmlinuz\n";
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=password inst.sshd\n";
echo "initrd \${base-url}/images/pxeboot/initrd.img\n";
echo "boot\n";
break;
case '00:11:22:33:44:55':
# boot from iSCSI
echo "set initiator-iqn iqn.2007-08.com.example.initiator:initiator\n";
# see http://ipxe.org/sanuri for the syntax
echo "sanboot iscsi:san.example.com:6:3260:0:iqn.2007-08.com.example.san:sometarget\n";
break;
case '\00:77:21:ab:cd:ee':
# boot boot.salstar.sk's super cool boot menu
echo "chain http://boot.salstar.sk\n";
break;
default:
# exit iPXE and let machine go on with BIOS boot sequence
echo "exit\n";
break;
}
?>
注意上面,我们是通过网卡的物理地址来判断模板的,用svc tag号更好。
第四个文件:boot3.php
<?php
$origin_str = file_get_contents($_REQUEST['file']);
$update_str = str_replace("{ip}", $_REQUEST['ip'], $origin_str);
$update_str = str_replace('{netmask}', $_REQUEST['mask'], $update_str);
$update_str = str_replace('{gateway}', $_REQUEST['gateway'], $update_str);
$update_str = str_replace('{hostname}', $_REQUEST['hostname'], $update_str);
echo $update_str;
?>
boot3.php的功能就是替换掉模板文件里的ip等,然后返回一个正确的ks文件。
这下就完美了,我们基本就需要修改ks下的boot2.php和centos7.ks,就可以控制远程安装了。
dhcp和tftp,就用dnsmasq和那一个gxpe就够了,甚至dhcp都是胡乱的。省了大事了。
四个文件的打包下载: http://www.rendoumi.com/soft/pxe.tar.gz
还有更好玩的: 网卡原生pxe-->gpxe-->pxelinux.0
大家尽情想象吧。