nova虚拟机启动拉取image的过程

这里只关注Nova virt的spawn函数,glance、nova后端为ceph

nova/virt/libvirt/driver.py
   def spawn(self, context, instance, image_meta, injected_files,
              admin_password, network_info=None, block_device_info=None):
        image_meta = objects.ImageMeta.from_dict(image_meta)
        disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
                                            instance,
                                            image_meta,
                                            block_device_info)
        self._create_image(context, instance,                                # 虚拟机拉取glance image
                           disk_info[‘mapping‘],
                           network_info=network_info,
                           block_device_info=block_device_info,
                           files=injected_files,
                           admin_pass=admin_password)
        xml = self._get_guest_xml(context, instance, network_info,
                                  disk_info, image_meta,
                                  block_device_info=block_device_info,
                                  write_to_disk=True)
        self._create_domain_and_network(context, xml, instance, network_info,
                                        disk_info,
                                        block_device_info=block_device_info)
        LOG.debug("Instance is running", instance=instance)
        
        def _wait_for_boot():   
            """Called at an interval until the VM is running."""
            state = self.get_info(instance).state
            if state == power_state.RUNNING:
                LOG.info(_LI("Instance spawned successfully."),
                         instance=instance)
                raise loopingcall.LoopingCallDone()
        timer = loopingcall.FixedIntervalLoopingCall(_wait_for_boot)    # loopingcall等待虚拟机running的状态
        timer.start(interval=0.5).wait()

nova/virt/libvirt/driver.py            
    def _create_image(self, context, instance,
                      disk_mapping, suffix=‘‘,
                      disk_images=None, network_info=None,
                      block_device_info=None, files=None,
                      admin_pass=None, inject_files=True,
                      fallback_from_host=None):
        booted_from_volume = self._is_booted_from_volume(        # 判断是不是boot_from_volume,boot_from_volume没有base image
            instance)
            
        if not booted_from_volume:
            root_fname = imagecache.get_cache_fname(disk_images, ‘image_id‘)   
            size = instance.root_gb * units.Gi

            if size == 0 or suffix == ‘.rescue‘:
                size = None

            backend = image(‘disk‘)
            if backend.SUPPORTS_CLONE:            # 只有backend为rbd的才支持clone操作
                def clone_fallback_to_fetch(*args, **kwargs):
                    try:
                        backend.clone(context, disk_images[‘image_id‘])   # clone操作在nova/virt/libvirt/imagebackend.py中class Rbd下
                    except exception.ImageUnacceptable:               # 除image格式为raw和iso外的格式都抛异常
                        libvirt_utils.fetch_image(*args, **kwargs)
                fetch_func = clone_fallback_to_fetch
            else:
                fetch_func = libvirt_utils.fetch_image
            self._try_fetch_image_cache(backend, fetch_func, context,        # 进入_try_fetch_image_cache函数
                                        root_fname, disk_images[‘image_id‘],
                                        instance, size, fallback_from_host)

nova/virt/libvirt/imagebackend.py                                            
    def clone(self, context, image_id_or_uri):
        image_meta = IMAGE_API.get(context, image_id_or_uri,
                                   include_locations=True)
        locations = image_meta[‘locations‘]

        LOG.debug(‘Image locations are: %(locs)s‘ % {‘locs‘: locations})

        if image_meta.get(‘disk_format‘) not in [‘raw‘, ‘iso‘]:        # image格式判断, 所以ceph image格式最好是raw,这样走的ceph的clone
            reason = _(‘Image is not raw format‘)
            raise exception.ImageUnacceptable(image_id=image_id_or_uri,
                                              reason=reason)

        for location in locations:
            if self.driver.is_cloneable(location, image_meta):
                return self.driver.clone(location, self.rbd_name) # 调用nova/virt/libvirt/storage/rbd_utils.py

        reason = _(‘No image locations are accessible‘)
        raise exception.ImageUnacceptable(image_id=image_id_or_uri,
                                          reason=reason)   
                                        
                                        
nova/virt/libvirt/driver.py                                                                                
    def _try_fetch_image_cache(self, image, fetch_func, context, filename,
                               image_id, instance, size,
                               fallback_from_host=None):
        try:
            image.cache(fetch_func=fetch_func,            # 进入cache函数
                        context=context,
                        filename=filename,
                        image_id=image_id,
                        user_id=instance.user_id,
                        project_id=instance.project_id,
                        size=size)
        except exception.ImageNotFound:        
            if not fallback_from_host:
                raise
            LOG.debug("Image %(image_id)s doesn‘t exist anymore "
                      "on image service, attempting to copy "
                      "image from %(host)s",
                      {‘image_id‘: image_id, ‘host‘: fallback_from_host},
                      instance=instance)

            def copy_from_host(target, max_size):
                libvirt_utils.copy_image(src=target,
                                         dest=target,
                                         host=fallback_from_host,
                                         receive=True)
            image.cache(fetch_func=copy_from_host,
                        filename=filename)

nova/virt/libvirt/imagebackend.py                                                
    def cache(self, fetch_func, filename, size=None, *args, **kwargs):
        """Creates image from template.

        Ensures that template and image not already exists.
        Ensures that base directory exists.
        Synchronizes on template fetching.

        :fetch_func: Function that creates the base image
                     Should accept `target` argument.
        :filename: Name of the file in the image directory
        :size: Size of created image in bytes (optional)
        """
        @utils.synchronized(filename, external=True, lock_path=self.lock_path)
        def fetch_func_sync(target, *args, **kwargs):
            # The image may have been fetched while a subsequent
            # call was waiting to obtain the lock.
            if not os.path.exists(target):         # 如果不存在base image的话
                fetch_func(target=target, *args, **kwargs)  # fetch_func是clone_fallback_to_fetch

        base_dir = os.path.join(CONF.instances_path,
                                CONF.image_cache_subdirectory_name)
        if not os.path.exists(base_dir):
            fileutils.ensure_tree(base_dir)
        base = os.path.join(base_dir, filename)

        if not self.check_image_exists() or not os.path.exists(base):
            self.create_image(fetch_func_sync, base, size,    base image如果不存在的话,进入create_image
                              *args, **kwargs)  

        if (size and self.preallocate and self._can_fallocate() and
                os.access(self.path, os.W_OK)):
            utils.execute(‘fallocate‘, ‘-n‘, ‘-l‘, size, self.path)  
            
