×
Community Blog How to Develop Serverless Devs Package Quickly?

How to Develop Serverless Devs Package Quickly?

This article introduces Serverless Devs Packages and package and component development.

By Jiangyu (Alibaba Cloud Serverless Product Manager)

Preface

Serverless Devs have been building in the open-source code and open ecosystem mode. There are two ways for community users to participate in the construction of Serverless Devs:

  1. Participate in Code Contribution: This way is common in open-source projects, which have a clear and definite process. Please refer to the code contribution documents for the contribution of Serverless Devs.
  2. Participate in Package Contribution: Applications or components can be developed and published to Serverless Registry for more people to learn and use. For this part, you can refer to this article.

An Introduction to Serverless Devs Packages

You need to know about Serverless Registry before talking about Serverless Devs Packages. Many R&D know that different languages/ecosystems have different package management platforms (such as Pypi in Python and NPM in Node.js).

The so-called package management platform, roughly speaking, aims to manage packages. The packages here often refer to certain functions or capabilities that others have encapsulated and can be directly used.

Here are two vivid examples. If we are engaged in artificial intelligence, it is not realistic to write various algorithms manually. We often use corresponding packages (such as Sklearn and Tensorflow) to load certain models quickly and then develop and perfect them on this basis.

We also hope to have a similar package management platform in the Serverless field, which is Serverless Registry:

Serverless Registry Python Pypi Nodejs NPM
Storage Content Serverless packages (including components and applications) Python packages Nodejs packages
Open or Not Yes Yes Yes
Official Source registry.devsapp.cn/simple pypi.python.org registry.npmjs.org
Examples of Other Sources Github registry, Gitee registry Tsinghua source, Douban source tnpm, cnpm
Private Deployment Supported Supported Supported
Tools Serverless Devs pip npm
Commands s pip npm
Usage Direct reference in s.yaml Reference in code after installation Reference in code after installation

Unlike Python's Pypi and Node.js's NPM, in Serverless Registry, packages are divided into two types: Component and Application.

To distinguish between Component and Application:

  • Component is similar to a script, through which some things can be done. For example, deploy a function to a cloud platform, debug a function, and view the logs of a function.
  • Application is similar to a case. For example, users can quickly create a Hello World application or an audio and video processing application through an Application.

Here is the difference between them in the Serverless Devs specification:

1

The relationship between Component and Application is that Application is the definition of an application case and needs to be deployed and launched through Component.

Perhaps the expression is somewhat abstract. It can be explained by a vivid case. Examples:

  • If you make a face recognition application through Python's Tensorflow framework, Tensorflow can be considered as a Component, and the face recognition application can be considered as an Application.
  • If you have made a personal blog through Node.js's Express, Fs, Path, and other dependencies, Express, Fs, Path, and other dependencies can be considered as different Components. The blog made can be considered as an Application.
  • Serverless Registry Model
  • Serverless Package Model

Package Development

The process to develop Serverless Packages is relatively simple because relatively complete scaffolding capabilities are provided in the Serverless Devs developer tools.

The developer only needs to execute the s init and select the Dev Template for Serverless Devs.

2

After the selection is completed, it is not difficult to find that we will continue to choose whether to develop a Component or an Application.

3

Component Development

After selecting Component Scaffolding, you need to give the Component to be developed a name (such as deployfunction).

4

At this time, you can enter the project directory of Component according to the system prompt:

5

You can open the current project through the IDE and perform dependency installation through the npm. (Serverless Devs is a Typescript-based project, so the development of components only supports Typescript and Node.js languages.)

6

At this point, you can open the src/index.ts file in the project, and it is easy to find that there is already a case:

import logger from './common/logger';
import { InputProps } from './common/entity';

export default class ComponentDemo {
 /**
  * demo instance
  * @param inputs
  * @returns
  */
 public async test(inputs: InputProps) {
   logger.debug(`input: ${JSON.stringify(inputs.props)}`);
   logger.info('command test');
   return { hello: 'world' };
 }
}

In this file, we can find a test (inputs) method. It is a case of printing inputs parameters and returning hello world. We can learn several things through this simple case:

