使用systemd.timer定时执行Python脚本备份数据库和网站

7

写在前面

上一篇写了如何使用Arch搭建Lnmp环境,但是数据不够安全,这一篇教程使用Systemd.timer定时器定时执行备份脚本,并且使用钉钉机器人每天定时推送备份信息!

1、脚本编写

我已经参考网上写好了备份数据库和网站的代码,如下:

#!/usr/bin/env python
# coding=utf-8
# filename : backup_ver1.py

import datetime
import json
import os
import requests

if not os.path.exists('/srv/backup/mysqldb_backup/'):
    os.mkdir('/srv/backup/mysqldb_backup/')
os.chdir('/srv/backup/mysqldb_backup/')

today = datetime.date.today()
yesterday = today - datetime.timedelta(days=5)
# 数据库设置
mysql_today_file_name = "/srv/backup/mysqldb_backup/mysql-" + str(today) + ".sql"
mysql_yesterday_file_name = "/srv/backup/mysqldb_backup/mysql-" + str(yesterday) + ".sql"
# 执行mysql代码
mysql_response_code = os.system(
    "mysqldump -u blog -ppasswd blog > /srv/backup/mysqldb_backup/mysql-`date +%Y-%m-%d`.sql")

mysql_file_size = int(os.path.getsize(mysql_today_file_name)) / 1024

if mysql_response_code == 0:
    mysql_text = "#### Message:\n\n > - MySqlDB Backup Completed!\n\n > - SQL_file_size:" + str(
        round(mysql_file_size, 4)) + "KB\n\n"
    if os.path.exists(mysql_yesterday_file_name):
        os.remove(mysql_yesterday_file_name)
else:
    mysql_text = "#### Message:\n\n > - MySqlDB Backup Error!\n\n > - Please check the server program.\n\n"

# 网站目录备份
# 设置备份的目录
source = '/srv/http'

if not os.path.exists('/srv/backup/http_backup/'):
    os.mkdir('/srv/backup/http_backup/')
os.chdir('/srv/backup/http_backup/')

# 数据库设置
http_today_file_name = "/srv/backup/http_backup/http-" + str(today) + ".tar"
http_yesterday_file_name = "/srv/backup/http_backup/http-" + str(yesterday) + ".tar"

http_file_size = int(os.path.getsize(http_today_file_name)) / 1024**2
# print(tar_command)
if tar_command == 0:
    http_text = "#### Message:\n\n > - HTTP FILE Backup Completed!\n\n > - HTTP_file_size:" + str(
        round(http_file_size, 4)) + "MB"
    if os.path.exists(http_yesterday_file_name):
        os.remove(http_yesterday_file_name)
else:
    http_text = "#### Message:\n\n > - HTTP FILE Backup Error!\n\n > - Please check the server program."
#钉钉机器人api
dingding_url = "https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxx"
headers = {"Content-Type": "application/json; charset=utf-8"}

post_data = {
    "msgtype": "markdown",
    "markdown": {
        "title": "HTTP FILE Backup Message",
        "text": mysql_text + http_text
    }
}

info = requests.post(dingding_url, headers=headers, data=json.dumps(post_data))


自动备份数据库和网站,备份超过五次后自动删除最早的数据。
需要自己申请钉钉机器人,在钉钉网页版就可以申请。
参考:https://www.jianshu.com/p/3382cf349a4f

2、设置定时发布

定时器单元

Timers 是以 .timer 为后缀的 systemd 单元文件。Timers 和其他单元配置文件是类似的,它通过相同的路径加载,不同的是包含了 [Timer] 部分。 [Timer] 部分定义了何时以及如何激活定时事件。Timers 可以被定义成以下两种类型:

  1. 单调定时器 即从一个时间点过一段时间后激活定时任务。所有的单调计时器都遵循如下形式: OnTypeSec=OnBootSecOnActiveSec 是常用的单调定时器。
  2. 实时定时器 (亦称"挂钟定时器") 通过日历事件激活(类似于 cronjobs )定时任务。 使用 OnCalender= 来定义实时定时器。

服务单元

