起因

前段时间被封了一个圣何塞的甲骨文云账号,上面我开了一个 4C 24G 的 ARM 实例,跑了很多东西,几乎所有以 dijk.eu.org 结尾的域名都在上面跑着。

当然,就包括博客的图片服务器。

这下好了,博客的图片全都挂了。

然后我把博客的图片服务器指定成了家里的服务器。优点是国内访问的速度快,缺点是家里的服务器不稳定。

所以,一个自然的需求就是监控家里的服务器,看看它是否在线。

但是,如果监控服务器的服务器本身都不够稳定,那监控就失去意义了。(没错,我说的就是白嫖的服务器。)

又免费,又相对稳定的服务,我熟悉的就只有 GitHub Actions 了。

效果图效果图

https://wang-guangxin.github.io/sites

代码

想要无限制的使用 GitHub Actions, 你需要一个公开的仓库。

所以我不得不把这套方案公开,尽管它实际上无比丑陋。

https://github.com/WANG-Guangxin/wang-guangxin.github.io

整体结构

这个图其实已经描述的比较清楚了,GitHub Actions 负责执行定时任务,然后 Shell 脚本负责执行 hexo 命令来生成静态页面,Python 脚本负责检查网站是否在线,然后根据结果来生成 Markdown 文件,以提供给 Hexo 来渲染。

下面就一一介绍这三部分。

GitHub Actions

https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/.github/workflows/main.yml


name: Deploy Hexo Site

on:
  push:
    branches:
      - master # Set a branch to trigger deployment
  schedule:
    - cron: '*/15 * * * *' # 每 15 分钟执行一次
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v2
      with:
        # This depth parameter is optional - fetching the full history can improve the accuracy of the GH Pages deployment action's change detection.
        # However, it can also increase the time required for the checkout step to complete.
        fetch-depth: 0

    - name: Use Node.js
      uses: actions/setup-node@v2
      with:
        node-version: '18' # Specify your Node.js version here

    - name: Install Dependencies
      run: npm install

    - name: Install Hexo
      run: npm install -g hexo-cli

    - name: Build-0
      run: bash ./build.sh
      env:
        notice_host_server: ${{ secrets.notice_host_server }}
        notice_user: ${{ secrets.notice_user }}
        notice_pwd: ${{ secrets.notice_pwd }}
        notice_mail: ${{ secrets.notice_mail }}
        notice_receiver: ${{ secrets.notice_receiver }}

    - name: Deploying-0
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: ./public

    - name: Build-1
      run: sleep 300 && bash ./build.sh
      env:
        notice_host_server: ${{ secrets.notice_host_server }}
        notice_user: ${{ secrets.notice_user }}
        notice_pwd: ${{ secrets.notice_pwd }}
        notice_mail: ${{ secrets.notice_mail }}
        notice_receiver: ${{ secrets.notice_receiver }}

    - name: Deploying-1
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: ./public

    - name: Build-2
      run: sleep 300 && bash ./build.sh
      env:
        notice_host_server: ${{ secrets.notice_host_server }}
        notice_user: ${{ secrets.notice_user }}
        notice_pwd: ${{ secrets.notice_pwd }}
        notice_mail: ${{ secrets.notice_mail }}
        notice_receiver: ${{ secrets.notice_receiver }}

    - name: Deploying-2
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: ./public

    - name: Commit changes
      uses: stefanzweifel/git-auto-commit-action@v4
      with:
        commit_message: Auto Commit
        branch: ${{ github.head_ref }}
        file_pattern: |
          data.csv
          siteenv        

简单解释一下,为什么这个定时任务设置的是每 15 分钟执行一次,而不是每 5 分钟执行一次。

这是因为 GitHub Actions 的定时任务执行时间不准确,基本都会又延迟,如果设置的是每 5 分钟执行一次,那么实际上会有很多次执行是在 5 分钟之后的,甚至 10 分钟之后的。

另外,在 Actions 的条款里,对每次 Actions 的执行时长限制是 30 分钟。

为了遵守条款的同时让这个监控更加稳定,我采取的方案是每 15 分钟执行一次 Actions,但每次 Actions 会部署 3 次 Hexo 网站,每次间隔 5 分钟,这样操作相对来说执行频率更高一些。

