简体   繁体   English

gRPC 节点:当 *Dockerizing* 服务时,请求不是通过服务的服务器 go 吗? [包括截图]

[英]gRPC-node: When *Dockerizing* Service, request doesn't go through service's server? [Screenshots included]

I created a really simple bookstore with a Books, Customer, and a main service.我创建了一个非常简单的书店,其中包含书籍、客户和主要服务。 This particular problem involves the main and books service.这个特殊的问题涉及到 main 和 books 服务。

I'm currently making a gRPC request called: "createBook", which creates a book in our DB, and also console logs.我目前正在发出一个名为“createBook”的 gRPC 请求,它会在我们的数据库中创建一本书,以及控制台日志。

When running the gRPC server (booksServer) without docker, the process runs smoothly.在没有 docker 的情况下运行 gRPC 服务器(booksServer)时,该过程运行顺利。

But as soon as I use docker, it seems as if a gRPC request doesn't go into the gRPC server...但是,一旦我使用 docker,gRPC 请求似乎不会 go 进入 gRPC 服务器......

By "using docker" I mean using docker to run the booksServer. “使用 docker”是指使用 docker 来运行 booksServer。 (As shown below) (如下所示)

Result: Without Docker结果:没有 Docker

As you can see, without docker, the request is fulfilled, and everything works as it should. 
Our gRPC client makes a call to the gRPC server (in which metadata is created) and the metadata is also sent back to the client. 
(Scroll down to see the gRPC server file with the method called "getBooks".)

在此处输入图像描述

booksServer (without docker)图书服务器(不带 docker) 在此处输入图像描述

*** Notice the console logs in the booksServer!!! ***

Let me run the booksServer (with docker)让我运行 booksServer(使用 docker)

(Dockerfile below) (下面的Dockerfile)

FROM node:12.14.0
WORKDIR /usr/src/app
COPY package*.json ./
COPY . /usr/src/app
RUN npm install
RUN npm install nodemon -g
EXPOSE 30043
CMD ["nodemon", "booksServer.js"



Here's my main service docker file too which initiates the request:

FROM node:12.14.0
WORKDIR /usr/src/app
COPY package*.json ./
COPY . /usr/src/app
# COPY wait-for-it.sh . 
# RUN chmod +x /wait-for-it.sh
RUN npm install
EXPOSE 4555
CMD ["node", "main.js"]

在此处输入图像描述 在此处输入图像描述

^^^ Notice how when dockerfile is used to run booksServer
it doesn't go/run inside the booksServer file 
***It does NOT produce any console.logs when I fire off a gRPC requesst***

This is what the booksServer.js file looks like这就是 booksServer.js 文件的样子在此处输入图像描述

Heres the Books Stub这是书根

//use this for bookInitiator
const path = require('path');
const PROTO_PATH = path.join(__dirname, "../protos/books.proto");

const grpc = require("grpc");
const protoLoader = require("@grpc/proto-loader");

const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
  keepCase: true,
  longs: String,
  enums: String,
  arrays: true
});

const BooksService = grpc.loadPackageDefinition(packageDefinition).BooksService;

// potential issues to fix 1) making localhost port dynamic 2) docker containerization may cause conflict

const client = new BooksService (
  "172.17.0.2:30043",
  grpc.credentials.createInsecure()
);

console.log("Creating stub inside booksStub");
module.exports = client;

Here's the gRPC Server file (with the binded ports).这是 gRPC 服务器文件(带有绑定的端口)。

// const PROTO_PATH = "../protos/books.proto";
const path = require('path');
const PROTO_PATH = path.join(__dirname, './protos/books.proto');
const grpc = require("grpc");
const protoLoader = require("@grpc/proto-loader");
const express = require("express");
const controller = require("./booksController.js");
const app = express();
app.use(express.json());

const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
  keepCase: true,
  longs: String,
  enums: String,
  arrays: true,
});

const booksProto = grpc.loadPackageDefinition(packageDefinition);

const { v4: uuidv4 } = require("uuid");

const server = new grpc.Server();

server.addService(booksProto.BooksService.service, {
  CreateBook: (call, callback) => {
    console.log("call to CreateBook");

    //sample will take the call information from the client(stub)
    const book = {
      title: call.request.title,
      author: call.request.author,
      numberOfPages: call.request.numberOfPages,
      publisher: call.request.publisher,
      
      id: call.request.id,
    };

    controller.createBook(book);

    let meta = new grpc.Metadata();
    meta.add("response", "none");
    console.log("metadata in createBook...: ", meta);
    call.sendMetadata(meta);

    callback(
      null,
      //bookmodel.create
      {
        title: `completed for: ${call.request.title}`,
        author: `completed for: ${call.request.author}`,
        numberOfPages: `completed for: ${call.request.numberOfPages}`,
        publisher: `completed for: ${call.request.publisher}`,
        id: `completed for: ${call.request.id}`,
      }
    );
  },
  GetBooks: (call, callback) => {
    console.log("call to GetBooks");
    // read from database
    let meta = new grpc.Metadata();
    meta.add('response', 'none');
    call.sendMetadata(meta);

    controller.getBooks(callback);
  }
});

