×
Community Blog Build Your First Serverless Website with Alibaba Cloud

Build Your First Serverless Website with Alibaba Cloud

In this article, we will be building a low-cost, serverless website using Alibaba Cloud Function Compute.

By Alberto Roura, Alibaba Cloud Tech Share Author. Tech Share is Alibaba Cloud's incentive program to encourage the sharing of technical knowledge and best practices within the cloud community.

Serverless is the buzzword among developers recently, right? Well, do you really know how to take full advantage of it? This tutorial will help you to create a small, serverless personal webpage by using Alibaba Cloud Function Compute. We're going to do this by using the tool "Fun", because this is all about having fun with serverless.

What Is Serverless?

Serverless is a new computing paradigm in which you can build applications composed of micro-services running as a response to events. Under this model the services automatically scales according to the usage. This means that you only get charge when they are executed, becoming the most "Pay-As-You-Go" model ever. Of course, this reduces the overall cost of maintenance for your apps, enabling you to more on the logic, deploying faster.

The classic approach to publish a website by your own is to have a web server, such as an Elastic Computer Service (ECS) instance, running non-stop. This means having an instance 24 hours a day, 7 days per week. Running the numbers that is about 730 hours per month. Or between $5~$15 every month depending on the plan and, on top of that, all the security and software updates involved in managing a server. I'm sure you prefer to spend that time and money on something more enjoyable, like a day on the mountains instead.

What Will We Build in This Tutorial?

For the purpose of learning, we will keep things simple and clear by setting up a simple "About Me" page. For this, we will leverage Object Storage Service (OSS), API Gateway, Function Compute and Table Store. To make that happen, the idea is to host a static HTML file in an OSS bucket with Public Read Permissions. This page will have a visit counter that will communicate via API Gateway with Function Compute, and keeping the visits count on Table Store. Does it sound complex? Keep reading, you will find it easy.

Let's Get Started

To start, create a folder for the project. Once inside it, create the file .env for the credentials and leave it there for now.

Install Fun

We said this tutorial will be based on "Fun". Fun is an official Alibaba Cloud tool to arrange serverless applications resources. Therefore we will use it to deploy our website backend by describing the resources in a template.yml file.

To install Fun, you only need to run in your terminal npm install @alicloud/fun -g. To verify that the installation went ok, type fun -h and see if the output prints the Fun help.

Get Credentials

Well, now that we have all ready to go, let's get the credentials. Log into the Alibaba Cloud web console and, from the top-right corner, click on AccessKey as shown below:

1

Once in the Security Management screen, copy the Access Key ID and the Access Key Secret into the .env file we created before:

ACCESS_KEY_SECRET=Replace This with your Access Key Secret
ACCESS_KEY_ID=Replace This with your Access Key
ACCOUNT_ID=Replace This with your Account ID
REGION=ap-southeast-2

Create the Template

As we mentioned before, the way Fun works is by reading a YAML file where all the resources are described, all that apart of the specific permissions for the Function Compute Service if needed.

The template.yml below describes the Function Compute Service AboutMePage, the Table Store Instance AboutMePageOTS and the API Group AboutMeAPI. Add the following under your project folder:

ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
  AboutMePage:
    Type: 'Aliyun::Serverless::Service'
    Properties:
      Description: 'Function Compute Service for the About Page'
      Policies:
      - AliyunOTSFullAccess
    visits:
      Type: 'Aliyun::Serverless::Function'
      Properties:
        Handler: visits.handler
        Runtime: nodejs8
        CodeUri: './'
        Timeout: 10
        EnvironmentVariables:
          InstanceName: AboutMePageOTS
          TableName: visitsTable
  AboutMePageOTS:
    Type: 'Aliyun::Serverless::TableStore'
    Properties:
      ClusterType: HYBRID
      Description: 'Table used to store visits'
    visitsTable:
      Type: 'Aliyun::Serverless::TableStore::Table'
      Properties:
        PrimaryKeyList:
        - Name: count_name
          Type: STRING
  AboutMeAPI:
    Type: 'Aliyun::Serverless::Api'
    Properties:
      StageName: RELEASE
      DefinitionBody:
        '/visits':
          get:
            x-aliyun-apigateway-api-name: visits_get
            x-aliyun-apigateway-fc:
              arn: acs:fc:::services/${AboutMePage.Arn}/functions/${visits.Arn}/

Create the Function

