需求背景
最近公司国资委系统上线,珍贵的业务数据批量录入,此时面临一个问题,万一数据出问题咋办,这可是上百个国资企业录入的数据啊,真丢了哭都没地哭啊,数据库数据备份需求来了。
我们系统使用的docker进行各个应用及数据库管理,数据库数据文件挂载在服务器本地目录下,因此数据库备份可以简化下,只要把数据文件挂载目录备份就好了。计划写个shell脚本定时执行。
知识点
针对此次备份涉及的知识点有:
1.shell执行时实现交互,因为要输入密码(权限问题tar挂载目录时,需要sudo;tar包需要scp到另外的服务存储,需要用scp命令。都需要输入密码)
2.linux环境下设置定时任务
准备条件
1. shell交互命令我用到expect交互工具,此工具需要安装;安装及使用教程可以网上搜索,执行如下命令,返回如下表示安装成功
$ expect expect1.1>
查看命令引用目录(加粗部分):
$ whereis expect expect: /usr/bin/expect /usr/share/man/man1/expect.1.gz
此时我们就可以使用expect工具了。
2. 定时任务使用crontab,一般系统已默认安装,需要提前确认crond服务是否启动,执行命令systemctl status crond,返回如下表示定时任务服务运行中
$ systemctl status crond ● crond.service - Command Scheduler Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2021-06-29 19:49:09 CST; 4 months 6 days ago Process: 12679 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS) Main PID: 1389 (crond) Memory: 808.0K CGroup: /system.slice/crond.service └─1389 /usr/sbin/crond -n
编写脚本
1.以下是交互输入密码完成数据库文件压缩备份的脚本,/mysql目录是数据库挂载目录。注意密码中 含特殊符号$,前面需要加上转义符
#!/usr/bin/expect spawn sudo tar -zvcf /home/gridnt/mariadb-backup.tar.gz /mysql expect "*password for gridnt:" {send "123456$789 "} expect "*\$*" {send "exit "} expect eof
expect具体语法可以网上查询学习,expect后“”范围内的内容可以参考实际执行命令的返回信息,支持模糊匹配,用*号代指多个字符
参考《Centos expect spawn、linux expect 用法https://www.cnblogs.com/zhangmingcheng/p/7449776.html》网友的文章,至少我看明白了
此处遇到一个问题,我除了使用expect外,还需要使用bash解释器做一些变量定义等简单逻辑,如何将expect与bash脚本写到一个shell脚本中呐,该难题留到最后解决
2.linux环境设置定时任务
分别使用了以下两种方式
$ crontab -e 直接添加
1 * * * * /home/backup.sh
$ vi /etc/crontab 直接添加到最后一行 1 * * * * /home/backup.sh
但是都未生效。根据网上说的修改配置文件之后需要重新加载配置文件或者重启crond才能生效,实际只要修改了配置文件即可生效,无需使用systemctl reload crond加载。
多个环境尝试后发现定时任务未生效是非root用户进行设置导致的,解决方案如下,当前用户gridnt,每天1点执行脚本,注意以下黄色标记部分:
$ vi /etc/crontab SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=gridnt # For details see man 4 crontabs # Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat # | | | | | # * * * * * user-name command to be executed * 1 * * * gridnt /home/backup.sh
困难总结
1.编写shell脚本过程中发现一个问题,我大部分脚本是#!/bin/bash开头,表示使用bash解释器,但交互部分的脚本则需要#!/usr/bin/expect开头,表示使用expect工具解释脚本。如何将bash和expect两个解释器组合使用呐,这是我遇到的第一个难题
解决此问题用到一个知识点EOF。Shell中通常将EOF与 << 结合使用,表示后续的输入作为子命令或子Shell的输入,直到遇到EOF为止,再返回到主调Shell。合并后脚本如下(未包含scp)
#!/bin/bash DATE=$( date +%Y%m%d) set timeout 30 password='123456$789'
/usr/bin/expect <<-EOF
spawn sudo tar -zvcf /home/mariadb-backup_${DATE}.tar.gz /mysql
expect "*password for gridnt:" {send "${password} "}
expect "*\$*" {send "exit "}
expect eof
EOF
2.我的定时任务不生效,更换多个服务器对比发现,当root用下设置定时任务时,定时任务成功,但是自定义账号时则失败。如何设置非root账号的定时任务,这是我遇到的第二个难题
解决此问题,需要了解crontab的任务是有指定用户的;此外学会查看日志跟踪定时任务
$ tail -f /var/log/cron
Nov 4 01:00:01 sasac-001 CROND[31376]: (gridnt) CMD (/home/backup.sh)