本文最后更新于 2024-11-09,文章内容可能已经过时。

Halo 备份和 S3 上传教程

环境要求

  • Python 3.x
  • boto3 库:用于与 S3 兼容服务交互
  • requests 库:用于发送 HTTP 请求

前提要求:如果你还没有安装alist或者任何s3服务的,你可以参考我的这篇文章(Alist/S3/阿里ossz制作随机图片api | 枫の屋 (6wd.cn))

注:如果你完成了alist的s3配置或者任何s3服务,您可以继续往下看了

最重要的,如果你的halo版本>=2.20请务必完成这一步操作!!

如果你是docker run启动,那么需要你在命令中间加一句

-e HALO_SECURITY_BASIC_AUTH_DISABLED=false

例:

docker run -d --name halo -p 8090:8090 -v ~/.halo2:/root/.halo2 -e HALO_SECURITY_BASIC_AUTH_DISABLED=false halohub/halo:2.20

2,如果你是docker-compose部署的,那么你需要在docker-compose.yaml中添加

    environment:
      - HALO_SECURITY_BASIC_AUTH_DISABLED=false

例:

version: "3"

services:
  halo:
    image: registry.fit2cloud.com/halo/halo:2.20
    restart: on-failure:3
    network_mode: "host"
    volumes:
      - ./halo2:/root/.halo2
    command:
      # 修改为自己已有的 MySQL 配置
      - --spring.r2dbc.url=r2dbc:pool:mysql://localhost:3306/halo
      - --spring.r2dbc.username=root
      - --spring.r2dbc.password=
      - --spring.sql.init.platform=mysql
      # 外部访问地址,请根据实际需要修改
      - --halo.external-url=http://localhost:8090/
      # 端口号 默认8090
      - --server.port=8090
# 额外启动脚本
    environment:
      - HALO_SECURITY_BASIC_AUTH_DISABLED=false

步骤一:安装依赖

使用以下命令安装所需的库:

pip install boto3 requests

步骤二:创建 Python 脚本

创建一个新的 Python 脚本(例如 backup_script.py),并将以下代码粘贴到文件中:

# 代码示例
import os
import base64
import time
import requests
import json
import boto3
from botocore.exceptions import NoCredentialsError, PartialCredentialsError
from datetime import datetime, timedelta  # 确保导入 timedelta
import logging

