如何構建OpenStack鏡像
本文以製作CentOS7.2鏡像為例,詳細介紹手動製作OpenStack鏡像詳細步驟,解釋每一步這麼做的原因。鏡像上傳到OpenStack glance,支持以下幾個功能:
- 支持密碼注入功能(nova boot時通過--admin-pass參數指定設置初始密碼)
- 支持根分區自動調整(根分區自動調整為flavor disk大小,而不是原始鏡像分區大小)
- 支持動態修改密碼(使用nova set-password命令可以修改管理員密碼)
手動製作鏡像非常麻煩和耗時,本文後面會介紹一個專門用於自動化構建鏡像的項目DIB,通過DIB只需要在命令行上指定elements即可製作鏡像,省去了重複下載鏡像、啟動虛擬機配置鏡像的繁雜步驟。
鏡像的宿主機操作系統為Ubuntu 14.04,開啟了VT功能(使用kvm-ok命令驗證)並安裝了libvirt系列工具,包括virsh、virt-manager、libguestfs-tools等。
1 手動製作OpenStack鏡像
1.1 下載鏡像
訪問官方鏡像地址下載,注意選擇中國的鏡像源,相對國外鏡像下載速度更快,進入後選擇版本為7.2.1511,在isos目錄下下載x86_64的Minimal鏡像,如果網速不給力,最好不要選擇下載Netinstall鏡像,因為這會在安裝時聯網下載大量的軟體包,重新安裝時需要重新下載這些軟體包。
1.2 創建虛擬機
首先創建一個qcow2格式鏡像文件,用於虛擬機的根磁碟,大小10G就夠了。
qemu-img create -f qcow2 centos.qcow2 10G # create disk image
使用以下腳本創建並啟動虛擬機:
NAME=centosROOT_DISK=centos.qcow2CDROM=`pwd`/CentOS-7-x86_64-Minimal-1511.isosudo virt-install --virt-type kvm --name $NAME --ram 1024 --disk $ROOT_DISK,format=qcow2 --network network=default --graphics vnc,listen=0.0.0.0 --noautoconsole --os-type=linux --os-variant=rhel7 --cdrom=$CDROM
啟動完成後,使用vnc client連接或者使用virt-manager、virt-viewer連接。
1.3 安裝OS
進入虛擬機控制台可以看到CentOS的啟動菜單,選擇Install Centos 7,繼續選擇語言後將進入INSTALLION SUMMARY,其中大多數配置默認即可,SOFTWARE SELECTION選擇Minimal Install,INSTALLATION DESTINATION需要選擇手動配置分區,我們只需要一個根分區即可,不需要swap分區,文件系統選擇ext4或者xfs,存儲驅動選擇Virtio Block Device,如圖:
配置完成後就可以開始安裝了,在CONFIGURATION中設置root臨時密碼,只需要暫時記住這個臨時密碼,製作完後cloud-init會重新設置root初始密碼。
大約幾分鐘後,即可自動完成安裝配置工作,最後點擊右下角的reboot重啟退出虛擬機。
1.4 配置OS
安裝好系統後,需要進行配置才能作為glance鏡像使用。首先啟動虛擬機(雖然上一步執行的是reboot,但貌似並不會自動啟動):
sudo virsh start centos
如果雲主機需要支持root ssh遠程登錄,需要開啟root遠程ssh登錄功能,修改配置文件/etc/ssh/sshd_config並修改PermitRootLogin值為yes,重啟ssh服務生效:
sudo systemctl restart sshd
注意:
- 不建議開啟密碼登錄功能,使用密鑰登錄更安全。
- 不建議開啟root遠程登錄。
為了加快安裝速度,可以配置為本地軟體源倉庫,若沒有本地鏡像倉庫,則選擇國內的軟體源,相對官網的速度下載要快。
mv my_repo.repo /etc/yum.repos.d/
acpid
acpid是一個用戶空間的服務進程, 用來處理電源相關事件,比如將kernel中的電源事件轉發給應用程序,告訴應用程序安全的退出,防止應用程序異常退出導致數據損壞。libvirt可以通過向guest虛擬機發送acpid事件觸發電源操作,使虛擬機安全關機、重啟等操作,相對於強制執行關閉電源操作更安全。通過acpid事件發送開關機信號即我們經常所說的軟重啟或者軟關機。
為了支持軟操作,虛擬機需要安裝acpid服務,並設置開機自啟動:
yum install -y acpidsystemctl enable acpid
提示:
- 用戶執行重啟或者關機操作時,OpenStack會首先嘗試調用libvirt的shutdown方法,即軟關機。
- 當軟關機執行失敗或者超時(默認120秒),則會調動libvirt的destroy方法,即強制關機,因此如果虛擬機關機或者重啟很慢,很可能是acpid沒有正常運行。
- 為了使虛擬機進程安全退出,減少數據損壞風險,盡量使用軟操作,硬操作可能導致程序崩潰或者數據丟失。
console log
當操作系統內核崩潰時會報出內核系統crash出錯信息,通常啟動的時候一閃而過, 而此時系統還沒有起來,不能通過遠程工具(比如ssh)進入系統查看,我們可以通過配置grub,把這些日誌重定向到Serial Console中,這樣我們就可以通過Serial console來訪問錯誤信息,以供分析和排錯使用。
修改配置文件/etc/default/grub,設置GRUB_CMDLINE_LINUX,:
GRUB_CMDLINE_LINUX="crashkernel=auto console=tty0 console=ttyS0,115200n8"
通過這個配置,內核信息會以115200的波特率同時發送到tty0和ttyS0串列埠設備。libvirt可以通過一個普通文件模擬這個串列埠:
<serial type="file"> <source path="/var/lib/nova/instances/99579ce1-f4c4-4031-a56c-68e85a3d037a/console.log"/> <target port="0"/></serial>
這樣內核產生的日誌發到ttyS0,實際上寫到console.log文件中。
OpenStack通過nova console-log命令可以獲取該文件內容,查看錯誤日誌。
qemu-guest-agent
qemu-guest-agent是運行在虛擬機內部的一個服務,libvirt會在本地創建一個unix socket,模擬為虛擬機內部的一個串口設備,從而實現了宿主機與虛擬機通信,這種方式不依賴於TCP/IP網路,實現方式簡單方便。
<channel type="unix"> <source mode="bind" path="/var/lib/libvirt/qemu/org.qemu.guest_agent.0.instance-00003c2c.sock"/> <target type="virtio" name="org.qemu.guest_agent.0"/> <address type="virtio-serial" controller="0" bus="0" port="1"/></channel>
如上宿主機的socket文件為org.qemu.guest_agent.0.instance-00003c2c.sock,在虛擬機內部為/dev/virtio-ports/org.qemu.guest_agent.0。
通過這種方式,宿主機可以發送指令寫到socket文件中,虛擬機內部的qemu-guest-agent會輪詢查看這個串列設備是否有指令,一旦接收到指令就可以執行對應的腳本,從而實現了宿主機控制虛擬機執行命令的功能,其中最常用的指令就是通過libvirt修改虛擬機密碼。更多關於qemu-guest-agent請參考官方文檔。
為了支持OpenStack平台動態修改虛擬機密碼功能,我們需要手動安裝qemu-guest-agent:
yum install -y qemu-guest-agent
修改/etc/sysconfig/qemu-ga配置文件:
TRANSPORT_METHOD="virtio-serial"DEVPATH="/dev/virtio-ports/org.qemu.guest_agent.0"LOGFILE="/var/log/qemu-ga/qemu-ga.log"PIDFILE="/var/run/qemu-ga.pid"BLACKLIST_RPC=""FSFREEZE_HOOK_ENABLE=0
可以查看qemu-guest-agent支持的指令:
$ virsh qemu-agent-command instance-000028d5 "{"execute":"guest-info"}" | python -m json.tool | grep "name" | cut -d ":" -f 2 | tr -d ""," ... guest-set-user-password guest-get-fsinfo guest-set-vcpus guest-get-vcpus ...
確認包含guest-set-user-password指令,支持修改管理員密碼。
zeroconf
zeroconf是一種古老的自動網路配置技術,在沒有DHCP服務的年代,所有伺服器都需要網管手動配置IP、hostname等,非常麻煩,zeroconf正好解決了這個問題,不過目前通常都通過DHCP獲取地址了。不過一些操作系統仍然會開啟這個服務,當DHCP獲取IP失敗時,會嘗試通過zeroconf配置。
zeroconf啟動時會自動創建一條路由169.254.0.0/16,而虛擬機訪問metadata服務的地址正好是169.254.169.254,如果啟動了zeroconf服務,由於路由衝突,虛擬機不能通過169.254.169.254路由到網路節點的metadata服務了。OpenStack虛擬機通常都是通過DHCP獲取IP的,因此我們並不需要zeroconf服務。為了虛擬機能夠訪問metadata服務,我們必須禁止zeroconf服務,關於該問題的更詳細討論可參考bug#983611:
echo "NOZEROCONF=yes" >> /etc/sysconfig/network
cloud-init
接下來安裝cloud-init,cloud-init是虛擬機第一次啟動時執行的腳本,主要負責從metadata服務中拉取配置信息,完成虛擬機的初始化工作,比如設置主機名、初始化密碼以及注入密鑰等。
# yum install -y cloud-init-0.7.6-bzr1.el7.centos.noarch.rpmyum install -y cloud-init
growpart
虛擬機製作鏡像時指定了根分區大小(比如我們設置為10GB),為了使虛擬機能夠自動調整為flavor disk指定的根磁碟大小,即自動擴容, 我們需要安裝glowpart(老版本叫growroot)並完成以下配置:
yum update -yyum install -y epel-releaseyum install -y cloud-utils-growpart.x86.64rpm -qa kernel | sed "s/^kernel-//" | xargs -I {} dracut -f /boot/initramfs-{}.img {}
完成以上工作後,我們的鏡像配置基本結束,刪除一些無用文件,清理history命令後執行關機:
/sbin/shutdown -h now
1.5 移除本地信息
在宿主機上運行以下命名,移除宿主機信息,比如mac地址等。
virt-sysprep -d centos # cleanup tasks such as removing the MAC address references
刪除虛擬機,鏡像製作完成。
virsh undefine centos # 刪除虛擬機
2.上傳鏡像
2.1 使用glance命令上傳鏡像
鏡像製作完成,上傳centos.qcow2到glance服務中。
glance image-create --file ./centos.qcow2 --disk-format qcow2 --container-format bare --name CentOS-7.2 --progress
2.2 通過rbd直接導入鏡像
由於鏡像通常比較大,上傳時如果使用glance API,則通過HTTP上傳,由於HTTP協議的限制,導致上傳非常慢,非常耗時。 如果Glance使用Ceph作為存儲後端,可以通過rbd直接導入(import)方式上傳到Ceph中,速度會大幅度提高。
首先需要把鏡像轉為raw格式:
qemu-img convert -f qcow2 -O raw centos.qcow2 centos.raw
通過glance create創建一個空鏡像,並記錄uuid(不需要指定文件路徑以及其它欄位,只是佔個坑):
glance image-create
使用rbd命令直接導入鏡像並創建快照:
rbd -p glance import centos.raw --image=$IMAGE_ID --new-format --order 24rbd -p glance snap create $IMAGE_ID@snaprbd -p glance snap protect $IMAGE_ID@snap
設置glance鏡像location url:
FS_ID=`ceph -s | grep cluster | awk "{print $2}"`glance location-add --url rbd://${FS_ID}/glance/${IMAGE_ID}/snap $IMAGE_ID
設置glance鏡像其它屬性:
glance image-update --name="CentOS-7.2-64bit" --disk-format=raw --container-format=bare
2.3 添加qemu-guest-agent屬性
OpenStack Nova是通過判斷鏡像元數據hw_qemu_guest_agent是否為yes決定是否支持qemu-guest-agent,代碼如下:
# nova/virt/libvirt/driver.pydef _add_qga_device(self, guest, instance): qga = vconfig.LibvirtConfigGuestChannel() qga.type = "unix" qga.target_name = "org.qemu.guest_agent.0" qga.source_path = ("/var/lib/libvirt/qemu/%s.%s.sock" % ("org.qemu.guest_agent.0", instance.name)) guest.add_device(qga)def _set_qemu_guest_agent(self, guest, flavor, instance, image_meta): # Enable qga only if the "hw_qemu_guest_agent" is equal to yes if image_meta.properties.get("hw_qemu_guest_agent", False): LOG.debug("Qemu guest agent is enabled through image " "metadata", instance=instance) self._add_qga_device(guest, instance) ...
由此可知,我們必須添加鏡像propertyhw_qemu_guest_agent=yes,否則libvert啟動虛擬機時不會創建qemu-guest-agent設備,虛擬機的qemu-guest-agent由於找不到對應的串列設備而導致修改密碼失敗。
glance image-update --property hw_qemu_guest_agent=yes $IMAGE_ID
3 DIB工具介紹
前面介紹了手動製作鏡像的過程,從鏡像下載到啟動虛擬機安裝操作系統,然後在虛擬機中完成配置,最後清除本地信息,整個過程非常繁雜、耗時,並且一旦製作鏡像的鏡像有點問題,就需要啟動虛擬機重新再來一遍,重複工作多,效率非常低。
假設製作鏡像時某個配置項錯了,能不能不通過啟動虛擬機進入系統去更改呢?答案是肯定的!我們只需要把製作好的鏡像通過loop設備掛載到本地(如果是qcow2格式,則需要通過nbd掛載),然後chroot到掛載目錄中修改配置文件即可,相對於啟動虛擬機進入系統去更改方便高效很多。
由此我們自然想到,我們可以把最初啟動虛擬機時安裝操作系統完成後的鏡像保存為base鏡像,以後再做鏡像時,只需要基於該base鏡像調整即可,省去了下載鏡像以及安裝操作系統這兩大耗時步驟。修改鏡像也不再需要啟動虛擬機,只需要根據前面介紹的方法,把鏡像掛載到本地,然後chroot到根分區修改即可。
OpenStack社區正是基於該思路,開發了DIB(disk image builder),它目前是OpenStack TripleO項目的子項目,專門用於構建OpenStack鏡像:
diskimage-builder is a flexible suite of components for building a wide-range of disk images, filesystem images and ramdisk images for use with OpenStack.
DIB把一些操作封裝成腳本,比如創建用戶(devuser)、安裝cloud-init(cloud-init)、配置yum源(yum)、部署tgtadm(deploy-tgtadm)等,這些腳本稱為elements,位於目錄diskimage-builder/diskimage_builder/elements,你可以根據自己的需求自己定製elements,elements之間會有依賴,依賴通過element-deps文件指定,比如elements centos7的element-deps為:
- cache-url
- redhat-common
- rpm-distro
- source-repositories
- yum
DIB會首先下載一個base鏡像,然後通過用戶指定的elements,一個一個chroot進去執行,從而完成了鏡像的製作,整個過程不需要啟動虛擬機。這有點類似Dockerfile的構建過程,Dockerfile的每個指令都會生成一個臨時的容器,然後在容器裡面執行命令。DIB則每個elements都會chroot到鏡像中,執行elements中的腳本。
比如製作ubuntu 14.04鏡像:
export DIB_RELEASE=trustydisk-image-create -o ubuntu-trusty.qcow2 vm ubuntu
創建Trove percona鏡像:
disk-image-create -a amd64 -o ubuntu-trusty-percona-5.6.33-guest-image -x ubuntu vm cloud-init-datasources ubuntu-trusty-guest ubuntu-trusty-percona
其中ubuntu-trustry-guest會安裝trove-guest-agent,ubuntu-trusty-percona會安裝percona組件。
製作鏡像時可以通過環境變數進行配置,比如創建ironic鏡像:
# 生成用戶鏡像 # ubuntu.qcow2:用戶最終使用的鏡像# ubuntu.vmlinuz:"Virtual Memory"的縮寫,具有引導的壓縮內核 # ubuntu.initrd: "initial ramdisk"的縮寫# Linux系統引導過程中使用的臨時根文件系統,包含基本linux命令,# 如ls,cd,tftp等 export DIB_DEV_USER_USERNAME=cloud-userexport DIB_DEV_USER_PASSWORD=secretexport DIB_DEV_USER_PWDLESS_SUDO=YESDIB_CLOUD_INIT_DATASOURCES="ConfigDrive, OpenStack" disk-image-create -o centos7 centos7 baremetal dhcp-all-interfaces grub2 cloud-init-datasources devuser
以上製作鏡像時會創建cloud-user用戶,密碼為secret,支持免密碼sudo,cloud-init的datasources為ConfigDriver和OpenStack。
通過DIB製作鏡像能夠更方便地管理和維護,實現自動化構建鏡像,建議OpenStack鏡像都直接使用DIB構建。
4.功能驗證
4.1 注入密碼和密鑰
使用剛剛創建的鏡像啟動一台雲主機,如果使用nova CLI工具,需要傳--admin-pass參數指定root密碼,並指定disk大小為20G的flavor。如果使用OpenStack Dashborad創建,需要簡單配置下dashborad使其支持配置雲主機密碼,如圖:
創建成功後進入vnc界面,使用root賬號以及設置的新密碼,如果登錄成功,說明注入密碼成功。
在創建一個同樣配額的虛擬機,指定keypair,創建完後,使用密鑰登錄,如果能夠登錄,說明密鑰注入成功。
4.2 動態調整根磁碟分區大小
運行以下命令檢查根磁碟是否自動調整分區和文件系統大小:
lsblkdf -h
如圖:
鏡像原始根分區大小為10GB,如果lsblk顯示vda大小為20GB,說明操作系統識別出根磁碟大小。如果df顯示/dev/sda1size為20GB,說明根磁碟的分區和文件系統均自動完成了擴容操作,growpart運行正常。
7.4 動態修改密碼
nova通過set-password子命令修改虛擬機管理員密碼:
nova set-password ${server_uuid}
重複輸入兩次密碼,如果執行成功,不會有任何輸出。
回到終端,退出之前的登錄,然後使用新的密碼重新登錄,如果登錄成功,則說明動態修改密碼成功!
5 總結
本文首先介紹了手動製作的OpenStack的鏡像步驟,然後提出一種更快捷的鏡像上傳方法,該方法只能適用於Ceph後端,最後引入OpenStack鏡像製作項目DIB,介紹了DIB的優勢。
6 參考文獻
- OpenStack image guid.
- acpid.
- Zero-configuration networking.
- Qemu guest agent.
- Image building tools for OpenStack.
推薦閱讀: