0x01 前言
在测试软件的部署过程经常要安装新的虚拟机,虽然用虚拟机模板是一种不错的解决方案,但某些情况下使用全新安装的迅才是首选。
centos7无论是通过CLI还是GUI的方式安装都要进行一些列配置,部署次数少还可以接受,久而久之会觉得这东西装起来真的好繁琐,完全没心思去折腾。为了偷懒,我决定通过kickstart与tftp结合我家里的pfsense实现自动安装。
0x02 准备
需要准备的东西还不少,首先需要一个DHCP服务器,并且配置网络启动的相关信息。在这篇文章里不涉及自建DHCP服务器的内容,因为我使用pfsense作为路由器,因此会有相关的服务。
登入pfsense并定位到以下页面:
- Services \ DHCP \ ServerLAN
在需要配置网络启动的网络中找到以下选项并配置即可,其中“Next Server”需要填写tftp服务器的地址:
然后需要安装tftp服务器,通过以下命令安装即可:
[root@web ~]# yum install -y tftp-server syslinux
实现网络启动需要用到文件,这些文件可以通过以下地址找到:
我写这篇文章的时候,centos最新版本是7.5.1804,当版本更新时,这个目录会被移至最新版本的目录下,所以这里放一个截图做记录:
- http://mirror.t.com/centos/base/
最后,还需要一台安装有GUI界面的centos7,用于运行kickstart以便生成配置文件。
0x03 tftp
pfsense的部分比较简单,就是一个服务指向的配置。当客户机请求DHCP服务内容时会返还网络启动的相关信息,在这里是tftp的服务器地址与BIOS文件。
tftp是至关重要的一步,它会将BIOS文件发送给客户机用于引导,其中的配置文件会包含启动方式等内容。
安装完tftp后需要启用tftp服务,首先修改配置文件:
# 打开文件 [root@web ~]# vim /etc/xinetd.d/tftp # 将disable的值设为no service tftp { socket_type = dgram protocol = udp wait = yes user = root server = /usr/sbin/in.tftpd server_args = -s /var/lib/tftpboot disable = no per_source = 11 cps = 100 2 flags = IPv4 }
然后进入以下目录并新建一个文件夹:
# 进入文件夹 [root@web ~]# cd /var/lib/tftpboot/ # 新建文件夹 [root@web tftpboot]# mkdir pxelinux.cfg
在这新建的文件夹下新建一个配置文件,内容如下:
# 新建文件 [root@web tftpboot]# vim pxelinux.cfg/default # 填入内容 default menu.c32 prompt 0 timeout 30 menu title ##### NGX Proj PXE Boot Menu ##### label 1 menu label ^1) Install CentOS 7 x64 - NGX Proj kernel vmlinuz append initrd=initrd.img inst.ks=http://mirror.t.com/centos/base/anaconda-ks.cfg
如果有多个选项,可以增加“label”块的内容,比如:
label 1 menu label ^1) Install CentOS 7 x64 - NGX Proj kernel vmlinuz append initrd=initrd.img inst.ks=http://mirror.t.com/centos/base/anaconda-ks.cfg label 2 menu label ^2) Install CentOS 7 x86 - NGX Proj x86 kernel vmlinuz append initrd=initrd.img inst.ks=http://mirror.t.com/centos/base/anaconda-ks_x86.cfg
因为我是通过网络进行自动安装,需要在“inst.ks”中指定kickstart生成的自动安装配置文件。因为我有自建的源镜像,所以地址如上。
当客户机启动时,会默认选择第一个选项为默认启动项。如果有多个启动项,你可能需要更长的等待时间,在上面配置文件中的“timeout”值为30,意为3秒,可以根据实际情况自行修改。
最后需要将启动需要的文件复制到tftpboot目录中:
[root@web tftpboot]# cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/ [root@web tftpboot]# cp /usr/share/syslinux/menu.c32 /var/lib/tftpboot/ [root@web tftpboot]# cp /usr/share/syslinux/memdisk /var/lib/tftpboot/ [root@web tftpboot]# cp /usr/share/syslinux/mboot.c32 /var/lib/tftpboot/ [root@web tftpboot]# cp /usr/share/syslinux/chain.c32 /var/lib/tftpboot/
还需要下载通过清华大学镜像站下载以下两个文件并放置到 /var/lib/tftpboot/ 目录中:
vmlinuz initrd.img
该文件夹中所有的文件含义如下:
- chain.c32:引导系统
- mboot.c32:通过内存引导
- memdisk:将内存模拟为磁盘
- menu.c32:菜单文件
- pxelinux.0:引导程序,用于加载kernel和initrd
- vmlinuz:内核
- initrd.img:虚拟根文件
完成后即可通过以下命令启动tftp服务:
# 设为开机启动 [root@web tftpboot]# systemctl enable tftp.socket # 立即启动 [root@web tftpboot]# systemctl start tftp.socket
然后建立一个虚拟机进行测试,需要注意的是,虚拟机需要一个可以和DHCP服务器通讯的网卡,但不需要光驱:
因为还没配置kickstart与安装源,所以启动后会有错误,如果出现以下信息则说明tftp服务器运作正常:
0x04 kickstart
在进行kickstart配置文件的编写前需要准备centos的基础源“base”,这个安装源里包含一个很重要的文件:comps.xml。这个文件里包含group list,有了它才可以获取最小化安装、桌面化安装或者是服务器级别安装所需要的软件包。
在该xml文件同级别的目录下还有一个Packages文件夹,存放着基础的软件包;一个repodata文件夹,存放着Packages文件夹下软件包信息的数据库:
其他文件和文件夹一般用不上。
准备好之后在有桌面环境的centos7系统上打开软件管理器并安装kickstart,然后运行:
根据实际情况选择并填写相关信息。
其实每次安装完系统,在root目录下都会有一个名为“anaconda-ks.cfg”的文件,而这款软件到最后也是生成这个文件。
因此,不想折腾有GUI桌面的centos系统,通过最小化安装,然后将root目录下的“anaconda-ks.cfg”文件复制到本地进行修改。
以下是我的配置文件:
#platform=x86, AMD64, or Intel EM64T #version=DEVEL # Install OS instead of upgrade install # Keyboard layouts keyboard 'us' # Root password rootpw --iscrypted $1$i5xGQgfg$Ar6fz7Xcv..KAPK3ISu/a. # Use network installation url --url="http://mirror.t.com/centos/base/" # System language lang en_US # System authorization information auth --useshadow --passalgo=sha512 # Use text mode install text # SELinux configuration selinux --disabled # Do not configure the X Window System skipx # Firewall configuration firewall --disabled # Network information network --bootproto=dhcp --device=eth0 # Reboot after installation reboot # System timezone timezone Asia/Hong_Kong # System bootloader configuration bootloader --location=mbr # Partition clearing information clearpart --none --initlabel # Disk partitioning information part pv.253 --fstype="lvmpv" --ondisk=sda --size=1 --grow part /boot --fstype="xfs" --ondisk=sda --size=1024 volgroup centos --pesize=4096 pv.253 logvol none --fstype="None" --size=1 --grow --thinpool --metadatasize=16 --chunksize=65536 --name=pool00 --vgname=centos logvol swap --fstype="swap" --size=1024 --name=swap --vgname=centos logvol / --fstype="xfs" --size=1 --grow --thin --poolname=pool00 --name=root --vgname=centos %packages @core perl wget bind-utils net-tools telnet %end %addon com_redhat_kdump --disable %end #%post --nochroot #hostnamectl set-hostname $(cat /sys/class/net/ens192/address | sed 's/://g' | cut -c 7-12) # #%end %post #echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf #echo "net.ipv6.conf.default.disable_ipv6 = 1" >> /etc/sysctl.conf echo "curl -fsSL "http://mirror.t.com/ngx-shell/ngx-pxe-setting-script.sh " | /bin/sh" >> /etc/rc.local chmod +x /etc/rc.d/rc.local rm -f /etc/yum.repos.d/* curl mirror.t.com/home.repo > /etc/yum.repos.d/home.repo yum clean all && yum install epel-release -y && rm -f /etc/yum.repos.d/epel* && yum update -y rm -f /etc/yum.repos.d/CentOS-* && rm -f /etc/yum.repos.d/epel* mkdir /tmp/vmtools \ && wget http://mirror.t.com/vmtools/latest.tar.gz -O /tmp/vmtools/latest.tar.gz \ && tar zxvf /tmp/vmtools/latest.tar.gz -C /tmp/vmtools \ && /tmp/vmtools/vmware-tools-distrib/vmware-install.pl -d \ && rm -rf /tmp/vmtools %end
我对其中的某些内容做了修改,以适配我的使用环境:
- url:值为我自有的镜像地址
- text:使用text模式安装而不加载GUI
- 分区:分为3个区
- swap:1GB
- boot:1GB
- /:剩下的空间
- packages:最小化安装(core)并安装wget与curl
- addon:关闭kdump
- post:
- 用私有的repo替换官方的repo文件
- 升级系统
- 安装vmtools
因为系统更新需要很长的时间,所以部署起来需要3到4分钟,所有流程完成后会自动重启。
编写完kickstart的配置文件后将其放置在pxelinux.cfg目录下default文件中“inst.ks”值所对应的目录中即可,该步骤不需要重启tftp,但需要确认能通过http服务访问。
0x05 结语
经过多次调试才找到适用于我环境的自动部署kickstart配置文件,因此不能照搬,要根据实际情况进行编写。
以下为安装完成后的配置脚本:
#!/bin/sh ######## hostname ######## LOCAL_IPADDR=$(hostname -I | cut -d ' ' -f 1) PTR_ANSWER=$(dig +short -x "$LOCAL_IPADDR") if [ -z "$PTR_ANSWER" ] ; then hostname=$(sed 's/://g' < /sys/class/net/ens192/address | cut -c 7-12) else hostname=$(echo "$PTR_ANSWER" | cut -d '.' -f 1) fi hostnamectl set-hostname "$hostname" ######## IPv6 ######## cp /usr/share/doc/glibc-common-2.17/gai.conf /etc/ && echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf ######## sysctl ######## cat <<EOF >> /etc/sysctl.conf # 允许内核分配所有可用的物理内存 vm.overcommit_memory = 1 # 单个进程允许的最大 fd 数量 fs.file-max = 10245760000 # linux 内核允许的最大 fd 数量 fs.nr_open = 10245760000 # 数据包转发 net.ipv4.ip_forward = 1 # 防范syn攻击 net.ipv4.tcp_syncookies = 1 # 禁用重用time_wait的tcp端口 net.ipv4.tcp_tw_reuse = 0 # fin_wait超时时间 net.ipv4.tcp_fin_timeout = 15 # 动态分配端口的范围 net.ipv4.ip_local_port_range = 20000 65535 # 套接字最大数量 net.ipv4.tcp_max_tw_buckets = 65535 # syn队列长度 net.ipv4.tcp_max_syn_backlog = 10240 # 最大设备队列长度 net.core.netdev_max_backlog = 10240 # listen()等待请求的最大数量 net.core.somaxconn = 10240 # tcp 连接丢包重传次数,达到此值将刷新路由缓存 net.ipv4.tcp_retries1 = 2 # tcp 连接丢包重传次数,达到此值将断开 TCP 连接 net.ipv4.tcp_retries2 = 4 # 放弃建立连接前内核发送syn包的数量 net.ipv4.tcp_syn_retries = 2 # 放弃连接前内核发送syn+ack包的数量 net.ipv4.tcp_synack_retries = 2 # keepalive idle空闲时间 net.ipv4.tcp_keepalive_time = 30 # keepalive intvl间隔时间 net.ipv4.tcp_keepalive_intvl = 2 # keepalive probes最大探测次数 net.ipv4.tcp_keepalive_probes = 3 # 内核允许的最大孤立socket数量 net.ipv4.tcp_max_orphans = 4096 # socket默认读buffer大小 net.core.rmem_default = 655350 # socket默认写buffer大小 net.core.wmem_default = 655350 # socket最大读buffer大小 net.core.rmem_max = 65535000 # socket最大写buffer大小 net.core.wmem_max = 65535000 # socket最大内存buffer大小 net.core.optmem_max = 65535000 # tcp_socket读buffer大小. min/default/max net.ipv4.tcp_rmem = 16384 1048576 12582912 # tcp_socket写buffer大小. min/default/max net.ipv4.tcp_wmem = 16384 1048576 12582912 # 开启tcp_fastopen net.ipv4.tcp_fastopen = 3 # 在路由中缓存 TCP 连接的各项指标 net.ipv4.tcp_no_metrics_save = 0 # 在连接空闲期间保持拥塞窗口的大小 net.ipv4.tcp_slow_start_after_idle = 0 # 磁盘 vm.dirty_background_ratio = 20 vm.dirty_ratio = 30 vm.dirty_expire_centisecs = 1000 vm.dirty_writeback_centisecs = = 300 vm.min_free_kbytes = 65536 vm.swappiness = 1 EOF ######## limits ######## cat <<EOF >> /etc/security/limits.conf * soft nofile 65535 * hard nofile 65535 * soft memlock unlimited * hard memlock unlimited EOF ######## PAM ######## echo "session required /usr/lib64/security/pam_limits.so" >> /etc/pam.d/login ######## repo ######## rm -f /etc/yum.repos.d/Centos*.repo rm -f /etc/yum.repos.d/epel*.repo yum clean all yum install -y iftop htop python-pip python36-pip python36-devel python36 bash-completion bash-completion-extras vim zabbix40-agent wget gcc \ ntpdate pip3.6 install -i https://pypi.tuna.tsinghua.edu.cn/simple pip -U pip3.6 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple pip3.6 install glances ######## crontab ######## echo "*/5 * * * * root ntpdate 10.1.1.1" >> /etc/crontab ######## zabbix-agent ######## sed -i 's/^Server=127\.0\.0\.1/Server=10\.1\.3\.0\/24/g' /etc/zabbix/zabbix_agentd.conf sed -i 's/^ServerActive=127\.0\.0\.1/ServerActive=web\.dev\.t\.com/g' /etc/zabbix/zabbix_agentd.conf sed -i "s/^Hostname=Zabbix server/Hostname=$hostname/g" /etc/zabbix/zabbix_agentd.conf wget -r -np -R "index.html*" -P /var/tmp --cut-dirs=99 http://mirror.t.com/ngx-shell/zabbix_agent_shell/ cp /var/tmp/mirror.t.com/*.conf /etc/zabbix/zabbix_agentd.d/ chown -R zabbix:zabbix /etc/zabbix/zabbix_agentd.d/ rm -f /etc/zabbix_agentd.conf && ln -s /etc/zabbix/zabbix_agentd.conf /etc/zabbix_agentd.conf systemctl enable zabbix-agent.service systemctl restart zabbix-agent.service ######## 删除预设的脚本 ######## sed -i '/.*ngx-pxe-setting-script\.sh.*/d' /etc/rc.d/rc.local rm -rf /etc/rc.local && ln -s /etc/rc.d/rc.local /etc/rc.local rm -f /root/*.cfg