在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
go-plugin 已经存在很长时间了,同时hashicorp公司的好多产品都在使用 项目准备
go mo init demo-plugin
go get github.com/hashicorp/go-plugin
go get github.com/hashicorp/go-hclog
├── Dockerfile
├── README.md
├── commons
│ └── greeter_interface.go
├── go.mod
├── go.sum
├── main.go
└── plugin
└── greeter_impl.go
代码说明go-plugin 的开发模式,是基于二进制文件按需运行的(plugin 为二进制应用,懒加载运行)
package commons
import (
"net/rpc"
"github.com/hashicorp/go-plugin"
)
// Greeter greeter
type Greeter interface {
Greet() string
}
// GreeterRPC Here is an implementation that talks over RPC
type GreeterRPC struct{ client *rpc.Client }
// Greet greet
func (g *GreeterRPC) Greet() string {
var resp string
// how to identifi
err := g.client.Call("Plugin.Greet", new(interface{}), &resp)
if err != nil {
// You usually want your interfaces to return errors. If they don't,
// there isn't much other choice here.
panic(err)
}
return resp
}
// GreeterRPCServer Here is the RPC server that GreeterRPC talks to, conforming to
// the requirements of net/rpc
type GreeterRPCServer struct {
// This is the real implementation
Impl Greeter
}
// Greet greet for service impl
func (s *GreeterRPCServer) Greet(args interface{}, resp *string) error {
*resp = s.Impl.Greet()
return nil
}
// GreeterPlugin This is the implementation of plugin.Plugin so we can serve/consume this
//
// This has two methods: Server must return an RPC server for this plugin
// type. We construct a GreeterRPCServer for this.
//
// Client must return an implementation of our interface that communicates
// over an RPC client. We return GreeterRPC for this.
//
// Ignore MuxBroker. That is used to create more multiplexed streams on our
// plugin connection and is a more advanced use case.
type GreeterPlugin struct {
// Impl Injection
Impl Greeter
}
// Server server
func (p *GreeterPlugin) Server(*plugin.MuxBroker) (interface{}, error) {
return &GreeterRPCServer{Impl: p.Impl}, nil
}
// Client client
func (GreeterPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
return &GreeterRPC{client: c}, nil
}
plugin/greeter_impl.go plugin 二进制程序的入口以及服务暴露 package main
import (
"demo-plugin/commons"
"os"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-plugin"
)
// Here is a real implementation of Greeter
type GreeterHello struct {
logger hclog.Logger
}
func (g *GreeterHello) Greet() string {
g.logger.Debug("message from GreeterHello.Greet")
return "dalong demoapp!"
}
// handshakeConfigs are used to just do a basic handshake between
// a plugin and host. If the handshake fails, a user friendly error is shown.
// This prevents users from executing bad plugins or executing a plugin
// directory. It is a UX feature, not a security feature.
var handshakeConfig = plugin.HandshakeConfig{
ProtocolVersion: 1,
MagicCookieKey: "BASIC_PLUGIN",
MagicCookieValue: "hello",
}
func main() {
logger := hclog.New(&hclog.LoggerOptions{
Level: hclog.Trace,
Output: os.Stderr,
JSONFormat: true,
})
greeter := &GreeterHello{
logger: logger,
}
// pluginMap is the map of plugins we can dispense.
var pluginMap = map[string]plugin.Plugin{
"greeter": &commons.GreeterPlugin{Impl: greeter},
}
logger.Debug("message from plugin", "foo", "bar")
// 暴露plugin 的rpc 服务,懒运行机制
plugin.Serve(&plugin.ServeConfig{
HandshakeConfig: handshakeConfig,
Plugins: pluginMap,
})
}
package main
import (
"demo-plugin/commons"
"fmt"
"log"
"os"
"os/exec"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-plugin"
)
func main() {
// Create an hclog.Logger
logger := hclog.New(&hclog.LoggerOptions{
Name: "plugin",
Output: os.Stdout,
Level: hclog.Info,
})
// We're a host! Start by launching the plugin process.
client := plugin.NewClient(&plugin.ClientConfig{
HandshakeConfig: handshakeConfig,
Plugins: pluginMap,
Cmd: exec.Command("./plugin/greeter"),
Logger: logger,
})
defer client.Kill()
// Connect via RPC
rpcClient, err := client.Client()
if err != nil {
log.Fatal(err)
}
// Request the plugin
raw, err := rpcClient.Dispense("greeter")
if err != nil {
log.Fatal(err)
}
// We should have a Greeter now! This feels like a normal interface
// implementation but is in fact over an RPC connection.
greeter := raw.(commons.Greeter)
fmt.Println("from plugin message:" + greeter.Greet())
}
// handshakeConfigs are used to just do a basic handshake between
// a plugin and host. If the handshake fails, a user friendly error is shown.
// This prevents users from executing bad plugins or executing a plugin
// directory. It is a UX feature, not a security feature.
var handshakeConfig = plugin.HandshakeConfig{
ProtocolVersion: 1,
MagicCookieKey: "BASIC_PLUGIN",
MagicCookieValue: "hello",
}
// pluginMap is the map of plugins we can dispense.
var pluginMap = map[string]plugin.Plugin{
"greeter": &commons.GreeterPlugin{},
}
FROM golang:1.14-alpine AS build-env
RUN /bin/sed -i 's,http://dl-cdn.alpinelinux.org,https://mirrors.aliyun.com,g' /etc/apk/repositories
WORKDIR /go/src/app
COPY . .
ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.cn
RUN apk update && apk add git \
&& go build -o ./plugin/greeter ./plugin/greeter_impl.go && go build -o basic .
FROM alpine:latest
RUN /bin/sed -i 's,http://dl-cdn.alpinelinux.org,https://mirrors.aliyun.com,g' /etc/apk/repositories
RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/*
COPY --from=build-env /go/src/app/basic .
COPY --from=build-env /go/src/app/plugin/greeter ./plugin/
ENTRYPOINT [ "./basic" ]
运行
go build -o ./plugin/greeter ./plugin/greeter_impl.go
go build -o basic .
./basic
参考资料https://github.com/hashicorp/go-plugin |
请发表评论