Linux Incron 实时文件监控与 Rsync 实时文件同步

By | 最新修改:2024-08-17

前言

本文前面的部分介绍 Linux 实时文件同步的基础 Inotify 的概念,然后介绍基于 Inotify 文件事件的类似于 Cron 的 incron

再就是如何安装和使用 incron,最后结合 incronRsync 举个实时文件同步的例子。

本文要实现的目标

如果读者是 Linux 用户,你是否有把本地文件上传到远程服务器,或者本地复制到本地的需求,有时还要在文件改变时与目标立即进行同步的进一步需求?

如果有,那么就请阅读这篇文章。这篇文章将带你走进如何在 Linux 下进行实时的文件同步。

实时同步与基于时间间隔/定时的同步

一般地,Linux 使用者使用 Cron 按设定的时间进行脚本的定时执行,那些符合定时执行需求的场景中,这种定时执行是好吃的“甜甜圈”,正好方便了人们。

然而,如果你需要实时无差异地进行同步, Cron 就显得有些不够用了。比如在本地电脑上进行代码的开发,然后上传至远程服务器进行执行和调试;在这种情况下,实时更新远程目录就成为了新的需求。

实时的原理

Linux 下的实时文件监视依赖于一种内核子系统,该核心子系统名叫 Inotify

Inotify 基于文件的 inodes,区别文件是否改动,它关注文件 的 inode 的变化。

它不是一个成型的软件,而是一套 API(应用编程接口),它提供函数形式的接口。

应用程序用它来监视目录/文件的更改,被监视的文件一经改动,该 API 便会通知应用程序来做下一步的操作。

如何去处理这种通知,以及如何来做下一步的操作,由应用程序决定,或应用程序作为经纪,并由外部程序,如 Shell 脚本程序进行处理。 incron 就是这样的应用程序。

基于事件触发的 Inotify

Inotify 是在版本号为 2.6.13 的 Linux 内核中集成进去的,自此之后就成为 Linux 内核的一个核心子系统。

Inotify 以事件为触发条件来监控文件系统的改动。

这些事件包括不限于写入、元数据改变、重命名、读取、删除、创建等等。

检查系统内核是否支持 Inotify

  1. 方法一: 终端执行命令 ls /proc/sys/fs/inotify/,如果列出以下文件,则表示系统支持 Inotify:
    max_queued_events  max_user_instances  max_user_watches
    

    以上三个文件决定着系统中 Inotify 能监视文件的最大数目。具体的请关注下未来的文章。

  2. 方法二: 执行命令 grep INOTIFY_USER /boot/config-$(uname -r),如果显示以下的内容,则表示支持 Inotify“:

    CONFIG_INOTIFY_USER=y
    

Incron和Rsync的Logo

incron

incron 是一款行为类似于 Linux 下的计划程序 Cron 的应用程序,称为 “Inotify cron”。

它模仿 Cron 的实现,两者的表操作有极其相似的特点。

不同的是,Cron 基于时间点为触发条件,而 incron 以文件系统事件为触发条件,然后来执行其他应用程序,如 Shell 脚本。

incron 的概念

上文提到, incron 基于 Inotify,其核心以 Inotify 提供的 API 为监控文件系统改动的基础。

除此之外,具体什么是 incron?它有哪些行为?

incron 安装到 Linux 机器后,它就分为两大部分,每个部分各司其职。

其一是 incron 的守护进程 incrondincrond 负责监控文件系统的更改,
以及执行表定义的命令(包括应用程序,如 Shell 脚本或其他)。

其二就是定义和管理 incron 表的 incrontab

经过配置后, incrontab 中的每一行就是 incron 表的规则,表规则中设置有要监控的目录/文件、触发的文件系统事件,以及文件系统事件触发后要执行的应用程序。

至于如何定义表,请继续阅读后面内容。

Linux 安装 incron

Debian 系操作系统

sudo apt update
sudo apt install -y incron

Fedora 系操作系统

# 非 root 用户要添加 sudo
yum install -y incron
# 或
dnf install -y incron

Arch Linux

sudo pacman -S rsync

