一、前置知识
CI\CD 即:持续集成(Continuous Integration)、持续交付(Continuous Delivery)、持续部署(Continuous Deployment)。GitHub Actions 是一个持续集成和持续交付 (CI/CD) 平台,可用于自动执行构建、测试和部署管道,换句话说就是通过Actions帮助我们去执行hexo s & hexo g & hexo d的操作并推到xxx.github.io仓库中
二、参考教程
最近看了店长的自动化部署方案,感觉真不错,本地hexo g渲染比较慢,通过git push触发Github Actions执行渲染并推送到站点中,以下是看到过的一些教程,我主要借鉴了黑石的方案来实现我自己的需求,大家可以选择适合自己需求的方案
| 常量 | 解释 |
|---|
| [Blogroot] | 本地存放博客源码的文件夹路径 |
| [SourceRepo] | 存放博客源码的私有仓库名 |
| [SiteBlogRepo] | 存放编译好的博客页面的公有仓库名 Site指站点,例如xxx.github.io仓库 |
| [Github Actions执行自动化部署] | 执行hexo clean & hexo g & hexo d |
三、解决方案
方案二是方案一的补充,方案一的所有设置都要做一遍
4.1、方案一(弃用)
首先明确我的需求:本地[Blogroot]push到[SourceRepo]触发Github Ations执行自动化部署到[GithubBlogRepo]、[服务器站点]
申请令牌
工作流也相当于一个虚拟机,token作用是在虚拟机上执行push操作,类似于通过给电脑和GitHub配置公私钥实现每次push时不需要输入密码
Settings->Developer->Personal access tokens->Generate new token

生成的令牌只会显示一次,记住令牌,如果忘记保存就删了重弄

更改博客配置文件
deploy: - - type: git - repository: - github: https://github.com/xxx/xxx.xxx.io.git,main - tecent: xxxu@xxx.xx.xxx.xxx:/xxx/hexo.git,master - #branch: main
deploy: + - type: git + repository: https://填写自己的token@github.com/GC-ZF/GC-ZF.github.io.git + branch: main
|
新建仓库并上传
新建一个Github 私有仓库(必须私有,如果公有,上传仓库后,会触发GitHub规则token自动失效)
在博客根路径下,找到主题文件[Blogroot]\themes\butterfly,将**.git**移出来
在博客根路径下的.gitignore加入忽略规则
.DS_Store Thumbs.db db.json *.log node_modules/ public/ .deploy*/ .vscode/ /.idea/ .deploy_git*/ .idea themes/butterfly/.git
|
在博客根路径下执行
git init git add . git commit -m "init" git branch -M main git remote add origin https://github.com/用户名/私有仓库名.git git push -u origin main
|
之后就可以在仓库中看到博客源码
可能出现的错误:查看仓库中themes\butterfly中是否有文件,如果没有将电脑端themes整个文件夹移走,再次执行push,然后将themes文件夹移回来,再次push,仓库就有主题文件了,如果以后更新主题文件重复操作移走->push->移回来->push
git add . git commit -m "init" git push
|
配置Github Actions
创建[Blogroot]\.github\workflows\autodeploy.yml文件并写入,如果没有移除主题文件的.git第38行为主题文件地址,如果移除了.git,则删除36~39行
name: Deploy
on: push: branches: - main
workflow_dispatch:
jobs: build: runs-on: ubuntu-latest
steps: - name: Checkout uses: actions/checkout@v2 with: ref: main
- name: Setup Node uses: actions/setup-node@v1 with: node-version: "14.x"
- name: Install Hexo run: | npm install hexo-cli -g - name: Cache Modules uses: actions/cache@v1 id: cache-modules with: path: node_modules key: ${{runner.OS}}-${{hashFiles('**/package-lock.json')}}
- name: 安装主题 run: | git clone -b master https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly - name: Install Dependencies if: steps.cache-modules.outputs.cache-hit != 'true' run: | npm ci - name: Generate run: | hexo clean hexo generate - name: Deploy run: | git config --global user.name '${{ secrets.GITHUBUSERNAME }}' git config --global user.email '${{ secrets.GITHUBEMAIL }}' git clone https://github.com/GC-ZF/GC-ZF.github.io.git .deploy_git export TZ='Asia/Shanghai' hexo deploy
- name: push VPS uses: cross-the-world/scp-pipeline@master with: host: ${{ secrets.USER_HOST }} user: ${{ secrets.USER_NAME }} pass: ${{ secrets.USER_PASS }} connect_timeout: 10s local: './.deploy_git/*' remote: ${{ secrets.VPSSITE }}
|
配置Secrets
之后需要自己到仓库的Settings->Secrets->actions 下添加环境变量,依次添加