每个 .timer 文件所在目录都得有一个对应的 .service 文件(如 foo.timerfoo.service)。.timer 用于激活并控制 .service 文件。 .service 文件中不需要包含 [Install] 部分,因为这由 timer 单元接管。必要时通过在定时器的 [Timer] 部分指定 Unit= 选项来控制一个与定时器不同名的服务单元。

摘抄自:ArchLinuxWiki

简单来说就是需要先自己建立一个service,然后使用timer定时执行,下面是我的servicetimer代码:

vim /usr/lib/systemd/system/backup.service

[Unit]
Description=Backup http files and mariadb

[Service]
ExecStart=/bin/python /srv/scripts/backup_ver1.py
ExecReload=/bin/python /srv/scripts/backup_ver1.py


可以看到,这个 Service 单元文件分成两个部分。

[Unit]部分介绍本单元的基本信息(即元数据),Description字段给出这个单元的简单介绍(名字叫做Backup)。

[Service]部分用来定制行为,Systemd 提供许多字段。


ExecStart:systemctl start所要执行的命令
ExecStop:systemctl stop所要执行的命令
ExecReload:systemctl reload所要执行的命令
ExecStartPre:ExecStart之前自动执行的命令
ExecStartPost:ExecStart之后自动执行的命令
ExecStopPost:ExecStop之后自动执行的命令

Timer部分

Service 单元只是定义了如何执行任务,要定时执行这个 Service,还必须定义 Timer 单元。

timer代码:

vim /usr/lib/systemd/system/backup.timer

[Unit]
Description=Backup http files and mariadb

[Timer]
OnCalendar=*-*-* 02:00:00
Unit=backup.service

[Install]
WantedBy=multi-user.target

这个 Timer 单元文件分成几个部分。

[Unit]部分定义元数据。

[Timer]部分定制定时器。Systemd 提供以下一些字段。

OnActiveSec:定时器生效后,多少时间开始执行任务
OnBootSec:系统启动后,多少时间开始执行任务
OnStartupSec:Systemd 进程启动后,多少时间开始执行任务
OnUnitActiveSec:该单元上次执行后,等多少时间再次执行
OnUnitInactiveSec: 定时器上次关闭后多少时间,再次执行
OnCalendar:基于绝对时间,而不是相对时间执行
AccuracySec:如果因为各种原因,任务必须推迟执行,推迟的最大秒数,默认是60秒
Unit:真正要执行的任务,默认是同名的带有.service后缀的单元
Persistent:如果设置了该字段,即使定时器到时没有启动,也会自动执行相应的单元
WakeSystem:如果系统休眠,是否自动唤醒系统

上面的脚本里面,OnCalendar=*-*-* 02:00:00 表示每天凌晨两点执行一次任务。其他的写法还有OnUnitActiveSec=Mon *-*-* 02:00:00表示每周一凌晨两点执行。

[Install] 和 target

backup.timer文件里面,还有一个[Install]部分,定义开机自启动(systemctl enable)和关闭开机自启动(systemctl disable)这个单元时,所要执行的命令。

上面脚本中,[Install]部分只写了一个字段,即WantedBy=multi-user.target。它的意思是,如果执行了systemctl enable backup.timer(只要开机,定时器自动生效),那么该定时器归属于multi-user.target

所谓 Target 指的是一组相关进程,有点像 init 进程模式下面的启动级别。启动某个Target 的时候,属于这个 Target 的所有进程都会全部启动。

multi-user.target是一个最常用的 Target,意为多用户模式。也就是说,当系统以多用户模式启动时,就会一起启动backup.timer。它背后的操作其实很简单,执行systemctl enable backup.timer命令时,就会在multi-user.target.wants目录里面创建一个符号链接,指向backup.timer

定时器相关命令

systemctl start backup.timer  #启动定时器

systemctl status backup.timer #查看定时器状态

systemctl enable backup.timer  #设置开机自启

定时器的操作和service是一样的,不需要过多介绍。

参考链接: http://www.ruanyifeng.com/blog/2018/03/systemd-timer.html

效果图:

效果图