如何使用gRPC向Kubernetes容器发送RPC请求触发脚本?
你的工作流程思路基本正确,几个细节调整+实现示例
首先得纠正一个小误区:gin是HTTP Web框架,和gRPC完全不是一个体系的哦~如果用Go开发gRPC客户端/服务端,直接用官方的google.golang.org/grpc库就好,生态成熟,文档也很完善。
接下来我把整个实现流程拆解清楚,附带代码片段和K8s配置:
1. 先定义gRPC服务协议(核心是.proto文件)
gRPC基于Protocol Buffers(简称Protobuf),首先得把服务接口和消息格式定义好,这是客户端和服务端的“约定”:
// script_executor.proto syntax = "proto3"; package scriptrunner; option go_package = "./scriptrunner"; // 定义服务:接收请求,执行脚本,返回结果 service ScriptExecutor { rpc RunScript (ScriptRequest) returns (ScriptResponse); } // 请求消息:可以给脚本传参数 message ScriptRequest { string script_args = 1; } // 响应消息:返回脚本的退出码、标准输出、错误输出 message ScriptResponse { int32 exit_code = 1; string stdout = 2; string stderr = 3; }
写完后用protoc工具生成Go代码(需要先安装protoc和Go的gRPC插件):
protoc --go_out=. --go-grpc_out=. script_executor.proto
2. 实现gRPC服务端(容器内运行,负责接收请求触发脚本)
服务端要监听指定端口,收到请求后调用你的脚本,然后把执行结果返回给客户端:
// server.go package main import ( "context" "os/exec" "scriptrunner" // 刚才生成的Protobuf代码包 "google.golang.org/grpc" "log" "net" ) // 实现gRPC服务接口 type server struct { scriptrunner.UnimplementedScriptExecutorServer } // 处理RunScript请求的核心逻辑 func (s *server) RunScript(ctx context.Context, req *scriptrunner.ScriptRequest) (*scriptrunner.ScriptResponse, error) { // 替换成你实际的脚本路径,比如./my-script.sh cmd := exec.Command("/bin/sh", "./my-script.sh", req.ScriptArgs) // 执行脚本,捕获输出和错误 stdout, err := cmd.Output() var stderr []byte exitCode := 0 if err != nil { // 如果是脚本执行退出错误,提取错误输出和退出码 if exitErr, ok := err.(*exec.ExitError); ok { stderr = exitErr.Stderr exitCode = exitErr.ExitCode() } else { return nil, err } } // 返回执行结果 return &scriptrunner.ScriptResponse{ ExitCode: int32(exitCode), Stdout: string(stdout), Stderr: string(stderr), }, nil } func main() { // 监听你指定的端口,比如50051 lis, err := net.Listen("tcp", ":50051") if err != nil { log.Fatalf("failed to listen: %v", err) } // 创建gRPC服务实例并注册我们的实现 grpcServer := grpc.NewServer() scriptrunner.RegisterScriptExecutorServer(grpcServer, &server{}) log.Printf("gRPC server listening at %v", lis.Addr()) if err := grpcServer.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }
3. 实现gRPC客户端(用来触发脚本的请求工具)
客户端代码负责连接容器的gRPC服务,发送请求并获取结果:
// client.go package main import ( "context" "scriptrunner" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "log" ) func main() { // 连接容器的地址+端口,比如Pod的IP或者K8s Service的地址,端口和服务端一致 conn, err := grpc.Dial("your-pod-ip:50051", grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Fatalf("could not connect to server: %v", err) } defer conn.Close() // 创建客户端实例 client := scriptrunner.NewScriptExecutorClient(conn) // 发送请求,这里可以给脚本传参数 resp, err := client.RunScript(context.Background(), &scriptrunner.ScriptRequest{ScriptArgs: "param1 param2"}) if err != nil { log.Fatalf("failed to trigger script: %v", err) } // 打印脚本执行结果 log.Printf("Exit Code: %d\n--- Stdout ---\n%s\n--- Stderr ---\n%s", resp.ExitCode, resp.Stdout, resp.Stderr) }
4. K8s Pod配置(暴露gRPC端口)
要让外部能访问容器的gRPC服务,需要在Pod的容器配置里声明暴露的端口:
apiVersion: v1 kind: Pod metadata: name: script-runner-pod spec: containers: - name: script-runner-container image: your-custom-image:latest # 这个镜像要包含gRPC服务端二进制、你的脚本和依赖环境 ports: - containerPort: 50051 # 和服务端监听的端口保持一致 name: grpc-port
如果需要从K8s集群外部访问,还可以配置NodePort类型的Service,或者支持gRPC的Ingress(比如NGINX Ingress)。
几个额外注意事项
- 打包镜像时,要确保脚本有可执行权限(可以在Dockerfile里加
RUN chmod +x /path/to/your-script.sh) - 生产环境不要用
insecure.NewCredentials(),要配置TLS加密gRPC连接 - 脚本依赖的工具(比如Python、curl等)也要包含在镜像里
内容的提问来源于stack exchange,提问作者jtee
相关产品推荐
相关产品推荐