负责生成 Hexo 网站的脚本是 build.sh,这里接收了 5 个环境变量,用于配置邮件通知。

- name: Build-0
  run: bash ./build.sh
  env:
    notice_host_server: ${{ secrets.notice_host_server }}
    notice_user: ${{ secrets.notice_user }}
    notice_pwd: ${{ secrets.notice_pwd }}
    notice_mail: ${{ secrets.notice_mail }}
    notice_receiver: ${{ secrets.notice_receiver }}

Shell 脚本

https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/build.sh

hexo clean # 清理 Hexo 缓存
python3 -m pip install --upgrade pip # 更新 pip
pip install -r requirements.txt # 安装 Python 依赖
python3 uptime.py # 执行 Python 脚本 -- 检查网站是否在线 -- 生成 siteenv 文件
source siteenv # 加载 siteenv 文件
cat siteenv # 打印 siteenv 文件
envsubst < "./template_index.md" > "./source/sites/index.md" # 替换模板文件中的变量
cat ./source/sites/index.md # 打印生成的 Markdown 文件
hexo generate # 生成 Hexo 网站

解释一下 envsubst 这个命令,它的作用是替换模板文件中的变量。

https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/template_index.md

模板 template_index.md 文件中有很多shell变量,这些变量会在 siteenv 文件中被定义。

执行 envsubst < "./template_index.md" > "./source/sites/index.md" 这个命令,就会把 template_index.md 文件中的变量替换成 siteenv 文件中的变量的值,然后生成 index.md 文件。

siteenv 文件的内容由 Python 脚本生成。

https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/siteenv

Python 脚本

https://github.com/WANG-Guangxin/wang-guangxin.github.io/blob/master/uptime.py

这里是整个 Uptime 监控的核心代码了。

全局变量总共四个,分别是 g_config, g_data_file, g_data_list, g_notice_enable


g_config = {
    "https://wgxls.site": 
    {
        "status": "STATUS_WGXLS_SITE='",
        "uptime7d": "WGXLS_SITE_UP_7='",
        "uptime24h": "WGXLS_SITE_UP_24='",
        "ssl": "WGXLS_SITE_SSL='",
    },
    "https://opengrok.dijk.eu.org":
    {
        "status": "STATUS_OPENGROK_DIJK_EU_ORG='",
        "uptime7d": "OPENGROK_DIJK_EU_ORG_UP_7='",
        "uptime24h": "OPENGROK_DIJK_EU_ORG_UP_24='",
        "ssl": "OPENGROK_DIJK_EU_ORG_SSL='"
    }
}

g_data_file = 'data.csv'
g_data_list = []
g_data_list.append([])
g_notice_enable = True

g_config 是一个字典,存储了需要监控的网站的信息。这里面的 key 是网站的域名,value 是一个字典,存储了网站的状态、7 天的在线时间、24 小时的在线时间、是否启用 SSL。

它的Value的value是一个字符串,这个字符串是为了生成一个可以被 Linux Shell 执行 source 的文件。

g_config 是需要和 template_index.md 文件中的变量对应的。

g_data_file 是一个文件名,用于把监控的数据持久化到磁盘,这样我每一执行 Python 脚本时从 g_data_file 中读取以往的数据,来计算 7 天的在线时间和 24 小时的在线时间。

g_data_list 是一个列表,用于在内存中存储监控的数据。

g_notice_enable 是一个布尔值,用于控制是否发送邮件通知。

监控的逻辑被我写成了一个纯面向过程的逻辑。

def main():
    read_csv_to_list() # 读取 data.csv 文件到 g_data_list
    remove_data_before_seven_days() # 删除 7 天之前的数据 
    for key, value in g_config.items(): # 遍历 g_config
        check_url(key) # 检查网站是否在线 数据存储在 g_data_list 同时更新 g_config
    calc_uptime() # 根据 g_data_list 计算 7 天的在线时间和 24 小时的在线时间 同时更新 g_config
    write_list_to_csv() # 把 g_data_list 写入 data.csv
    write_env() # 根据 g_config 生成 siteenv 文件
    if g_notice_enable: # 如果 g_notice_enable 为 True
        do_notice() # 发送邮件通知

网站状态发生改变的话,会发送邮件通知。

有兴趣的话可以看看完整的代码。

Star 一下也行