如何使基于rclone sync的Puppet代码实现幂等性,仅在S3同步的压缩包变更时执行解压与Docker镜像加载操作?
看起来你遇到的核心问题是:Puppet里的rclone sync Exec资源每次都会执行(哪怕文件没变化),导致后续的解压和Docker加载操作也被不必要地触发。要解决这个问题,我们需要从两个方向入手:让rclone同步仅在文件真的需要更新时执行,以及让后续操作仅在压缩包确实变更时才触发。
1. 先让rclone同步的Exec具备真正的幂等性
默认情况下,Puppet的Exec资源只要没有onlyif/unless/creates这类条件,每次都会执行。而rclone sync本身是幂等的,但我们需要告诉Puppet:只有当源文件和本地文件不一致时,才运行sync命令。
可以用rclone check来做前置检查,把它加到Exec的unless参数里:
exec { "fetch_${file[s3_filename]}_from_${file[s3_bucket_name]}": user => "bolt", command => "/usr/bin/rclone sync --ignore-checksum --config /usr/local/etc/rclone/${file[s3_bucket_name]}.conf ${file[s3_bucket_name]}:${file[s3_bucket_name]}/${file[s3_path]}/${file[s3_filename]} /tmp/rclone", # 只有当rclone check检测到文件不一致时,才执行sync unless => "/usr/bin/rclone check --config /usr/local/etc/rclone/${file[s3_bucket_name]}.conf ${file[s3_bucket_name]}:${file[s3_bucket_name]}/${file[s3_path]}/${file[s3_filename]} /tmp/rclone/${file[s3_filename]}", }
这样,当S3上的文件和本地文件完全一致时,rclone check会返回0,Exec就会跳过执行,不会触发后续的资源刷新。
2. 让解压操作仅在压缩包变更时触发
你之前尝试的subscribe+refreshonly思路是对的,但需要调整File资源的配置,确保它能准确检测到文件内容的变化,从而触发后续的解压操作。
首先,修改设置权限的File资源,明确让它检测文件内容的MD5变化:
-> file { "${file[s3_filename]}": path => "/tmp/rclone/${file[s3_filename]}", mode => '0700', owner => "bolt", group => "bolt", checksum => md5, # 强制Puppet检查文件内容的MD5,而不只是权限/所有者 }
然后调整解压的Exec资源,去掉creates(因为旧的解压文件存在会阻止新的解压,即使压缩包已经更新),改用subscribe监听File资源的变化,并且设置refreshonly => true:
-> exec { "decompress_${file[s3_filename]}": command => "/usr/bin/tar xzf /tmp/rclone/${file[s3_filename]}", cwd => "/tmp/rclone", subscribe => File["${file[s3_filename]}"], refreshonly => true, # 只有当订阅的File资源发生变化时,才执行这个命令 }
3. 让Docker镜像加载也具备幂等性
最后,为了避免重复加载同一个镜像,可以给load_docker_image的Exec加上unless条件,检查目标镜像是否已经存在。如果你的镜像有固定标签,可以直接检查标签;如果标签不固定,可以从tar包的manifest文件中提取镜像信息:
-> exec { "load_docker_image_${file[s3_filename]}": command => "/usr/bin/docker load -i /tmp/rclone/test.tar", require => [ Exec["check_md5_${file[s3_filename]}"], Exec["decompress_${file[s3_filename]}"], ], # 示例:从tar包的manifest中提取镜像标签,检查是否已存在 unless => "/usr/bin/docker inspect $(/usr/bin/tar xfO /tmp/rclone/test.tar manifest.json | /usr/bin/jq -r '.[0].RepoTags[0]') > /dev/null 2>&1", }
整合后的完整流程
现在整个流程的逻辑是:
- 先检查S3文件和本地文件是否一致,不一致才执行rclone sync
- 同步完成后,修正文件权限,同时检测文件内容变化
- 只有当文件内容真的变化时,才执行解压操作
- 解压完成后,检查镜像是否已存在,不存在才加载
这样就能完全实现幂等性:只有当S3上的压缩包真的更新时,后续的解压和镜像加载操作才会运行,否则所有步骤都会跳过。
备注:内容来源于stack exchange,提问作者ARTE