# 设置日志配置
log_file_path = '/www/wwwroot/Docker/halo/backup-auto/backup_log.txt' # 这个地方写你日志的路径
logging.basicConfig(filename=log_file_path, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Halo用户信息
user = "username"  # 替换为您的 Halo 用户名
password = "password"  # 替换为您的 Halo 密码

# 自定义 S3 兼容服务配置
aws_access_key_id = "aws-id"  # 替换为您的 AWS 访问密钥ID
aws_secret_access_key = "aws-key"  # 替换为您的 AWS 秘密访问密钥
aws_bucket_name = "bucket-name"  # 替换为您的 S3 存储桶名称
aws_region = "auto"  # S3 存储桶所在的 AWS 区域
endpoint_url = "http://ip:端口"  # 自定义的 S3 兼容服务的 endpoint(ip+端口/域名)

# 网站地址
website = "https://6wd.cn"  #halo域名地址
# halo备份文件夹路径
backup_halo_path = "~/halo/halo2/backups" #填写你的备份文件地址

# 设置有效期(天)
expiry_days = 3  # 可以设置为任何值,例如3天
expires_at = (datetime.utcnow() + timedelta(days=expiry_days)).strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'

# Halo API不变
backup_api = website + "/apis/migration.halo.run/v1alpha1/backups"
check_api = website + "/apis/migration.halo.run/v1alpha1/backups?sort=metadata.creationTimestamp%2Cdesc"

# 获取当前时间
now_time = datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
auth_header = "Basic " + base64.b64encode((user + ":" + password).encode()).decode()

payload = json.dumps({
    "apiVersion": "migration.halo.run/v1alpha1",
    "kind": "Backup",
    "metadata": {
        "generateName": "suki-backup-",
        "name": ""
    },
    "spec": {
        "expiresAt": expires_at,  # 设置有效期
    }
})
headers = {
    'Content-Type': 'application/json',
    'Authorization': auth_header,
}

# 发送备份请求
response = requests.post(backup_api, headers=headers, data=payload)
print(response.text)

if response.status_code == 201:
    print("备份请求成功!")
    while True:
        time.sleep(10)  # 等待10秒后再次检查状态
        check_response = requests.get(check_api, headers=headers)
        if check_response.status_code == 200:
            backup_data = json.loads(check_response.text)
            items = backup_data.get("items", [])
            if items and items[0]["status"]["phase"] == "SUCCEEDED":
                print("备份完成!")
                # 捕获带有时间戳的最新文件
                backup_files = [f for f in os.listdir(backup_halo_path) if f.endswith('.zip')]
                backup_files.sort(reverse=True)
                if backup_files:
                    new_backup_name = backup_files[0]
                    file_path = os.path.join(backup_halo_path, new_backup_name)
                    print(f"文件准备上传:{file_path}")
                    break
            elif items and items[0]["status"]["phase"] == "RUNNING":
                print("正在备份!")
        else:
            print(f"查询备份请求失败!错误代码:{check_response.status_code}")
else:
    print(f"备份请求失败!错误代码:{response.status_code}")

# 检查文件是否存在并上传到自定义 S3 兼容服务
if os.path.exists(file_path):
    def upload_to_s3(file_path):
        try:
            # 创建 S3 客户端
            s3_client = boto3.client(
                's3',
                aws_access_key_id=aws_access_key_id,
                aws_secret_access_key=aws_secret_access_key,
                endpoint_url=endpoint_url,
                region_name=aws_region
            )

            print(f"正在上传文件 {file_path} 到存储桶 {aws_bucket_name}...")
            # 使用 upload_file 方法上传整个文件
            s3_client.upload_file(file_path, aws_bucket_name, os.path.basename(file_path))
            print("上传完成!")
            return True

        except FileNotFoundError:
            print(f"文件不存在:{file_path}")
            return False
        except NoCredentialsError:
            print("AWS 凭证未找到,请检查配置。")
            return False
        except PartialCredentialsError:
            print("AWS 凭证不完整,请检查配置。")
            return False
        except Exception as e:
            print(f"上传过程中发生错误:{e}")
            return False

    # 尝试上传到自定义 S3 兼容服务
    upload_to_s3(file_path)
else:
    print(f"文件不存在:{file_path}")

步骤三:配置脚本

在脚本中,您需要输入以下信息:

  • Halo 用户名:在提示中输入您的 Halo 用户名。
  • Halo 密码:在提示中输入您的 Halo 密码。
  • AWS 访问密钥ID:在提示中输入您的 AWS 访问密钥ID。
  • AWS 秘密访问密钥:在提示中输入您的 AWS 秘密访问密钥。
  • S3 存储桶名称:输入您创建的 S3 存储桶名称。
  • 自定义 S3 兼容服务的 endpoint:输入您的 S3 服务的 endpoint (ip+端口/域名)。

步骤四:设置有效期

您可以在脚本中设置备份的有效期(以天为单位)。例如,将 expiry_days 设置为 3 表示有效期为 3 天。

expiry_days = 3  # 备份有效期(天)

步骤五:运行脚本

在终端中运行以下命令:

python3 /path/to/your/backup_script.py

步骤六:查看日志

所有输出信息将显示在终端中。确保检查 S3 存储桶,以确认文件是否上传成功。

步骤七:设置自动化

自动化一般使用宝塔的计划任务点击右上角的“添加任务”按钮,在“任务类型”中选择“Shell 脚本”或“Python 脚本”,在“任务内容”中输入以下命令:

python3 /www/wwwroot/Docker/halo/backup-auto/backup_script.py >> /www/wwwroot/Docker/halo/backup-auto/backup_log.txt 2>&1

这条命令会将脚本的标准输出和错误输出都重定向到 backup_log.txt 文件中。

在“定时”部分,选择您希望执行任务的频率(例如:每小时、每天等)。点击“提交”按钮,保存您的定时任务。

image-20240918050023067

可以手动运行一次任务,确保一切正常,并查看日志文件确认任务是否如预期执行。(不要着急!!!他会有几分钟延迟没有日志,这是脚本正在执行,请不要连续点击,否则服务器会炸掉

image-20240918050053173

如果在设置过程中遇到任何问题,或者有其他问题需要解决,请告诉我!

注意事项

  • 确保您的 AWS 凭证正确且具有上传权限。
  • 确保脚本能够访问指定的 S3 存储桶。