在博客根路径执行
git add . git commit -m "add actions" git push
|
查看actions运行结果,以及xxx.github.io仓库、服务器站点路径中是否更新(可能出现的错误,用户权限不足)

4.2、方案二(弃用)
使用方案一,github毕竟是外网,服务器在大陆,同步给服务器这一步骤速度感人,第一次同步大概需要半个多小时,当服务器存在文件之后的同步需要5分钟左右,GitHub Actions每个月普通用户只有2000分钟,抛开付费,就这个时间长短不是我的预期
@二花提供给我一个思路:本地[Blogroot]push到[SourceRepo]触发Github Ations执行自动化部署到[GithubBlogRepo]、[GiteeBlogRepo],之后[服务器站点]同步[GiteeBlogRepo]内的资源。实测速度不超2min
新建Gitee公有仓库
在Gitee新建一个仓库,并添加默认文件README.md(Github执行工作流,Gitee不能为空,我也不知道为什么,只是见报错提示了),将仓库**公开并确保main**是主分支
利用ssh工具
cd /www/wwwroot/hexo git clone https://gitee.com/gc-zhang/blog.git
|
设置网站根目录为blog即我Gitee的仓库名字

配置密钥
配置密钥是为了让Github和Gitee之间连通,实现同步操作
在电脑命令行终端或 Git Bash 使用命令 ssh-keygen -t rsa -C "任意命名" -f "id_rsa_github to gitee" 生成 SSH Key。(⚠️注意直接连续三次回车,此处不要设置密码,生成的公私钥用于下面 GitHub / Gitee 的配置,以保证公私钥成对,否则从 GitHub -> Gitee 的同步将会失败。)生成的 id_rsa_github to gitee 是私钥,id_rsa_github to gitee.pub 是公钥。
在 私有仓库 的「Settings -> Secrets」路径下配置好命名为 GITEE_RSA_PRIVATE_KEY 和 GITEE_PASSWORD 的两个变量。其中:GITEE_RSA_PRIVATE_KEY 存放 id_rsa 私钥;GITEE_PASSWORD 存放 Gitee 帐号的密码。

- 在 GitHub 的个人设置页面「Settings -> SSH and GPG keys」配置 SSH 公钥(即:
id_rsa_github to gitee.pub),命名随意。 - 在 Gitee 的个人设置页面「安全设置 -> SSH 公钥」配置 SSH 公钥(即:
id_rsa_github to gitee.pub),命名随意。

