推荐一个定时备份数据库的脚本

在线上数据库,为了保证数据安全,我们经常要做一些定时的数据备份。这个过程既繁琐又枯燥,我花了几天时间整理了一个备份脚本,并在生产环境测试并使用。

项目地址:https://github.com/aim-leo/db-auto-backup
如果你喜欢,请给我一个star,如有issue,请提交给我。

db-backup说明文档

特性

  • 支持mysql和mongodb数据库
  • 支持本地和Docker容器内的数据导出
  • 使用ubuntu自带的crontab循环调用达到定时备份
  • 可配置远程git地址,定时上传到远程服务器
  • 支持tar压缩
  • 可配置最大备份数,定时清理最旧的备份
  • 可导入yaml配置文件

备份脚本 db-backup.sh

示例

// 将本地的mongodb数据库的test实例导出到/tmp/test-db-backup下
bash db-backup.sh -d test -o /tmp/test-db-backup


// 从名称为mysql的docker容器内导出test数据库.并压缩,到当前目录
bash db-backup.sh -d test -t mysql -z

// 使用yaml文件配置导出mysql下test数据库,并上传到对应的git
bash db-backup.sh -f example.yaml

// example.ymal
database:
  type: mysql
  name: test
  user: root
  pwd: 123456-abc
docker_container: mysql  // mysql在docker容器中,容器名是mysql
output_dir: /tmp/test-db-backup
max_file: 30    // 超过30个备份自动删除最开始的备份
push2git: true  // 上传到git
gzip: true   // 用tar压缩成.tar.gz文件
git:
  remote: git@github/***/***.git  // 你的git地址,需要在远程git上新建项目
  branch: master

所有参数

 Usage:
     bash db-backup.sh -d [database] -o [output_dir] ...
   
   Database options: (recommand define it at yaml)
     -d | --database_name [name]                Input the database you want to dump(required)
     -t | --database_type [type]                Input the database type, enum: [mysql, mongo]
     -h | --database_host [host]                Input the database host, defalut localhost
     -p | --database_port [port]                Input the database port, defalut { mysql: 3306, mongodb: 27017 }
     -u | --database_user [user]                Input the database user, mysql is required, mongo is optional
     -s | --database_pwd  [pwd]                 Input the database pwd, mysql is required, mongo is optional
   
   Git options: (recommand define it at yaml, required when push2git set true)
     -e | --git_user_name [name]                Input the git user name, required when use http protocol
     -w | --git_user_pwd [pwd]                  Input the git user pwd, required when use http protocol
     -i | --git_user_email [email]              Input the git user email, required when use http protocol
     -r | --git_remote [remote]                 Input the git remote, accept http | ssh protocol
     -b | --git_branch [branch]                 Input the git branch, default master
   
   Optional options:
     -o | --output_dir [output_dir]             Input the dir you want to output the file, defalut current path
     -f | --config_yaml [config_yaml]           Input the yaml path contain your config, defalut at output_dir/backup.yaml
     -n | --file_name [filename]                Input the filename, default DATABASE_db_TIME
     -l | --log_dir [log_dir]                   Input the dir you want to output the log, defalut /tmp/db-backup
     -c | --docker_container [container]        If your database is runing at docker, Input the container ID or name here
     -m | --max_file [max_file]                 Expect a Number, if backup file overflow, it will auto remove the oldest file
     -g | --push2git                            Whether to auto add && commit && push to git, default false
     -z | --gzip                                Whether to gzip the dir, default false
   
   Auxiliary options:
     -h | --help                                Get help
     -v | --version                             Get current version

-o | --output_dir [output_dir]

  • 作用: 指定要导出文件的路径
  • 必填: 使用cron自动备份时必填一个绝对路径,且确保该目录可写
  • 默认: 当手动调用时,未指定则为当前调用脚本的路径