incrond 命令参数

在前台运行

-n--foreground:在前台运行 incrond

root 用户需要 sudo

这对测试、调试和优化起着重要的作用。

结束正在运行的守护进程实例

-k--kill:终止正在运行的守护进程的实例。

root 用户需要 sudo

指定守护进程配置文件的路径

-f <FILE>--config=<FILE>:指定配置文件的其他路径。

默认的配置文件位于 /etc/incron.conf

更多关于 incrond 的介绍,请阅读文档: man incrond

incron 的两种运行方式——前台运行和守护进程

在前台运行 incrond

只须运行:

# 在非 root 用户下
sudo incrond -n
# 或
sudo incrond --foreground
# 在 root 用户下可不用 sudo

在前台运行的时候,产生的标准错误输出将输出到屏幕上。

想要结束它,可以在其他终端执行 sudo incrond -k,或者直接 Ctrl c

基于 SystemD 的守护进程

一般情况下,系统通过安装软件包的方式安装的 incron 都带有 SystemD 的启动文件。

此时,只需要以下命令便可启动 incron 的守护进程:

sudo systemctl start incron.service
# 或者
sudo systemctl start incrond.service

查看启动状态:

systemctl status -l incron.service
或者:
systemctl status -l incrond.service

开机启动:

sudo systemctl enable incron.service
# 或者
sudo systemctl enable incrond.service

incron 表的两种类型

incron 的表根据创建者有两种类型,其中一个是系统创建的系统表,另一个是用户创建的用户表。

用户表包含 root 用户和其他用户。

系统表所指定运行的命令具有 root 用户的权限,而用户表具有其相应用户的权限。

并且,按照规定,用户表只能监控自身具有读权限的相应目录和文件。

用户表以用户名称为文件名,存放在 /var/spool/incron/ 目录路径下;而系统表存入于 /etc/incron.d/ 目录路径下。

要访问 /var/spool/incron/ 需要 root 用户或 sudo 权限。

incrontab

incrontabInotify cronincron)的表操纵器。它创建、删除、修改和列出用户表。

每个用户具有自己的表,任何给定的表中的命令将作为拥有该表的用户执行。

当表被修改时,或者守护进程启动时,incron 都会读取 incrontab 表,表与 incrond 进行挂钩。

incrontab 命令参数

incrontab 是操纵和管理 incron 表的命令行工具。

它结合一些命令行参数选项管理着所有用户表。

它有以下的命令行参数:

  1. -u--user:(仅能 root 用户使用)以该参数指定的用户执行以下的一些操作,如 -l-e 等。

    该选项主要用于操作系统用户的表:

    比如: nginx、www、postfix 等等。

  2. -l--list:列出当前用户的所有 incron 表规则。

    如果指定 -u 参数,则表示列出其指定用户的所有表规则。

  3. -r--remove:执行此参数将没有任何警告的情况下永久删除当前用户表。

  4. -e--edit:指定该参数将会用设定或默认的文本编辑器打开用户表并编辑之。

    它会用一个临时文件来编辑,保存文件后,更改后的文件内容会保存到 /var/spool/incron/username

    普通用户不用提权也可使用。

  5. -t--types:列出所有支持的事件类型,以英文逗号分隔。

  6. -d--reload:让守护进程重新加载当前表。

    由于旧表在修改后保存时守护进程会自动重新加载。

    所以该功能主要用于新建的表(可能是允许了新的用户),或者用于重置 IN_ONESHOT 事件。

  7. -f <FILE>--config=<FILE>:指定另一个位置的配置文件。此功能需要 root 权限。

更多关于 incrontab 的资料请阅读文档: man incrontab

incrontab 授权用户

incron 有两个文件来进行对用户使用的授权,一个是 /etc/incron.allow,另一个是 /etc/incron.deny

这两个文件不都是为“准入”而设计的,前者肯定是,但是后者是相反的,类似于黑名单,在它的列表中,如果出现了某个用户名,那么该用户将不能使用 incron

然而在前者列表中出现的用户,将被允许使用 incron

如果都删除了这两个文件,那么将允许所有的用户使用 incron。这是很不安全的做法!