关注 Gitee 公众号
如果不需要使用gitee的静态页面跳过此步,如果使用,先做完实名认证再把仓库的Gitee Page打开,确保可以打开,否则工作流会不通过
关注 Gitee 官方公众号,并绑定个人 Gitee 帐号,用于接收帐号登录通知、以及绕过短信验证码校验,见错误及解决方案 第 3 点。
配置Github Actions
在方案一的基础上修改[Blogroot]\Blog\.github\workflows\autodeploy.yml,看64行之后跟着注释配置
name: Deploy # 部署
on: # 触发条件 push: branches: - main # 推送到 main 分支(这里的分支名很重要,不要弄错了)
workflow_dispatch: # 手动触发
jobs: build: runs-on: ubuntu-latest
steps: - name: Checkout # Checkout 仓库 uses: actions/checkout@v2 with: ref: main
- name: Setup Node # 安装 Node.js uses: actions/setup-node@v1 with: node-version: "12.x"
- name: Install Hexo # 安装 Hexo run: | npm install hexo-cli -g - name: Cache Modules # 缓存 Node 插件 uses: actions/cache@v1 id: cache-modules with: path: node_modules key: ${{runner.OS}}-${{hashFiles('**/package-lock.json')}}
- name: Install Dependencies # 如果没有缓存或 插件有更新,则安装插件 if: steps.cache-modules.outputs.cache-hit != 'true' run: | # **如果仓库里没有 package-lock.json,上传一下,npm ci 必须要有 package-lock.json** npm ci - name: Generate # 生成 run: | hexo clean hexo generate - name: Deploy # 部署 run: | git config --global user.name '${{ secrets.GITHUBUSERNAME }}' git config --global user.email '${{ secrets.GITHUBEMAIL }}' git clone https://github.com/GC-ZF/GC-ZF.github.io.git .deploy_git export TZ='Asia/Shanghai' hexo deploy - - name: push VPS # 部署到云服务器 - uses: cross-the-world/scp-pipeline@master - with: - host: ${{ secrets.USER_HOST }} - user: ${{ secrets.USER_NAME }} - pass: ${{ secrets.USER_PASS }} - connect_timeout: 10s - local: './.deploy_git/*' - remote: ${{ secrets.VPSSITE }}
# 删除方案一,“push VPS”接着往下写 - name: Sync to Gitee # 同步Gitee uses: wearerequired/git-mirror-action@master env: # 注意在 Settings->Secrets 配置 GITEE_RSA_PRIVATE_KEY SSH_PRIVATE_KEY: ${{ secrets.GITEE_RSA_PRIVATE_KEY }} with: # 注意替换为你的 GitHub 源仓库地址 source-repo: git@github.com:GC-ZF/GC-ZF.github.io.git # 注意替换为你的 Gitee 目标仓库地址 destination-repo: git@gitee.com:gc-zhang/blog.git
# 如果需要Gitee Page,取消注释 # - name: Build Gitee Pages # uses: yanglbme/gitee-pages-action@main # with: # # 注意替换为你的 Gitee 用户名 # gitee-username: gc-zhang # # 注意在 Settings->Secrets 配置 GITEE_PASSWORD # gitee-password: ${{ secrets.GITEE_PASSWORD }} # # 注意替换为你的 Gitee 仓库,仓库名严格区分大小写,请准确填写,否则会出错 # gitee-repo: gc-zhang/blog # # 要部署的分支,默认是 master,若是其他分支,则需要指定(指定的分支必须存在) # branch: main
- name: VPS clone Gitee # 连接服务器并克隆Gitee uses: cross-the-world/ssh-pipeline@master env: WELCOME: "ssh pipeline" with: host: ${{ secrets.USER_HOST }} user: ${{ secrets.USER_NAME }} pass: ${{ secrets.USER_PASS }} connect_timeout: 10s script: | cd /www/wwwroot/hexo/blog # cd /站点路径/Gitee的仓库名字 git pull
|
配置Secrets

