ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

动手搭建ServerLess服务

2022-07-22 20:37:52  阅读:264  来源: 互联网

标签:ServerLess name 代码 DB 动手 article fn 搭建


一、前言

​ 通常我们在做ServerLess的时候会想到用各种云的Faas服务,比如腾讯云,AWS,阿里云等等。但我们很少去研究自己怎么搭建一个ServerLess服务。本篇文章重点会讲解如何自己在服务器上搭建ServerLess服务,并如何使用它。

二、什么是ServerLess?

​ Serverless,又叫无服务器。Serverless 强调的是一种架构思想和服务模型,让开发者无需关心基础设施(服务器等),而是专注到应用程序业务逻辑上。Serverless 也是下一代计算引擎。

​ Serverless 与 FaaS(函数即服务)通常被视为可以互换的术语,但这并不准确。Serverless 是一种抽象层次更高的架构模式,而**“FaaS + BaaS”只是 Serverless 这种架构模式的一种实现**。

​ 其中,FaaS 是一种特定类型的服务,例如 AWS Lambda,Google Cloud Functions,Azure Functions,阿里云函数计算和腾讯云云函数等等;而 BaaS(后端即服务)可以理解为其他类型的托管服务,例如数据库服务,对象存储服务和日志服务等等。

ServerLess具有以下特征:

  • 免运维:不需要管理服务器主机或者服务器进程。

  • 弹性伸缩:根据负载进行自动规模伸缩与自动配置。伸缩范围零到无穷大。

  • 按需付费:根据使用情况决定实际成本。

  • 高可用:具备隐含的高可用性。

三、ServerLess技术选型

​ 两种方案,一种基于现有的Faas云服务,这样不用关心搭建和维护,只需要购买就行了(这种方式我就不讲了,大家可以直接去看腾讯云官网文档)。另一种是自己搭建SeverLess服务端。在这里我们不讲第一种方式,我们讲第二种方式。

​ 搭建服务有很多开源的方案,首先最火的是的OpenFaas库,它是基于kubernetes服务的,环境搭建比较复杂。出于快速上手的目的,选用一块轻量级的SeverLess服务的库。这里我们选用fnproject。它入手简单,只需要有docker环境,即可运行。可以实现快速部署。

fnproject 是一个原生容器无服务器项目,它几乎支持任何编程语言,并且几乎可以在任何地方运行。Fn 是用 Go 语言编写的,因此性能较好且十分轻量。Fnproject 支持 AWS Lambda 风格(AWS Lambda是亚马逊提供的serverless服务),因此你可以轻松导入你的 Lambda 函数并通过 Fnproject 启动它。

四、ServerLess基础服务搭建

​ 首先我们需要安装FnProject,它只支持Linux / Mac 两种系统, 对于Window用户,我建议安装一个ubuntu的操作系统。基于WSL2的话,还是比较简单的。

​ FnProject的服务端和客户端都是在一个程序中,所以我们只需要安装一个fn-cli就可以了。下面我讲一下详细的安装步骤。

Mac安装示例:

​ 使用Homebrew安装 (这里有个坑,大家要换国内的镜像源,不然会很慢,清华镜像

brew update && brew install fn
复制代码

​ 或者使用FnProject的脚本安装

curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh
复制代码

Windows安装说明:

​ 首先升级你的系统支持WSL2协议, 安装Ubuntu系统,然后用上面的脚本安装即可。

最后启动ServerLess服务

fn start
#默认会走8080端口
fn start -p 9080 
#可以指定一个端口启动
#这里注意,如果修改端口后,还需要修改环境变量
export FN_API_URL=http://127.0.0.1:9080 
复制代码

五、生成ServerLess应用

fnproject 提供一下五种语言的支持,分别都有对应的教程,在这里我们主要讲的是nodejs语言,其他语言大家可以自行去看。

fn init --runtime node nodeTest #初始化node项目的结构
复制代码

然后我们来看一下nodeTest的目录结构

img

理解func.yaml文件作用

schema_version: 20180708
name: nodetest
version: 0.0.1
runtime: node
build_image: fnproject/node:14-dev
run_image: fnproject/node:14
entrypoint: node func.js
复制代码
  • schema_version 服务的唯一标识 ,它决定哪些字段是可以用的

  • name 服务的名称,也是所在的目录名称

  • Version 当前的函数的版本

  • runtime 运行的语言信息

  • build_image 打包的docker镜像

  • run_image 运行的docker镜像

  • entrypoint 函数是由docker启动的,这个是最后docker执行的命令,node func.js,代表启动这个node服务

func.js是我们的代码文件,比较简单,输出hello world,内容如下

const fdk=require('@fnproject/fdk');

fdk.handle(function(input){
  let name = 'World';
  if (input.name) {
    name = input.name;
  }
  console.log('\nInside Node Hello World function')
  return {'message': 'Hello ' + name}
})
复制代码

六、ServerLess部署

首先我们需要create app appname 一个node应用,对于现有的函数应用进行管理的app,也相当于给你的函数应用一个命名空间。这个app name 也是部署需要用到的。在同一个app下的函数,可以一起部署。

#在当前函数代码目录下执行
fn create app nodeApp
复制代码

创建完后,我们就可以部署我们的函数应用了。 这里fnproject为我们提供deploy命令

fn --verbose deploy --app nodeApp --local
复制代码

这里说明一些参数

  • --verbose 这能将控制台中命令执行的细节和过程打印出来。
  • --app 指定app name
  • --local 如果你的ServerLess服务在本地机器的这里需要指定,如果在远程机器上,这里就不需要它

img

执行过程中,fnproject会自动构建docker镜像,并自动执行安装npm install , 执行完后,我们会看到上面的结果。

验证并访问函数应用

我们如何访问这个Severless服务呢?FnProject提供了两种调用方式。

第一种是采用CLI命令行的方式去调用

fn invoke nodeApp nodetest  #invoke是fn提供给我们可以直接调用funcApp的命令
{"message":"Hello World"}  #这个是控制台的打印输出
复制代码

上面的函数例子,我们发现有一个input参数, 那么我们怎么将参数传递给func app呢?

这里我们可以通过shell的管道命令传递过去。

echo -n '{"name":"Felix"}' | fn invoke nodeApp nodetest --content-type application/json
{"message":"Hello Felix"}  #这个是控制台的打印输出
复制代码

第二种就是采用API接口方式去调用。

首先我们需要获取函数的Api地址,通过下面命令可以获取到Api地址。

fn inspect function nodeApp nodetest
{
        "annotations": {
                "fnproject.io/fn/invokeEndpoint": "http://localhost:8080/invoke/01FG6BBGV9NG8G00GZJ0000002"
        },
        "app_id": "01FG681T38NG8G00GZJ0000001",
        "created_at": "2021-09-22T08:53:31.113Z",
        "id": "01FG6BBGV9NG8G00GZJ0000002",
        "idle_timeout": 30,
        "image": "nodetest:0.0.2",
        "memory": 128,
        "name": "nodetest",
        "timeout": 30,
        "updated_at": "2021-09-22T08:53:31.113Z"
}
复制代码

http://localhost:8080/invoke/01FG6BBGV9NG8G00GZJ0000002 这个地址就是我们nodetest 服务的请求地址。我们可以通过Postman调用,可以在代码里面通过ajax调用。

这里我用curl去演示一下。我就一步到了,用POST请求直接传递数据调用接口

curl -X "POST" -H "Content-Type: application/json" -d '{"name":"Felix"}' http://localhost:8080/invoke/01FG6BBGV9NG8G00GZJ0000002
{"message":"Hello Felix"}  #这个是控制台的打印输出
复制代码

到这里,我们关于一些基本的能力都讲完了,那我们讲一点高级的应用。比如如何访问数据库,自定义DockerFile文件,如何debug等。

七、ServerLess进阶演示

首先我们先来看一看,如何访问Mysql, 首先我们先用docker装一下Mysql

#先拉取镜像
docker pull mysql:5.7 
#启动mysql镜像
docker run -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
复制代码

环境变量处理,对于Mysql连接的话,我们需要考虑对db_host单独配置。避免写死在代码中。

FnProject提供了丰富的环境变量,供我们使用

  • DB_HOST_URL 数据库的地址链接.

  • DB_USER 数据库的用户名.

  • DB_PASSWORD 数据库的密码.

#配置数据库基本信息 
fn cf a nodeApp DB_HOST_URL 172.29.149.191  #这里需要指定容器宿主Ip
fn cf a nodeApp DB_HOST_PORT 3306
fn cf a nodeApp DB_NAME db_test
fn cf a nodeApp DB_USER root
fn cf a nodeApp DB_PASSWORD 123456

#通过此命令可以查看环境变量
fn ls cf a nodeApp
复制代码

目前是一个空的数据库,我们需要创建简单数据库和一张表结构

简单起见,我们通过命令行创建数据库和表吧。方便后面的演示。

 #进入mysql容器内
 docker exec -it mysql bash
 #CLI登录mysql
 mysql -uroot -p123456
 #创建数据库
 create database db_test;
 use db_test;
 #创建表
CREATE TABLE IF NOT EXISTS `article`(
        `article_id` INT UNSIGNED AUTO_INCREMENT, 
        `article_title` VARCHAR(100) NOT NULL,
        `article_author` VARCHAR(40) NOT NULL,
        PRIMARY KEY ( `article_id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
#插入一条测试数据
INSERT INTO article (article_title,article_author) VALUES("Attention is all you need","Bengio")
复制代码

然后给我们的nodeTest 函数应用赋能。 安装连接mysql的npm包.

传统mysql连接拼接sql语句,我一直不提倡用这个方式。 我选一个支持sql builder的npm工具。

这里我用一款国外比较流行的库knex(我就不介绍这款工具的使用了,大家自行学习)

然后下面我们修改func.js的代码

const fdk=require('@fnproject/fdk');


fdk.handle(async function(input,ctx){
  let name = 'World';
  if (input.name) {
    name = input.name;
  }
  const knex = require('knex')({
    client: 'mysql',
    connection: {
      host : ctx.config['DB_HOST_URL'], //获取数据库配置环境变量
      port : ctx.config['DB_HOST_PORT'],
      user : ctx.config['DB_USER'],
      password : ctx.config['DB_PASSWORD'],
      database : ctx.config['DB_NAME']
    }
  });
  // 根据传入的 name查询数据表
  const rows = await knex('article').where('article_title','like',`%${name}%`)
  return rows
})
#下面我们将代码重新部署一下
fn --verbose deploy --app nodeApp --local
# 然后执行接口
curl -X "POST" -H "Content-Type: application/json" -d '{"name":"you"}' http://localhost:8080/invoke/01FG6BBGV9NG8G00GZJ0000002
# 下面直接获得接口返回的JSON
[{"article_id":1,"article_title":"Attention is all you need","article_author":"Bengio"}]
复制代码

到此我们完成对数据库的访问。 举一反三同样,我们同样也可以访问redis,mongodb等外部服务。 但是这里有一个问题,我们缺少连接池,每次都需要重新创建一个新连接,这种方式不太高效。但对一些小的应用,用完就关闭,也可以满足了。 但做好也有办法可以解决,一个是将连接操作放外面。或者对这种连接操作,再单独做函数应用,类似微服务化的方式。在这里我就不展开讲了。 这里只是让大家通过自己动手搭建,来逐步理解ServerLess是怎么工作的。

八、ServerLess最后总结

在此,我只是简单的动手搭建了一个最基本的ServerLess服务,真正用于生产,还需要考虑更多。服务注册发现、健康检查、配置、容错,监控,流量,接入Kubernetes等 都是需要考虑的事情。 但ServerLess也有一定的弊端,开发、调试有点不太方便,你需要自己写单元测试提前在本地运行好。不然就只能看控制台日志。本地做的话,也需要注意,把业务拆细一点。代码太长也是不利于调试的。 对前端来说,可以用ServerLess快速实现一些想法,不依赖服务端的介入。还是很不错的。


作者:FelixCoder
链接:https://juejin.cn/post/7011383405799538719
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

标签:ServerLess,name,代码,DB,动手,article,fn,搭建
来源: https://www.cnblogs.com/cangqinglang/p/16507892.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有