乐趣区

关于github:如何快速开发-Serverless-Devs-Package


作者 | 江昱(阿里云 Serverless 产品经理)​

前言

Serverless Devs 始终在以开源代码、凋谢生态的模式进行建设,所以在社区用户参加 Serverless Devs 的建设过程中,就会有两条路径:

1、参加奉献代码:参加代码的奉献绝对于来说是有着清晰明确的流程,并且也是参加开源我的项目常见的路径,Serverless Devs 的贡献者文档,能够参考代码奉献文档;

2、参加奉献 Package:能够开发利用或者组件,公布到 Serverless Registry,以供更多人学习、参考或者应用;这一部分内容能够参考本文;​

Serverless Devs Package 介绍

在说什么是 Serverless Devs Packages 之前,须要先说一下 Serverless Registry, 置信很多研发同学都是晓得,不同语言 / 生态都有本人的包治理平台,例如 Python 语言的 Pypi,Node.js 的 NPM。

而所谓的包治理平台,粗犷来说就是治理“包”的,这里的“包”,往往指的是他人曾经封装了的某些性能或者能力,咱们能够间接应用,而无需咱们反复造轮子。

说两个比拟形象的例子,如果是搞人工智能,咱们不太事实要手动的来写各种算法,往往会通过 Sklearn,Tensorflow 等对应的包来疾速的加载某些模型,而后在这个根底上再提高的开发和欠缺。

而在 Serverless 畛域,咱们也心愿有一个相似的包治理平台,那就是 Serverless Registry:

|

Serverless Reigstry Python Pypi Nodejs NPM
存储内容 Serverless packages(包含 Components 和 Application) Python packages Nodejs packages
是否凋谢规范
官网源 registry.devsapp.cn/simple pypi.python.org registry.npmjs.org
其它源举例 Github registryGitee registry 清华源、豆瓣源 tnpm、cnpm
是否反对私有化 反对 反对 反对
配套工具 Serverless Devs 开发者工具 Python 包管理工具(pip) Node.js 打包管理工具(npm)
配套命令 s pip npm
如何应用 在 s.yaml 中间接援用 装置之后,在代码中援用 装置之后,在代码中援用

与 Python 的 Pypi,Node.js 的 NPM 不同的是,在 Serverless Regsitry 中,Package 是分成两类的,一类是 Component,一类是 Application。

针对 Component 和 Application 的艰深来作辨别:

  • Component:指的是组件,相似于一个脚本,通过这个脚本能够做一些事件。例如部署一个函数到某个云平台,调试某个函数,查看某个函数的日志等;
  • Application:指的是利用,相似于一个案例。例如通过某个 Application,能够让用户疾速的创立一个 Hello World 的利用,创立一个音视频解决的利用等;
    在 Serverless Devs 的标准中,有对于二者的一个区别图:


而对于 Component 和 Application 的关系是:Application 是一个利用案例的定义,须要通过 Component 进行部署上线。

或者下面的示意有些许的形象,其实能够用一个形象的案例进行解释。例如:

  • 你通过 Python 的 Tensorflow 框架,做了一个人脸识别的利用,那么此时 Tensorflow 就能够认为是一个 Component,而人脸识别的利用就能够认为是一个 Application;
  • 你通过 Node.js 的 Express、Fs、Path 等依赖,做了一个集体博客,那么此时 Express、Fs、Path 等依赖,就能够认为是不同的 Component,而做进去的这个博客,就能够认为是一个 Application;
  • Serverless Registry Model
  • Serverless Package Model

开发 Package

开发者开发 Serverless Package 的流程相对来说是比较简单的。因为在 Serverless Devs 开发者工具中,曾经提供了绝对残缺的脚手架能力。

开发者只须要执行 s init,并且抉择 Dev Template for Serverless Devs 即可:

抉择实现,不难发现,此时会让咱们持续抉择是开发 Component 还是开发 Application:

开发 Component

当抉择 Component Scaffolding 之后,须要给行将开发的 Component 起一个名字(例如 deployfunction):


此时,能够依据体统提醒,进入到 Component 的我的项目目录:

此时,能够通过 IDE 关上以后我的项目,并通过 npm 进行依赖装置_(因为 Serverless Devs 是基于 Typescript 的我的项目,所以组件的开发仅反对 Typescript 和 Node.js 语言)_:


此时,能够关上我的项目中 src/index.ts 文件,不难发现曾经存在一个案例:

import logger from ‘./common/logger’;
import {InputProps} from ‘./common/entity’;

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

在该文件中,咱们不难发现存在一个 test(inputs)办法,该办法是一个打印 inputs 参数,并返回 hello world 的案例,然而通过这个简略的案例,咱们能够理解到几个事件:

公共办法就是用户能够应用的命令

在我的项目中,咱们能够写多个办法对外裸露,目前只有一个 test,然而咱们能够减少任何 public 办法,而这些办法将会成为该组件的命令。例如:

 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’};
  }​