server.bind("0.0.0.0:30043", grpc.ServerCredentials.createInsecure());
console.log("booksServer.js running at 0.0.0.0:30043");
console.log("Inside Books Server!");
console.log("call from books server");

server.start();

horus.js (custom made simple tracing tool), grab trace grabs the journey of a certain request and sends it back to the gRPC client as metadata horus.js(定制的简单追踪工具),抓取追踪抓取某个请求的旅程并将其作为元数据发送回 gRPC 客户端

const fs = require("fs");
const grpc = require("grpc");
const path = require("path");

class horus {
  constructor(name) {
    this.serviceName = name; // represents the name of the microservices
    this.startTime = null;
    this.endTime = null;
    this.request = {};
    this.targetService = null; // represents the location to which the request was made
    this.allRequests = []; // array which stores all requests
    this.timeCompleted = null;
    this.call;
  }

  static getReqId() {
    // primitive value - number of millisecond since midnight January 1, 1970 UTC
    // add service name/ initials to the beginning of reqId?
    return new Date().valueOf();
  }

  // start should be invoked before the request is made
  // start begins the timer and initializes the request as pending
  start(targetService, call) {
    this.startTime = Number(process.hrtime.bigint());
    this.request[targetService] = "pending"; // {books: 'pending', responseTime: 'pending'}
    this.request.responseTime = "pending";
    this.targetService = targetService;
    this.call = call;
    this.request.requestId = horus.getReqId();
  }
  // end should be invoked when the request has returned
  end() {
    this.endTime = Number(process.hrtime.bigint());
    this.request.responseTime = (
      (this.endTime - this.startTime) /
      1000000
    ).toFixed(3); //converting into ms.
    this.sendResponse();
    this.request.timeCompleted = this.getCurrentTime();
  }
  // grabTrace accepts inserts trace into request
  // trace represents the "journey" of the request
  // trace expects metaData to be 'none when the server made no additional requests
  // trace expects metaData to be the request object generated by the server otherwise
  // in gRPC, the trace must be sent back as meta data. objects should be converted with JSON.parse
  grabTrace(metaData) {
    //console.log("incoming meta data ", metaData);
    console.log("Inside Grab Trace Method.");
    console.log("Metadata inside grabTrace: ", metaData);
    if (metaData === "none" || metaData === undefined) this.request[this.targetService] = "none";
    else {
      metaData = JSON.parse(metaData);
      this.request[this.targetService] = metaData;
    }
    this.allRequests.push(this.request);
    this.sendResponse();
  }
  // displayRequests logs to the console all stored requests
  // setTimeout builds in deliberate latency since metadata may be sent before or after a request is done processing
  displayRequests() {
    console.log("\n\n");
    console.log("Logging all requests from : ", this.serviceName);
    this.allRequests.forEach((request) => {
      console.log("\n");
      console.log(request);
    });
    console.log("\n\n");
  }
  // sends response via metadata if service is in the middle of a chain
  sendResponse() {
    if (
      this.request.responseTime === "pending" ||
      this.request[this.targetService] === "pending" ||
      this.call === undefined
    )
      return;
    console.log("Inside send response");
    let meta = new grpc.Metadata();
    meta.add("response", JSON.stringify(this.request));
    console.log('meta in send response: ', meta)
    this.call.sendMetadata(meta);
  }
  writeToFile() {
    console.log("call to writeToFile");
    console.log("logging request obj ", this.request);
    let strRequests = "";
    for (let req of this.allRequests) {
      // First write to file - contains Total
      // subsequent - chained requests
      strRequests += `Request ID: ${req.requestId}\n`;
      strRequests += `"${
        Object.keys(req)[0]
      }" service -> Response received in ${Object.values(req)[1]} ms (Total)\n`;
      strRequests += `Timestamp: ${req.timeCompleted}\n`;
      // while we don't hit an empty object on the 1st key, go inside
      // add numbering in order for nested requests inside original?!
      let innerObj = Object.values(req)[0];
      while (innerObj !== "none") {
        strRequests += `"${
          Object.keys(innerObj)[0]
        }" service -> Response received in ${Object.values(innerObj)[1]} ms\n`;
        strRequests += `Timestamp: ${innerObj.timeCompleted}\n`;
        innerObj = Object.values(innerObj)[0];
      }
      strRequests +=
        "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
    }
    console.log('strRequests', strRequests)
    fs.writeFile(this.serviceName + 'data' + '.txt', strRequests, { flag: "a+" }, (err) => {
      if (err) {
        console.error(err);
      }
    }); //'a+' is append mode
  }

module.exports = horus;


main.js (initiates gRPC client request) main.js(发起 gRPC 客户端请求)

const path = require('path');
// const grpc = require("grpc");
const customersStub = require("./stubs/customersStub.js");
const booksStub = require("./stubs/booksStub.js");
const horusTracer = require(path.join(__dirname, "./horus/horus.js"));

//In master branch
console.log("Stub is Inside main service!!!");

const book = {
  title: "ITttttt",
  author: "Stephen King",
  numberOfPages: 666,
  publisher: "Random House",
  id: 200,
};

const bookId = {
  id: 200
}

const customer = {
  id: 123,
  name: "Lily",
  age: 23,
  address: "Blablabla",
  favBookId: 100
};

const customerId = {
  id: 123
}

let ht = new horusTracer("main");


function CreateBook () {
  ht.start('books')
  booksStub.CreateBook(book, (error, response) => {
    if (error) console.log("there was an error ", error);
    ht.end();
    ht.displayRequests();
    ht.writeToFile();
  }).on('metadata', (metadata) => {
    console.log("Before grab trace is invoked!");
    ht.grabTrace(metadata.get('response')[0]);
  });
}

}