-f | --config_yaml [config_yaml]

  • 作用: 指定yaml配置文件, 推荐使用yaml配置的方式而不是逐个指定
  • 必填: 非必填,但当未使用-d --database_name时,需要指定一个yaml文件,且需要包含database_name的配置
  • 默认: 如果未指定,脚本会在导出目录下匹配backup.yaml文件,如果找到将导入该配置

-n | --file_name [filename]

  • 作用: 指定导出的文件名,当使用cron定时备份时不推荐指定该项
  • 必填: 非必填, 且不推荐填写
  • 默认: {DATABASE_NAME}_db_{TIME} 默认是包含数据库明和时间的字串

-l | --log_dir [log_dir]

  • 作用: 指定日志路径
  • 必填: 非必填
  • 默认: 默认在/tmp/db-backup下创建一个以当天日期命名的log文件,但是当该配置未读取前,日志将会输出在/tmp/db-backup/tmp.log下

-c | --docker_container [container]

  • 作用: 当数据库运行在docker容器里时,在这里指定容器的name或者id
  • 必填: 非必填,当不填是默认连接本地数据库

-m | --max_file [max_file]

  • 作用: 指定导出文件的最多数量,脚本会按照文件名称排序,当目录下的文件大于该值,会自动删除一定数量的文件,这也是为什么不推荐自定义导出的文件名的原因,因为要用于排序,确保程序删除的是最老的备份
  • 必填: 非必填,当不填写时文件数目无限制

-g | --push2git

  • 作用: 是否自动备份到git
  • 默认: false

-z | --gzip

  • 作用: 是否使用tar来压缩文件,当指定该参数,文件将会压缩成NAME.tar.gz, 解压缩时,请使用 tar -zxvPf NAME.tar.gz
  • 默认: false

-h | --help

  • 作用: 获取帮助

-v | --version

  • 作用: 获取当前版本

数据库相关

-d | --database_name [name]

  • 作用: 指定要备份的数据库
  • 必填: true(如果在yaml中指定了可不填)

-t | --database_type [type]

  • 作用: 指定要备份的数据库类型
  • 可选值: mongo mysql
  • 必填: false
  • 默认值: mongo

-h | --database_host [host]

  • 作用: 指定要备份的数据库地址
  • 必填: false
  • 默认值: localhost

-p | --database_port [port]

  • 作用: 指定要备份的数据库端口
  • 必填: false
  • 默认值: mysql: 3306 mongo: 27017

-u | --database_user [user]

  • 作用: 指定要备份的数据库用户名
  • 必填: 当备份mysql数据库时必填

-s | --database_pwd [pwd]

  • 作用: 指定要备份的数据库密码
  • 必填: 当备份mysql数据库时必填

GIT相关

当指定参数-g,或者--push2git时,脚本会把备份后的文件传到指定的git地址,此时需要指定以下参数

注意, 当使用cron自动运行此脚本时, git无法获取到当前的ssh-keygen,而手动运行脚本时则正常,这是因为cron是以root用户身份运行脚本,而ssh-key保存在当前用户(可能不是root)下,
此时备份会失败,可选的解决办法有:

  • 在脚本中指定用户的用户名 密码 邮箱
  • 在root下生成ssk-keygen,并添加到git服务器

-e | --git_user_name [name]

  • 作用: 指定git用户名
  • 必填: 当使用https协议时必填

-w | --git_user_pwd [pwd]

  • 作用: 指定git密码
  • 必填: 当使用https协议时必填

-i | --git_user_email [email]

  • 作用: 指定git邮箱
  • 必填: 当使用https协议时必填

-r | --git_remote [remote]

  • 作用: 指定git地址
  • 必填: 开启备份时必填

-b | --git_branch [branch]

  • 作用: 指定git分支
  • 默认值: master

挂载自动备份 add-schedule.sh

用法

sudo bash add-schedule.sh [yaml_path] [cron_time_config]

我们使用cron来运行定时任务,该程序在ubuntu下默认安装