The Public Method Is the Command That the User Can Use

In a project, we can write multiple methods to expose to the outside. Currently, there is only one test, but we can add any public methods that will become commands for the component. Examples:

public async test(inputs: InputProps) {
   logger.debug(`input: ${JSON.stringify(inputs.props)}`);
   logger.info('command test for test');
   return { hello: 'world' };
 }

public async deploy(inputs: InputProps) {
   logger.debug(`input: ${JSON.stringify(inputs.props)}`);
   logger.info('command test for deploy');
   return { hello: 'world' };
 }

When we use the component, it has two commands: the test command and the deploy command. We can compile the basic development state of the project to verify our idea: npm run watch:

7

We can find the example directory and test the deploy method. For example:

8

From the s.yaml file example below, it can be seen that this yaml has two services (component-test and component-test2).

Both services use the same component. Therefore, the expected result is obtained after the s deploy is executed, which means the deploy method is executed.

Similarly, we can execute the test command to see the effect.

9

The Logic to Be Implemented Can Be Freely Implemented within the Method

In other words, when the Serverless Devs tool loads a component, it passes the corresponding parameters to the specified method and executes the method. Therefore, any function you want to achieve can be written in the corresponding method.

Let's take the Serverless Registry Component project as an example. There is a Login function, and I implemented the following in Login:

/**
    * demo login
    * @param inputs
    * @returns
    */
   public async login(inputs: InputProps) {

       const apts = {
           boolean: ['help'],
           alias: {help: 'h'},
       };
       const comParse = commandParse({args: inputs.args}, apts);
       if (comParse.data && comParse.data.help) {
           help([{
               header: 'Login',
               content: `Log in to Serverless Registry`
           }, {
               header: 'Usage',
               content: `$ s cli registry login <options>`
           }, {
               header: 'Options',
               optionList: [
                   {
                       name: 'token',
                       description: '[Optional] If you already have a token, you can configure it directly',
                       type: String,
                   }
               ],
           }, {
               header: 'Examples without Yaml',
               content: [
                   '$ s cli registry login',
                   '$ s cli registry login --token my-serverless-registry-token',
               ],
           },]);
           return;
       }
       const tempToken = comParse.data ? comParse.data.token : null
       let st = 0
       let user
       if (tempToken) {
           const fd = await fse.openSync(`${getRootHome()}/serverless-devs-platform.dat`, 'w+')
           await fse.writeSync(fd, tempToken)
           await fse.closeSync(fd)
           st = 1
       } else {

           const token = random({length: 20})
           const loginUrl = `https://github.com/login/oauth/authorize?client_id=beae900546180c7bbdd6&redirect_uri=http://registry.devsapp.cn/user/login/github?token=${token}`

           // output remind
           logger.warn("Serverless registry no longer provides independent registration function, but will uniformly adopt GitHub authorized login scheme.")
           logger.info("The system will attempt to automatically open the browser for authorization......")
           try {
               await sleep(2000)
               opn(loginUrl)
           } catch (e) {
               logger.info("Failed to open the default address. Please try to open the following URL manually for authorization: ")
               logger.info(loginUrl)
           }
           await logger.task('Getting', [
               {
                   title: 'Getting login token ...',
                   id: 'get token',
                   task: async () => {
                       for (let i = 0; i < 100; i++) {
                           await sleep(2000)
                           const tempResult = await request('http://registry.devsapp.cn/user/information/github', {
                               params: {
                                   token: token,
                               },
                           })
                           if (!tempResult.Error && tempResult.safety_code) {
                               // or obtained as a result, the storage state
                               const fd = await fse.openSync(`${getRootHome()}/serverless-devs-platform.dat`, 'w+')
                               await fse.writeSync(fd, tempResult.safety_code)
                               await fse.closeSync(fd)
                               st = 1
                               user = tempResult.login
                               break
                           }
                       }
                   },
               }
           ])
       }
       if (st == 1) {
           logger.log(`${user ? user + ': ' : ''}Welcome to Serverless Devs Registry.`, "green");
       } else {
           logger.error("Login failed. Please log in to GitHub account on the pop-up page and authorize it, or try again later.")
       }
       return null;
   }