在博客根路径执行
git add . git commit -m "add actions" git push
|
- 检查github私有仓库是否触发工作流,工作流结束之后
- 查看Gitee仓库是否更新
- 查看服务器站点目录是否更新或直接访问站点
- 部署完毕!100篇文章用时2min已经很快了
第三步站点目录未更新?有时可能会由于服务器网络问题导致服务器同步Gitee仓库失败,单独拿出服务器更新这一步,再建一个手动触发的Action[Blogroot]\Blog\.github\workflows\handdeploy.yml,修改21~23,当第三步更新失败可以在Github仓库下手动执行此Action
name: Hand Deploy
on: workflow_dispatch:
jobs: build: runs-on: ubuntu-latest
steps: - name: VPS clone Gitee uses: cross-the-world/ssh-pipeline@master env: WELCOME: "ssh pipeline" with: host: ${{ secrets.USER_HOST }} user: ${{ secrets.USER_NAME }} pass: ${{ secrets.USER_PASS }} connect_timeout: 10s script: | cd /www/wwwroot/hexo # cd /站点路径 rm -rf blog # rm -rf Gitee的仓库名字 git clone https://gitee.com/gc-zhang/blog.git # Gitee仓库
|
4.3 方案三
2023.01.06更新,晚上和@心流聊天发现同步服务器慢的主要原因是source/下有大量的静态文件(图片、自己做的html页面),导致hexo g后的public/文件夹70+M,正常在10~20M,而方案二走了国内Gitee平台所以起了加速作用,@心流的解决办法是利用 rsync(remote sync 远程同步),使用 rsync 命令备份数据时,不会直接覆盖以前的数据,而是先判断已经存在的数据和新数据的差异,只有数据不同时才会把不相同的部分覆盖。所以只有首次上传会慢一些,妙啊!
原文传送门:Github Action自动部署博客:推送到Github公共仓库+服务器私有仓库+刷新腾讯云CDN | 心流
腾讯云刷新CDN参考文档:内容分发网络 CDN 刷新目录-API 文档-文档中心-腾讯云
其中主要区别是我用的非root用户,需要对权限做额外操作
- 服务器下对博客路径修改用户与权限:
chown -R ubuntu:755 /www/wwwroot/hexo - 工作流中
EXCLUDE: ".git/,.user.ini" 比心流多一个.user.ini,因为防跨站文件不能修改权限属性所以不对这个文件做同步
申请令牌
Settings->Developer->Personal access tokens->Generate new token

生成的令牌只会显示一次,记住令牌,如果忘记保存就删了重弄

新建仓库并上传
新建一个Github 私有仓库
在博客根路径下,找到主题文件[Blogroot]\themes\butterfly,将 .git 移出来
在博客根路径下的.gitignore加入忽略规则
.DS_Store Thumbs.db db.json *.log node_modules/ public/ .deploy*/ .vscode/ /.idea/ .deploy_git*/ .idea themes/butterfly/.git
|
在博客根路径下执行
git init git add . git commit -m "init" git branch -M main git remote add origin https://github.com/用户名/私有仓库名.git git push -u origin main
|
之后就可以在仓库中看到博客源码
配置刷新CDN
刷新CDN通过Action一并实现,没有CDN此项跳过
如果小白没跑通整个Action而放弃使用Action部署(滴滴小张也可以滴),类似插件推荐:腾讯云CDN主动刷新插件 张洪Heo
为了保证安全性,使用子用户的secretId、secretKey,打开用户 - 控制台新建用户

依次编辑用户名、访问方式、用户权限


