
简介这是一份面向OpenStack运维工程师与云平台开发者的Python工具脚本专为解决Cinder卷备份服务在多租户场景下的功能局限而设计如跨租户备份可见性控制、自动备份轮换、运行中卷的无中断备份等实际运维痛点。资源包共4个文件含核心脚本cinderback.py实现全量/单卷备份还原、元数据导出导入、快照临时卷机制、README.md使用说明与权限配置、requirements.txt依赖声明及.gitignore开发规范整体仅11KB轻量易部署。目前已有313人学习下载适合中高级云平台从业者快速集成、二次开发或作为Cinder Backup Service增强方案参考。读者可直接复用其多租户凭据管理逻辑、备份生命周期控制策略及兼容旧版cinderclient的降级处理机制显著提升OpenStack块存储灾备流程的自动化与健壮性。1. Cinder 备份不是点个按钮就完事这个 Python 脚本把「备份策略落地」变成了可复现、可审计、可回滚的标准化动作你有没有遇到过这样的场景OpenStack 环境里 Cinder 卷数量涨到两百多个某天凌晨三点告警——某个关键业务卷的快照链意外断裂备份窗口已过恢复点目标RPO彻底失效。运维同事翻遍 Horizon 控制台和cinder backup-create手动命令日志发现根本没留执行记录更别说失败重试、保留周期控制、跨后端归档这些刚需。这不是理论风险是真实踩过的坑。cinderback 就是为解决这类问题而生的它不是一个花哨的 Web 界面而是一套轻量、无依赖、纯命令行驱动的 Python 脚本集合专治 Cinder 备份的「不可控、不可查、不可管」。它不替换 Cinder 原生备份服务而是站在其之上用清晰的 YAML 策略文件定义「谁、在什么时间、对哪些卷、按什么规则备份、保留几份、失败怎么兜底」。适合中小规模 OpenStack 部署、CI/CD 流水线集成、或需要将备份行为纳入配置即代码GitOps流程的团队。如果你还在用 crontab 一堆零散 shell 脚本拼凑 Cinder 备份cinderback 就是你该立刻拉下来的「后悔药」。2. 从零跑通第一个备份任务环境准备、策略定义与三步执行闭环2.1 环境依赖与认证配置为什么必须用 openstacksdk 而非旧版 python-cinderclientcinderback 的核心通信层基于openstacksdk而非已废弃的python-cinderclient。这不是为了追新而是因为openstacksdk提供了统一的认证抽象clouds.yaml、细粒度的异常分类如ResourceNotFoundvsConflictException以及对多云、多域、多项目认证的原生支持。很多翻车案例都源于用旧 client 在 Keystone v3 环境下因 domain_id 缺失导致认证 401而openstacksdk会明确抛出InvalidServiceCatalog异常便于脚本精准捕获。安装只需一行pip install openstacksdk pyyaml python-dateutil提示务必确认你的 OpenStack 环境已启用 Cinder Backup 服务cinder-backup进程运行正常且对应后端如 Ceph RBD、POSIX 文件系统已正确配置并测试通过。cinderback 不负责后端连通性验证它只调用 Cinder API。认证配置推荐使用clouds.yaml标准方式存于~/.config/openstack/clouds.yamlclouds: myprod: auth: auth_url: https://openstack-api.example.com:5000/v3 username: backup-operator password: your-secure-password project_name: services user_domain_name: Default project_domain_name: Default # 必须显式指定否则 openstacksdk 可能默认用 v2 identity_api_version: 3 region_name: RegionOne interface: public verify: true # 生产环境务必设为 true禁用 SSL 验证是重大安全风险验证是否生效运行openstack --os-cloudmyprod volume list --limit 1若返回一个卷信息则认证成功。这是 cinderback 后续所有操作的前提。2.2 编写你的第一份备份策略YAML 结构解析与字段含义精讲cinderback 的策略文件如backup-policy.yaml是整个流程的“大脑”。它不是 JSON 那种纯数据格式而是带逻辑的声明式配置。以下是一个生产可用的最小完整策略示例我们逐字段拆解# backup-policy.yaml version: 1.0 # 全局配置块 global: cloud: myprod # 对应 clouds.yaml 中的 cloud 名称 backup_timeout: 3600 # 备份任务超时秒数Cinder 默认是 3600这里显式声明 retry_times: 3 # 单次备份失败后重试次数 retry_delay: 60 # 重试间隔秒数 # 备份规则列表按顺序匹配执行 rules: - name: critical-db-volumes description: 数据库主从卷每小时全量保留最近 24 份 # 卷匹配条件支持正则、前缀、标签、项目 ID 多种方式 volume_filter: regex: ^db-(master|slave)-[0-9]$ # 匹配 db-master-01, db-slave-02 等 # 或者用标签tags: [env:prod, role:database] # 或者用项目project_id: a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8 schedule: cron: 0 * * * * # 每小时第 0 分钟执行crontab 格式 # 也支持简单周期interval_hours: 1 retention: count: 24 # 保留最多 24 份备份 # 或者按时间keep_days: 7 # 备份选项 options: container: cinder-backup-prod # Cinder 备份容器名通常对应后端存储池 incremental: false # 关键此处设为 false 表示强制全量备份 force: true # 绕过卷状态检查如卷处于 in-use 状态仍可备份 - name: dev-test-volumes description: 开发测试卷每天一次保留 7 天 volume_filter: prefix: dev- schedule: cron: 0 2 * * * # 每天凌晨 2 点 retention: keep_days: 7 options: container: cinder-backup-dev incremental: true # 开发环境可启用增量节省空间关键字段说明volume_filter: 这是策略的核心。regex最灵活但注意 Python 正则语法如^和$是行首行尾锚点prefix最简单高效tags需要卷已打标cinder volume-set --property envprod vol-idproject_id用于隔离项目级备份。schedule.cron: 使用标准 crontab 语法。cinderback 内部用croniter库解析支持hourly,daily等别名但建议用数字格式以避免歧义。retention.countvsretention.keep_days: 二者互斥。count按备份创建时间倒序删旧keep_days按备份创建时间戳计算删除早于now - keep_days的所有备份。生产环境我倾向count因为备份频率可能不均keep_days容易导致实际保留份数远超预期。options.incremental: Cinder 原生增量备份依赖快照链完整性。如果卷频繁做快照又删除增量链极易断裂。cinderback的incremental: true会先调用cinder backup-create --incremental但失败时自动降级为全量并记录警告日志——这是它比裸调 API 更鲁棒的地方。2.3 三步执行启动守护进程、手动触发与状态监控cinderback 提供两种运行模式daemon常驻后台按 cron 自动执行和run-once手动触发单次。新手务必从run-once开始确保策略无误后再切 daemon。步骤一手动触发一次观察全流程# 在策略文件同目录下执行 python cinderback.py run-once --policy backup-policy.yaml --dry-run--dry-run参数至关重要它会模拟执行全过程列出匹配的卷、打印将要调用的 Cinder API、计算保留策略影响但绝不真正创建任何备份。输出类似DRY RUN MODE ENABLED Found 3 volumes matching rule critical-db-volumes: [db-master-01, db-slave-01, db-slave-02] Would create backup for db-master-01 with options: {container: cinder-backup-prod, incremental: False, force: True} Would retain max 24 backups for this rule; currently 18 exist, so no cleanup needed.确认无误后去掉--dry-runpython cinderback.py run-once --policy backup-policy.yaml你会看到实时日志[INFO] Creating backup for db-master-01... [SUCCESS] Backup b1234567-890a-bcde-f012-34567890abcd created.步骤二启动守护进程生产部署# 后台运行日志输出到文件 nohup python cinderback.py daemon --policy backup-policy.yaml --log-file /var/log/cinderback.log /dev/null 21 # 查看进程 ps aux | grep cinderback守护进程会持续轮询根据schedule.cron时间点自动触发。它内部使用APScheduler库支持优雅重启发送SIGTERM会等待当前任务完成再退出。步骤三监控与验证不要只信日志。直接查 Cinder API# 查看所有备份按创建时间倒序 openstack --os-cloudmyprod backup list --sort-column created_at --sort-dir desc --limit 10 # 查看某卷的全部备份 openstack --os-cloudmyprod backup list --volume volume-id重点关注status字段available表示成功error表示失败需查日志creating表示进行中。cinderback 的日志会精确记录每个备份的backup_id和耗时方便与 API 结果交叉验证。3. 备份失败别急着重启服务五个高频现象的根因定位与修复路径3.1 现象VolumeNotFound异常频发但openstack volume list显示卷存在原因cinderback 在执行时卷已被其他流程如自动伸缩、CI/CD 销毁删除但策略文件中的volume_filter仍匹配到该卷 ID 的历史缓存或残留元数据。openstacksdk的get_volume()方法在卷不存在时抛出ResourceNotFound而 cinderback 默认将其作为致命错误终止本次规则执行。解决在策略文件的global块中添加容错配置global: # ... 其他配置 skip_missing_volumes: true # 遇到 VolumeNotFound 时跳过该卷继续处理下一个 log_missing_volumes: true # 将跳过的卷 ID 记录到日志便于审计注意skip_missing_volumes: true是生产环境强烈推荐的设置。它让备份任务具备“弹性”避免单个卷异常导致整批备份中断。3.2 现象备份任务卡在creating状态超过backup_timeout最终报BackupTimeoutError原因Cinder Backup 服务本身卡住常见于后端存储如 CephIO 延迟飙升、网络分区、或备份容器container所在存储池空间不足。cinderback 的backup_timeout只是客户端超时它会向 Cinder 发送backup-delete请求尝试清理但若 Cinder 服务无响应备份记录可能滞留在creating状态。解决立即检查后端登录cinder-backup节点查看/var/log/cinder/cinder-backup.log搜索ERROR和WARNING重点关注rbd或posix相关错误。手动清理僵尸备份在 Cinder 数据库通常是 MySQL中执行请先备份数据库-- 查找超时的 creating 状态备份 SELECT id, volume_id, created_at FROM backups WHERE status creating AND created_at DATE_SUB(NOW(), INTERVAL 2 HOUR); -- 将其状态强制置为 error谨慎操作 UPDATE backups SET status error, updated_at NOW() WHERE id b123...;预防在cinder.conf中调优backup_operation_timeout单位秒并确保cinder-backup服务有足够资源CPU、内存、磁盘 IO。3.3 现象retention策略未生效备份数量持续增长原因retention规则只在每次成功创建新备份后才触发清理。如果备份任务长期失败如认证过期、网络不通就不会进入清理逻辑。另一个常见原因是volume_filter匹配范围过大导致不同规则的备份被混在一起清理——cinderback 的retention是按rule.name隔离的但如果你在多个规则中用了相同的container名而retention又只按count那么清理时会统计该container下所有备份而非仅本规则创建的。解决确保备份成功先解决上述 3.1、3.2 问题让备份稳定。规则隔离为每个rule配置唯一的options.container例如cinder-backup-prod-db,cinder-backup-prod-app。这样retention.count: 24就只会清理该容器下本规则创建的备份不会误删其他规则的备份。手动触发清理cinderback.py cleanup --policy backup-policy.yaml --rule critical-db-volumes可强制执行一次清理用于紧急情况。3.4 现象incremental: true备份失败日志显示NoValidHost或BackupNotSupported原因Cinder 原生增量备份要求卷必须有有效的、未被删除的快照作为基准。如果卷近期做过cinder snapshot-delete或快照被 Cinder 自动清理如remove_snapshots_in_db配置增量链就断了。此时 Cinder 会拒绝增量请求返回BackupNotSupported。解决方案一推荐在策略中为关键卷禁用增量incremental: false。全量备份虽然耗时耗空间但 100% 可靠。方案二启用 Cinder 的backup_use_same_host配置需重启cinder-backup服务强制备份与卷在同一节点执行减少网络传输开销提升增量成功率。方案三在cinderback.py源码中找到create_backup函数在捕获BackupNotSupported异常后自动降级为全量备份并记录WARNING日志。这需要你修改源码但能实现真正的“智能降级”。3.5 现象cron时间不生效守护进程未在预期时间触发原因cinderback daemon使用APScheduler的CronTrigger它依赖系统本地时间system timezone。如果cinderback进程运行的服务器时区与clouds.yaml中 OpenStack 环境的时区不一致例如服务器是Asia/Shanghai而 OpenStack 的cinder.conf中default_timezone设为UTC会导致 cron 解析的时间点错位。解决统一时区将cinderback运行服务器的时区设为与 OpenStack 环境一致。在 Ubuntu 上sudo timedatectl set-timezone UTC sudo systemctl restart systemd-timesyncd验证 cron 解析在cinderback.py同目录下临时运行一个 Python 脚本from apscheduler.triggers.cron import CronTrigger from datetime import datetime trigger CronTrigger.from_crontab(0 * * * *) next_time trigger.get_next_fire_time(None, datetime.now()) print(Next fire time:, next_time) # 确认输出时间是否符合预期如果时间不对一定是时区问题。4. 策略即代码用 Git 版本控制备份规则与自动化 CI/CD 集成4.1 将 backup-policy.yaml 纳入 Git 仓库分支、评审与回滚把backup-policy.yaml当作核心基础设施代码来管理是提升备份可靠性的分水岭。我所在的某高校 OpenStack 实验室就将所有 Cinder 备份策略放在一个独立的openstack-backup-policiesGit 仓库中采用main生产、staging预发布、feature/*特性分支的三分支模型。main分支受保护禁止直接推送。所有变更必须通过 Pull RequestPR合并。PR 模板强制填写变更描述、影响范围如“影响所有 db-* 卷”、回滚步骤如“revert commit xxx 并重启 daemon”。自动化检查CI 流水线如 GitHub Actions在 PR 提交时自动执行# .github/workflows/policy-check.yml name: Policy Validation on: [pull_request] jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - name: Install dependencies run: pip install openstacksdk pyyaml - name: Dry-run policy run: python cinderback.py run-once --policy backup-policy.yaml --dry-run - name: Check YAML syntax run: python -c import yaml; yaml.safe_load(open(backup-policy.yaml))任何dry-run失败或 YAML 语法错误PR 将被阻止合并。这堵住了 80% 的低级错误如正则写错、缩进错误、字段名拼错。回滚当某次策略更新导致备份异常只需在 Git 中git revert commit-hash生成新的回滚 PR审批通过后自动部署。整个过程可审计、可追溯、无手工干预。4.2 与 OpenStack 部署流水线联动备份策略随环境自动注入在 Terraform 或 Ansible 部署 OpenStack 环境时cinderback 的配置不应是事后手工配置。我们采用“配置注入”模式在 Ansible Playbook 中将backup-policy.yaml模板化变量来自环境定义。# roles/cinderback/templates/backup-policy.j2 version: 1.0 global: cloud: {{ openstack_cloud_name }} backup_timeout: {{ backup_timeout_seconds }} rules: {% for vol_group in volume_groups %} - name: {{ vol_group.name }} volume_filter: {% if vol_group.type regex %} regex: {{ vol_group.pattern }} {% elif vol_group.type prefix %} prefix: {{ vol_group.prefix }} {% endif %} schedule: cron: {{ vol_group.cron_schedule }} retention: count: {{ vol_group.retention_count }} options: container: {{ vol_group.backup_container }} incremental: {{ vol_group.incremental | lower }} {% endfor %}部署时Ansible 根据group_vars/prod.yml中定义的volume_groups渲染出最终的backup-policy.yaml并推送到所有cinder-backup节点的/etc/cinderback/目录。随后执行# 重启守护进程加载新策略 systemctl restart cinderback-daemon这样当你用 Ansible 创建一个新的prod-db项目时只要在group_vars/prod.yml中加入volume_groups: - name: prod-db-volumes type: regex pattern: ^prod-db-[0-9]$ cron_schedule: 0 */2 * * * retention_count: 48 backup_container: cinder-backup-prod-db incremental: false新项目的备份策略就自动生效了。环境即代码备份即代码二者完全同步。4.3 审计与报告自动生成备份健康度日报cinderback 本身不提供报表但它的结构化日志和 API 可轻松对接监控体系。我们用一个简单的 Python 脚本backup-report.py每日凌晨 3 点运行生成 HTML 报告邮件#!/usr/bin/env python3 # backup-report.py import openstack from datetime import datetime, timedelta import smtplib from email.mime.text import MIMEText # 连接 OpenStack conn openstack.connect(cloudmyprod) # 查询过去 24 小时所有备份 end_time datetime.utcnow() start_time end_time - timedelta(hours24) backups conn.block_storage.backups( sort_keycreated_at, sort_dirdesc, created_at__gtestart_time.isoformat() Z, created_at__lteend_time.isoformat() Z ) # 统计 total 0 success 0 failed 0 for b in backups: total 1 if b.status available: success 1 elif b.status error: failed 1 # 生成 HTML 报告 html f h2Cinder 备份健康度日报 ({start_time.strftime(%Y-%m-%d %H:%M)} - {end_time.strftime(%Y-%m-%d %H:%M)})/h2 pstrong总任务数/strong{total}/p pstrong成功/strong{success} ({success/total*100:.1f}%)/p pstrong失败/strong{failed} ({failed/total*100:.1f}%)/p pstrong失败详情/strong/p ul for b in backups: if b.status error: html fli{b.id} (卷: {b.volume_id}) - {b.fail_reason or 未知错误}/li html /ul # 发送邮件 msg MIMEText(html, html) msg[Subject] fCinder Backup Report - {end_time.strftime(%Y-%m-%d)} msg[From] backup-monitorexample.com msg[To] ops-teamexample.com with smtplib.SMTP(localhost) as server: server.send_message(msg)这个脚本被加入 crontab成为团队每日晨会的第一份材料。它不追求炫酷图表只回答最核心的问题“昨天备份稳不稳”、“哪几个卷挂了”。从那以后我每次上线新策略都强制走一遍backup-report.py的本地调试确认它能正确解析我的策略并生成预期的统计口径。希望帮到你。本文还有配套的精品资源点击获取