There are several main points in this method:

  1. The inputs parameter analysis is to obtain the user input parameter.
  2. If the user input parameters are with the -h or --help parameters, output the corresponding help information.
  3. If the user input parameter has a --token, the --token corresponding value is stored in a file.
  4. If the user does not have --token input, open the browser, access the login address of Serverless Registry, and obtain the relevant login token.

So, the same method, if it is a method or commands to deploy a function, can we package and compress the code in this method, call the relevant creation function, and update the interface of the function to create the function? Another example, if you want to make a method to delete a function, can you call the interface of the delete function in it?

Therefore, no matter what function you want to implement, it can be implemented in the corresponding method.

Specifications in the Development Process

As mentioned before, Serverless Devs will call the method with some parameters, but what do the parameters look like? What is the format, and how should we parse it?

What is the use of the final return of the project? How do I obtain the key information of a user in a project? How do I obtain various parameters that users write in YAML? How do I get the parameters that a user passes when executing a command?

You can refer to the Component Model Code Specification of the Serverless Devs Package Development Specification Document. In the document, we can find:

The structure of the inputs parameter is:

{
   "command": "", 
   "project": {
       "projectName": "", 
       "component": "",
       "provider": "",
       "access": ""
   },
   "credentials": {},
   "prop": {},
   "args": "",
   "argsObj": []
}

The meaning of these parameters:

Contents Meaning
command The command that is used by the user
project The basic information about the project of the user
credentials The information about the key
prop The properties or parameters the user configures
args The parameter passed by the user (string form)
argsObj The parameter passed by the user (the parsed parameter is passed as an array)

A more specific example is that in the case code above, there is a test method, which is the method of functional implementation. When the user runs the test command, the system calls the method using the related parameters. Example:

The component is named hexo, and the core code of the component is shown in the preceding figure. It has a test method, and the YAML on the user side is listed below:

edition: 1.0.0        #  The YAML specification version of the command line, which follows the Semantic Versioning specification
name: FullStack       #  Project name
access: xxx-account1  #  Key alias

services:
 HexoComponent:
   component: hexo
   props:
     region: 'cn-hangzhou'
     codeUri: './src'

When the user runs the s test mytest -a -b abc command, the following inputs are returned in the test method:

{
   "command": "test", 
   "project": {
       "projectName": "HexoComponent", 
       "component": "hexo",
       "provider": "alibaba",
       "access": "release"
   },
   "credentials": {
       "AccountID": "********",
       "AccessKeyID": "********",
       "AccessKeySecret": "********"
   },
   "prop": {
       "Region": "cn-hangzhou",
       "CodeUri": "./src"
   },
   "args": "mytest -a -b abc",
   "argsObj": [
     "mytest", "-a", "-b", "abc"
   ]
}

Then, the test method prints the log and so on and returns the final result to the command line tool: { "hello": "world" }.

You can refer to the core package provided by Serverless Devs for more information about how to return help files, how to obtain key information, and how to parse user input content.

In the toolkit, we can see many methods to help us quickly use it.

10

For example, you can introduce the core package and use the corresponding getCredential method to obtain the user's key.

  • Method 1: When no parameters are passed, the default key information will be obtained.
   const { getCredential } = require('@serverless-devs/core');
   async function get() {
     const c = await getCredential();
     console.log('c', c);
   }
  • Method 2: Pass parameters to obtain the specified key information
   const { getCredential } = require('@serverless-devs/core');
   async function get() {
     // Inputs received by the component
     const inputs = {};
     const c = await getCredential(inputs, 'custom', 'AccountIdByCustom', 'SecretIDByCustom');
     console.log('c', c);
   }

Component Description

After writing our component functions, we can describe the components. The so-called component description tells Serverless Registry what component it is and what functions it has. The description is in the publish.yaml.

11

You can refer to the component model metadata for the content of this file and the values of some parameters.

In addition to publish.yaml, there are other files in the directory in the Serverless Package specification.