在博客根目录下创建 cdn.py,填写cred、params变量
import json from tencentcloud.common import credential from tencentcloud.common.profile.client_profile import ClientProfile from tencentcloud.common.profile.http_profile import HttpProfile from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException from tencentcloud.cdn.v20180606 import cdn_client, models try: cred = credential.Credential("AKIDSuWyFJtYBBxUhGbhZCDzWryr", "jEVXKwL01pp8D5jGhak4YyBB") httpProfile = HttpProfile() httpProfile.endpoint = "cdn.tencentcloudapi.com"
clientProfile = ClientProfile() clientProfile.httpProfile = httpProfile client = cdn_client.CdnClient(cred, "", clientProfile)
req = models.PurgePathCacheRequest() params = { "Paths": [ "https://zhsher.cn" ], "FlushType": "delete" } req.from_json_string(json.dumps(params))
resp = client.PurgePathCache(req) print(resp.to_json_string())
except TencentCloudSDKException as err: print(err)
|
配置Github Actions
新建[Blogroot]\.github\workflows\autodeploy.yml
- 第六步
hexo algolia为algolia搜索,gulp为文件压缩任务,按需删除(教程记录在博客搭建博文) - 第七步
clean-exclude变量为Hexo-SEO-AutoPush SEO自动提交插件的配置,按需删除(教程记录在博客搭建博文,原则上可以一起写到此工作流里通过curl请求提交,但是这个插件是真的好用!) - 第九步刷新腾讯云CDN资源,按需删除
- 第十步备份源码至Gitee,按需删除(教程在本篇方案二中有记录。讲道理Github一个私仓就够,多地备份给我这种强迫症用的嘎嘎,需求不高所以不重写了)
name: Deploy
on: push: branches: - main
workflow_dispatch:
jobs: build: runs-on: ubuntu-latest
steps: - name: 1. 检出仓库 uses: actions/checkout@v2 with: ref: main
- name: 2. 安装 Node.js uses: actions/setup-node@v3 with: node-version: "16.x"
- name: 3. 安装 Hexo run: | npm install hexo-cli -g
- name: 4. 缓存 Node 插件 uses: actions/cache@v1 id: cache-modules with: path: node_modules key: ${{runner.OS}}-${{hashFiles('**/package-lock.json')}}
- name: 5. 安装依赖 if: steps.cache-modules.outputs.cache-hit != 'true' run: | npm ci
- name: 6. 生成静态文件 run: | hexo clean hexo generate hexo algolia gulp export TZ='Asia/Shanghai'
- name: 7. 部署到 github page uses: JamesIves/github-pages-deploy-action@v4 with: token: ${{ secrets.GITHUBTOKEN }} repository-name: ${{ secrets.GITHUBUSERNAME }}/${{ secrets.GITHUBUSERNAME }}.github.io branch: main folder: public clean-exclude: | public/.github/ commit-message: "${{ github.event.head_commit.message }} Updated By Github Actions"
- name: 8. 推送到服务器私有仓库 uses: easingthemes/ssh-deploy@main env: SSH_PRIVATE_KEY: ${{ secrets.SERVER_PRIVATE_KEY }} ARGS: "-avz --delete" SOURCE: "public/" REMOTE_HOST: ${{ secrets.SERVER_HOST }} REMOTE_USER: ${{ secrets.SERVER_USER }} TARGET: ${{ secrets.SERVER_PATH }} EXCLUDE: ".git/,.user.ini"
- name: 9. 刷新CDN run: | pip install --upgrade pip pip install tencentcloud-sdk-python pip install tencentcloud-sdk-python-cdn python3 cdn.py
- name: 10. 备份Gitee uses: wearerequired/git-mirror-action@master env: SSH_PRIVATE_KEY: ${{ secrets.GITEE_RSA_PRIVATE_KEY }} with: source-repo: git@github.com:GC-ZF/Blog-Backups.git destination-repo: git@gitee.com:gc-zhang/blog-backups.git
|
配置Secrets
如果服务器先前配过PEM格式的公私钥,可跳过添加公私钥,或利用cat xxx >> xxx写入到旧密钥后一行
在服务器下生成密钥,回车三次得到公私钥ubuntu_blog_action、ubuntu_blog_action.pub
cd /home/ubuntu/.ssh ssh-keygen -m PEM -t rsa -b 4096 -f "ubuntu_blog_action"
|
复制ubuntu_blog_action.pub中内容给authorized_keys
cat ubuntu_blog_action.pub >> authorized_keys
|
其中服务器用户应有站点路径的操作权限,例如为ubuntu赋权
su - root chown -R ubuntu:755 /www/wwwroot/hexo
|

在博客根路径执行
git add . git commit -m "add actions" git push
|
四、总结
彩蛋?这样自动化部署的目的还有一个优点,你可以直接在[SourceRepo]即Github博客源码仓库中直接修改文章提交后自动触发Github Ations执行自动化部署到[GithubBlogRepo]、GiteeBlogRepo、[服务器站点],有点typecho那感觉了吧嘿嘿,之后本地同步通过在博客路径下git pull同步仓库源码,是不是很方便!小张已经尽力去记录全过程了,如果感觉太晦涩难懂,先简单学习一下git版本控制,或者向我提问嘿嘿
最后感谢@二花指点我好多,自己第一次学着写工作流,边学边写,二花不仅给我讲了特别多我不懂的原理,还提供了Gitee充当媒介的方案,真的好棒!
2023.01.06总结:rsync 命令真的妙啊!推荐阅读Linux rsync命令用法详解