• VMware vSphere 是 VMware 的虚拟化平台,可将数据中心转换为包括 CPU、存储和网络资源的聚合计算基础架构。
  • VMware vSphere 文档中心

vSphere 的两个核心组件是 ESXi和vCenter Server。

  • ESXi是用于创建并运行虚拟机和虚拟设备的虚拟化平台。
  • vCenter Server是一项服务,用于管理网络中连接的多个主机,并将主机资源池化。

管理虚拟机

Linux自定义规范

vSphere虚拟化实现从模板克隆虚拟机,通过自定义规范管理器实现对虚拟机的主机名、IP地址、网关、dns等的定制。

  public static void createLinuxCustomizationSpec(String specName, String domain, String hostname) {
        String hostName = "***";
        String username = "***";
        String password = "***";
        
        ServiceInstance instance = null;
        try {
            instance = Session.getInstance(hostName, username, password);
            // InventoryNavigator inventoryNavigator = new InventoryNavigator(rootFolder);
            CustomizationSpecManager csm = instance.getCustomizationSpecManager();

            if (csm.doesCustomizationSpecExist(specName) == false) {
                csm.createCustomizationSpec(createCustomizations(specName, domain, hostname));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

配置虚拟机硬件

虚拟磁盘的磁盘格式
选项操作
与源格式相同使用与源虚拟机相同的格式。
厚置备延迟置零以默认的厚格式创建虚拟磁盘。创建过程中为虚拟磁盘分配所需空间。创建时不会擦除物理设备上保留的任何数据,但是以后从虚拟机首次执行写操作时会按需要将其置零。
厚置备置零创建支持群集功能(如 Fault Tolerance)的厚磁盘。在创建时为虚拟磁盘分配所 需的空间。与厚置备延迟置零格式相反,在创建过程中会将物理设备上保留的数据置零。创建这种格式的磁盘所需的时间可能会比创建其他类型的磁盘所用时间长。
精简置备使用精简置备格式。最初,精简置备的磁盘只使用该磁盘初所需要的数据存储空间。如果以后精简磁盘需要更多空间,则它可以增长到为其分配的大容量。精简置备是创建虚拟磁盘的快方法。当使用精简置备时,要监控实际存储使用情况,避免在用尽物理存储空间时出现各种状况。
扩充虚拟磁盘

扩展虚拟硬盘的大小会导致虚拟机关闭时间延长。如果虚拟磁盘的类型属于厚置备快速置零,则关闭时间会延长。

如果创建的是精简置备格式的虚拟磁盘,则可以将该磁盘转换为厚置备格式的磁盘。
精简置备的磁盘开始时很小,并且其初所占用的存储空间刚好可以执行初始操作。转换之后,磁盘将扩充到全部容量,占用磁盘创建时为其置备的整个数据存储空间。
在这里插入图片描述

代码

连接VCent服务器(URL、用户名和密码)
ServiceInstance si = new ServiceInstance(vCenterURL, username, password, true);
查询接口
private static ManagedEntity getObjectByTypeAndName(InventoryNavigator inventoryNavigator, String type, String name) throws RemoteException {
        return inventoryNavigator.searchManagedEntity(type, name);
}

示例:

// Datastore
Datastore datastore = (Datastore) inventoryNavigator.searchManagedEntity("Datastore", dataStoreName);
// VirtualMachine
VirtualMachine virtualMachine = (VirtualMachine) inventoryNavigator.searchManagedEntity("VirtualMachine", virtualMachineName);
//ClusterComputeResource
ClusterComputeResource clusterComputeResource = (ClusterComputeResource) inventoryNavigator.searchManagedEntity("ClusterComputeResource", clusterName);
// Folder
Folder folder = (Folder) inventoryNavigator.searchManagedEntity("Folder", folderName);
// ResourcePool
ResourcePool pool = (ResourcePool) inventoryNavigator.searchManagedEntity("ResourcePool", poolName);
获取CPU、内存、datastore容量信息
    /**
     * @Descriotion 获取CPU、内存、datastore容量信息
     */
    public static Map<String, Map<String, Object>> getDatastoreInfo(ServiceInstance serviceInstance) {

        Map<String, Map<String, Object>> datastoreInfo = new HashMap<>();

        try {
            Folder rootFolder = serviceInstance.getRootFolder();
            ManagedEntity[] mes = new InventoryNavigator(rootFolder).searchManagedEntities("HostSystem");

            //逻辑判断
            if (mes == null || mes.length == 0) {
                serviceInstance.getServerConnection().logout();
            } else {
                for (int i = 0; i < mes.length; i++) {
                    Map<String, Object> temp = new HashMap<>();
                    HostSystem hostSystem = (HostSystem) mes[i];
                    HostListSummary summary = hostSystem.getSummary();

                    double sumMem = (double) hostSystem.getHardware().memorySize / 1024 / 1024; //内存总容量(MB)
                    Integer curMem = summary.quickStats.overallMemoryUsage; //内存使用容量(MB)

                    Integer sumCpu = summary.getHardware().getNumCpuCores() * summary.getHardware().cpuMhz; //CPU总容量(MHz)
                    Integer curCpu = summary.quickStats.overallCpuUsage; //CPU使用容量(MHz)

                    temp.put("curCpu", curCpu);
                    temp.put("sumCpu", sumCpu);
                    temp.put("sumMem", sumMem);
                    temp.put("curMem", curMem);

                    Datastore[] datastores = hostSystem.getDatastores();
                    for (Datastore ds : datastores) {
                        DatastoreSummary summary1 = ds.getSummary();
                        double freeSpace = (double) summary1.freeSpace / 1024.0 / 1024;
                        double sumDisk = (double) summary1.capacity / 1024.0 / 1024; //磁盘总容量(MB)
                        double curDisk = sumDisk - freeSpace; //磁盘使用容量(MB)
                        temp.put("sumDisk", sumDisk);
                        temp.put("curDisk", curDisk);
                    }

                    datastoreInfo.put(hostSystem.getName(), temp);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return datastoreInfo;
    }
从模板创建虚拟机
    /**
     * @Descriotion 从模板创建虚拟机
     */
    public static JSONObject createLinuxVMFromTemplate(VmArgs va, String hostName, String username, String password, String clusterName, String dnsArray[]) {

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", 500);

        String templateName = va.getTemplateName();
        String vmName = va.getVmName();
        String vmIp = va.getVmIp();
        int numCPUS = va.getNumCPUS();
        Long memMB = va.getMemMB();
        boolean powerOn = va.isPowerOn();
        boolean thinProvision = va.isThinProvision();
        boolean flag = false;

        ServiceInstance instance = null;
        String poolName = "";
        VirtualMachine templateVM = null;
        ResourcePool pool = null;
        ClusterComputeResource computerResource = null;
        InventoryNavigator inventoryNavigator = null;
        Task task = null;
        Folder rootFolder = null;

        try {
            instance = Session.getInstance(hostName, username, password);

            rootFolder = instance.getRootFolder();
            inventoryNavigator = new InventoryNavigator(rootFolder);

            // 判断是否存在名为"LINUX"的自定义规范,如不存在,则创建该规范
            CustomizationSpecManager csm = instance.getCustomizationSpecManager();
            if (csm.doesCustomizationSpecExist("LINUX") == false) {
                csm.createCustomizationSpec(createCustomizations("LINUX", "fltec.com", "orderer"));
            }
            // 获取自定义规范
            CustomizationSpec customizationSpec = getCustomizationSpecByName(instance, "LINUX");

            // 根据虚拟机名称查找虚拟机
            templateVM = getVirtualMachineTemplateByName(inventoryNavigator, templateName);
            if (templateVM == null) {
                System.out.println("Get template error.");
                log.error("Get template error.");
                instance.getServerConnection().logout();
                jsonObject.put("error", "Get template error.");
                log.error("Get template error.");
                return jsonObject;
            }

            // VirtualMachineRelocateSpec:移动或复制指定虚拟机,使用不同的DataStore或HostSystem。
            VirtualMachineRelocateSpec virtualMachineRelocateSpec = new VirtualMachineRelocateSpec();
            if (null != poolName && !"".equals(poolName)) {
                pool = (ResourcePool) inventoryNavigator.searchManagedEntity("ResourcePool", poolName);
                virtualMachineRelocateSpec.setPool(pool.getMOR());
            } else {
                computerResource = (ClusterComputeResource) inventoryNavigator.searchManagedEntity("ClusterComputeResource", clusterName);
                virtualMachineRelocateSpec.setPool(computerResource.getResourcePool().getMOR());

                HostSystem[] hosts = computerResource.getHosts();
                for (int j = 0; j < hosts.length; j++) {
                    HostListSummary summary = hosts[j].getSummary();
                    // CPU核数
                    if (summary.getHardware().getNumCpuCores() < numCPUS) {
                        log.error("error", "numCPUS arg error: " + numCPUS + ". max value is " + summary.getHardware().getNumCpuCores());
                        if (j == (hosts.length - 1)) {
                            jsonObject.put("error", "numaCPUS arg error: " + numCPUS + ". max value is " + summary.getHardware().getNumCpuCores());
                            return jsonObject;
                        }
                        continue;
                    }
                    // 内存
                    if (((summary.getHardware().memorySize / 1024 / 1024) - summary.getQuickStats().getOverallMemoryUsage()) < memMB) {
                        log.error("error", "memorySize arg error: " + memMB + "MB. max value is " + ((summary.getHardware().memorySize / 1024 / 1024) - summary.getQuickStats().getOverallMemoryUsage()) + "MB");
                        if (j == (hosts.length - 1)) {
                            jsonObject.put("error", "memorySize arg error: " + memMB + "MB. max value is " + ((summary.getHardware().memorySize / 1024 / 1024) - summary.getQuickStats().getOverallMemoryUsage()) + "MB");
                            return jsonObject;
                        }
                        continue;
                    }
                    // Datastore容量
                    Datastore[] datastoress = hosts[j].getDatastores();
                    for (Datastore ds : datastoress) {
                        DatastoreSummary summary1 = ds.getSummary();
                        /*
                          System.out.println((double) templateVM.getSummary().storage.committed / 1024 / 1024 / 1024);   // 模板已用容量(GB)
                        */
                        if ((summary1.getFreeSpace() / 1024 / 1024 / 1024) > (double) templateVM.getSummary().storage.committed / 1024 / 1024 / 1024 + 5.0) {
                            flag = true;
                            virtualMachineRelocateSpec.setDatastore(ds.getMOR());
                            ArrayList<Integer> diskKeys = getVirtualDiskKeys(templateVM);
                            VirtualMachineRelocateSpecDiskLocator[] diskLocator = new VirtualMachineRelocateSpecDiskLocator[diskKeys.size()];
                            for (int i = 0; i < diskKeys.size(); i++) {
                                diskLocator[i] = new VirtualMachineRelocateSpecDiskLocator();
                                diskLocator[i].datastore = ds.getMOR();
                                diskLocator[i].setDiskId(diskKeys.get(i));
                                diskLocator[i].setDiskMoveType(VirtualMachineRelocateDiskMoveOptions.moveAllDiskBackingsAndDisallowSharing.toString());
                                VirtualDiskFlatVer2BackingInfo backing = new VirtualDiskFlatVer2BackingInfo();
                                if (thinProvision)
                                    backing.setThinProvisioned(true);//the point
                                // setDiskMode and setFileName don't work, but vijava needs these.
                                backing.setDiskMode(VirtualDiskMode.persistent.name());
                                backing.setFileName("[" + ds.getName() + "] " + vmName + "/" + vmName + diskKeys.get(i).toString() + ".vmdk");
                                diskLocator[i].setDiskBackingInfo(backing);
                            }
                            virtualMachineRelocateSpec.setDisk(diskLocator);
                        } else {
                            log.error("error", "diskSize arg error: " + (double) templateVM.getSummary().storage.committed / 1024 / 1024 / 1024 + 5.0 +"G. max value is " + (summary1.getFreeSpace() / 1024 / 1024 / 1024) + "G");
                            if (j == (hosts.length - 1)) {
                                jsonObject.put("error", "diskSize arg error: " + (double) templateVM.getSummary().storage.committed / 1024 / 1024 / 1024 + 5.0 +"G. max value is " + (summary1.getFreeSpace() / 1024 / 1024 / 1024) + "G");
                                return jsonObject;
                            }
                        }
                    }
                    if (flag == true) {
                        break;
                    }
                }
            }

            // 设定创建虚拟机的属性信息
            VirtualMachineConfigSpec configSpec = new VirtualMachineConfigSpec();
            // 设置CPU核数
            configSpec.setNumCPUs(numCPUS);
            // 设置内存大小
            configSpec.setMemoryMB(memMB);

            ArrayList<VirtualDeviceConfigSpec> virtualDeviceConfigSpecs = new ArrayList<VirtualDeviceConfigSpec>();
            // 添加硬盘
            if (va.isAddDisk()) {
                String diskMode = VirtualDiskMode.persistent.name();
                String diskName = vmName + "-" + RandomStringUtils.randomAlphanumeric(12);
                VirtualDeviceConfigSpec vDiskSpec = null;
                vDiskSpec = createAddDiskConfigSpec(templateVM, va.getDiskSizeGB(), diskMode, diskName, thinProvision);
                virtualDeviceConfigSpecs.add(vDiskSpec);
            }
            // 添加网卡
            if (va.isAddAdapter()) {
                Network[] networks = computerResource.getNetworks();

                for (Network nw : networks) {
                    if (nw.getName().equals("VM Network")) {
                        virtualDeviceConfigSpecs.add(createAddAdapterSpec(nw));
                    }
                }
            }
            VirtualDeviceConfigSpec[] vDiskSpecArray = new VirtualDeviceConfigSpec[virtualDeviceConfigSpecs.size()];
            configSpec.setDeviceChange(virtualDeviceConfigSpecs.toArray(vDiskSpecArray));

            // 设置静态IP
            CustomizationAdapterMapping customizationAdapterMapping = createCustomizationAdapterMapping(vmIp);
            if (va.isAddAdapter()) {
                CustomizationAdapterMapping cam = createCustomizationAdapterMapping(va.getAdapterIp());
                customizationSpec.setNicSettingMap(new CustomizationAdapterMapping[]{customizationAdapterMapping, cam});
            } else
                customizationSpec.setNicSettingMap(new CustomizationAdapterMapping[]{customizationAdapterMapping});

            // Linux, use globle ip setting
            CustomizationGlobalIPSettings cgips = new CustomizationGlobalIPSettings();
            cgips.setDnsServerList(dnsArray);
            customizationSpec.setGlobalIPSettings(cgips);

            // 创建 Linux 的自定义规范 (保存自定义规范中的 Linux 客户机操作系统设置)
            CustomizationLinuxPrep linuxPrep = new CustomizationLinuxPrep();
            linuxPrep.setDomain("test.com");
            CustomizationFixedName fixedName = new CustomizationFixedName();
            fixedName.setName(vmName);
            linuxPrep.setHostName(fixedName);
            linuxPrep.setTimeZone("Asia/Shanghai");// https://vdc-download.vmware.com/vmwb-repository/dcr-public/6b586ed2-655c-49d9-9029-bc416323cb22/fa0b429a-a695-4c11-b7d2-2cbc284049dc/doc/timezone.html
            customizationSpec.setIdentity(linuxPrep);

            // 虚拟机克隆规范
            VirtualMachineCloneSpec cloneSpec = new VirtualMachineCloneSpec();
            cloneSpec.setLocation(virtualMachineRelocateSpec);
            cloneSpec.setPowerOn(powerOn);
            cloneSpec.setTemplate(false);
            cloneSpec.setConfig(configSpec);
            cloneSpec.setCustomization(customizationSpec);

            task = templateVM.cloneVM_Task((Folder) templateVM.getParent(), vmName, cloneSpec);
            System.out.print("Creating virtual machine: " + vmName + "...");
            log.info("Creating virtual machine: " + vmName + "...");
            String result = task.waitForTask();

            if (result.equals(Task.SUCCESS)) {
                System.out.println("success");
                log.info("success");
                jsonObject.put("success", "success");
                jsonObject.put("code", 200);
                return jsonObject;
            } else {
                TaskInfo ti = task.getTaskInfo();
                System.out.println("failed to create virtual machine: " + ti.getError().getLocalizedMessage());
                log.error("fail: " + ti.getError().getLocalizedMessage());
                jsonObject.put("error", "failed to create virtual machine: " + ti.getError().getLocalizedMessage());
                return jsonObject;
            }
        } catch (Exception e) {
            log.error(e.getMessage() + e.getLocalizedMessage());
        } finally {
            instance.getServerConnection().logout();
        }
        return jsonObject;
    }

测试

虚拟机创建失败后,不占用系统资源

磁盘剩余空间只允许创建一台虚拟机时,两个线程同时创建虚拟机
开始创建一段时间后,两台虚拟机均创建失败
提示:无法完成文件的网络复制
此时,主机剩余的可用磁盘容量和开始创建虚拟机之前的相同。
在这里插入图片描述

虚拟机硬盘扩展的上限
  1. 在主机1创建类型为厚置备快速置零的虚拟机
  2. 在主机1创建类型为精简置备的虚拟机
  3. 在主机2创建类型为厚置备快速置零的虚拟机
    在这里插入图片描述
    结论:
  • 同一个模板,精简置备和厚制备的磁盘上限不一样
  • 在不同的主机上,同一个模板,同一种方案,磁盘的上限也不一样
为虚拟机添加的磁盘没有挂载
  1. 为虚拟机添加3个大小为1G的硬盘
    在这里插入图片描述
    在这里插入图片描述
  2. lsblk命令用于列出所有可用块设备的信息,并显示他们之间的依赖关系。由下图可知,新建的磁盘没有挂载到根目录。
    在这里插入图片描述
配置磁盘信息时,要配置diskMode和fileName
class ExceptionDemo
{
    public static void main(String[] args) {
        try {
            throw new Exception("My Exception");
        } catch (Exception e) {
            System.err.println("Caught Exception");
            System.err.println("getMessage():" + e.getMessage());
            System.err.println("getLocalizedMessage():" + e.getLocalizedMessage());
            System.err.println("toString():" + e);
            System.err.println("printStackTrace():");
            e.printStackTrace();
        }
    }
}

以上代码运行输出结果为:

Caught Exception
getMessage():My Exception
getLocalizedMessage():My Exception
toString():java.lang.Exception: My Exception
printStackTrace():
java.lang.Exception: My Exception
   at ExceptionDemo.main(ExceptionDemo.java:5)

如果不配置diskModefileName,会报如下错误:

  1. Required property diskMode is missing from data object of type VirtualDiskFlatVer2BackingInfo
  2. Required property fileName is missing from data object of type VirtualDiskFlatVer2BackingInfo

fileName配置的是虚拟机磁盘文件的名称,但是设置不生效。
在这里插入图片描述

指定虚拟机所使用的数据存储
  1. 主机1剩余空间不足以创建一台虚拟机,主机2可以。
  2. 如果没有指定虚拟机所使用的数据存储,则只会在模板所在的主机(主机1)创建虚拟机。
    提示:数据存储“”上的磁盘空间不足。

待解决的问题

扩展虚拟机磁盘

从模板部署虚拟机的时候,需要扩展虚拟机磁盘。如果直接添加新的磁盘,需要挂载。如果修改磁盘空间大小,有调整上限,暂时无法获取具体的上限值。
初步考虑:

  1. 在创建模板的时候,磁盘大小设置为可能需要的最大大小。
  2. 将模板的磁盘格式设置为精简置备。
  3. 新建的虚拟机的磁盘格式也设置为精简置备。
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