在線升級glance鏡像技巧
0.背景
我們經常需要更新glance鏡像,比如上傳的鏡像可能有配置問題,或者我們需要對已有的鏡像進行軟件包升級或者預裝一些新的軟件包等。當時著手這件事是由于我們對cloud-init進行了大量的patch,需要同步到glance鏡像中,如果重新制作鏡像然后傳輸到生產環境再上傳,不僅工作非常繁瑣,還非常消耗時間,我們希望能夠在原來的鏡像基礎之上直接升級cloud-init。
1.通過快照方式更新鏡像
最簡單的方式是通過創建一個云主機,然后更新cloud-init后創建快照形成新的鏡像(注意刪除/var/lib/cloud下的文件,否則cloud-init下次啟動時不會重新拉取metadata)。可是我們遇到的問題是,老版本的cloud-init在L版中注入密碼和密鑰都失敗,并且安裝的qemu-guest-agent不支持修改密碼,因此完全沒有辦法登錄云主機。因此必須另辟蹊徑。
2.glance存儲后端使用本地文件系統
于是我們想到把鏡像掛載到本地文件系統中,然后chroot到鏡像文件系統環境中進行升級配置。如果glance鏡像使用本地文件系統作為存儲后端,鏡像格式為raw,掛載鏡像就非常簡單了:
- losetup /dev/loop0 image.img
- kpartx -a /dev/loop0
- mount /dev/mapper/loop0p1 /mnt/image
如果是qcow2格式,需要安裝qemu-nbd工具包,并且加載nbd內核模塊:
- modprobe nbd max_part=63
- qemu-nbd -c /dev/nbd0 image.img
- mount /dev/nbd0p1 /mnt/image
如果鏡像文件系統中使用LVM,可以使用以下方法初始化:
- vgscan
- vgchange -ay
- mount /dev/VolGroupName/LogVolName /mnt/image
chroot進行后執行相關操作后,卸載鏡像文件系統:
- umount /mnt/image
- vgchange -an VolGroupName
- killall qemu-nbd
- kpartx -d /dev/loop0
- losetup -d /dev/loop0
以上方法參考Mounting-raw-and-qcow2-vm-disk-images。
本文重點不在于基于本地文件系統作為存儲后端的情況,重點介紹基于Ceph存儲后端的操作方法,下文將詳細介紹過程。
3.基于Ceph存儲后端的更新方法
我們知道使用ceph作為存儲后端時,鏡像首先會生成一個以snap命名的快照,比如glance有一個鏡像id為35fcb79c-43a1-4b59-83d7-f4e46a524419,則在rbd中有對應的image,命名與glance鏡像id一致,我們查看其快照:
- rbd snap ls --image openstack-images/35fcb79c-43a1-4b59-83d7-f4e46a524419 2>/dev/null
輸出:
- SNAPID NAME SIZE
- 94604 snap 20480 MB
我們不能直接修改快照snap,因為它是protect的,只能讀不能寫。直接修改鏡像的話不能同步到快照中,并且出錯也不好回滾。
因此我們的做法是先復制一個rbd image副本.
首先使用glance命令行工具獲取需要更新的鏡像的id:
- IMAGE_ID=$(glance image-list --name "CentOS 7.1 64bit 2>/dev/null | awk --re-interval '/\w{8}-.*/{print $2}')
使用rbd命令拷貝一份鏡像副本,假設POOL變量為glance使用的ceph池:
- rbd cp $POOL/${IMAGE_ID} $POOL/${IMAGE_ID}_copy
掛載鏡像到本地文件系統中:
- rbd map $POOL/${IMAGE_ID}_copy
- # /dev/rbd0
- mount /dev/rbd0p1 /mnt
注意由于鏡像是Linux文件系統,因此通常只有一個根分區,如果是windows鏡像,***個分區通常是隱藏分區,C盤是第二個分區,因此掛載時注意選擇rbd0p2,其中p表示partition。
掛載到本地后,可以拷貝軟件包、配置模板等到鏡像文件系統中,比如/mnt/root/,然后chroot到鏡像文件系統中:
- cd /mnt # /mnt是我們需要chroot的根目錄
- # mount -t proc proc proc/ # 掛載proc
- # To use an internet connection in the chroot environment copy over the DNS details:
- cp /etc/resolv.conf etc/resolv.conf # 覆蓋即可,生成云主機會自動覆蓋
- # To change root into a bash shell:
- chroot /mnt bash # chroot 到/mnt中,如果提示bash命令找不到,使用絕對路徑試試 chroot /mnt /bin/bash
- # 初始化環境變量
- source /etc/profile
- source ~/.bashrc
- # 如果提示找不到ls等命令,需要手動設置PATH變量: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/bin
- # Tip: Optionally, create a unique prompt to be able to differentiate your chroot environment:
- export PS1="(chroot) $PS1"
接下來就可以執行命令對鏡像進行更新了,比如更新cloud-init:
- yum remove cloud-init # Remove the old version package
- rpm -i cloud-init-0.7.6-bzr1.el7.centos.noarch.rpm # Install the pacakge
升級qemu-guest-agent:
- yum install -y qemu-guest-agent
- rpm -aq | grep qemu-guest-agent
- # qemu-guest-agent-2.3.0-4.el7.x86_64
執行完所有的更新操作后,完成以下清理工作:
- yum clean all
- rm -rf /root/* # 危險?。。h除根目錄下拷貝的臨時文件,執行前確認無有用文件!
- exit # 退出chroot環境
- cd # 切換到家目錄,工作目錄不能位于/mnt,否則卸載不了
- umount --recursive /mnt/ # 如果busy怎么辦?lsof查看哪個進程占用,如果還是不行試試使用 --lazy 參數
- rbd unmap /dev/rbd0 # 從rbd中卸載
***需要更新glance,我們的方法是先創建一個glance空鏡像實例,不需要指定鏡像文件,只是占個坑,拿到新鏡像id:
- NEW_IMAGE_ID=`glance image-create | grep id | awk '{print $4}'` || { echo 'Error: glance image-create failed !' ; exit 1; }
接下來更新我們的rbd image,命名為新創建鏡像實例id并設置快照:
- rbd mv $POOL/${IMAGE_ID}_copy $POOL/${NEW_IMAGE_ID}
- rbd --pool=$POOL --image=${NEW_IMAGE_ID} --snap=snap snap create
- rbd --pool=$POOL --image=${NEW_IMAGE_ID} --snap=snap snap protect
***更新glance鏡像元數據:
- glance image-update --name="$DISPLAY_NAME" --disk-format=raw --container-format=bare --is-public=True ${NEW_IMAGE_ID}
- glance image-update --property image_meta="$image_meta" ${NEW_IMAGE_ID}
- glance image-update --property hw_qemu_guest_agent=yes $IMAGE_ID
- # ...
- # update image location
- FSID=`ceph -s | grep cluster | awk '{print $2}'`
- glance image-update --location rbd://$FSID/$POOL/$IMAGE_ID/snap ${NEW_IMAGE_ID}
- if [[ $IMAGE_LABEL == "Windows" || $IMAGE_LABEL == "windows" ]]; then
- glance image-update --property hw_video_model=qxl --property hw_video_ram=64 --property os_admin_user=Administrator $IMAGE_ID
- fi
***對新鏡像進行功能驗證,如果沒有問題,就可以安全的刪除老的鏡像了。
【本文是51CTO專欄作者“付廣平”的原創文章,如需轉載請通過51CTO獲得聯系】