Serverless + GitHub Actions 完美自動化部署靜態網站

做爲強迫症患者,一直對自動化部署很是癡迷,我的認爲全自動部署最重要的就是穩定可靠。通過研究測試,最終使用 GitHub 和騰訊雲兩大平臺,成功完成了全自動部署網站的實踐。javascript

本文來自 Serverless 社區用戶「Stille」投稿

方案簡介

業務需求

博主有一個簡單的純靜態文檔站點 docs.ioiox.com,使用的的是 docsify 項目的 Markdown 渲染程序,平時經過本地 VSCode 編輯文檔,並提交到 GitHub。早前是直接使用 GitHub Pages 綁定域名來訪問,但因爲網絡問題,體驗並很差。php

尋求方案

騰訊雲對象存儲 COS 服務可以提供靜態網頁服務,並能夠配置 CDN 域名進行訪問。那麼就須要解決如下兩個問題:java

  1. 如何使 GitHub 自動同步文件到騰訊雲 COS
  2. 騰訊雲 COS 對應的 CDN 如何自動刷新

解決方案

  • GitHub Action - 配置每次 Push 代碼後自動上傳到 COS
  • 騰訊云云函數 SCF - 檢測到 COS 內文件變更後自動刷新對應的 CDN 連接

方案流程圖

第一階段 - GitHub Actions

2019 年 11 月,GitHub 正式開放了 GitHub Actions 這個功能,再也不須要申請就能自由使用,目前是按照 workflow 的使用時長來收費,我的用戶每個月 2000 分鐘的免費額度也基本夠用了。git

獲取騰訊雲 API 密鑰

登陸騰訊雲控制面板 - 訪問控制 - 訪問密鑰 - API 密鑰管理github

新建密鑰express

新建密鑰

此密鑰擁有全部權限,爲保證安全,也能夠添加子用戶,配置 COS,CDN 對應的權限json

配置騰訊雲 COS

登陸騰訊雲控制面板 - 對象存儲 - 存儲桶列表ubuntu

建立存儲桶api

選擇適合你的區域,設置權限爲 公有讀私有寫.瀏覽器

serverless

serverless

獲取存儲桶相關信息

serverless

配置 GitHub Actions

GitHub倉庫 - Settings - Secrets

添加 SecretIdSecretKey 分別爲剛纔獲取的騰訊雲 API 密鑰

serverless

GitHub倉庫 - Actions

默認會有不少推薦的 workflows,這裏選擇 Set up a workflow yourself 本身來配置。

serverless

系統會建立一個 workflow 的 yml 配置文件,刪除預設代碼,複製如下樣本代碼。

圖上標紅兩處需修改成剛纔建立存儲桶獲取的名稱和區域

而後右上角提交便可。

serverless

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 -rs --delete -f ./ / --ignore "./.git/*"

測試 GitHub Actions

提交 yml 後系統檢測到 main.yml 的 push,便會開始運行這個 workflow,根據 yml 配置文件,能夠看出整個工做流簡單理解爲安裝了騰訊雲的 coscmd 工具,並根據配置的 SecretIdSecretKeyBUCKETREGION 上傳整個倉庫到騰訊雲 COS,同時忽略掉 .git 文件夾。其中 upload -rs 命令會使用 md5 比對存儲桶中已存在的文件,相同文件將會跳過上傳。

serverless

serverless

第二階段 - 騰訊雲函數 SCF

serverless

配置騰訊雲 CDN 域名

登陸騰訊雲控制面板 - 對象存儲

進入建立的存儲桶 - 基礎配置 - 開啓靜態網站

serverless

域名管理

添加自定義加速域名,並設置域名指向生成的CNAME地址,源站類型改成靜態網站源站

serverless

控制面板 - 內容分發網絡 - 域名管理

點擊添加的域名 - 高級配置

開啓 HTTPS,設置強制跳轉 HTTPS,並更改跳轉方式爲 301。在點擊前往配置申請免費證書。

serverless

配置雲函數 SCF

登陸騰訊雲控制面板 - 雲函數

首次使用雲函數可能會跳出 服務受權 框,須要前往訪問添加並贊成受權便可。該角色對本次添加的雲函數沒有影響。

serverless

serverless

選擇和你存儲桶相同區域並新建

填寫函數名,運行環境選擇 Php 5.6,建立方式選擇 空白函數 下一步。

serverless

serverless

函數配置

上部分保持默認便可

刪除默認代碼,複製如下樣本代碼至此.

圖上標紅兩處需修改成以前獲取的 API 密鑰,注意此處的 ID 和 KEY 順序和以前配置 GitHub Actions 時是相反的,並把 CDN 連接改成你的域名,若是域名已配置過 HTTPS 和證書,確保此處爲 https。

完成便可

serverless

serverless

函數代碼樣本

<?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 配置正確,點擊測試,返回成功。

serverless

添加觸發方式

此處須要分別添加 所有建立所有刪除 兩個觸發方式

觸發方式:COS 觸發

COS Bucket:選擇你的存儲桶 (請再次確保存儲桶和雲函數的區域相同)

事件類型:所有建立所有刪除

serverless

測試配置

騰訊雲控制檯 - 內容分發網絡

左側刷新預熱 - 操做記錄 - 查詢

能夠看到剛纔測試成功的一條記錄,如今能夠嘗試在 Push 代碼到 GitHub 來完整的測試整個流程了。

serverless

Serverless Framework 30 天試用計劃

咱們誠邀您來體驗最便捷的 Serverless 開發和部署方式。在試用期內,相關聯的產品及服務均提供免費資源和專業的技術支持,幫助您的業務快速、便捷地實現 Serverless!

詳情可查閱: Serverless Framework 試用計劃

One More Thing

3 秒你能作什麼?喝一口水,看一封郵件,仍是 —— 部署一個完整的 Serverless 應用?

複製連接至 PC 瀏覽器訪問: https://serverless.cloud.tenc...

3 秒極速部署,當即體驗史上最快的 Serverless HTTP 實戰開發!

傳送門:

歡迎訪問:Serverless 中文網,您能夠在 最佳實踐 裏體驗更多關於 Serverless 應用的開發!


推薦閱讀: 《Serverless 架構:從原理、設計到項目實戰》
相關文章
相關標籤/搜索