该脚本提供简单的方法来挂在定时任务,你也可以手动添加脚本到/etc/crontab下,使用sudo vim /etc/crontab

确保使用sudo运行该脚本, 每个yaml只能在crontab中同时注册一次,当该yaml文件已注册时,会自动覆盖之前的配置

yaml_path
  • 作用: 指定备份的yaml配置文件
  • 必填: true
cron_time_config
  • 作用: 指定调用脚本的时间配置
  • 必填: false
  • 默认: 5 * * * *" 每个小时的第5分钟调用一次,你可以指定其他的配置,参考cron配置,请确保使用""包裹该字串

挂载自动备份 delete-schedule.sh

用法

删除已注册在crontab下的yaml配置

sudo bash delete-schedule.sh [yaml_path]

配置文件示例 example.yaml

database:
  type: mysql
  name: <database>
  user: <name>
  pwd: <pwd>
docker_container: mysql
output_dir: /home/<database>-db-backup
max_file: 30
push2git: false
gzip: true
git:
  user:
    name: <name>
    email: ***@gmail.com
    pwd: <pwd>
  remote: git@github/***/***.git
  branch: master

常见问题

为什么我配置了git,文件也正常导出了,但是不能自动提交?

通常的原因是无法获取到git配置,查看log, 最后的输出一般停在Begin push to origin/master

当使用cron自动运行此脚本时, git无法获取到当前的ssh-keygen,而手动运行脚本时则正常,这是因为cron是以root用户身份运行脚本,而ssh-key保存在当前用户(可能不是root)下,
此时备份会失败,可选的解决办法有:

在脚本中指定用户的用户名 密码 邮箱

// 在yaml中指定这部分:
git:
  user:
    name: <name>
    email: ***@gmail.com
    pwd: <pwd>
  remote: https://github/***/***.git (必须是https协议的git地址)

或者
在root下生成ssk-keygen,并添加到git服务器

// 以root当时登录,确保cron可访问到ssh-key
sudo su

ssh-keygen -t rsa -C "***@gmail.com"

然后将/root/.ssh/id_rsa.pub的内容添加到你的git服务器的ssh-key列表, 参考connect github with ssh

当我配置output_dir为/home/mysql-db-backup, 但我的git项目名是mysql-db-backup2时,实际导出目录是什么?

output_dir指定的就是最终导出目录,不管git的项目名称是什么,最后导出的目录就是配置目录

在脚本首次运行时,如果output_dir不存在,则会新建它,如果配置了git,则会首先拉取该项目,然后再导出文件

使用的导出方法是

git clone $GIT_REMOTE $OUTPUT_DIR

所以最后导出的路径是mysql-db-backup

当我使用tar -zxvf $NAME.tar.gz时,为什么会解压失败?

请使用tar -zxvPf $NAME.tar.gz来解压文件

为什么我指定了log_dir,但是某些输出没有写到该文件夹下?

在脚本未读取到配置的log_dir前, 输出的内容将被写到/tmp/db-backup/tmp.log下

我指定了max_file,到文件数量超过之后,为什么脚本并没有删除最原始的备份?

请检查是否错误指定了file_name,因为脚本默认以时间命名文件,默认以文件名排序,当文件名不统一时,排序将会混乱,请使用默认命名

当我把多个数据库备份到同一个文件夹会怎么样?

理论上是支持的, 但是不推荐这么做, 最好是一个数据库一个导出文件夹,一个git地址

为什么我在导出的目录下运行git命令,会报权限错误?

cron默认用root用户来运行命令, 当首次运行时, 程序拉取了远程分支的文件, 则该目录的权限为最高,普通用户无法操作,请使用sudo来运行

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,194评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,058评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,780评论 0 346
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,388评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,430评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,764评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,907评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,679评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,122评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,459评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,605评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,270评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,867评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,734评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,961评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,297评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,472评论 2 348

推荐阅读更多精彩内容