在ZStack云平台上,使用本地存储的主存储创建云主机失败,原因是主存储的容量不够,检查集群内部的物理机发现“可用量”与“可用物理容量”相差较大,需要如何处理?
可用量和可用物理容量异常:
(图1 可用量和可用物理容量异常)
云平台环境:ZStack企业版3.6.0
网络环境:扁平网络/VPC网络
存储环境:本地存储
管理节点操作系统:ZStack定制版CentOS 7.6系统
云主机系统:CentOS 7.6系统
云平台上频繁的使用不同的镜像进行云主机创建和删除或者有些曾经使用过的镜像现在已经不在使用了,导致imagecache(镜像缓存)容量过多占用了主存储的容量。
需要通过镜像缓存清理脚本进行释放imagecache所占用的容量;清理image cache分为两部分:
第一部分在需要清理的计算节点上执行,第二部分在管理节点数据库中执行。
1. 第一部分:在需要清理镜像缓存的计算节点上执行(相关脚本见附录)。
a) 上传脚本【findlocalcache.py】到服务器目录后,执行如下命令
# python findlocalcache.py [主存储目录] [该计算节点 uuid]
备注:
主存储目录例如【/zsstack_ps】这种目录;
计算节点uuid可以在ZStack云平台上“物理机”详情页可以找到。
云平台上查看物理机uuid
(图2 物理机uuid)
b) 上述动作执行完成之后,在当前目录下会生成 rm_cache.sh 和 clean_db.sql 两个文件。
c) 在当前计算节点执行 bash rm_cache.sh,执行完成后可以释放 image cache所占用容量。
d) 最后将文件clean_db.sql 拷贝到管理节点服务器上(若环境是双管理节点,请拷贝到两个管理节点服务器上)。
2. 第二部分:管理节点上数据库中执行
a) 首先,备份好管理节点数据库,在两个管理节点上都要执行如下命令:
# zstack-ctl dump_mysql
b) 进入主管理节点(vip 所在)数据库,执行以下操作。
# 进入数据库的命令
mysql -uroot -pzstack.mysql.password
# 在数据库中执行以下操作
source /root/clean_db.sql exit
c) 进入备管理节点数据库,执行以下操作。
# 进入数据库的命令
mysql -uroot -pzstack.mysql.password
# 在数据库中执行以下操作
use zstack; source /root/clean_db.sql exit
3. 若有多台物理机出现异常,在异常的物理机上按顺序步骤1、2。
4. 最终在ZStack平台上物理机容量显示释放,可用容量变大。
(图3 清理后物理机上面可用容量和可用物理容量显示)
附录
脚本【findlocalcache.py】,代码如下:
import os import sys import struct ps_path = str(sys.argv[1]) host_uuid = str(sys.argv[2]) image_path = os.path.join(ps_path, 'imagecache/template/') to_del_list = [] def get_all_file(p_path): all_files = [] def get_file(path): files = os.listdir(path) for fi in files: fi_d = os.path.join(path, fi) if os.path.isdir(fi_d): get_file(fi_d) else: all_files.append(os.path.join(path, fi_d)) get_file(p_path) return all_files def get_all_backing_files(path): file_list = get_all_file(path) backing_files = set() for f in file_list: backing_file = qcow2_get_backing_file(f) backing_files.add(backing_file) return backing_files def qcow2_get_backing_file(path): with open(path, 'r') as resp: magic = resp.read(4) if magic != 'QFI\xfb': return "" # read backing file info from header resp.seek(8) backing_file_info = resp.read(12) backing_file_offset = struct.unpack('>Q', backing_file_info[:8])[0] if backing_file_offset == 0: return "" backing_file_size = struct.unpack('>L', backing_file_info[8:])[0] resp.seek(backing_file_offset) return resp.read(backing_file_size) def start(): bk_files = get_all_backing_files(ps_path) cache_tmp_list = set(get_all_file(image_path)) cache_list = set() for c in cache_tmp_list: if 'qcow2' in c: cache_list.add(c.strip()) # print cache_list - bk_files to_remove = cache_list - bk_files rm_cache_fd = open('rm_cache.sh', 'w') rm_cache_fd.write('#!/bin/bash\n') clean_db_fd = open('clean_db.sql', 'w') for tr in to_remove: print tr print os.path.dirname(tr) clean_cmd = "rm -rf " + os.path.dirname(tr) rm_cache_fd.write(clean_cmd + '\n') cache_path = 'file://%s;hostUuid://%s' % (tr, host_uuid) print cache_path clean_db_fd.write('delete from ImageCacheVO where installUrl = \'%s\';\n' % cache_path) # os.system(clean_cmd) rm_cache_fd.close() clean_db_fd.close() start()