一键部署区块链背后的秘密(下)


前言


《一键部署区块链背后的秘密(上)》中,我们详细讲述了 BaaS 驱动的概念、功能设计以及驱动在 BaaS 内发挥的巨大价值,即实现主体架构与业务代码解耦,实现更灵活、快捷的异构链和异构主机接入。

本文将与大家一同探究驱动运行机制及内部构造,深挖驱动的本质特性,详细呈现驱动之间的协同机制,从而立体地呈现:BaaS平台如何在资源相互隔离的前提下,高效支持不同区块链底层平台部署在不同的主机资源中,达到一键部署区块链服务的能力


要点回顾


在BaaS内,我们定义了两种重要的驱动类型:主机驱动和链驱动。

其中主机驱动负责统管主机资源的生命周期。

链驱动负责统管链和节点资源的生命周期。


驱动的承载器——核心驱动容器环境


每个驱动代码结构统一,支持自动化生成代码,其基本结构如下:

  • ui(驱动页面)

    a)src/actions(资源管理操作)

  • driver(驱动后端服务)

    a)actions(资源管理操作)

    b)coreface(与核心驱动容器环境通信)

    c)main.go(程序入口)

  • config.yaml(驱动配置)
  • logo.svg(驱动 logo)
  • pack.sh(驱动打包脚本)

其中,驱动页面作为微前端嵌入BaaS控制台,支持用户可视化操作,而驱动后端服务则作为HTTP服务负责提供对资源的全生命周期管理。

因此,前端请求可通过核心驱动容器环境 这一“介质”将请求转发给具体的驱动,随后,驱动通过核心驱动容器环境SDK与之进行GRPC通信,最终将数据存储在BaaS数据库当中。

一方面,BaaS通过上述模式定义了通用的驱动协议,另一方面,借助驱动中pack.sh 脚本将驱动打包成压缩文件后,调用核心驱动容器环境的驱动上传接口实现驱动包上传操作,实现对不同类型资源的管理能力,从而真正实现“可插拔”。



主机驱动与链驱动的桥梁



我们知道,支持单一主机类型并在该环境内部署并管理一种区块链底层平台是较为简单的,但若想囊括绝大部分主机类型以及区块链底层平台绝非易事。

实践中,当且仅当链和节点资源被部署在主机环境上才会成为真正的资源,而未部署前他们对于链驱动而言可视为若干配置文件。因此,通过分析资源的本质属性,我们抽象了一个统一的Command接口,该接口可视为连接主机驱动与链驱动之间的桥梁,而驱动内部则负责核心能力实现。

通过驱动和Command接口的有机组合,后续如BaaS平台需要新增支持新的主机环境,只需实现相应的Command接口即可,从根本上实现X种区块链底层在Y个资源环境下的兼容,省去X*Y次重复劳动。



小试牛刀


为便于理解实际运作,我们编写了一个基础demo 。(真实场景中主机驱动和链驱动是通过趣链BaaS 提供的核心驱动引擎接口以及网络进行通信的,本文旨在帮助大家直观感受Command接口如何链接主机驱动和链驱动。)

  • 首先,创建autodeploy项目
mkdir autodeploy && cd autodeploygo mod init authdeploy
  • 定义主机驱动Command接口
type HostDriver interface {  Command(req *ExecCommandReq) (*ExecCommandRes, error)}
type ExecCommandReq struct { MachineID int Command string // 可扩展其他能力, 如文件等}

type ExecCommandRes struct { Desc string}
  • 定义主机驱动与链驱动的桥梁
// Core 主体服务type Core struct{}

// ExecCommand core 定义链驱动与主机驱动的桥梁func (c Core) ExecCommand(req *ExecCommandReq) (res *ExecCommandRes, err error) { var hd HostDriver

uuid := getHostDriverByMachineID(req.MachineID) // 主机驱动, core 服务根据主机 req 中的主机 ID 获取所用的主机驱动 switch uuid { case "colocation": hd = &Colocation{} res, err = hd.Command(req) }

return res, err}

func getHostDriverByMachineID(ID int) string { // TODO // 根据 machine ID 获取所用的主机驱动 return "colocation"}
  • 实现主机驱动command接口
// Colocation 托管主机驱动type Colocation struct{}

// Command colocation 驱动实现的 Command 接口func (c *Colocation) Command(req *ExecCommandReq) (*ExecCommandRes, error) { command := exec.Command("bash", "-c", req.Command) output, err := command.CombinedOutput() if err != nil { return nil, err } return &ExecCommandRes{Desc: string(output)}, nil}
  • 定义链驱动部署节点方法,屏蔽主机间的差异
// Hyperchain 链驱动type Hyperchain struct{}

func (h *Hyperchain) DeployNode(req *ExecCommandReq) (*ExecCommandRes, error) { core := &Core{} return core.ExecCommand(req)}
  • main方法
// Hyperchain 链驱动type Hyperchain struct{}

func (h *Hyperchain) DeployNode(req *ExecCommandReq) (*ExecCommandRes, error) { core := &Core{} return core.ExecCommand(req)}

func main() { // Hyperchain 驱动, 将节点部署在 colocation 主机上 { hpc := Hyperchain{} res, err := hpc.DeployNode(&ExecCommandReq{ MachineID: 1, Command: "./deploy.sh", // 执行脚本完成节点的部署 }) if err != nil { fmt.Println(err) return } fmt.Println(res.Desc) }}



总结


BaaS 通过设计可插拔形式的驱动,实现不同区块链底层平台资源的生命周期管理能力,但这还远远不够,因为具体的资源层均是主机驱动加以控制的。