作者 | 江昱(阿里云 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 registry、Gitee 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;
}
在该办法中次要存在几个事件:
- 对 inputs 参数解析,获取用户输出的参数内容;
- 如果用户输出的参数带有 - h 或者 –help 参数,则输入对应的帮忙信息;
- 如果用户输出的参数存在 –token,则将 –token 对应的值存入到某个文件中;
- 如果用户没有带有 –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 间接部署的我的项目,那么你就能够:
- s init 创立一个利用模板
- 把你的那个我的项目,脱敏后,间接放在 src 目录下
- 对利用进行形容,例如编辑 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 中,办法很简略:
- 创立一个 Repo(代码仓库)
- 将整个利用或者组件推到该仓库
- 公布一个 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 的这个我的项目,自身也是以后文章的一个最佳实际。)
在实现组件或者利用的开发流程之后,须要:
- 注册并登录 Serverless Registry,实际上就是执行 s cli registry login
- 进行组件的公布,实际上就是 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 流动、直播,用户最佳实际。