I was trying to understand what kind of image nova image-create creates. It’s not entirely obvious from its help output, which says — Creates a new image by taking a snapshot of a running server. But what kind of snapshot? let’s figure.

nova image-create operations

The command is invoked as below

 $  nova image-create fed18 "snap1-of-fed18" --poll  

Drilling into nova’s source code — nova/virt/libvirt/driver.py — this is what image-create does:

  1. If the guest — based on which snapshot is to be taken — is running, nova calls libvirt’s virsh managedsave, which saves and stops a running guest, to be restarted later from the saved state.

  2. Next, it creates a qcow2 internal disk snapshot of the guest (now offline).
  3. Then, extracts the internal named snapshot from the qcow2 file & exports it to a RAW format and temporarily places in $instances_path/snapshots.
  4. Deletes the internal named snapshot from the qcow2 file.
  5. Finally, uploads that image into OpenStack glance service — which can be confirmed by running glance image-list.

Update: Steps 2 and 4 above are now effectively removed with this upstream change.

Remove unnecessary steps for cold snapshots
Up until now when we created cold snapshots we were stopping the
instance, create an internal snapshot, extract the snapshot to a file
and then delete the internal snapshot before bringing up the instance.If the instance is shut down, there's no concurrent writer, so the image
can be directly extracted without taking an internal snapshot first,
because the snapshot and the current state are the same.In this patch the creation and deletion of the internal snapshot are
removed to eliminate the extra steps and optimize the creation of
snapshots a bit.

A simple test
To get a bit more clarity, let’s try nova’s actions on a single qocw2 disk — with a running Fedora 18 OS — using libvirt’s shell virsh and QEMU’s qemu-img:

# Save the state and stop a running guest
$ virsh managedsave fed18 # Create a qemu internal snapshot
$ qemu-img snapshot -c snap1 fed18.qcow2 # Get information about the disk
$ qemu-img info fed18.qcow2 # Extract the internal snapshot,
# convert it to raw and export it a file
$ qemu-img convert -f qcow2 -O raw -s \     snap1 fed18.qcow2 snap1-fed18.img # Get information about the new image
# extracted from the snapshot
$ qemu-img info snap1-fed18.img # List out file sizes of the original
# and the snapshot
$ ls -lash fed18.qcow2 snap1-fed18.qcow2 # Delete the internal snapshot
# from the original disk
$ qemu-img snapshot -d snap1 fed18.qcow2 # Again, get information of the original disk
$ qemu-img info fed18.qcow2 # Start the guest again
$ virsh start fed18

Thanks to Nikola Dipanov for helping me on where to look.

Update: A few things I missed to mention (thanks again for comments from Nikola) — I was using libvirt, kvm as underlying hypervisor technologies, with OpenStack Folsom release.

http://blog.csdn.net/epugv/article/details/9832535

def snapshot(self, context, instance, image_href, update_task_state):
        """Create snapshot from a running VM instance.

This command only works with qemu 0.14+
        """
        try:
            virt_dom = self._lookup_by_name(instance['name'])#获取域
        except exception.InstanceNotFound:
            raise exception.InstanceNotRunning(instance_id=instance['uuid'])

(image_service, image_id) = glance.get_remote_image_service(
            context, instance['image_ref'])
        try:
            base = image_service.show(context, image_id)#获取实例镜像的base
        except exception.ImageNotFound:
            base = {}

#image_href是一个url,包括网页上输入的信息
        _image_service = glance.get_remote_image_service(context, image_href)

#create一个image_service这个类对象,并从image_href中解析出一个image id
        snapshot_image_service, snapshot_image_id = _image_service
        snapshot = snapshot_image_service.show(context, snapshot_image_id)

metadata = {'is_public': False,
                    'status': 'active',
                    'name': snapshot['name'],
                    'properties': {
                                   'kernel_id': instance['kernel_id'],
                                   'image_location': 'snapshot',
                                   'image_state': 'available',
                                   'owner_id': instance['project_id'],
                                   'ramdisk_id': instance['ramdisk_id'],
                                   }
                    }
        if 'architecture' in base.get('properties', {}):
            arch = base['properties']['architecture']
            metadata['properties']['architecture'] = arch