这两个文件可被 root 用户,或者 sudo 的使用者编辑。

文件内容的格式是一行一个用户。

编辑 incrontab 表

使用 incrontab 命令的 -e 选项(incrontab -e)打开当前登录用户的 incron 表编辑器。

每行一个规则。

如果指定 -u 参数,那么编辑表命令就变成 incrontab -u username -e,不过这需要 root 用户。

incron 环境变量

incrond 的文档是这样写的:

对于系统表,使用默认(与 incrond 本身相同)环境变量集。这同样适用于 root 的表。

对于非 root 用户表,清除整个环境,然后只设置这些变量:LOGNAME、USER、USERNAME、SHELL、HOME 和 PATH。

变量(PATH 除外)从用户数据库(例如/etc/passwd)获取值。PATH 变量设置为 /usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin。

参考:https://linux.die.net/man/8/incrond

incron 表的规则

incron 表的规则离不开监视路径、文件事件和执行的命令。

incron 的文件事件

阅读本文到这里,相信大家都知道 incron 是靠文件系统事件驱动的了。

那么 incron 都有哪些事件呢?

incron 支持以下的事件(掩码符号):

  1. IN_ACCESS:文件被访问(打开)。
  2. IN_ATTRIB:文件元数据被更改(如权限、时间戳、扩展属性、用户 ID、用户组,等等)。

  3. IN_CLOSE_WRITE:文件以写的方式打开并且关闭。

  4. IN_CLOSE_NOWRITE:文件不以写的方式打开并且关闭。

  5. IN_CLOSE:以上两个条目的合并。

  6. IN_CREATE:在监视的目录中创建新的文件/目录。

  7. IN_DELETE:在监视的目录中删除文件/目录。

  8. IN_DELETE_SELF:监视的文件/目录自己被删除。

  9. IN_MODIFY:文件被修改。

  10. IN_MOVE_SELF:监视的文件/目录自己被移动。

  11. IN_MOVED_FROM:从监视的目录中移出目录/文件。

    当文件被重命名时,发生在包含老文件名称的目录上。

  12. IN_MOVED_TO:移动文件进入监视的目录。

    当文件被重命名时,发生在包含新文件名称的目录上。

  13. IN_MOVE:以上两者的合并。或者这可以理解为对文件的重命名触发的文件事件。

  14. IN_OPEN:文件被打开。

  15. IN_ALL_EVENTS:此符号定义为上述所有事件的位掩码。

  16. IN_DONT_FOLLOW:如果它是一个符号链接,不要取消引用路径名。

    更明白地解释就是不要追踪此符号链接指向的目标。

  17. IN_ONESHOT:仅能监视一次事件。

    在一次事件发生后,并且在重启或重置 incrond 之前将不再监视设置有该掩码的表规则。

  18. IN_ONLYDIR:如果它是一个目录,只监视路径名(不监视文件)。

  19. IN_NO_LOOP:该符号禁用监视事件,直到当前事件被完全处理(直到其子进程退出)。

    此掩码符号防止监视的事件发生无限循环。

    如果此事件无效,或者当前 incrontab 不支持它,那么就用 loopable=true 代替它。

    incrontab -t 列出所有当前系统中 incrond 支持的所有文件系统事件,如果 IN_NO_LOOP 不在其列表中,那么就表示不支持此事件。

    incrond 文档中写有:

    守护进程本身目前没有防止循环的保护。

    如果执行的命令是由于 一个事件会导致相同的事件,它会导致无限循环,除非标志掩码包含 指定了 loopable=true

  20. IN_IGNORED:监控项被移除。
  21. IN_ISDIR:触发事件的是一个目录。

  22. IN_Q_OVERFLOW:事件队列溢出。

  23. IN_UNMOUNT:监视的文件系统被卸载(unmount)。

incron 表的规则是怎样的

本文前面说了,所谓“表的规则”是 incron 表的一行。

表的一行规则包含要监视的目录或文件路径、incron 定义的事件掩码(符号或数字,多个以英文逗号分隔),以及处理事件触发后的处理程序。

