Serverless + GitHub Actions perfectly automates the deployment of static websites

As obsessive-compulsive patients, they have always been obsessed with automatic deployment, and I think the most important thing about automatic deployment is stability and reliability. After research and test, we finally use GitHub and Tencent cloud platforms to successfully complete the practice of fully automatic website deployment.

This article is contributed by "still", a member of the Serverless community

Scheme introduction

Business requirements

Bloggers have a simple static document site docs.ioiox.com , using docsify The Markdown renderer of the project usually edits documents through local VSCode and submits them to GitHub. Earlier, we used GitHub Pages to bind domain names directly to access, but due to network problems, the experience was not good.

Seeking solutions

Tencent cloud object storage COS service can provide static web services and configure CDN domain name for access. Then we need to solve the following two problems:

  1. How to make GitHub automatically synchronize files to Tencent cloud COS
  2. How to automatically refresh the CDN corresponding to Tencent cloud COS

Solution

  • GitHub Action - configure to automatically upload to COS after each Push code
  • Tencent cloud function SCF - automatically refresh the corresponding CDN link after detecting the change of files in COS

Scheme flow chart

Phase 1 - GitHub Actions

In November 2019, GitHub officially opened the function of GitHub Actions, which can be used freely without any application. At present, it is charged according to the usage time of workflow, and the free quota of 2000 minutes per month for individual users is basically enough.

Get Tencent cloud API key

Log in to Tencent cloud control panel - access control - access key - API key management

New key

This key has all permissions. To ensure security, you can also add sub users and configure the permissions corresponding to COS and CDN

Configure Tencent cloud COS

Log in to Tencent cloud control panel - object storage - bucket list

Create bucket

Select the area suitable for you, and set the permissions to public read and private write

Get bucket related information

Configure GitHub Actions

GitHub warehouse - Settings - Secrets

Add SecretId and SecretKey to the Tencent cloud API key just obtained

GitHub warehouse - Actions

There will be many recommended workflows by default. Here, select Set up a workflow yourself to configure.

The system will create a workflow yml configuration file, delete the default code, and copy the following sample code.

The two red marks on the figure need to be modified to the name and area obtained by the bucket just created

Then submit in the upper right corner.