disk_path = libvirt_utils.find_disk(virt_dom)#磁盘路径
        source_format = libvirt_utils.get_disk_type(disk_path)#快照源的格式

image_format = CONF.snapshot_image_format or source_format

# NOTE(bfilippov): save lvm as raw
        if image_format == 'lvm':
            image_format = 'raw'

# NOTE(vish): glance forces ami disk format to be ami
        if base.get('disk_format') == 'ami':
            metadata['disk_format'] = 'ami'
        else:
            metadata['disk_format'] = image_format

metadata['container_format'] = base.get('container_format', 'bare')

snapshot_name = uuid.uuid4().hex

(state, _max_mem, _mem, _cpus, _t) = virt_dom.info()
        state = LIBVIRT_POWER_STATE[state]

# NOTE(rmk): Live snapshots require QEMU 1.3 and Libvirt 1.0.0.
        #            These restrictions can be relaxed as other configurations
        #            can be validated.
        if self.has_min_version(MIN_LIBVIRT_LIVESNAPSHOT_VERSION,
                                MIN_QEMU_LIVESNAPSHOT_VERSION,
                                REQ_HYPERVISOR_LIVESNAPSHOT) \
                and not source_format == "lvm":
            live_snapshot = True##判断版本信息和源格式,由此决定是live还是cold
        else:
            live_snapshot = False

# NOTE(rmk): We cannot perform live snapshots when a managedSave
        #            file is present, so we will use the cold/legacy method
        #            for instances which are shutdown.
        if state == power_state.SHUTDOWN:##实例SHUTDOWN状态的用cold
            live_snapshot = False

# NOTE(dkang): managedSave does not work for LXC
        if CONF.libvirt_type != 'lxc' and not live_snapshot:
            if state == power_state.RUNNING or state == power_state.PAUSED:
                virt_dom.managedSave(0)#This method will suspend a domain and save its memory contents to a file on disk

snapshot_backend = self.image_backend.snapshot(disk_path,
                snapshot_name,
                image_type=source_format)# Returns snapshot for given image,并带上后端格式

if live_snapshot:
            LOG.info(_("Beginning live snapshot process"),
                     instance=instance)
        else:
            LOG.info(_("Beginning cold snapshot process"),
                     instance=instance)
            snapshot_backend.snapshot_create()#调用snapshot_backend中带的格式类的#snapshot_create()
                                           # Create a snapshot in a disk image
                                           #这里是qcow2用的是qemu-img snapshot –c…

update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD)
        snapshot_directory = CONF.libvirt_snapshots_directory
        fileutils.ensure_tree(snapshot_directory)
        with utils.tempdir(dir=snapshot_directory) as tmpdir:#
            try:
                out_path = os.path.join(tmpdir, snapshot_name)
                if live_snapshot:
                    # NOTE (rmk): libvirt needs to be able to write to the
                    #             temp directory, which is owned nova.
                    utils.execute('chmod', '777', tmpdir, run_as_root=True)
                    self._live_snapshot(virt_dom, disk_path, out_path,
                                        image_format)
                else:
                    snapshot_backend.snapshot_extract(out_path, image_format)#转换镜像格式,并output到out_path下
            finally:
                if not live_snapshot:
                    snapshot_backend.snapshot_delete()
                # NOTE(dkang): because previous managedSave is not called
                #              for LXC, _create_domain must not be called.
                if CONF.libvirt_type != 'lxc' and not live_snapshot:
                    if state == power_state.RUNNING:
                        self._create_domain(domain=virt_dom)
                    elif state == power_state.PAUSED:
                        self._create_domain(domain=virt_dom,
                                launch_flags=libvirt.VIR_DOMAIN_START_PAUSED)
                LOG.info(_("Snapshot extracted, beginning image upload"),
                         instance=instance)

# Upload that image to the image service