This is the heart of our project, as it will be the piece of code that will register the visits and retrieve the latest number. The code is using nodejs8 as Runtime and supports the creation of the first value in the table if it doesn't exist. So, for now, write the following code in a file called visits.js:

const TableStore = require('tablestore')
const Long = TableStore.Long

async function getViewsCount(client) {
    const response = await client.getRow({
        tableName: process.env['TableName'],
        primaryKey: [{ count_name: 'views' }],
        maxVersions: 1,
    })

    return response.row && response.row.primaryKey
        ? response.row.attributes[0].columnValue.toNumber()
        : null
}

exports.handler = function (event, context, callback) {
    (async () => {
        let success = false
        let views = null

        const client = new TableStore.Client({
            accessKeyId: context.credentials.accessKeyId,
            secretAccessKey: context.credentials.accessKeySecret,
            stsToken: context.credentials.securityToken,
            endpoint: `http://${process.env['InstanceName']}.${context.region}.ots.aliyuncs.com`,
            instancename: process.env['InstanceName'],
        })

        do {
            views = await getViewsCount(client) || 0

            const tableName = process.env['TableName']
            const updateOfAttributeColumns = [{ PUT: [{ count: Long.fromNumber(views + 1) }] }]
            const primaryKey = [{ count_name: 'views' }]
            const condition = views
                ? new TableStore.Condition(TableStore.RowExistenceExpectation.IGNORE, new TableStore.SingleColumnCondition('count', Long.fromNumber(views), TableStore.ComparatorType.EQUAL))
                : new TableStore.Condition(TableStore.RowExistenceExpectation.EXPECT_NOT_EXIST, null)

            try {
                await client.updateRow({
                    tableName,
                    condition,
                    primaryKey,
                    updateOfAttributeColumns,
                })
                success = true
            } catch (ex) {
                console.log(ex)
            }
        } while (!success)

        callback(null, { isBase64Encoded: false, statusCode: 200, body: views })
    })()
}

Deploy

This step is very straightforward, as Fun includes a command to automatically deploy all the resources defined in the template. For this, we will run fun deploy and wait for the process to finish. It prints a very neat output to inform all what is really happening. From the output we will really need one thing, the API gateway identifier. Somewhere in the last lines, find something like URL: GET http://722919aa644345e39ac1e872cc387e25-ap-southeast-2.alicloudapi.com/time, well, copy that URL for later, as we don't need it right now.

Create a Public Bucket

Traditionally, you'll serve the files using a web server installed in an ECS Instance, said server would interact with the visitor preparing the page contents and sending it back. In this serverless approach, the files will be served from an OSS bucket.

To create a bucket, go to the OSS Console and, from the right panel, click on "Create Bucket". Give a meaningful name to it and select "Public Read" under Access Control List. As a result, this will expose the contents of the bucket to anyone on the Internet. Confirm the creation clicking on "Ok". To serve static sites using the bucket, there is still something else we need to touch. For this, open the just-created bucket and go to the "Basic Settings" tab. Once in, click in the "Configure" button under "Static Pages" and type "index.html" next to "Default Homepage". That will tell OSS which file to serve by default. Just like using a web server like Apache or Nginx.

Upload Your Page

Because we need 3 files for this, I prepared a GitHub repository for you to download the files to your local machine and upload them to your bucket. Once you clone it, go to the "oss" folder. The files that need to go to the root folder of your bucket are the ones named index.html, bg.jpg and style.css.

Before uploading them, be sure to edit the index.html. This file is a template, so just tweak it with your own data. Most importantly, and to make the counter work, just find and replace API_ENDPOINT_URL_GOES_HERE with the URL we copied in the "Deploy" step.

You are now ready to upload all 3 files to the bucket.

Enjoy your serverless, #NoOps life!

If you followed correctly all the steps, you now will be able to just navigate to your bucket (ie your-bucket-name.oss-ap-southeast-2.aliyuncs.com). As a result, your new shiny "About Me" page will work.

1 1 1
Share on

Alibaba Clouder

2,605 posts | 747 followers

You may also like

Comments

5006456523727382 April 29, 2019 at 7:42 am

I have encountered and error when running fun deploy, as follows:-GET /services/AboutMePage failed with 403. requestid: 9bee9f1d-3424-b3c4-c6d6-095a46157e9f, message: FC service is not enabled for current user..

Alibaba Clouder

2,605 posts | 747 followers

Related Products