Razor对iPXE的使用
iPXE是Razor主要依赖的技术,配合iPXE就能实现服务器节点固件和Razor的交互。
iPXE是开源的网络启动固件,提供了全部的PXE功能,而且加入更多的高级特性,
比如:支持从HTTP服务器、iSCSI SAN、FC SAN、AoE SAN、无线网络、广域网、Infiniband网络启动;通过脚本控制boot流程。
Razor主要利用HTTP服务器启动和脚本控制两个特性。
部分网卡需要特殊配置以支持通过iPXE安装Razor-Microkernel
服务器启动时
搭建iPXE服务需要DHCP服务和ftp服务,具体过程就不详述了。
服务器在进行网络启动时,iPXE会根据配置提供两种boot方式。下面的代码清单是iPXE的默认配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
default menu.c32
prompt 0
menu title Razor Boot Menu
timeout 50
f1 help.txt
f2 version.txt
label razor-boot
menu label Automatic Razor Node Boot
kernel ipxe.lkrn
append initrd=razor.ipxe
label boot-else
menu label Bypass Razor
localboot 1
可以看到,使用razor-boot方式会下载tftp服务器上的ipxe.lkrn和razor.ipxe脚本文件进行启动,如下图所示
服务器会根据razor.ipxe脚本文件向Razor Server发起http请求,从这里就开始进入Razor的控制流程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!ipxe
isset ${net0/mac} && dhcp net0 ||
isset ${net1/mac} && dhcp net1 ||
isset ${net2/mac} && dhcp net2 ||
isset ${net3/mac} && dhcp net3 ||
isset ${net4/mac} && dhcp net4 ||
isset ${net5/mac} && dhcp net5 ||
isset ${net6/mac} && dhcp net6 ||
isset ${net7/mac} && dhcp net7 ||
chain http://168.1.43.39:8026/razor/api/boot?hw_id=${net0/mac}_${net1/mac}_${net2/mac}_${net3/mac}_$
{net4/mac}_${net5/mac}_${net6/mac}_${net7/mac} || goto error
:error
sleep 15
reboot
Razor最终会返回http应答,其中包含可执行iPXE脚本,告诉服务器按何种方式启动。
比如,服务器是首次启动,则会告诉服务器下载Razor-Microkernel并启动。
下面的代码清单说明Razor返回的执行脚本内容,其中指明了kernel和initrd的下载路径
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def get_boot_script ( default_mk )
image_svc_uri = "http:// #{ @config . image_svc_host } : #{ @config . image_svc_port } /razor/image/mk/ #{ default_mk . uuid } "
rz_mk_boot_debug_level = @config . rz_mk_boot_debug_level
# only allow values of 'quiet' or 'debug' for this parameter; if it's anything else set it
# to an empty string
rz_mk_boot_debug_level = '' unless [ 'quiet' , 'debug' ]. include? rz_mk_boot_debug_level
boot_script = ""
boot_script << "#!ipxe \n "
boot_script << "kernel #{ image_svc_uri } / #{ default_mk . kernel } maxcpus=1"
boot_script << " #{ rz_mk_boot_debug_level } " if rz_mk_boot_debug_level && ! rz_mk_boot_debug_level . empty?
boot_script << " || goto error \n "
boot_script << "initrd #{ image_svc_uri } / #{ default_mk . initrd } || goto error \n "
boot_script << "boot || goto error \n "
boot_script << " \n\n\n "
boot_script << ":error \n echo ERROR, will reboot in #{ @config . mk_checkin_interval } \n sleep #{ @config . mk_checkin_interval } \n reboot \n "
boot_script
end
下图是Razor Server的日志,可以看到hw_id为043a的节点在通过iPXE发起boot请求后,Server返回了Razor-Microkernl的地址。
对于服务器,在收到http应答后会执行脚本到指定地址下载Razor-Microkernel并启动,下图为服务器控制台输出
OS安装过程中
在iPXE发起boot的http请求时,如果Razor Server发现node已经和policy进行了绑定,则返回http应答中包含的执行脚本会指明OS镜像的路径。
例如,安装Ubuntu时,返回的iPXE脚本如下代码清单所示,此代码清单为Ubuntu ModelTemplate的一部分
1
2
3
4
5
6
7
8
9
10
#!ipxe
echo Razor < %= @label %> model boot_call
echo Installation node UUID : <%= node . uuid %>
echo Installation image UUID: <%= @image_uuid %>
echo Active Model node state : < %= @current_state %>
sleep 3
kernel <%= " #{ image_svc_uri } / #{ @image_uuid } / #{ kernel_path } #{ kernel_args ( policy_uuid ) } " %> || goto error
initrd <%= " #{ image_svc_uri } / #{ @image_uuid } / #{ initrd_path } " %> || goto error
boot
如下图所示,iPXE会到指定路径下载Ubuntu安装镜像进行启动
OS安装过程详解
Razor-Microkernel发现Server方法
MK在启动时会检测Server的IP地址并主动进行checkin操作,检测方式有两种:
在/proc/cmdline 文件中查找razor.ip或razor.server值作为Server的IP地址
使用/etc/resolv.conf中的DNS服务器IP地址作为Server的IP地址
具体代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def discover_rz_server_ip
discover_by_pxe or discover_by_dns or discover_by_dhcp
end
def discover_by_pxe
begin
contents = File . open ( "/proc/cmdline" , 'r' ) { | f | f . read }
server_ip = contents . split . map { | x | $1 if x . match ( /razor.ip=(.*)/ )} . compact
if server_ip . size == 1
return server_ip . join
else
return false
end
rescue
return false
end
end
def discover_by_dns
begin
contents = File . open ( "/proc/cmdline" , 'r' ) { | f | f . read }
server_name = contents . split . map { | x | $1 if x . match ( /razor.server=(.*)/ )} . compact
server_name = server_name . size == 1 ? server_name . join : 'razor'
require 'socket'
return TCPSocket . gethostbyname ( server_name ) [ 3 . . - 1 ]. first || false
rescue
return false
end
end
def discover_by_dhcp
udhcp_file = "/tmp/nextServerIP.addr"
begin
contents = File . open ( udhcp_file , 'r' ) { | f | f . read }
return contents . strip
rescue
return false
end
end
Razor的程序结构
Razor的主要程序结构如下图所示:
典型流程:
Razor中Policy的绑定过程
先解释一下概念
Node:能够被Razor管理到的一台服务器就是一个Node,可以是虚拟化或物理机
Model:Razor中将一种OS类型的安装方式抽象为一个model,比如针对Ubuntu Precise的安装就会有一个precise的model存在,其中详细定义了OS的安装配置、安装过程、安装中的状态变化、安装中Node和Razor的交互、安装后的处理等等。model是和OS类型紧密相关的。
Policy:Razor根据Policy将Node和Model联系在一起。Policy与Model为1对1,与Node为1对N关系。Policy的匹配规则类似防火墙的过滤规则,具有先后优先级。优先级高的Policy会先生效,并将Model和Node绑定。
Active_model:Active_model是一个Policy对象,可以理解为生效的Policy。Razor发现某个Node符合一条Policy规则,则生成一个Policy对象,将状态设定为active,指明绑定的Node。之后OS的安装过程,Node都是根据这个Active_model定义的流程和规则在进行操作。
current_state与返回命令的映射表如下图: