前言
作为强迫症患者,一直对自动化部署非常痴迷,个人认为全自动部署最重要的就是稳定可靠,经过研究测试,最终使用GitHub和腾讯云两大平台,成功完成了全自动部署网站的实践.
方案简介
业务需求
博主有一个简单的纯静态文档站点 docs.ioiox.com
,使用的的是 docsify
项目的Markdown渲染程序.平时通过本地VSCode编辑文档,并提交到Github,早前是直接使用GitHub Pages绑定域名来访问,但由于网络问题,体验并不好.
寻求方案
腾讯云COS对象存储服务能够提供静态网页服务,并可以配置CDN域名进行访问,那么就需要解决以下两个问题:
- 如何使GitHub自动同步文件到腾讯云COS
- 腾讯云COS对应的CDN如何自动刷新
解决方案
- GitHub Action - 配置每次Push代码后自动上传到COS
- 腾讯云 SCF云函数 - 检测到COS内文件变动后自动刷新对应的CDN链接
方案流程图
第一阶段 - GitHub Actions
2019年11月,GitHub 正式开放了 GitHub Actions 这个功能,不再需要申请就能自由使用,公共仓库完全免费,个人私有仓库目前是按照 workflow 的使用时长来收费,每月 2000 分钟的免费额度也基本够用了.
获取腾讯云API密钥
登录腾讯云控制面板 - 访问控制 - 访问密钥 - API密钥管理
新建密钥
配置腾讯云COS
登录腾讯云控制面板 - 对象存储 - 存储桶列表
创建存储桶
选择适合你的区域,设置权限为公有读私有写
.
获取存储桶相关信息
配置GitHub Actions
GitHub仓库 - Settings - Secrets
添加SecretId
和SecretKey
分别为刚才获取的腾讯云API密钥
GitHub仓库 - Actions
默认会有很多推荐的workflows,这里选择Set up a workflow yourself
自己来配置.
系统会创建一个workflow的yml配置文件,删除预设代码,复制以下样本代码.图上标红两处需修改为刚才创建存储桶获取的名称和区域
然后右上角提交即可
yml配置文件样本
name: Upload to COS
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Install coscmd
run: sudo pip install coscmd
- name: Configure coscmd
env:
SECRET_ID: ${{ secrets.SecretId }}
SECRET_KEY: ${{ secrets.SecretKey }}
BUCKET: docs-1300533487
REGION: ap-shanghai
run: coscmd config -a $SECRET_ID -s $SECRET_KEY -b $BUCKET -r $REGION
- name: Upload
run: coscmd upload -rfs --delete ./ / --ignore "./.git/*"
测试GitHub Actions
提交yml后系统检测到main.yml的push,便会开始运行这个workflow,根据yml配置文件,可以看出整个工作流简单理解为安装了腾讯云的coscmd工具,并根据配置的SecretId
SecretKey
BUCKET
REGION
上传整个仓库到腾讯云COS,同时忽略掉.git文件夹.其中upload -rfs
命令会使用md5比对存储桶中已存在的文件,相同文件将会跳过上传.当本地即仓库中文件删除时--delete
参数将同步删除存储桶中对应的文件,保持完全同步.
第二阶段 - 腾讯云 SCF云函数
配置腾讯云CDN域名
登录腾讯云控制面板 - 对象存储
进入创建的存储桶 - 基础配置 - 开启静态网站
域名管理
添加自定义加速域名,并设置域名指向生成的CNAME地址,源站类型改为静态网站源站
.
控制面板 - 内容分发网络 - 域名管理
点击添加的域名 - 高级配置
开启HTTPS,设置强制跳转HTTPS,并更改跳转方式为301.在点击前往配置申请免费证书.
配置SCF云函数
登录腾讯云控制面板 - 云函数
首次使用云函数可能会跳出服务授权
框,需要前往访问添加并同意授权即可.该角色对本次添加的云函数没有影响.
选择和你存储桶相同区域并新建
填写函数名,运行环境选择Php 5.6
,创建方式选择空白函数
下一步.
函数配置
上部分保持默认即可
删除默认代码,复制以下样本代码至此.图上标红两处需修改为之前获取的API密钥,注意此处的ID和KEY顺序和之前配置GitHub Actions时是相反的,并把CDN链接改为你的域名,如果域名已配置过HTTPS和证书,确保此处为https.
完成即可
函数代码样本
<?php
$gl = 1;
function main_handler($event, $context) {
$eve = json_decode(json_encode($event,JSON_FORCE_OBJECT),true);
$usr_url=strval($eve["Records"][0]["cos"]["cosObject"]["url"]);
//截取object部分
$object=substr($usr_url,strpos($usr_url,"/",8));
/*需要填写您的密钥,可从 https://console.cloud.tencent.com/capi 获取 SecretId 及 $secretKey*/
$secretKey='XXXXXXXXXXXXXX';
$secretId='XXXXXXXXXXXXXX';
$action='RefreshCdnUrl';
$HttpUrl="cdn.api.qcloud.com";
/*除非有特殊说明,如MultipartUploadVodFile,其它接口都支持GET及POST*/
$HttpMethod="GET";
/*是否https协议,大部分接口都必须为https,只有少部分接口除外(如MultipartUploadVodFile)*/
$isHttps =true;
$nurl="https://XXXX.XXXX.com".$object; // 示例:$nurl="http://abc.com".$object;
//print_r($nurl);
/*下面这五个参数为所有接口的 公共参数;对于某些接口没有地域概念,则不用传递Region(如DescribeDeals)*/
$COMMON_PARAMS = array(
'Nonce' => rand(),
'Timestamp' =>time(NULL),
'Action' =>$action,
'SecretId' => $secretId,
'SignatureMethod' => 'HmacSHA256',
'urls.0' => $nurl
);
$PRIVATE_PARAMS = array();
//**********执行CDN刷新URL操作**********/
CreateRequest($HttpUrl,$HttpMethod,$COMMON_PARAMS,$secretKey, $PRIVATE_PARAMS, $isHttps);
return "RefreshCdnUrl OK";
}
/***************CDN API调用方法***************/
function CreateRequest($HttpUrl,$HttpMethod,$COMMON_PARAMS,$secretKey, $PRIVATE_PARAMS, $isHttps)
{
$FullHttpUrl = $HttpUrl."/v2/index.php";
/***************对请求参数 按参数名 做字典序升序排列,注意此排序区分大小写*************/
$ReqParaArray = array_merge($COMMON_PARAMS, $PRIVATE_PARAMS);
ksort($ReqParaArray);
/**********************************生成签名原文**********************************
* 将 请求方法, URI地址,及排序好的请求参数 按照下面格式 拼接在一起, 生成签名原文,此请求中的原文为
* GETcvm.api.qcloud.com/v2/index.php?Action=DescribeInstances&Nonce=345122&Region=gz
* &SecretId=AKIDz8krbsJ5yKBZQ ·1pn74WFkmLPx3gnPhESA&Timestamp=1408704141
* &instanceIds.0=qcvm12345&instanceIds.1=qcvm56789
* ****************************************************************************/
$SigTxt = $HttpMethod.$FullHttpUrl."?";
$isFirst = true;
foreach ($ReqParaArray as $key => $value)
{
if (!$isFirst)
{
$SigTxt = $SigTxt."&";
}
$isFirst= false;
/*拼接签名原文时,如果参数名称中携带_,需要替换成.*/
if(strpos($key, '_'))
{
$key = str_replace('_', '.', $key);
}
$SigTxt=$SigTxt.$key."=".$value;
}
/*********************根据签名原文字符串 $SigTxt,生成签名 Signature******************/
$Signature = base64_encode(hash_hmac('sha256', $SigTxt, $secretKey, true));
/***************拼接请求串,对于请求参数及签名,需要进行urlencode编码********************/
$Req = "Signature=".urlencode($Signature);
foreach ($ReqParaArray as $key => $value)
{
$Req=$Req."&".$key."=".urlencode($value);
}
/*********************************发送请求********************************/
if($HttpMethod === 'GET')
{
if($isHttps === true)
{
$Req="https://".$FullHttpUrl."?".$Req;
}
else
{
$Req="http://".$FullHttpUrl."?".$Req;
}
$Rsp = file_get_contents($Req);
}
else
{
if($isHttps === true)
{
$Rsp= SendPost("https://".$FullHttpUrl,$Req,$isHttps);
}
else
{
$Rsp= SendPost("http://".$FullHttpUrl,$Req,$isHttps);
}
}
var_export(json_decode($Rsp,true));
}
function SendPost($FullHttpUrl, $Req, $isHttps)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $Req);
curl_setopt($ch, CURLOPT_URL, $FullHttpUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if ($isHttps === true) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
}
$result = curl_exec($ch);
return $result;
}
?>
测试函数代码
确认API及CDN配置正确,点击测试,返回成功.
添加触发方式
此处需要分别添加全部创建
和全部删除
两个触发方式
触发方式 : COS触发
COS Bucket : 选择你的存储桶 (请再次确保存储桶和云函数的区域相同)
事件类型 : 全部创建
和全部删除
测试配置
腾讯云控制台 - 内容分发网络
左侧刷新预热 - 操作记录 - 查询
可以看到刚才测试成功的一条记录,现在可以尝试在Push代码到GitHub来完整的测试整个流程了.
结语
随着COSCMD的
的更新,支持了--delete
参数,但是一直没有测试成功.十分感谢热心网友大神的留言分享,在加了-f
忽略提示的参数后,目前已经完全支持删除功能,完美的实现了同步需求.
26 条评论
这是我的测试仓库,想测试单独传一个文件能否传,然后用到其他项目上,结果失败了,能否看看是哪出问题了?
https://github.com/liwenjie119/testftp
你这个yml自己写的?
用你的修改了一部分,推送单独的文件到腾讯云,如果是网络问题的话设置到国外的存储桶会不会好点?
那应该不会,我传输很快啊,我看yml,你是自己创建了个占容量的空文件,会不会和这个有关,试试真实上传文件看看如何吧
看来确实有影响,我试着git push上去一个文件然后往cos推送,能推送,但是只有十几k,把存储桶换到硅谷就20mb/s,目前已经部署正常使用了
有报错,上传文件不上去
[error]Process completed with exit code 255.Upload ./artifact/test => cos://xxx-xxx/test
('Connection aborted.', error(32, 'Broken pipe'))
Upload file failed
Retry to upload ./artifact/test => cos://xxx-xxx/test
('Connection aborted.', error(32, 'Broken pipe'))
Upload file failed
看错误像是网络问题,是不是文件太大?还是延迟设置太低?
这个是真厉害,本地装wp,然后插件生成纯静态,然后上传上去,白嫖了一个网站。
哈哈.最近研究这个还是很有用的..
昨天又研究了下webhook,成功push后推送到centos中,也是一样的效果,适合于非静态网站需要vps部署的.回头在写篇博客.
oss及cdn都收费的吧?每月费用如何?
cdn每月有免费10G,只是存放静态站点,流量不大够用了.
存储空间放网站这么小,基本也没什么费用.
确实,很多站10G都用不完