CreateBook(); //Works

What I think is the issue.我认为是什么问题。


Edit: murgatroid99 mentioned that it was a networking issue with docker!


~~~~~~~~~
I initially thought this was a networking issue, but I don't think it is 
because all my docker files are running on the default bridge network. 
So they all technically can communicate with one another...

Is it something wrong with nodemon interacting with Docker? 
Does the server not output the console logs...? 
Is the server actually running and working...?

Do I need a reverse proxy like nginx?

``

The problem is that your server is binding to "127.0.0.1:30043".问题是您的服务器绑定到“127.0.0.1:30043”。 You say that you are running the docker images using the default bridge network.您说您正在使用默认桥接网络运行 docker 映像。 In that mode the docker image has a different (virtual) network than the host machine has, so its loopback address is different from the host machine's loopback address.在该模式下,docker 映像具有与主机不同的(虚拟)网络,因此其环回地址与主机的环回地址不同。 To fix that, you can instead bind the server to 0.0.0.0:30043 or [::]:30043 to bind to other network interfaces that the client can connect to from outside of the docker container.要解决此问题,您可以改为将服务器绑定到0.0.0.0:30043[::]:30043以绑定到客户端可以从 docker 容器外部连接到的其他网络接口。

For the same reason, connecting the client to localhost:30043 will not work: its "localhost" address also refers to the loopback interface within the docker container.出于同样的原因,将客户端连接到localhost:30043将不起作用:它的“localhost”地址也指 docker 容器内的环回接口。 You should instead replace "localhost" with the IP address of the server container.您应该将“localhost”替换为服务器容器的 IP 地址。

Alternatively, as described in this question , you can network the docker containers in "host" mode so that they share the same network with the host machine.或者,如本问题所述,您可以将 docker 容器以“主机”模式联网,以便它们与主机共享同一网络。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用默认 gRPC 服务模板的 Dockerizing.Net 核心服务不起作用 - Dockerizing .Net Core Service with default gRPC service template is not working 对 Windows 服务进行 Docker 化 - Dockerizing a Windows Service 通过 Traefik 从 Go 客户端调用 gRPC 服务(Go-micro) - Call gRPC service (Go-micro) from Go client through Traefik gRPC 节点错误:JSON 中的意外令牌 u 在 position 0 - gRPC-Node Error: Unexpected token u in JSON at position 0 如何请求在 Cloud Run 上运行的 Go 制作的 gRPC 服务器 - How to request gRPC server made by Go running on Cloud Run gRPC 未实现/未知服务 - gRPC Unimplemented/Unknown Service 当通过带有ELB的EC2容器服务对Rails应用进行泊坞管理时,我仍需要nginx吗? - When dockerizing a rails app with EC2 container service with ELB do I still need nginx? Django 应用程序在 dockerizing 时显示“在 http://0.0.0.0:8000/ 启动开发服务器”但未显示在浏览器上 - Django app while dockerizing gives "Starting development server at http://0.0.0.0:8000/" but doesn't show up on browser Dockerizing Node.js 应用程序时的 EADDRNOTAVAIL - EADDRNOTAVAIL when Dockerizing Node.js app 更新服务时Postgres AWS EBS卷不持久 - Postgres AWS EBS volume doesn't persist when updating service
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM