614 lines
28 KiB
Markdown
614 lines
28 KiB
Markdown
# RemoveWeeklySnapshot
|
||
|
||
Vmware 虚拟机自动化程序:自动化导出虚拟机和快照信息,自动化删除旧快照。
|
||
|
||
## Todo List
|
||
|
||
- [x] Yaml 文件保存配置信息
|
||
- [x] 通过 Yaml 文件信息连接vCenter/Esxi
|
||
- [x] 文件获取所有 vms
|
||
- [x] 获取所有 snapshots
|
||
- [x] 筛选出15天(半个月)前的 snapshots
|
||
- [x] 以上内容以 Excel 表格的形式导出,超出 15 天的快照蓝色底填充标识
|
||
- [x] 最后删除 15 天前的 snapshot,并同时记录删除的 snapshot 日志信息
|
||
- [x] 设置计划任务,每周六(或 每15 天)执行一次
|
||
- [ ] 增加排除不能删除的 snapshots 信息,用红色底填充标识
|
||
- [ ] 删除快照前/后发送邮件通知
|
||
- [ ] 多线程删除(控制每台 vCenter 不可以同时删除超过 4 个快照)
|
||
- [ ] 改用数据库保存管理节点账号密码(加密)
|
||
|
||
|
||
|
||
## 输出所有可用的属性和方法
|
||
|
||
| 你想获取 | 代码 | 示例输出 |
|
||
| ------------ | ----------------------------------- | ---------------------------------------------- |
|
||
| **名称** | `vm.name` | `"WebServer-01"` |
|
||
| **MOID** | `vm._moId` | `"vm-12"` |
|
||
| **电源状态** | `vm.runtime.powerState` | `poweredOn` / `poweredOff` |
|
||
| **开机时间** | `vm.runtime.bootTime` | `datetime` 对象 |
|
||
| **CPU数** | `vm.config.hardware.numCPU` | `4` |
|
||
| **内存(MB)** | `vm.config.hardware.memoryMB` | `8192` |
|
||
| **操作系统** | `vm.config.guestFullName` | `"CentOS 7 (64-bit)"` |
|
||
| **IP地址** | `vm.guest.ipAddress` | `"192.168.1.100"` |
|
||
| **主机名** | `vm.guest.hostName` | `"webserver01.local"` |
|
||
| **存储路径** | `vm.config.files.vmPathName` | `"[Datastore1] WebServer-01/WebServer-01.vmx"` |
|
||
| **快照数量** | `len(vm.snapshot.rootSnapshotList)` | `3` |
|
||
|
||
|
||
|
||
>以下这些方法和属性主要用于操作虚拟机(VM)、快照、存储和其他资源。
|
||
>
|
||
>vm
|
||
>├── 基础标识
|
||
>│ ├── name VM名称
|
||
>│ └── _moId 内部ID (vm-12)
|
||
>│
|
||
>├── runtime 【运行状态】
|
||
>│ ├── powerState poweredOn/Off/Suspended
|
||
>│ ├── bootTime 开机时间
|
||
>│ └── host 所在物理机
|
||
>│
|
||
>├── config 【硬件配置】
|
||
>│ ├── hardware CPU/内存/硬盘
|
||
>│ ├── guestFullName 操作系统
|
||
>│ └── files VMX文件路径
|
||
>│
|
||
>├── guest 【客户机内部信息】
|
||
>│ ├── hostName 主机名
|
||
>│ ├── ipAddress IP地址
|
||
>│ └── toolsStatus VMware Tools状态
|
||
>│
|
||
>├── snapshot 【快照】
|
||
>│ └── rootSnapshotList 快照树
|
||
>│
|
||
>├── storage 【存储】
|
||
>│ └── perDatastoreUsage 各数据存储用量
|
||
>│
|
||
>├── network 【网络】
|
||
>│ └── [Network] 连接的端口组
|
||
>│
|
||
>└── summary 【快速汇总】
|
||
>├── overallStatus 整体健康状态
|
||
>└── quickStats 实时性能数据
|
||
>
|
||
>1. **AcquireMksTicket / AcquireTicket**:获取访问虚拟机控制台的票据,允许用户通过 Web 界面访问 VM。
|
||
>2. **Clone / CloneVM_Task**:克隆一个虚拟机,创建其副本。
|
||
>3. **CreateSnapshot / CreateSnapshot_Task**:创建虚拟机快照,以保存当前 VM 的状态。
|
||
>4. **Destroy / Destroy_Task**:删除虚拟机及其所有数据。
|
||
>5. **PowerOn / PowerOnVM_Task**:启动虚拟机。
|
||
>6. **PowerOff / PowerOffVM_Task**:关闭虚拟机。
|
||
>7. **Reset / ResetVM_Task**:重置虚拟机,相当于按下重启按钮。
|
||
>8. **RevertToCurrentSnapshot / RevertToCurrentSnapshot_Task**:将虚拟机恢复到当前快照的状态。
|
||
>9. **Migrate / MigrateVM_Task**:迁移虚拟机到不同的主机或数据存储。
|
||
>10. **SetCustomValue**:设置自定义属性值,以便在虚拟机上存储额外信息。
|
||
>
|
||
>### 属性列表
|
||
>
|
||
>这些属性通常包含关于虚拟机或其他资源的状态和配置信息。以下是一些关键属性的说明:
|
||
>
|
||
>1. **name**:虚拟机的名称。
|
||
>2. **guest**:关于虚拟机操作系统的信息,如操作系统类型、版本等。
|
||
>3. **config**:虚拟机的配置详情,例如 CPU、内存、硬盘等。
|
||
>4. **runtime**:虚拟机的运行时状态,包括电源状态(开机、关机、挂起等)。
|
||
>5. **snapshot**:当前虚拟机的快照信息。
|
||
>6. **summary**:虚拟机的概述信息,包括状态、资源使用情况等。
|
||
>7. **resourcePool**:虚拟机所在的资源池。
|
||
>8. **datastore**:虚拟机的存储位置,指向其使用的存储库。
|
||
>9. **overallStatus**:虚拟机的总体状态,可能是正常、警告、错误等。
|
||
>10. **recentTask**:最近执行的任务列表。
|
||
>
|
||
>### 其他属性
|
||
>
|
||
>- **capability**:虚拟机支持的功能,如支持的虚拟硬件版本。
|
||
>- **declaredAlarmState**:声明的警报状态,用于监控虚拟机的健康状况。
|
||
>- **triggeredAlarmState**:触发的警报状态,显示当前激活的警报。
|
||
|
||
```python
|
||
for vm in vm_view.view:
|
||
print(dir(vm)) # 输出所有可用的属性和方法
|
||
# print(vm.summary)
|
||
# print(vm.snapshot)
|
||
# print(vars(vm.summary))
|
||
```
|
||
|
||
``` json
|
||
['AcquireMksTicket', 'AcquireTicket', 'Answer', 'AnswerVM', 'ApplyEvcMode', 'ApplyEvcModeVM_Task', 'Array', 'AttachDisk', 'AttachDisk_Task', 'CheckCustomizationSpec', 'Clone', 'CloneVM_Task', 'ConsolidateDisks', 'ConsolidateVMDisks_Task', 'CreateScreenshot', 'CreateScreenshot_Task', 'CreateSecondary', 'CreateSecondaryEx', 'CreateSecondaryVMEx_Task', 'CreateSecondaryVM_Task', 'CreateSnapshot', 'CreateSnapshotEx', 'CreateSnapshotEx_Task', 'CreateSnapshot_Task', 'CryptoUnlock', 'CryptoUnlock_Task', 'Customize', 'CustomizeVM_Task', 'DefragmentAllDisks', 'Destroy', 'Destroy_Task', 'DetachDisk', 'DetachDisk_Task', 'DisableSecondary', 'DisableSecondaryVM_Task', 'DropConnections', 'EnableSecondary', 'EnableSecondaryVM_Task', 'EstimateStorageForConsolidateSnapshots_Task', 'EstimateStorageRequirementForConsolidate', 'ExportVm', 'ExtractOvfEnvironment', 'InstantClone', 'InstantClone_Task', 'MakePrimary', 'MakePrimaryVM_Task', 'MarkAsTemplate', 'MarkAsVirtualMachine', 'Migrate', 'MigrateVM_Task', 'MountToolsInstaller', 'PowerOff', 'PowerOffVM_Task', 'PowerOn', 'PowerOnVM_Task', 'PromoteDisks', 'PromoteDisks_Task', 'PutUsbScanCodes', 'QueryChangedDiskAreas', 'QueryConnections', 'QueryFaultToleranceCompatibility', 'QueryFaultToleranceCompatibilityEx', 'QueryUnownedFiles', 'RebootGuest', 'ReconfigVM_Task', 'Reconfigure', 'RefreshStorageInfo', 'Reload', 'ReloadFromPath', 'Relocate', 'RelocateVM_Task', 'RemoveAllSnapshots', 'RemoveAllSnapshots_Task', 'Rename', 'Rename_Task', 'Reset', 'ResetGuestInformation', 'ResetVM_Task', 'RevertToCurrentSnapshot', 'RevertToCurrentSnapshot_Task', 'SendNMI', 'SetCustomValue', 'SetDisplayTopology', 'SetScreenResolution', 'ShutdownGuest', 'StandbyGuest', 'StartRecording', 'StartRecording_Task', 'StartReplaying', 'StartReplaying_Task', 'StopRecording', 'StopRecording_Task', 'StopReplaying', 'StopReplaying_Task', 'Suspend', 'SuspendVM_Task', 'Terminate', 'TerminateFaultTolerantVM', 'TerminateFaultTolerantVM_Task', 'TerminateVM', 'TurnOffFaultTolerance', 'TurnOffFaultToleranceForVM_Task', 'UnmountToolsInstaller', 'Unregister', 'UnregisterVM', 'UpgradeTools', 'UpgradeTools_Task', 'UpgradeVM_Task', 'UpgradeVirtualHardware', '_GetMethodInfo', '_GetMethodList', '_GetMoId', '_GetPropertyInfo', '_GetPropertyList', '_GetServerGuid', '_GetStub', '_InvokeAccessor', '_InvokeMethod', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__firstlineno__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__static_attributes__', '__str__', '__subclasshook__', '__weakref__', '_methodInfo', '_moId', '_propInfo', '_propList', '_serverGuid', '_stub', '_version', '_wsdlName', 'alarmActionsEnabled', 'availableField', 'capability', 'config', 'configIssue', 'configStatus', 'customValue', 'datastore', 'declaredAlarmState', 'disabledMethod', 'effectiveRole', 'environmentBrowser', 'guest', 'guestHeartbeatStatus', 'layout', 'layoutEx', 'name', 'network', 'overallStatus', 'parent', 'parentVApp', 'permission', 'recentTask', 'reloadVirtualMachineFromPath_Task', 'resourceConfig', 'resourcePool', 'rootSnapshot', 'runtime', 'setCustomValue', 'snapshot', 'storage', 'summary', 'tag', 'triggeredAlarmState', 'value']
|
||
```
|
||
|
||
|
||
|
||
### 获取虚拟机属性
|
||
|
||
获取和打印出虚拟机 (VM) 概要信息的所有属性,提供了关于虚拟机的基本信息,`vm.summary` 会返回一个字典,包含常见属性。可以使用 vm.guest.ipAddress 方法获取到虚拟机的IP地址等。
|
||
|
||
```python
|
||
print(vm.summary)
|
||
```
|
||
|
||
> (vim.vm.Summary) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> vm = 'vim.VirtualMachine:1',
|
||
> runtime = (vim.vm.RuntimeInfo) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> device = (vim.vm.DeviceRuntimeInfo) [
|
||
> (vim.vm.DeviceRuntimeInfo) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> runtimeState = (vim.vm.DeviceRuntimeInfo.VirtualEthernetCardRuntimeState) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> vmDirectPathGen2Active = false,
|
||
> vmDirectPathGen2InactiveReasonVm = (str) [
|
||
> 'vmNptDisabledOrDisconnectedAdapter'
|
||
> ],
|
||
> vmDirectPathGen2InactiveReasonOther = (str) [],
|
||
> vmDirectPathGen2InactiveReasonExtended = <unset>,
|
||
> uptv2Active = <unset>,
|
||
> uptv2InactiveReasonVm = (str) [],
|
||
> uptv2InactiveReasonOther = (str) [],
|
||
> reservationStatus = <unset>,
|
||
> attachmentStatus = 'red',
|
||
> featureRequirement = (vim.vm.FeatureRequirement) []
|
||
> },
|
||
> key = 4000
|
||
> }
|
||
> ],
|
||
> host = 'vim.HostSystem:ha-host',
|
||
> connectionState = 'connected',
|
||
> powerState = 'poweredOff',
|
||
> vmFailoverInProgress = <unset>,
|
||
> faultToleranceState = 'notConfigured',
|
||
> dasVmProtection = <unset>,
|
||
> toolsInstallerMounted = false,
|
||
> suspendTime = <unset>,
|
||
> bootTime = <unset>,
|
||
> suspendInterval = 0,
|
||
> question = <unset>,
|
||
> memoryOverhead = <unset>,
|
||
> maxCpuUsage = 5184,
|
||
> maxMemoryUsage = 4096,
|
||
> numMksConnections = 0,
|
||
> recordReplayState = 'inactive',
|
||
> cleanPowerOff = false,
|
||
> needSecondaryReason = <unset>,
|
||
> onlineStandby = false,
|
||
> minRequiredEVCModeKey = <unset>,
|
||
> consolidationNeeded = false,
|
||
> offlineFeatureRequirement = (vim.vm.FeatureRequirement) [
|
||
> (vim.vm.FeatureRequirement) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> key = 'cpuid.lm',
|
||
> featureName = 'cpuid.lm',
|
||
> value = 'Bool:Min:1'
|
||
> }
|
||
> ],
|
||
> featureRequirement = (vim.vm.FeatureRequirement) [],
|
||
> featureMask = (vim.host.FeatureMask) [],
|
||
> vFlashCacheAllocation = <unset>,
|
||
> paused = false,
|
||
> snapshotInBackground = false,
|
||
> quiescedForkParent = <unset>,
|
||
> instantCloneFrozen = false,
|
||
> cryptoState = <unset>,
|
||
> suspendedToMemory = <unset>,
|
||
> opNotificationTimeout = <unset>,
|
||
> iommuActive = <unset>
|
||
> },
|
||
> guest = (vim.vm.Summary.GuestSummary) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> guestId = <unset>,
|
||
> guestFullName = <unset>,
|
||
> toolsStatus = 'toolsNotRunning',
|
||
> toolsVersionStatus = 'guestToolsUnmanaged',
|
||
> toolsVersionStatus2 = 'guestToolsUnmanaged',
|
||
> toolsRunningStatus = 'guestToolsNotRunning',
|
||
> hostName = <unset>,
|
||
> ipAddress = <unset>,
|
||
> hwVersion = <unset>
|
||
> },
|
||
> config = (vim.vm.Summary.ConfigSummary) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> name = 'VMware vCenter Server Appliance',
|
||
> template = false,
|
||
> vmPathName = '[datastore1] VMware vCenter Server Appliance/VMware vCenter Server Appliance.vmx',
|
||
> memorySizeMB = 4096,
|
||
> cpuReservation = 0,
|
||
> memoryReservation = 0,
|
||
> numCpu = 2,
|
||
> numEthernetCards = 1,
|
||
> numVirtualDisks = 13,
|
||
> uuid = '564d7d77-f37f-64a7-47f2-a131a337c070',
|
||
> instanceUuid = '529e8be2-58ca-617c-ad7e-7f66de667471',
|
||
> guestId = 'other3xLinux64Guest',
|
||
> guestFullName = 'Other 3.x Linux (64-bit)',
|
||
> annotation = 'VMware vCenter Server Appliance',
|
||
> product = <unset>,
|
||
> installBootRequired = <unset>,
|
||
> ftInfo = <unset>,
|
||
> managedBy = <unset>,
|
||
> tpmPresent = false,
|
||
> numVmiopBackings = 0,
|
||
> hwVersion = <unset>
|
||
> },
|
||
> storage = (vim.vm.Summary.StorageSummary) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> committed = 37476296711,
|
||
> uncommitted = 303123661815,
|
||
> unshared = 37476296711,
|
||
> timestamp = 2026-02-19T09:11:27.701184Z
|
||
> },
|
||
> quickStats = (vim.vm.Summary.QuickStats) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> overallCpuUsage = <unset>,
|
||
> overallCpuDemand = <unset>,
|
||
> overallCpuReadiness = <unset>,
|
||
> guestMemoryUsage = <unset>,
|
||
> hostMemoryUsage = <unset>,
|
||
> guestHeartbeatStatus = 'gray',
|
||
> distributedCpuEntitlement = <unset>,
|
||
> distributedMemoryEntitlement = <unset>,
|
||
> staticCpuEntitlement = <unset>,
|
||
> staticMemoryEntitlement = <unset>,
|
||
> grantedMemory = <unset>,
|
||
> privateMemory = <unset>,
|
||
> sharedMemory = <unset>,
|
||
> swappedMemory = <unset>,
|
||
> balloonedMemory = <unset>,
|
||
> consumedOverheadMemory = <unset>,
|
||
> ftLogBandwidth = <unset>,
|
||
> ftSecondaryLatency = <unset>,
|
||
> ftLatencyStatus = <unset>,
|
||
> compressedMemory = <unset>,
|
||
> uptimeSeconds = <unset>,
|
||
> ssdSwappedMemory = <unset>,
|
||
> activeMemory = <unset>,
|
||
> memoryTierStats = (vim.vm.Summary.QuickStats.MemoryTierStats) []
|
||
> },
|
||
> overallStatus = 'green',
|
||
> customValue = (vim.CustomFieldsManager.Value) []
|
||
> }
|
||
|
||
|
||
|
||
### 获取快照属性
|
||
|
||
输出快照所有信息
|
||
|
||
```python
|
||
print(vm.snapshot)
|
||
```
|
||
|
||
>(vim.vm.SnapshotInfo) {
|
||
>dynamicType = <unset>,
|
||
>dynamicProperty = (vmodl.DynamicProperty) [],
|
||
>currentSnapshot = 'vim.vm.Snapshot:1-snapshot-3',
|
||
>rootSnapshotList = (vim.vm.SnapshotTree) [
|
||
>(vim.vm.SnapshotTree) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> snapshot = 'vim.vm.Snapshot:1-snapshot-1',
|
||
> vm = 'vim.VirtualMachine:1',
|
||
> name = 'snap-01', # 第一层快照
|
||
> description = 'Ansible snapshot',
|
||
> id = 1,
|
||
> createTime = 2026-02-17T03:26:08.834505Z,
|
||
> state = 'poweredOff',
|
||
> quiesced = false,
|
||
> backupManifest = <unset>,
|
||
> childSnapshotList = (vim.vm.SnapshotTree) [
|
||
> (vim.vm.SnapshotTree) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> snapshot = 'vim.vm.Snapshot:1-snapshot-2',
|
||
> vm = 'vim.VirtualMachine:1',
|
||
> name = 'snap-02', # 第二层快照
|
||
> description = 'test-Ansible snapshot',
|
||
> id = 2,
|
||
> createTime = 2026-02-17T08:57:39.122511Z,
|
||
> state = 'poweredOff',
|
||
> quiesced = false,
|
||
> backupManifest = <unset>,
|
||
> childSnapshotList = (vim.vm.SnapshotTree) [
|
||
> (vim.vm.SnapshotTree) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> snapshot = 'vim.vm.Snapshot:1-snapshot-3',
|
||
> vm = 'vim.VirtualMachine:1',
|
||
> name = '虚拟机快照 2026%252f2%252f19 12:28:36', # 第二层快照
|
||
> description = '',
|
||
> id = 3,
|
||
> createTime = 2026-02-19T04:28:38.007703Z,
|
||
> state = 'poweredOn',
|
||
> quiesced = false,
|
||
> backupManifest = <unset>,
|
||
> childSnapshotList = (vim.vm.SnapshotTree) [],
|
||
> replaySupported = false
|
||
> }
|
||
> ],
|
||
> replaySupported = false
|
||
> }
|
||
> ],
|
||
> replaySupported = false
|
||
>}
|
||
>]
|
||
>}
|
||
|
||
|
||
|
||
## PY 文件作用
|
||
|
||
``` powershell
|
||
PS D:\PycharmProjects\RemoveWeeklySnapshot> tree /F
|
||
卷 Date 的文件夹 PATH 列表
|
||
卷序列号为 0E45-0F72
|
||
D:.
|
||
│ main.py
|
||
│ README.md
|
||
│ requirements.txt
|
||
│
|
||
├─config
|
||
│ │ config.yaml
|
||
│ │ settings.py
|
||
│
|
||
├─core
|
||
│ │ data_exporter.py
|
||
│ │ get_vm_snapshots.py
|
||
│ │ remove_snapshots.py
|
||
│ │ vm_connector.py
|
||
│
|
||
├─logs
|
||
│ 2026-02-21-vm_snapshot_cleanup.log
|
||
│
|
||
├─output
|
||
│ old_snapshots-2026-02-21.yaml
|
||
│ vm_snapshots_report-2026-02-21.xlsx
|
||
│
|
||
├─utils
|
||
│ │ logger.py
|
||
```
|
||
|
||
|
||
|
||
## 所用到的 Python 库
|
||
|
||
``` powershell
|
||
PS D:\PycharmProjects\RemoveWeeklyShapshot> pip freeze > requirements.txt
|
||
APScheduler==3.11.2
|
||
openpyxl==3.2.0b1
|
||
pandas==3.0.1
|
||
pyvmomi==9.0.0.0
|
||
PyYAML==6.0.3
|
||
```
|
||
|
||
``` shell
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
|
||
|
||
## 构建 Docker 镜像
|
||
|
||
### 新建数据目录
|
||
|
||
``` shell
|
||
mkdir -p ~/removeweeklysnapshot/{config,logs,output} && cd ~/removeweeklysnapshot
|
||
```
|
||
|
||
### 安装 Docker
|
||
|
||
``` shell
|
||
sudo curl https://download.docker.com/linux/centos/docker-ce.repo -o /etc/yum.repos.d/docker.repo
|
||
sudo dnf install docker-ce -y && docker -v
|
||
sudo systemctl enable --now docker && systemctl status docker
|
||
```
|
||
|
||
### Dockerfile 文件
|
||
|
||
``` dockerfile
|
||
cat << 'EOF' > Dockerfile
|
||
FROM python:3.14.3-slim
|
||
# 配置时区
|
||
ENV TZ=Asia/Shanghai
|
||
RUN ln -fs /usr/share/zoneinfo/$TZ /etc/localtime && dpkg-reconfigure -f noninteractive tzdata
|
||
# 下载代码
|
||
ADD https://gitcode.junlan.site/junlan/RemoveWeeklyShapshot/archive/Dev.tar.gz /app/
|
||
# 解压压缩文件(最后 mv 命令改名)
|
||
RUN tar -xzf /app/Dev.tar.gz -C /app/ && rm /app/Dev.tar.gz && mv /app/removeweeklyshapshot /app/removeweeklysnapshot
|
||
# 设置工作目录
|
||
WORKDIR /app/removeweeklysnapshot
|
||
# 安装必要的软件和 python 库
|
||
RUN apt-get update && apt-get install procps tzdata -y && pip install -r requirements.txt && chmod +x main.py
|
||
# 添加项目根目录到 Python 路径
|
||
ENV PYTHONPATH=/app/removeweeklysnapshot
|
||
# 容器内执行启动程序
|
||
CMD ["python3", "/app/removeweeklysnapshot/main.py"]
|
||
EOF
|
||
```
|
||
|
||
### 执行构建 Docker 镜像
|
||
|
||
``` shell
|
||
sudo docker build --no-cache -t removeweeklysnapshot .
|
||
```
|
||
|
||
### 构建 Compose 文件
|
||
|
||
``` yaml
|
||
cat << 'EOF' > compose.yaml
|
||
services:
|
||
removeweeklysnapshot:
|
||
container_name: removeweeklysnapshot
|
||
image: removeweeklysnapshot
|
||
volumes:
|
||
- /home/junlan/removeweeklysnapshot/logs:/app/removeweeklysnapshot/logs
|
||
- /home/junlan/removeweeklysnapshot/output:/app/removeweeklysnapshot/output
|
||
# - /home/junlan/removeweeklysnapshot/config/config.yaml:/app/removeweeklysnapshot/config/config.yaml
|
||
restart: always
|
||
stdin_open: true
|
||
tty: true
|
||
EOF
|
||
```
|
||
|
||
### 运行容器
|
||
|
||
``` shell
|
||
sudo docker compose up -d
|
||
```
|
||
|
||
### 查看状态
|
||
|
||
``` shell
|
||
# 查看镜像构建历史记录
|
||
[junlan@localhost ~]$ sudo docker history removeweeklysnapshot
|
||
IMAGE CREATED CREATED BY SIZE COMMENT
|
||
ff84aa4fde3b 35 minutes ago CMD ["python3" "/app/removeweeklysnapshot/ma… 0B buildkit.dockerfile.v0
|
||
<missing> 35 minutes ago ENV PYTHONPATH=/app/removeweeklysnapshot 0B buildkit.dockerfile.v0
|
||
<missing> 35 minutes ago RUN /bin/sh -c apt-get update && apt-get ins… 216MB buildkit.dockerfile.v0
|
||
<missing> 36 minutes ago WORKDIR /app/removeweeklysnapshot 0B buildkit.dockerfile.v0
|
||
<missing> 36 minutes ago RUN /bin/sh -c tar -xzf /app/Dev.tar.gz -C /… 51.4kB buildkit.dockerfile.v0
|
||
<missing> 36 minutes ago ADD https://gitcode.junlan.site/junlan/Remov… 16.6kB buildkit.dockerfile.v0
|
||
<missing> 36 minutes ago RUN /bin/sh -c ln -fs /usr/share/zoneinfo/$T… 1.65MB buildkit.dockerfile.v0
|
||
<missing> 36 minutes ago ENV TZ=Asia/Shanghai 0B buildkit.dockerfile.v0
|
||
<missing> 2 weeks ago CMD ["python3"] 0B buildkit.dockerfile.v0
|
||
<missing> 2 weeks ago RUN /bin/sh -c set -eux; for src in idle3 p… 36B buildkit.dockerfile.v0
|
||
<missing> 2 weeks ago RUN /bin/sh -c set -eux; savedAptMark="$(a… 36.6MB buildkit.dockerfile.v0
|
||
<missing> 2 weeks ago ENV PYTHON_SHA256=a97d5549e9ad81fe17159ed02c… 0B buildkit.dockerfile.v0
|
||
<missing> 2 weeks ago ENV PYTHON_VERSION=3.14.3 0B buildkit.dockerfile.v0
|
||
<missing> 2 weeks ago RUN /bin/sh -c set -eux; apt-get update; a… 3.81MB buildkit.dockerfile.v0
|
||
<missing> 2 weeks ago ENV PATH=/usr/local/bin:/usr/local/sbin:/usr… 0B buildkit.dockerfile.v0
|
||
<missing> 2 weeks ago # debian.sh --arch 'amd64' out/ 'trixie' '@1… 78.6MB debuerreotype 0.17
|
||
|
||
|
||
[junlan@localhost removeweeklyshapshot]$ sudo docker images
|
||
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
|
||
python:3.14.3-slim 486b8092bfb1 176MB 45.5MB
|
||
removeweeklysnapshot:latest 6f17fcaaef99 512MB 140MB
|
||
|
||
[junlan@localhost removeweeklyshapshot]$ sudo docker compose ps
|
||
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
|
||
removeweeklysnapshot removeweeklysnapshot "python3 /removeweek…" removeweeklysnapshot 34 seconds ago Up 15 seconds
|
||
|
||
[junlan@localhost removeweeklyshapshot]$ sudo docker compose logs removeweeklysnapshot -f
|
||
removeweeklysnapshot | 2026-02-22 16:01:50,113 - INFO - ✅ 成功加载配置,共 1 个管理节点
|
||
removeweeklysnapshot | 2026-02-22 16:01:50,954 - INFO - ✓ 导出任务已设置: 每周 sun 16:05
|
||
removeweeklysnapshot | 2026-02-22 16:01:50,954 - INFO - ✓ 删除任务已设置: 每周 sun 16:10
|
||
removeweeklysnapshot | 2026-02-22 16:01:50,956 - INFO - 调度器已启动,等待执行任务...
|
||
removeweeklysnapshot | 2026-02-22 16:05:00,002 - INFO - 🔍 开始收集VM和快照信息...
|
||
removeweeklysnapshot | 2026-02-22 16:05:00,269 - INFO - 成功连接到节点: vcsa8.snimay.com
|
||
removeweeklysnapshot | 2026-02-22 16:05:01,251 - INFO - 获取到 5 台虚拟机
|
||
removeweeklysnapshot | 2026-02-22 16:05:01,252 - INFO - 📝 开始导出Excel报表...
|
||
removeweeklysnapshot | 2026-02-22 16:05:01,257 - INFO - 总共有 4 个快照
|
||
removeweeklysnapshot | 2026-02-22 16:05:01,377 - DEBUG - Excel 文件已生成: /app/removeweeklysnapshot/output/vm_snapshots_report-2026-02-22.xlsx
|
||
removeweeklysnapshot | 2026-02-22 16:05:01,377 - INFO - 📝 开始导出 Yaml 文件...
|
||
removeweeklysnapshot | 2026-02-22 16:05:01,378 - INFO - 可删除的快照有 0 个
|
||
removeweeklysnapshot | 2026-02-22 16:05:01,379 - DEBUG - YAML 文件已生成: /app/removeweeklysnapshot/output/old_snapshots-2026-02-22.yaml
|
||
removeweeklysnapshot | 2026-02-22 16:05:01,379 - INFO - ========== Excel和Yaml文件导出完成 ==========
|
||
|
||
[junlan@localhost removeweeklyshapshot]$ sudo docker exec -it removeweeklysnapshot bash
|
||
root@07c30da6408a:/removeweeklysnapshot# ps -ef
|
||
UID PID PPID C STIME TTY TIME CMD
|
||
root 1 0 0 15:12 pts/0 00:00:01 python3 /removeweeklysnapshot/main.py
|
||
root 11 0 0 15:15 pts/1 00:00:00 bash
|
||
root 17 11 0 15:15 pts/1 00:00:00 ps -ef
|
||
|
||
```
|
||
|
||
|
||
|
||
### 修改代码进行临时测试
|
||
|
||
- 修改 ==config.yaml== 文件
|
||
- `snapshot_retention_days: 0` :定义删除多少天前的快照
|
||
- `schedule`:自定义改参数下的时间
|
||
|
||
|
||
``` yaml
|
||
cat << 'EOF' > ~/removeweeklysnapshot/config/config.yaml
|
||
# 管理节点配置(包含vCenter和ESXi)
|
||
management_nodes:
|
||
# vCenter节点
|
||
- type: vcenter # 标记类型为vcenter
|
||
name: vc1 # 节点名称(用于日志)
|
||
host: vcsa8.xxx.com # 地址
|
||
user: administrator@vcsa.local
|
||
password: Root@2020
|
||
max_delete_concurrent: 4 # 该节点最大并发删除数
|
||
|
||
# 全局策略配置
|
||
global:
|
||
disable_ssl_verify: true # ESXi连接特殊配置(禁用SSL验证,ESXi默认自签证书)
|
||
snapshot_retention_days: 1 # 可选,默认值 15 天
|
||
# 定时任务配置
|
||
schedule:
|
||
export: # 导出 Excel 和 Yaml 文件的时间
|
||
day_of_week: 'sun' # 星期几:mon,tue,wed,thu,fri,sat,sun
|
||
hour: 15 # 小时 (0-23)
|
||
minute: 58 # 分钟 (0-59)
|
||
second: 0 # 秒 (可选)
|
||
|
||
delete: # 删除快照的时间
|
||
day_of_week: 'sun'
|
||
hour: 15
|
||
minute: 59
|
||
second: 0
|
||
EOF
|
||
|
||
==================================================================================================
|
||
|
||
cat << 'EOF' > compose.yaml
|
||
services:
|
||
removeweeklysnapshot:
|
||
container_name: removeweeklysnapshot
|
||
image: removeweeklysnapshot
|
||
volumes:
|
||
- ~/removeweeklysnapshot/logs:/app/removeweeklysnapshot/logs
|
||
- ~/removeweeklysnapshot/output:/app/removeweeklysnapshot/output
|
||
- ~/removeweeklysnapshot/config/config.yaml:/app/removeweeklysnapshot/config/config.yaml
|
||
restart: always
|
||
stdin_open: true
|
||
tty: true
|
||
EOF
|
||
```
|
||
|
||
#### 进入容器测试
|
||
|
||
手动执行 `main.py` 运行
|
||
|
||
``` shell
|
||
[junlan@localhost removeweeklysnapshot]$ sudo docker exec -it removeweeklysnapshot bash
|
||
root@63869672d333:/app/removeweeklyshapshot# python main.py
|
||
2026-02-21 15:42:56,070 - INFO - ✅ 成功加载配置,共 2 个管理节点
|
||
2026-02-21 15:42:56,556 - INFO - 定时任务已设置:每周六凌晨4点导出文件,晚上7点删除快照
|
||
2026-02-21 15:43:00,000 - INFO - 🔍 开始收集VM和快照信息...
|
||
2026-02-21 15:43:00,054 - INFO - 成功连接到节点: 192.168.40.133
|
||
2026-02-21 15:43:03,319 - ERROR - 处理节点 192.168.40.135 失败:[Errno 113] No route to host
|
||
2026-02-21 15:43:03,319 - INFO - 获取到 2 台虚拟机
|
||
2026-02-21 15:43:03,319 - INFO - 📝 开始导出Excel报表...
|
||
2026-02-21 15:43:03,322 - INFO - 总共有 3 个快照
|
||
2026-02-21 15:43:03,340 - DEBUG - Excel 文件已生成: /removeweeklysnapshot/output/vm_snapshots_report.xlsx
|
||
2026-02-21 15:43:03,340 - INFO - 📝 开始导出 Yaml 文件...
|
||
2026-02-21 15:43:03,340 - INFO - 可删除的快照有 3 个
|
||
2026-02-21 15:43:03,342 - DEBUG - YAML 文件已生成: /removeweeklysnapshot/output/old_snapshots.yaml
|
||
2026-02-21 15:43:03,342 - INFO - ========== Excel和Yaml文件导出完成 ==========
|
||
2026-02-21 15:44:00,001 - INFO - 🗑️ 开始删除过旧快照...
|
||
2026-02-21 15:44:00,004 - INFO - 连接 192.168.40.133 进行删除快照...
|
||
2026-02-21 15:44:00,050 - INFO - 成功连接到节点: 192.168.40.133
|
||
2026-02-21 15:44:00,081 - INFO - 正在删除 Snapshot: VMware vCenter Server Appliance-快照测试-(1-snapshot-7)
|
||
2026-02-21 15:44:01,100 - INFO - ✅ 删除成功: VMware vCenter Server Appliance-快照测试-(1-snapshot-7)
|
||
2026-02-21 15:44:01,125 - INFO - 正在删除 Snapshot: VMware vCenter Server Appliance-快照测试-第二层快照-(1-snapshot-8)
|
||
2026-02-21 15:44:02,139 - INFO - ✅ 删除成功: VMware vCenter Server Appliance-快照测试-第二层快照-(1-snapshot-8)
|
||
2026-02-21 15:44:02,164 - INFO - 正在删除 Snapshot: test-vm-01-snap-01-(4-snapshot-9)
|
||
2026-02-21 15:44:03,178 - INFO - ✅ 删除成功: test-vm-01-snap-01-(4-snapshot-9)
|
||
2026-02-21 15:44:03,184 - INFO - ========== VM快照清理任务执行完成 ==========
|
||
|
||
```
|
||
|