Sample yml profile

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/*"

Test GitHub Actions

System detected after submitting YML main.yml According to the YML configuration file, we can see that the whole workflow is simply understood as the installation of Tencent cloud's coscmd tool, and upload the entire warehouse to Tencent cloud COS according to the configured SecretId, SecretKey, BUCKET, and REGION, while ignoring the. git folder. The upload RS command will use md5 to compare the existing files in the BUCKET, and the same file will skip the upload.

The second stage - Tencent cloud function SCF

Configure Tencent cloud CDN domain name

Log in to Tencent cloud control panel - object storage

Enter the created bucket - basic configuration - open static website

Domain name management

Add a custom acceleration domain name, and set the domain name to point to the generated CNAME address. The source site type is changed to static site source site.

Control panel - content distribution network - domain name management

Click Add domain name - Advanced Configuration

Turn on HTTPS, set the forced jump HTTPS, and change the jump mode to 301. Click go to configuration to apply for free certificate.

Configure cloud function SCF

Log in to Tencent cloud control panel - cloud function

Using cloud functions for the first time may pop out of the service authorization box. You need to go to the access add and agree to the authorization. This role has no effect on the cloud function added this time.

Select the same area as your bucket and create a new one

Fill in the function name, select Php 5.6 for the running environment, and select blank function for the creation mode.

Function configuration

Keep the upper part default

Delete the default code and copy the following sample code here

The two red marks on the figure need to be changed to the API KEY obtained before. Note that the order of ID and KEY here is the opposite to that when GitHub Actions was configured before, and change the CDN link to your domain name. If https and certificate have been configured for the domain name, make sure it is https here.

Just finish

Function code sample

<?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"]);

    //Intercept the object part
    $object=substr($usr_url,strpos($usr_url,"/",8));

    /*You need to fill in your key from https://console.cloud.tencent.com/capi  Get secret ID and $secret key*/
    $secretKey='XXXXXXXXXXXXXX';
    $secretId='XXXXXXXXXXXXXX';
    $action='RefreshCdnUrl';

    $HttpUrl="cdn.api.qcloud.com";
    /*Unless otherwise specified, such as MultipartUploadVodFile, other interfaces support GET and POST*/
    $HttpMethod="GET";
    /*https protocol or not, most interfaces must be https, except for a few (such as MultipartUploadVodFile)*/
    $isHttps =true;
    $nurl="https://XXXX.XXXX.com".$object; / / example: $nurl="http://abc.com".$object;
    //print_r($nurl);

    /*The following five parameters are the common parameters of all interfaces; for some interfaces without the concept of Region, Region (such as DescribeDeals) need not be passed*/
    $COMMON_PARAMS = array(
                    'Nonce' => rand(),
                    'Timestamp' =>time(NULL),
                    'Action' =>$action,
                    'SecretId' => $secretId,
                    'SignatureMethod' => 'HmacSHA256',
                    'urls.0' => $nurl
                    );
    $PRIVATE_PARAMS = array();
    //**********Perform CDN refresh URL operation**********/
    CreateRequest($HttpUrl,$HttpMethod,$COMMON_PARAMS,$secretKey, $PRIVATE_PARAMS, $isHttps);
   return "RefreshCdnUrl OK";
}
/***************CDN API Call method***************/
function CreateRequest($HttpUrl,$HttpMethod,$COMMON_PARAMS,$secretKey, $PRIVATE_PARAMS, $isHttps)
{
        $FullHttpUrl = $HttpUrl."/v2/index.php";

        /***************Arrange the request parameters in ascending dictionary order according to the parameter names. Note that this sort is case sensitive*************/
        $ReqParaArray = array_merge($COMMON_PARAMS, $PRIVATE_PARAMS);
        ksort($ReqParaArray);

        /**********************************Generate signature original**********************************
         * The request method, URI address, and sorted request parameters are spliced together according to the following format to generate the original signature
         * 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;
                /*When splicing the original signature, if the parameter name carries_ , need to be replaced with*/
                if(strpos($key, '_'))
                {
                        $key = str_replace('_', '.', $key);
                }
                $SigTxt=$SigTxt.$key."=".$value;
        }
        /*********************Generate Signature according to the original Signature string $SigTxt******************/
        $Signature = base64_encode(hash_hmac('sha256', $SigTxt, $secretKey, true));

        /***************Splicing request string. For request parameters and signatures, urlencode is required********************/
        $Req = "Signature=".urlencode($Signature);
        foreach ($ReqParaArray as $key => $value)
        {
                $Req=$Req."&".$key."=".urlencode($value);
        }

        /*********************************Send request********************************/
        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;
}
?>

Test function code

Confirm that the API and CDN are configured correctly. Click test to return to success.

Add trigger method

Here, you need to add two triggering methods: create all and delete all

Trigger mode: COS trigger

COS Bucket: select your bucket (please make sure again that the bucket and cloud function have the same area)

Event types: create all and delete all

Test configuration

Tencent cloud console - content distribution network

Left refresh preheating - operation record - query

You can see a record of the successful test just now. Now you can try to test the whole process from Push code to GitHub.

Serverless Framework 30 day trial plan

We invite you to experience the most convenient way to develop and deploy Serverless. During the trial period, the related products and services provide free resources and professional technical support to help your business quickly and conveniently realize Serverless!

Details can be found at: Serverless Framework trial plan

One More Thing

What can you do in three seconds? Take a sip, read an email, or - deploy a complete Serverless application?

Copy link to PC browser: https://serverless.cloud.tencent.com/deploy/express

Deploy in 3 seconds and experience the fastest Serverless HTTP Practical development!

Transfer gate:

Welcome to: Serverless Chinese network , you can Best practices Experience more about Serverless application development!

Recommended reading: Serverless architecture: from principle, design to project implementation

Tags: github network PHP git

Posted on Fri, 19 Jun 2020 06:33:55 -0400 by slick101