CentOS镜像的制作
# CentOS镜像的制作
# 前置条件
下面这些步骤是在一个带图形化界面的CentOS7机器上操作的,这个机器下面我们称它为宿主机,因此我们需要先准备:
- 一个安装了图形化桌面环境的CentOS 7
- CentOS 7.x的镜像,我这里是7.9,放到/tmp目录下;
- 宿主机CPU开启虚拟化支持
- 在宿主机上执行下面的命令安装下面步骤中所需要的rpm依赖:
yum install qemu-kvm libvirt virt-install virt-viewer virt-manager -y
其中virt-viewer是可视化的GUI组件。
# 镜像创建流程
# 1.创建空白镜像文件
首先执行下面命令创建一个空白的镜像文件
[root@controller2 ~]# qemu-img create -f qcow2 /tmp/centos.qcow2 10G
Formatting '/tmp/centos.qcow2', fmt=qcow2 size=10737418240 encryption=off
cluster_size=65536 lazy_refcounts=off refcount_bits=16
2
3
4
如果直接用图形化界面安装虚拟机,也可以省略调这个流程,但是图形化安装的虚拟机镜像文件默认 路径是/var/lib/libvirt/images目录。
# 2.安装虚拟机操作系统(使用界面安装即可)
然后使用virt-install命令安装一个CentOS虚拟机或者直接使用virt-manager的图形化界面安装:
virt-install --virt-type kvm --name centos7.9 --ram 1024 \
--disk /tmp/centos.qcow2,format=qcow2 --network network=default \
--graphics vnc,listen=0.0.0.0 --noautoconsole --os-type=linux \
--os-variant=centos7.0 --location=/tmp/CentOS-7-x86_64-DVD-2009.iso
2
3
4
需要把iso文件放在/tmp目录下,避免一些额外的权限配置问题。在宿主机上安装了图形界面后,打开virt-manager,就能看到刚才命令创建的虚拟机。如下所示:
双击虚拟机名称,就能进入到虚拟机的console界面,此时开始安装。在虚拟机配置界面修改时区为上海,设置硬盘自动分区,设置网络为dhcp获取方式,域名使用默认的。进入安装流程,在安装流程中,设置需要的root密码和普通用户centos。
分区格式和硬盘自动扩展的关系
上面配置流程中选择的是硬盘自动分区,那么它默认使用的根分区格式是LVM格式,后面安装的cloudinit和cloud-utils-growpart包无法自动扩展LVM格式,需要自己手动写一个脚本来帮助cloud-init工具自动扩展系统盘,脚本命令依次是:
growpart /dev/vda 2 #先扩大/dev/vda2分区的大小
pvresize /dev/vda2 # 再扩大/dev/vda2这个pv的大小
num=$(vgdisplay | grep 'Free PE' | awk '{print $5}') #这里获取新的PE总数量
vgchange -l $num /dev/centos # 扩大根分区vg的大小,num是新的PE总数
lvresize -l +$[num-256] /dev/centos/root # 减去256个PE的大小给Swap
xfs_growfs / #扩大根文件系统大小
2
3
4
5
6
把这些命令写入到一个脚本autoExtendRootPartition.sh文件中,放在宿主机上,稍后使用。
如果不想使用上面的脚本来自动扩展硬盘分区,而是使用openstack自带的cloud-init来自动扩展分区,那么在安装这个虚拟机操作系统的时候,硬盘需要手动分区。一般只保留/boot、/、swap分区,同时swap分区必须在/ 分区之前,否则自动扩展程序会出错。要么就干脆不要swap分区。这样的话,根目录就直接对应的是/dev/vda2。
# 3.卸载光驱
虚拟机一般用不上光驱,因此一般需要把虚拟机里这个设备给卸载。等到虚拟机系统安装完毕,可以先使用下面的命令确认cdrom在系统中对应的文件名称,如下所示:
virsh dumpxml centos79
命令结果输出如下:
<domain type='kvm' id='9'>
<name>centos79</name>
<uuid>aeda72dc-5682-4cf4-a44a-97611c587aae</uuid>
<memory unit='KiB'>1048576</memory>
<currentMemory unit='KiB'>1048576</currentMemory>
<vcpu placement='static'>1</vcpu>
...
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='/tmp/CentOS-7.9-x86_64-DVD-2009.iso'/>
<backingStore/>
<target dev='hda' bus='ide'/>
<readonly/>
<alias name='ide0-0-0'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
使用root用户在宿主机上运行下面的命令弹出光驱,然后使用virsh重启。如果你是要GUI来弹出硬盘,可以使用停止和启动按钮来重启。(建议使用界面来弹出光驱)
# virsh detach-disk --type cdrom --mode readonly centos79 "" hda
# virsh reboot centos79
2
如果发现该命令对该版本的镜像没有效果,可以在virt-manager上通过图形界面进行分离。基本流程是:
- 把虚拟机关机
- 点击界面上的小灯泡图标,打开硬件配置,找到IDE CDROM
- 点击邮件,选择remove hardware
- 确认删除cdrom 然后重新启动该虚拟机,进入下面配置流程。
# 4.基本服务配置
等到虚拟机系统安装完毕后,登陆到虚拟机中。配置镜像使用的一些内网服务,例如将镜像源修改为内网的源:
cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
curl http://mirrors.avlyun.org/repo/centos7.repo > /etc/yum.repos.d/CentOS-Base.repo
2
安装常见的软件vim和net-tools,命令是:
yum install vim net-tools -y
然后配置ACPI服务,这个服务是宿主机用来控制虚拟机的一个中介服务,安装命令是:
yum install acpid
systemctl start acpid
systemctl enable acpid
2
3
如果有其他你们自己的基本服务需要安装,例如配置你们自己的管理组件,监控组件等等,也可以在这一步里都配置好。
禁用zeroconf路由
为了实例能够访问元数据服务,需要禁用zeroconf路由,命令是:
echo "NOZEROCONF=yes" > /etc/sysconfig/network
关闭防火墙和SELinux
不关闭防火墙,会导致启动的实例无法连接到元数据服务器,获取主机名等信息。命令是:
systemctl disable firewalld
systemctl stop firewalld
2
SELinux一般默认禁用,打开/etc/selinux/config文件,修改配置如下:
selinux=disabled
# 5.配置实例匹配元数据
实例在启动的过程中,必须和元数据(metadata)服务交互,来执行若干任务。例如获取ssh公钥,获取用户数据脚本等。要保证实例能够执行这些任务,有两种方式:
- 安装一个cloud-init RPM包,这也是推荐的方式
- 修改/etc/rc.local文件来匹配元数据服务需要的数据。
使用cloud-init来匹配公钥
cloud-init会自动从元数据服务中获取到公钥信息,并且保存到用户家目录下的authorized_keys文件中。因此需要安装这个包。cloud-initramfs-tools工具是用来在虚拟机启动时自动扩大系统分区的,因为上面创建的虚拟机镜像默认大小只有10G,这个工具在启动时会根据选择的虚拟机实例类型中的硬盘大小,自动配置根分区的大小。
cloud-utils-growpart工具是用来提供分区自动扩容的命令的。这3个组件的安装命令是:
yum install cloud-init cloud-utils cloud-initramfs-tools cloud-utils-growpart -y
这个时候如果发生了包冲突,例如cloud-init需要的一些包版本比较旧,而系统安装的比较新,可以使用yum的降级命令将包的版本降下来,然后就可以正常安装成功。
cloud-init将获取到的公钥保存在哪个目录取决于不同的发行版,在CentOS上默认是放在centos用户目录下,如果你要将它保存到不同的用户目录下,可以修改/etc/cloud/cloud.cfg文件,配置内容格式是:
users:
- name: admin
2
上面的格式是配置了将公钥放在admin用户目录下
修改/etc/rc.local文件来匹配元数据服务需要的数据
如果不使用cloud-init来获取虚拟机元数据,则需要写一个脚本来从元数据服务中获取公钥并写入用户家目录,脚本内容如下:
if [ ! -d /root/.ssh ]; then
mkdir -p /root/.ssh
chmod 700 /root/.ssh
fi
# Fetch public key using HTTP
ATTEMPTS=30
FAILED=0
while [ ! -f /root/.ssh/authorized_keys ]; do
curl -f http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key \
> /tmp/metadata-key 2>/dev/null
if [ \$? -eq 0 ]; then
cat /tmp/metadata-key >> /root/.ssh/authorized_keys
chmod 0600 /root/.ssh/authorized_keys
restorecon /root/.ssh/authorized_keys
rm -f /tmp/metadata-key
echo "Successfully retrieved public key from instance metadata"
echo "*****************"
echo "AUTHORIZED KEYS"
echo "*****************"
cat /root/.ssh/authorized_keys
echo "*****************"
fi
done
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 6. 配置console
要想nova console-log命令在以这个CentOS7镜像创建的虚拟机上正常运行,你需要执行下面几个步骤:
(1)编辑/etc/default/grub文件
配置GRUB_CMDLINE_LINUX选项,删除rhgb quiet,然后添加console=tty0 console=ttyS0,115200n8到选项中
例如:
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=cl/root rd.lvm.lv=cl/swap \
console=tty0 console=ttyS0,115200n8"
2
(2)运行下面的命令保存配置,生成新的引导参数:
grub2-mkconfig -o /boot/grub2/grub.cfg
引导项配置好以后在虚拟机里使用root用户执行关机命令关闭虚拟机:
poweroff
# 7. 虚拟机清理
在虚拟机启动的时候,操作系统会记录虚拟网卡的mac地址,例如/etc/sysconfig/network-scripts/ifcfg-eth0。然而每次镜像启动的不同实例的虚拟网卡都需要有不同的mac地址,所以类似这样的唯一性信息必须从虚拟机的配置文件里清除掉。完成这个任务的工具叫做virt-sysprep,能够执行大量的虚拟机清理任务,例如移除mac地址引用。清理一个虚拟机的命令如下:
virt-sysprep -d centos79
如果没有这个命令的话,还需要先安装,安装命令是:
yum install libguestfs-tools -y
-d参数后面是虚拟机的名称。virt-sysprep命令的执行过程如下:
[ 0.0] Examining the guest ...
[ 29.9] Performing "abrt-data" ...
[ 29.9] Performing "backup-files" ...
[ 31.3] Performing "bash-history" ...
[ 31.4] Performing "blkid-tab" ...
[ 31.4] Performing "crash-data" ...
[ 31.4] Performing "cron-spool" ...
[ 31.4] Performing "dhcp-client-state" ...
[ 31.4] Performing "dhcp-server-state" ...
[ 31.4] Performing "dovecot-data" ...
[ 31.5] Performing "logfiles" ...
[ 31.6] Performing "machine-id" ...
[ 31.6] Performing "mail-spool" ...
[ 31.6] Performing "net-hostname" ...
[ 31.6] Performing "net-hwaddr" ...
[ 31.6] Performing "pacct-log" ...
[ 31.6] Performing "package-manager-cache" ...
[ 31.7] Performing "pam-data" ...
[ 31.7] Performing "passwd-backups" ...
[ 31.8] Performing "puppet-data-log" ...
[ 31.8] Performing "rh-subscription-manager" ...
[ 31.8] Performing "rhn-systemid" ...
[ 31.8] Performing "rpm-db" ...
[ 31.8] Performing "samba-db-log" ...
[ 31.8] Performing "script" ...
[ 31.8] Performing "smolt-uuid" ...
[ 31.9] Performing "ssh-hostkeys" ...
[ 31.9] Performing "ssh-userdir" ...
[ 31.9] Performing "sssd-db-log" ...
[ 31.9] Performing "tmp-files" ...
[ 31.9] Performing "udev-persistent-net" ...
[ 31.9] Performing "utmp" ...
[ 31.9] Performing "yum-uuid" ...
[ 31.9] Performing "customize" ...
[ 32.0] Setting a random seed
[ 32.0] Setting the machine ID in /etc/machine-id
[ 32.1] Performing "lvm-uuids" ...
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
这条命令会清理掉机器里面所有账号的.ssh目录,如果你想保留对应的key文件,例如你们公司自己的管理公钥。则需要通过不同的命令行选项来注入对应的文件,在宿主机上执行命令如下所示:
virt-sysprep -d centos7.8.2003 --ssh-inject root:file:yourkey.pub \
--ssh-inject centos:file:yourkey.pub \
--firstboot-command "chattr +i /root/.ssh/authorized_keys" \
--firstboot autoExtendRootPartition.sh
2
3
4
配置项说明:--ssh-inject 将公钥内容保存在antiykey.pub文件中,然后通过上面的语法,注入到镜像内。--firstboot-command选项是要首次启动时要执行的命令,我这里是将root用户的authorized_keys文件加上-i 特殊标志位,添加这个标志位会导致在启动实例的时候注入公钥失败,因此如果你不需要的话,就不要添加这个选项。--firtboot命令是在首次启动时运行上面的自动扩展分区的脚本,将root分区大小扩展到和实例类型中匹配的硬盘大小。
# 8. 取消libvirt域(domain)设置
现在你可以把虚拟机镜像文件上传到Glance镜像服务了,不再需要通过libvirt管理的这个虚拟机镜像。使用virsh undefine vm-image命令来通知libvirt,取消我们上面创建的虚拟机centos79注册,在宿主机上执行:
virsh undefine centos79
这个时候在libvirt里就看不到这个虚拟机的记录,只剩下它的硬盘镜像文件。在将镜像导入openstack集群之前,还可以把镜像文件再压缩一下,在宿主机上执行下面的命令是:
virt-sparsify /path/to/source.qcow2 --compress /path/to/output.qcow2
这个命令会将镜像中没有使用的硬盘空间全部使用0填充,能极大的压缩原来镜像的大小。压缩完成后,就可以基于这个虚拟机镜像文件,使用qemu-img create命令在OpenStack集群里创建需要使用的镜像文件,示例命令格式是:
openstack image create --file centos-7.9-x86_64.qcow2 --disk-format qcow \
--container-format bare --public centos-7.9-x86_64
2
如果想将镜像格式转换成raw格式,那么可以使用下面的命令,在宿主机上执行:
qemu-img convert -f qcow -O raw centos-7.9-x86_64.qcow2 centos-7.9-x86_64.raw
就可以把qcow2格式的镜像文件转换为raw格式,转换之后,镜像会变大。