update_task_state(task_state=task_states.IMAGE_UPLOADING,
                     expected_state=task_states.IMAGE_PENDING_UPLOAD)
            with libvirt_utils.file_open(out_path) as image_file:
                image_service.update(context,
                                     image_href,
                                     metadata,
                                     image_file)
                LOG.info(_("Snapshot image upload complete"),
                         instance=instance)

def _live_snapshot(self, domain, disk_path, out_path, image_format):
        """Snapshot an instance without downtime."""
        xml = domain.XMLDesc(0) # Save a copy of the domain's running XML file

# Abort is an idempotent operation, so make sure any block
        # jobs which may have failed are ended.
        try:
            domain.blockJobAbort(disk_path, 0)#Cancel the active block job on the given disk.
        except Exception:
            pass

def _wait_for_block_job(domain, disk_path):
            status = domain.blockJobInfo(disk_path, 0)#进度
            try:
                cur = status.get('cur', 0)
                end = status.get('end', 0)
            except Exception:
                return False

if cur == end and cur != 0 and end != 0:
                return False
            else:
                return True

# NOTE (rmk): We are using shallow rebases as a workaround to a bug
        #             in QEMU 1.3. In order to do this, we need to create
        #             a destination image with the original backing file
        #             and matching size of the instance root disk.
        src_disk_size = libvirt_utils.get_disk_size(disk_path)
        src_back_path = libvirt_utils.get_disk_backing_file(disk_path,
                                                            basename=False)
        disk_delta = out_path + '.delta'
# Creates a COW image with the given backing file
        libvirt_utils.create_cow_image(src_back_path, disk_delta,
                                       src_disk_size)#由此命令完成'qemu-img', 'create', '-f', 'qcow2'……

try:
            # NOTE (rmk): blockRebase cannot be executed on persistent
            #             domains, so we need to temporarily undefine it.
            #             If any part of this block fails, the domain is
            #             re-defined regardless.
            if domain.isPersistent():
                domain.undefine()

# NOTE (rmk): Establish a temporary mirror of our root disk and
            #             issue an abort once we have a complete copy.
            domain.blockRebase(disk_path, disk_delta, 0,
                               libvirt.VIR_DOMAIN_BLOCK_REBASE_COPY |
                               libvirt.VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT |
                               libvirt.VIR_DOMAIN_BLOCK_REBASE_SHALLOW)#实现live快照的地方,参考图1、2,http://www.libvirt.org/html/libvirt-libvirt.html#VIR_DOMAIN_BLOCK_REBASE_COPY

while _wait_for_block_job(domain, disk_path):
                time.sleep(0.5)

domain.blockJobAbort(disk_path, 0)
            libvirt_utils.chown(disk_delta, os.getuid())
        finally:
            self._conn.defineXML(xml)

# Convert the delta (CoW) image with a backing file to a flat
        # image with no backing file.
        libvirt_utils.extract_snapshot(disk_delta, 'qcow2', None,
                                       out_path, image_format)