简而言之,表的一行规则:

<路径> <掩码> <命令>

其中:

  1. “<路径>”是要监视的文件系统中目录或文件的绝对路径;
  2. “<掩码>”是在 Inotify 接口代码中定义的事件掩码;

    也是本文前面所述的事件掩码,它可以是掩码符号或者掩码数字;

  3. “<命令>”则是一个可执行文件的绝对路径或者在环境变量中指定的目录路径下的命令本身。

请不要试图在表定义的规则中将标准输出和错误输出到其他文件,因为这注定是徒劳的。

incron 的通配符

既然介绍了如何设置一条表规则,那么现在就举个使用通配符(其实就是特殊的 Shell 变量)的例子。

incron 有以下的变量可在表的规则中使用:

  • $$:美元符号;
  • $@:监视的文件系统路径;
  • $#:事件的相关文件名;
  • $%:事件掩码符号(是文本);
  • $&:事件掩码数字。

可将上面这些变量以参数形式传入到脚本中处理。

以下是示例:

表规则:

/code/php/htdocs IN_ALL_EVENTS /data/home/after-os-installation/rsync/test.sh $$ $@ $# $% $&

以下是脚本文件 /data/home/after-os-installation/rsync/test.sh 的内容(该文件要让当前用户可读):

echo "$1 $2 $3 $4 $5" >> ~/test.log

文件 ~/test.log 显示的结果:

$ /code/php/htdocs wp-load.php IN_OPEN 32

上面的示例中,/code/php/htdocs<路径>,路径后面一般不带斜杠; IN_ALL_EVENTS<掩码>
/data/home/after-os-installation/rsync/test.sh<命令>,后面紧接着的是要输入 <命令> 的参数。

查看日志

前面(章节《incron 表的规则是怎样的》)提到,不要尝试在表规则中进行标准输出错误输出,因为规则的运行效果通过系统日志输出。

在 Debian 系的 Linux 系统,是在 /var/log/syslog 这个文件中输出系统消息日志;红帽系(Fedora 等)在文件 /var/log/messages 输出日志。

若是想查看实时日志输出,可执行以下命令:

tail -f /var/log/syslog

举例:利用 incron 和 Rsync 进行实时文件备份

远程文件备份常见的工具

说到 Linux 下远程文件备份,大多数情况下会联想到 SCP、FTP、SFTP、Rsync 等众多的工具。前面这些工具中,有的可以增量备份,有的只能进行全量备份。

什么是全量备份

全量备份是每次备份都会把备份源的所有文件都复制到(远程)目标目录。

这样做的缺点是,如果要备份的文件太多,那么会导致整个备份过程耗时过久。

什么是增量备份

相对于全量备份,增量备份仅复制有变化的文件。

常见做法是,第一次备份进行全量备份,把源目录下(可能要经排除之后)的所有文件全部复制进(远程)目的目录;之后的备份就进行增量备份。

不一定所有的备份工具都有增量备份的功能。有的工具通过编写 Shell 脚本来“模拟”增量备份,而 Rsync 自身就有增量备份的功能(当使用 --delete 参数,再次执行同步时,源目录增删文件地在目标目录进行相同的操作)。

什么是 Rsync

Rsync,全称 remote sync,是一款远程和本地文件同步工具,同时,用它来进行本地与本地间备份也可。它使用一种算法通过仅移动已更改的文件部分来最小化复制的数据量,这也就是增量备份。

Rsync 通过 SSH 方式传输文件

Rsync 可通过 SSH 像 SCP 一样进行本地与远程的文件有加密地传输。

这种传输方式,优点是加密,缺点是不能指定上传到远程服务器的文件用户属主和属组,属主和属组默认为 SSH 上传的用户名。

举例:

rsync -av --delete /path/to/test/dir/  utest@test.com:/tmp

上述的 Rsync 命令把本地的路径为 test/dir/ 的目录通过 SSH 上传到域名为 test.com 的远程服务器上面的 /tmp 目录。

其中:

-a:表示目录递归上传,以及把路径为 test/dir/ 的目录下元数据有改动的文件都上传。