此时,咱们在应用该组件时,组件就具备了两个命令:test 命令和 deploy 命令,为了验证咱们的想法,咱们能够对我的项目进行根底的开发态的编译:npm run watch:


此时,咱们能够找到 example 目录,进行 deploy 办法的测试,例如:


通过 example 上面的 s.yaml 文件,咱们不难看出,这个 yaml 有两个 service_(别离是 component-test 和 component-test2)。_

并且这两个 service,都用了咱们同一个组件。所以,在执行 s deploy 之后取得到预期的后果:即执行了 deploy 办法。

同样的,咱们也能够执行 test 命令看一下成果:


要实现的逻辑能够在办法内自在实现

换句话来说,Serverless Devs 工具在加载组件的时候,实际上就是将对应的参数,传递到指定的办法,并且执行该办法。所以,你要实现什么性能都能够写在对应的办法里。

以 Serverless Registry Component 我的项目为例,我在该我的项目中,存在一个 Login 的性能,所以我在 Login 中实现了以下内容:

 /**
     * demo 登陆
     * @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}

            // 输入揭示
            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/us…’, {
                                params: {
                                    token: token,
                                },
                            })
                            if (!tempResult.Error && tempResult.safety_code) {
                                // 或失去后果, 存储状态
                                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;
    }

在该办法中次要存在几个事件:

  1. 对 inputs 参数解析,获取用户输出的参数内容;
  2. 如果用户输出的参数带有 - h 或者 –help 参数,则输入对应的帮忙信息;
  3. 如果用户输出的参数存在 –token,则将 –token 对应的值存入到某个文件中;
  4. 如果用户没有带有 –token 输出,则间接关上浏览器,拜访 Serverless Registry 的登陆地址,并进行相干登陆 token 的获取;

那么同样的办法,如果是一个部署函数的办法或者命令,咱们是不是能够在这个外面实现打包压缩代码,而后调用相干创立函数,更新函数的接口进行函数的创立呢?再比方,想要做一个删除函数的办法,是不是能够在外面调用删除函数的接口呢?

所以能够认为,无论想要实现什么性能,都能够在对应的办法中实现。

对于开发过程中的一些标准

在下面咱们说到,Serverless Devs 会带着某些参数调用该办法,那么参数是什么样子的?格局如何,咱们该如何解析呢?

再比方,我的项目最初的 return 有什么用途?如何在我的项目中获取用户的密钥信息?用户在 Yaml 中写的各种参数如何获取?用户在执行命令时候传递的参数如何获取?

其实这些都能够参考:Serverless Devs Package 的开发标准文档的组件模型代码标准,在这里咱们不难发现:

入参 inputs 的构造为:

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

其中,这些参数的含意:

目录 含意
command 用户所执行的命令
project 用户的我的项目根本信息
credentials 用户的密钥信息
prop 用户配置的属性 / 参数
args 用户传递的参数(字符串模式)
argsObj 用户传递的参数(解析后的,以数组模式传递)

一个更为具体的例子是,在下面的案例代码中,有一个 test 办法,该办法就是性能实现的办法。此时当用户应用 test 命令时,零碎就会携带参数调用该办法。以一个实在案例作为举例说明:

该组件名为 hexo,组件外围代码如上所示,具备一个 test 办法,此时用户侧的 Yaml 为:

edition: 1.0.0        #  命令行 YAML 标准版本,遵循语义化版本(Semantic Versioning)标准
name: FullStack       #  项目名称
access: xxx-account1  #  秘钥别名

services:
  HexoComponent:
    component: hexo
    props:
      region: ‘cn-hangzhou’
      codeUri: ‘./src’​

当用户执行 s test mytest -a -b abc,此时,组件代码中的 test 办法,收到的 inputs 参数实际上是:

{
    “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”
    ]
}

此时 test 办法会打印日志信息等,并返回最终的后果给命令行工具:{“hello”: “world”}

而对于如何返回帮助文件,如何获取密钥信息,如何解析用户的输出内容,则能够参考 Serverless Devs 提供的 core 包:

在该工具包中,咱们能够看到诸多的办法助力咱们疾速的应用:


例如,获取用户应用密钥,就能够间接引入 core 包,应用对应的 getCredential 办法即可:

  • 应用办法 1:不传任何参数的时候,会获取 default 密钥信息

    const {getCredential} = require(‘@serverless-devs/core’);
    async function get() {
      const c = await getCredential();
      console.log(‘c’, c);
    }

  • 应用办法 2:传参数,获取指定的密钥信息

    const {getCredential} = require(‘@serverless-devs/core’);
    async function get() {
      // 组件接管的 inputs
      const inputs = {};
      const c = await getCredential(inputs, ‘custom’, ‘AccountIdByCustom’, ‘SecretIDByCustom’);
      console.log(‘c’, c);
    }

组件的形容

在实现咱们的组件性能编写之后,就能够进行组件的形容,所谓的组件的形容,就是要通知 Serverless Registry,这是一个什么组件,有哪些性能。形容内容在 publish.yaml 中:


对于该文件的内容以及局部参数的取值,能够参考组件模型元数据。

当然,除了 publish.yaml 之外,在 Serverless Package 的标准中,目录哪还有其余的文件:

|- src # 目录名字能够变更
|   └── 代码目录  
|- package.json: 须要定义好 main   
|- publish.yaml: 我的项目的资源形容   
|- readme.md: 我的项目简介  
|- version.md: 版本更新内容

其中:

目录 必须 含意
src 举荐存在 对立搁置性能实现,当然也能够换成其余的名称,或者平铺到我的项目下,然而举荐通过 src 来做对立的寄存
package.json 必须存在 Node.js 的 package.json,须要形容分明组件的入口文件地位
publish.yaml 必须存在 Serverless Devs Package 的开发辨认文档
readme.md 必须存在 对该组件的形容,或帮忙文档信息
version.md 举荐存在 版本的形容,例如以后版本的更新内容等

最新版本的标准(0.0.2 版本),将会在近期上线,和 0.0.1 版本不同的是,新版本的 Properties 参数将遵循 JSON Scheme 标准,目前可参考 pr#386)

开发 Application

当抉择 Application Scaffolding 之后,须要给行将开发的 Application 起一个名字(例如 helloworld):


Serverless Package 中的 Application 开发绝对更为简略,无论是任何编程语言,无论是任何我的项目,只有能够通过 Serverless Devs 开发者工具进行部署,就能够把它包装成为一个利用。

或者更为精确的来表述,只有你当初有一个能够通过 Serverless Devs 间接部署的我的项目,那么你就能够:

  1. s init 创立一个利用模板
  2. 把你的那个我的项目,脱敏后,间接放在 src 目录下
  3. 对利用进行形容,例如编辑 publish.yaml,编辑 version.md,编辑 readme.md 等

这一部分具体情况,能够参考利用模型文档:

非凡格局:在利用模型中,须要存在 src/s.yaml 文件,作为 Serverless Devs 辨认和应用的资源、行为形容文件,在该文件中,可能波及到局部内容是须要用户进行填写的,例如用户的密钥名字,用户部署业务的地区等。此时能够参考:

  • “{{access}}”:间接揭示用户须要输出 access 这样的一个参数,作为 Yaml 中所必须的参数;
  • ‘{{bucket | alibaba oss bucket}}’::间接揭示用户须要输出 bucket 这样的一个参数,作为 Yaml 中所必须的参数,并以 | 之后的内容 ”alibaba oss bucket” 作为解释这个参数的含意;
    例如,在某利用的 s.yaml 中体现为:

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

在实现 Serverless Package 的开发之后,为了给更多人应用,还能够将公布到 Registry 中。

公布到 Github/Gitee

对于公布到 Github 或者 Gitee 中,办法很简略:

  1. 创立一个 Repo(代码仓库)
  2. 将整个利用或者组件推到该仓库
  3. 公布一个 Release:此时,在客户端,用户就能够通过 s set registry 进行 registry 的切换,来应用绝对应的性能了。例如,我在 Github 的账户为 anycodes,我就能够创立一个仓库,名字为 demo,此时,我将我的组件 / 利用上传到这个仓库中,而后公布一个 Release。此时,我在客户端,将 registry 切换到 Github,而后就能够:
  • 在应用组件的时候,指定组件名为仓库,例如 anycodes/demo
  • 在初始化利用的时候,也能够间接指定利用,例如 anycodes/application

    公布到 Serverless Registry

若想把 Package 公布到 Serverless Registry,能够思考应用 Serverless Registry Component。

(Serverless Registry 的客户端工具,也是一个组件,所以能够认为 Serverless Registry Component 的这个我的项目,自身也是以后文章的一个最佳实际。)

在实现组件或者利用的开发流程之后,须要:

  1. 注册并登录 Serverless Registry,实际上就是执行 s cli registry login
  2. 进行组件的公布,实际上就是 s cli registry publish

当然,Serverless Registry Component 这个我的项目,除了登陆和公布之外,还有诸多其余的性能,例如:

  • 查看以后登陆账号公布过的 Package
  • 查看某个 Package 的版本信息
  • 查看某个 Package 指定版本信息
  • 删除某个指定版本的 Package
  • 对登陆 token 进行更新

总结

家喻户晓,一个残缺的技术架构的倒退,离不开生态社区对他的赋能,无论是 Docker 的 Dockerhub 还是 Python 的 Pypi,再或者是 Node.js 的 NPM,生态的活跃度和咱们开发者的幸福感是正相干的。

咱们也十分心愿 Serverless Devs 能够通过 Serverless Regsitry 这样一个凋谢的生态,和更多的人一起玩转 Serverless 架构,也期待更多优良的 Package,被更为宽泛的利用。

(END)

更多内容关注 Serverless 微信公众号(ID:serverlessdevs),会集 Serverless 技术最全内容,定期举办 Serverless 流动、直播,用户最佳实际。

退出移动版