[转] OpenStack — nova image-create, under the hood的更多相关文章

  1. Openstack Nova 源码分析 — Create instances (nova-conductor阶段)

    目录 目录 前言 Instance Flavor Instance Status Virt Driver Resource Tracker nova-conductor Create Instance ...

  2. OpenStack Nova 制作 Windows 镜像

    OpenStack Nova 制作 Windows 镜像   windows虚拟机ubuntuimage防火墙云计算 本贴转自http://www.vpsee.com 上次 VPSee 给 OpenS ...

  3. OpenStack Nova 高性能虚拟机之 NUMA 架构亲和

    目录 文章目录 目录 写在前面 计算平台体系结构 SMP 对称多处理结构 NUMA 非统一内存访问结构 MPP 大规模并行处理结构 Linux 上的 NUMA 基本对象概念 NUMA 调度策略 获取宿 ...

  4. Openstack Nova 源码分析 — 使用 VCDriver 创建 VMware Instance

    目录 目录 前言 流程图 nova-compute vCenter 前言 在上一篇Openstack Nova 源码分析 - Create instances (nova-conductor阶段)中, ...

  5. OpenStack Nova启动实例流程

    1.概述 启动一个新的实例,会涉及到OpenStack Nova中的多个组件: API服务器,接收用户端的请求,并且将其传递给云控制器. 云控制器,处理计算节点.网络控制器.API服务器和调度器之前的 ...

  6. Openstack Nova 控制服务 和 计算服务 (六)

    Openstack Nova 控制服务 和 计算服务 (六) 引用: https://docs.openstack.org/ocata/zh_CN/install-guide-rdo/nova.htm ...

  7. OpenStack nova VM migration (live and cold) call flow

    OpenStack nova compute supports two flavors of Virtual Machine (VM) migration: Cold migration -- mig ...

  8. 如何删除 OpenStack Nova 僵尸实例

    转自:http://www.vpsee.com/2011/11/how-to-delete-a-openstack-nova-zombie-instance/ 前天强制重启一台 OpenStack N ...

  9. 深挖Openstack Nova - Scheduler调度策略

    深挖Openstack Nova - Scheduler调度策略   一.  Scheduler的作用就是在创建实例(instance)时,为实例选择出合适的主机(host).这个过程分两步:过滤(F ...

  10. OpenStack Nova

    OpenStack Nova 简介 OpenStack 中的 Nova 负责维护和管理云环境的计算资源 Nova 在现有 Linux 服务器上作为一组守护线程来提供服务 Nova 由多个服务器进程组成 ...

随机推荐

  1. centos7 安装部署zabbix

    由于zabbix提供集中的web监控管理界面,因此服务在web界面的呈现需要LAMP架构支持. php 连接mysql服务,因为7版本mysql要收费,所以我们安装mariadb, 一.安装LAMP环 ...

  2. ubuntu18.04微信小程序学习笔记

    安装微信小程序开发工具 安装 https://github.com/cytle/wechat_web_devtools 创建快捷方式 sudo nautilus //在/usr/share/appli ...

  3. Django之ORM操作

    Django之ORM操作 前言 Django框架功能齐全自带数据库操作功能,本文主要介绍Django的ORM框架 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计 ...

  4. postman笔记1--postman的安装教程

    一.postman插件的安装 第一步:首先在网上下载postman插件的安装包,下载到自己的本地进行解压(如果懒得去下载的同学,可以根据网盘分享的安装包去下载:链接:https://pan.baidu ...

  5. 解决删除镜像时image is referenced in multiple repositories

    1.查看镜像 docker images rt@:~# docker images REPOSITORY TAG IMAGE ID CREATED SIZE hours ago MB f8ab12e0 ...

  6. T-SQL流程控制语句

    文章目录 if else语句 简单case语句 搜索式case语句 while语句 if else语句 格式: IF 布尔表达式 BEGIN END ELSE BEGIN END 示例: DECLAR ...

  7. sha1withRSA算法

    RAS_USE_PRIVATE_ENCRYPT(3021300906052b0e03021a05000414 + SHA1(DATA))

  8. Unity Button事件的简洁处理

    看到很多人依然还是通过最原始的方法给button绑定事件并处理,这种通过Find往子集一个个的查找,获取到后再绑定事件这种操作很费事,有些人则是对查找对象写了个方法自动往子集遍历更方便获取对象,但还是 ...

  9. 使用PYTHON完成排序(堆排序)

    class HeapStructure: def __init__(self, ls): self.ls = ls def shift_up(self, index): # 上移使符合堆要求 if i ...

  10. Python爬虫学习--用Python结合Selenium实现 明日之子节目直播时为自己喜欢的选手自动点赞拉票!!!

    声明:本脚本纯属娱乐,请勿用来非法点赞拉票,任何使用不当造成的后果自行承担. 闲话: 明日之子第二季开始好久了,作者一直再追,特别喜欢里面那个酷酷的小哥-蔡泽明.前两天晋选9大厂牌,采取的是直播的形式 ...