|- src # The name of the directory can be changed. 
| └ ──Code directory 
|- package.json: The main must be defined.
|- publish. yaml: Project resource description 
|- readme.md: Project description 
|- version.md: Version update content

The following table describes the parameters in the structure.

Contents Required Meaning
src Recommended The directory that contains all the required files to build the project in a unified manner. You can change the name of the directory and have the directory tiled under the project. We recommend using src as the directory for unified file management.
package.json Yes The package.json file of Node.js, in which the handler of the component is recorded.
publish.yaml Yes The Serverless Devs Package development documentation.
readme.md Yes The description or the help documentation of the component
version.md Recommended The version description, such as the updates of the current version

The latest version of the specification (version 0.0.2) will be launched soon. Unlike version 0.0.1, the Properties parameter of the new version will follow the JSON Scheme specification. Please see pr#386 for more information.

Application Development

After Application Scaffolding is selected, you need to give the Application to be developed a name (such as helloworld).

12

Application development in Serverless Packages is relatively simple. No matter any programming language or project, it can be packaged as an application as long as it can be deployed through Serverless Devs developer tools.

More accurately, as long as you have a project that can be directly deployed through Serverless Devs, you can:

  1. s init creates an application template.
  2. After desensitization, put your project directly under the src directory
  3. Describe the application, such as editing publish.yaml, version.md, and readme.md.

Please refer to the application model documentation for details in this section:

Special Format: In the application model, the src/s.yaml file that contains resources and behavior description is required for Serverless Devs to identify and use. A user must specify specific content in this file, such as the key name and the region where the user deploys business. You can refer to:

  • "{{ access }}": It reminds the user that a parameter (such as access) is required as a parameter in YAML.
  • '{{ bucket | alibaba oss bucket }}': Directly remind the user that a parameter (such as a bucket) needs to be entered as a necessary parameter in YAML, and the content "alibaba oss bucket" after | is used to explain the meaning of this parameter.

For example, an application's s.yaml is expressed as:

edition: 1.0.0
access: "{{ access }}"

services:
 website-starter:
  component: devsapp/website
   actions:
     pre-deploy:
       - run: npm install
         path: ./
       - run: npm run build
         path: ./
   props:
     bucket: '{{ bucket | alibaba oss bucket }}'
     src:
       codeUri: ./
       publishDir: ./build
       index: index.html
     region: cn-hangzhou
     hosts:
       - host: auto

Package Publish

After you develop a Serverless Package, you can publish it to Registry.

Publish to GitHub/Gitee

If you want to publish to GitHub or Gitee, the method is simple:

  1. Create a Repo (code repository)
  2. Push the entire application or component to the repository
  3. Publish a Release: At this time, the user can switch the registry through s set registry to use the corresponding function in the client. For example, if your account in GitHub is anycodes, you can create a repository named demo. You can upload your components/applications to this repository and publish a release. Switch the registry to GitHub on the client and then:
  • When you use a component, you can specify the component name repository, such as anycodes/demo.
  • When you initialize an application, you can also specify an application, such as anycodes/application.

Publish to Serverless Registry

If you want to publish a package to Serverless Registry, consider using Serverless Registry Component.

(The client tool of Serverless Registry is also a component, so it can be considered that the Serverless Registry Component project is also a best practice of the current article.)

After completing the component or application development process, you need to:

  1. Register and log on to Serverless Registry, which is the execution of s cli registry login
  2. The release of the component is s cli registry publish.

Besides login and release, this project Serverless Registry Component has many other functions, such as:

  • View the Packages published by the current login account
  • View the version information of a Package
  • View information about a specified version of a Package
  • Delete a Package of a specified version
  • Update the login token

Summary

As we all know, the development of a complete technical architecture cannot be separated from the empowerment of the ecological community. Whether it is Docker's Docker Hub, Python's Pypi, or Node.js's NPM, the popularity of the ecology is positively correlated with the happiness of our developers.

We hope Serverless Devs can help more people learn about Serverless architecture through an open ecosystem like Serverless Registry. We also hope more excellent packages will be widely used.

0 1 0
Share on

You may also like

Comments