我正在尝试运行我的WASM过滤器,以便使用net/http模块进行外部HTTP调用。特使未能加载WASM代码。为什么进口失败?
特使/伊斯蒂奥版本:istio/proxyv2 2:1.11.4
SDK版本:v0.16.1-0.20220127085108-af57b89bc 067
TinyGo版本: tinygo版本0.22.0达尔文/ and 64(使用go版本go1.17.6和LLVM版本13.0.0)
错误日志
2022-01-31T20:34:18.513749Z error envoy wasm Failed to load Wasm module due to a missing import: env.time.resetTimer
2022-01-31T20:34:18.513794Z error envoy wasm Failed to load Wasm module due to a missing import: env.time.stopTimer
2022-01-31T20:34:18.513807Z error envoy wasm Failed to load Wasm module due to a missing import: env.time.startTimer
2022-01-31T20:34:18.513817Z error envoy wasm Failed to load Wasm module due to a missing import: env.sync/atomic.AddInt32
2022-01-31T20:34:18.513826Z error envoy wasm Failed to load Wasm module due to a missing import: wasi_snapshot_preview1.fd_filestat_get
2022-01-31T20:34:18.513833Z error envoy wasm Failed to load Wasm module due to a missing import: wasi_snapshot_preview1.fd_pread
2022-01-31T20:34:18.513840Z error envoy wasm Failed to load Wasm module due to a missing import: wasi_snapshot_preview1.fd_prestat_get
2022-01-31T20:34:18.513846Z error envoy wasm Failed to load Wasm module due to a missing import: wasi_snapshot_preview1.fd_prestat_dir_name
2022-01-31T20:34:18.513854Z error envoy wasm Failed to load Wasm module due to a missing import: wasi_snapshot_preview1.path_open
2022-01-31T20:34:18.513864Z error envoy wasm Wasm VM failed Failed to initialize Wasm code
2022-01-31T20:34:18.517062Z critical envoy wasm Plugin configured to fail closed failed to load
2022-01-31T20:34:18.517191Z warning envoy config gRPC config for type.googleapis.com/envoy.config.core.v3.TypedExtensionConfig rejected: Unable to create Wasm HTTP filter
tinygo build -o main.wasm -scheduler=asyncify -target=wasi main.go实际代码
package main
import (
"errors"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
"io/ioutil"
"time"
"net/http"
)
const (
sharedDataKey = "hello_world_shared_data_key"
)
func main() {
proxywasm.SetVMContext(&vmContext{})
}
type (
vmContext struct{}
pluginContext struct {
// Embed the default plugin context here,
// so that we don't need to reimplement all the methods.
types.DefaultPluginContext
}
httpContext struct {
// Embed the default http context here,
// so that we don't need to reimplement all the methods.
types.DefaultHttpContext
}
)
// Override types.VMContext.
func (*vmContext) OnVMStart(vmConfigurationSize int) types.OnVMStartStatus {
proxywasm.LogInfo("Inside OnVMStart")
http := http.Client{Timeout: time.Duration(10) * time.Second}
resp, err := http.Get("http://SOME_URL:8001/echo?message=hello_world")
if err != nil {
proxywasm.LogWarnf("Error calling hello_world/echo on OnVMStart: %v", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
proxywasm.LogWarnf("Error parsing hello_world/echo response on OnVMStart: %v", err)
}
proxywasm.LogInfof("Response Body : %s", body)
initialValueBuf := []byte("body")
if err := proxywasm.SetSharedData(sharedDataKey, initialValueBuf, 0); err != nil {
proxywasm.LogWarnf("Error setting shared hello_world data on OnVMStart: %v", err)
}
return types.OnVMStartStatusOK
}
// Override types.DefaultVMContext.
func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
return &pluginContext{}
}
// Override types.DefaultPluginContext.
func (*pluginContext) NewHttpContext(contextID uint32) types.HttpContext {
return &httpContext{}
}
// Override types.DefaultHttpContext.
func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
for {
value, err := ctx.getSharedData()
if err == nil {
proxywasm.LogInfof("shared data value: %s", value)
} else if errors.Is(err, types.ErrorStatusCasMismatch) {
continue
}
break
}
return types.ActionContinue
}
func (ctx *httpContext) getSharedData() (string, error) {
value, cas, err := proxywasm.GetSharedData(sharedDataKey)
if err != nil {
proxywasm.LogWarnf("error getting shared data on OnHttpRequestHeaders with cas %d: %v ", cas, err)
return "error", err
}
shared_value := string(value)
return shared_value, err
}发布于 2022-02-01 15:51:00
不幸的是,这并不容易。
TinyGo可能支持这个模块,但是在使用特使的WASM模块时,您不能“只”调用一些任意的API。
更准确地说,WASM模块运行在沙箱中,只能进行运行时显式允许的调用。对于特使,wasm代理sdk提供了一种简单的机制来调用这些API。
proxy-wasm-go-sdk提供了您可以使用的这些API调用。
有一个函数proxywasm.DispatchHttpCall。然而,你必须“使用特使的方式”进行http电话。
注意,该调用中的“集群”不是一个简单的URL,而是一个使节群。如果您有任何使用Istio代理定义的服务,也可以尝试使用Istio定义的集群(如outbound|80||some-service.some-namespace.svc.cluster.local )。
例如,您可以使用istioctl查找代理配置(例如,用于入口网关):
istioctl proxy-config all istio-ingressgateway-YOUR-POD -o json | less在Istio中添加ServiceEntries时,您也可能在网格中得到这样一个“集群”。请注意,服务条目也可以引用外部主机,而不仅仅是集群服务中的.
否则,您可能会尝试添加类似于基于公使的速率限制的手动集群,尽管这也很容易出错。
- applyTo: CLUSTER
match:
cluster:
service: ratelimit.default.svc.cluster.local
patch:
operation: ADD
# Adds the rate limit service cluster for rate limit service defined in step 1.
value:
name: rate_limit_cluster
type: STRICT_DNS
connect_timeout: 10s
lb_policy: ROUND_ROBIN
http2_protocol_options: {}
load_assignment:
cluster_name: rate_limit_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: ratelimit.default.svc.cluster.local
port_value: 8081在这是对Lua特使过滤器的描述中,您可以看到一些例子。虽然不是WASM,但原则仍然是一样的。
去吧,你可以试试
headers := [][2]string{
{":method", "GET"},
{":path", "/echo?message=hello_world"},
{":authority", "SOME_HOST"},
{":scheme", "http"},
}
_, err := proxywasm.DispatchHttpCall("CLUSTER",
headers,
nil,
nil,
1000,
func(numHeaders, bodySize, numTrailers int) {
resp, _ := proxywasm.GetHttpCallResponseBody(0, 10000)
r := string(resp)
proxywasm.LogDebugf("RESPONSE %v", r)
},
)https://stackoverflow.com/questions/70933142
复制相似问题