-v:表示显示文件传输的详细信息。若不指定该选项,则会进入静默模式,整个传输过程不会有任何的东西打印出来。

--delete:表示删除目标目录中有的而源目录没有的文件。

utest:这是 SSH 登录的用户名。

本章节的示例仅适合 SSH 端口为默认的 22,并且不需要密钥验证的场景下。

指定密钥文件

上一章节的示例简单完整地演示出如何利用 Rsync 通过 SSH 通道上传文件资料。

这一章节的示例设置了 SSH 的非默认端口,以及应用上 SSH 密钥传输。

举例:

rsync -av --delete -e "ssh -p 23123 -i ~/.ssh/id_rsa" /path/to/test/dir/  utest@test.com:/tmp

以上示例中:

-e:指定 SSH 的相关配置,其中包括: -p 指定 SSH 端口 23123-i 指定 SSH 登录用的私钥(私有密钥,公钥在远程服务器上)。

同步备份接收方文件的属主问题

Rsync 通过 SSH 通道上传到服务器的文件属主和属组均为此次 SSH 方式登录的用户名。

如果需要文件上传到服务器后赋予指定的属主和属组呢?

以上的这种需求可通过配置 Rsync 服务器端,并且使用 Rsync 协议来解决问题。

关于如何配置 Rsync 服务器端请参阅:Linux 下 Rsync 文件同步与增量备份

结合 Rsync 和 incron 来实时同步文件

本章节讲解如何结合 Rsyncincron 远程实时同步文件数据。

首先要有个源目录/文件

这时里要同步到远程的是一个目录,其目录路径是: /path/to/test/dir/

然后设置要监视的文件事件

IN_CREATE,IN_DELETE,IN_CLOSE_WRITE,IN_MOVE

它们分别触发的事件是:创建新的文件、删除文件、写入并关闭文件和重命名文件/目录。

创建文件事件触发后要执行的脚本

把下面的命令写入一个当前系统登录用户可读的地方,这里 Shell 脚本的路径是:/home/username/remote-utest.sh

该脚本文件的内容是:

#!/bin/sh
# 这里要求 SSH 密钥不能有密码,否则就无法同步
# 密钥不能有密码,也就是生成密钥时设置为空密码。
rsync -av --delete -e "ssh -p 23123 -i ~/.ssh/id_rsa_no_passwd" /path/to/test/dir/ utest@test.com:/tmp

应用当前用户下的 incron 表来设置实时同步

执行 incrontab -e 打开 incrontab 表的配置文件,然后添加以下一行:

/path/to/test/dir IN_CREATE,IN_DELETE,IN_CLOSE_WRITE,IN_MOVE /home/username/remote-utest.sh

保存文件,然后退出。

就这样简单几个步骤就把 incron 结合 Rsync 进行实时文件同步配置好了。

/path/to/test/dir 目录下做一些操作,如添加文件、修改文件、删除文件、重命名文件等等,同时,远程都会有相应的文件变化。

后记

本文详述了如何在 Linux 下进行实时的文件同步。在多个章节中,
详细介绍了什么是 Inotifyincronincrondincrontab 和文件事件(掩码)等等实时同步的必要基础知识。

文章的后面还介绍了基于 SSH 的 Rsync 文件传输,
同时也通过 Rsync 示例说明如何在不使用 SSH 默认端口和使用 SSH 密钥的方式登录 SSH 通道来传输文件数据。

在文章的最后,举了个 Rsyncincron 配合的实例来验证文件的实时同步。

由于篇幅原因,还有许多的内容不能全部一一列举出来,还望见谅!

在后续的篇章中,可能还会继续有关于 Rsyncincron 的文章发布出来。

请关注一下网站和微信公众号获取最新文章。



程序知路

鉴于本人的相关知识储备以及能力有限,本博客的观点和描述如有错漏或是有考虑不周到的地方还请多多包涵,欢迎互相探讨,一起学习,共同进步。

本文章可以转载,但是需要说明来源出处!

本文使用的部分图片来源于网上,若是侵权,请与本文作者联系删除: admin@icxzl.com