nova/virt/libvirt/imagebackend.py    
    def create_image(self, prepare_template, base, size, *args, **kwargs):

        if not self.check_image_exists():
            prepare_template(target=base, max_size=size, *args, **kwargs)  # prepare_template这里是fetch_func_sync

        # prepare_template() may have cloned the image into a new rbd
        # image already instead of downloading it locally
        if not self.check_image_exists():                    # 如果走的是rbd clone操作,这里就不会用rbd import了
            self.driver.import_image(base, self.rbd_name)
        self.verify_base_size(base, size)

        if size and size > self.get_disk_size(self.rbd_name):
            self.driver.resize(self.rbd_name, size)

总结: nova、glance后端为ceph,raw格式的image没有base image, qcow2格式还是有base image的。

时间: 2024-10-25 06:08:56

nova虚拟机启动拉取image的过程的相关文章

openstack学习笔记一 虚拟机启动过程代码跟踪

本文主要通过对虚拟机创建过程的代码跟踪.观察虚拟机启动任务状态的变化,来透彻理解openstack各组件之间的作用过程. 当从horizon界面发送一个创建虚拟机请求,horizon api 将会依据前端给定的数据信息.调用novaclient 生成一个创建虚拟机的http post 请求来创建vm服务. >/usr/lib/python2.6/site-packages/horizon/api/nova.py(334)server_create() > /usr/lib/python2.6/

【分析】dalvik虚拟机启动过程(二)

源码版本:Android-4.4.4_r2 提示:大部分分析直接注释在代码内. 接着上一篇[分析]dalvik虚拟机启动过程(一) JNI_CreateJavaVM函数调用dvmCreateJNIEnv创建JNIEnv后,接着又调用了dvmStartup函数初始化VM: /* * VM 初始化. * VM initialization. Pass in any options provided on the command line. * Do not pass in the class nam

【分析】dalvik虚拟机启动过程(三)

源码版本:Android-4.4.4_r2 提示:大部分分析直接注释在代码内. 相关文章: [分析]dalvik虚拟机启动过程(一) [分析]dalvik虚拟机启动过程(二) 在AndroidRuntime::start中调用AndroidRuntime::startVm函数启动了虚拟机,然后又调用了AndroidRuntime::startReg函数注册Android函数: /* * 向 VM 注册Android本地函数. * Register android native functions

【Docker学习之三】Docker查找拉取镜像、启动容器、容器使用

环境 docker-ce-19.03.1-3.el7.x86_64 CentOS 7 一.查找.拉取镜像.启动容器1.查找镜像-docker search默认查找Docker Hub上的镜像,举例:Docker安装nginx [[email protected] ~]# docker search nginx NAME DESCRIPTION STARS OFFICIAL AUTOMATED nginx Official build of Nginx. 11866 [OK] jwilder/ng

k8s从Harbor拉取启动镜像测试

登陆harbor [[email protected] ~]# docker login 192.168.180.105:1180 Username: admin Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.

在idea中编写自动拉取、编译、启动springboot项目的shell脚本

idea 开发环境搭建 idea中安装shell开发插件 服务器具备的条件 已经安装 lsof(用于检查端口占用) 已安装 git 安装 maven 有 java 环境 背景 代码提交到仓库后,需要在服务器上重新部署 springboot 的代码,每次自己打jar包上传到服务器步骤太繁琐,考虑把要使用的命令放在脚本中 初始化拉取指定分支的代码 blog_int.sh #!/usr/bin/env bash cd /data/code/ git clone -b V3.0.0 [email pro

K8s之Pod资源管理及创建Harbor私有镜像仓库(含镜像拉取操作,中途含排错)

pod是k8s管理的最小单元 pod中有多个容器,现实生产环境中只有一个容器 特点: 1.最小部署单元2.一组容器的集合3.一个Pod中的容器共享网络命令空间4.Pod是短暂的 Pod容器分类: 1:infrastructure container 基础容器(透明的过程,用户无感知) 维护整个Pod网络空间 node节点操作 `查看容器的网络` [[email protected] ~]# cat /opt/kubernetes/cfg/kubelet KUBELET_OPTS="--logto

rsync推送和拉取

rsync格式: # 拷贝本地文件.当SRC和DES路径信息都不包含有单个冒号":"分隔符时就启动这种工作模式.如:rsync -a /data /backup rsync [OPTION]... SRC DEST # 使用一个远程shell程序(如rsh.ssh)来实现将本地机器的内容拷贝到远程机器.当DST路径地址包含单个冒号":"分隔符时启动该模式.如:rsync -avz *.c foo:src rsync [OPTION]... SRC [US[email

Kafka consumer消息的拉取及偏移的管理

消费者拉取消息并处理主要有4个步骤: 获取消费者所拉取分区的偏移位置OffsetFetchRequest(新的消息是从偏移位置开始的) 创建FetchReqeust,生成Map<Node, FetchRequest>,以消费者所拉取消息的节点为key来分组,所消费的TopicPartition的数据为value,并放入到unsent队列 调用poll方法实际发送请求给相应的node,如果返回成功,在onSecuss方法中,消息被保存在completedFetches中 从completedFe