gRPC-웹 요청용 Envoy Proxy
샘플 코드
샘플 코드 준비됐으니 가능하면 손 옆에서 읽어보세요.[1]
디렉토리 구조
목차의 구성은 다음과 같다.
./
├── Makefile # 各種コマンド
├── client # gRPC-Web Client 関連
│ ├── client.js
│ ├── dist
│ ├── index.html
│ └── generated
│ └── helloworld
│ ├── helloworld_grpc_web_pb.js
│ └── helloworld_pb.js
├── docker-compose.yml # Envoy の起動設定
├── proto # protobuf
│ └── helloworld
│ └── helloworld.proto
├── proxy # Envoy 関連
│ ├── Dockerfile
│ └── envoy.yaml
└── server # gRPC Server 関連
├── go.mod
├── go.sum
└── main.go
└── generated
└── helloworld
├── helloworld.pb.go
└── helloworld_grpc.pb.go
prootobuf의 정의
prootobuf의 정의는 다음과 같다.
proto/helloworld/helloworld.proto
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
gRPC 서버 준비
위의 protoo에 해당하는 gRPC 서버를 준비합니다.이번에는 gRPC의 문서QuickStart를 참고하여 실시하였으며, 상세한 내용은 생략하였다.
cd server
go run main.go
evans -r --host localhost -p 50051
______
| ____|
| |__ __ __ __ _ _ __ ___
| __| \ \ / / / _. | | '_ \ / __|
| |____ \ V / | (_| | | | | | \__ \
|______| \_/ \__,_| |_| |_| |___/
more expressive universal gRPC client
helloworld.Greeter@localhost:50051> call SayHello
name (TYPE_STRING) => Envoy
{
"message": "Hello Envoy"
}
gRPC-웹 센터 준비
JavaScript를 사용하여 gRPC-Web Client를 설치합니다.
코드 자동 생성
프로토에 대응하는 클라이언트 코드를 자동으로 생성합니다.
protoc -I=./proto ./proto/helloworld/helloworld.proto \
--js_out=import_style=commonjs:client/generated \
--grpc-web_out=import_style=commonjs,mode=grpcwebtext:client/generated
클라이언트 구현
자동 생성된 파일을 사용하여 gRPC-웹 클라이언트 구현
client/client.js
const {HelloRequest} = require('./generated/helloworld/helloworld_pb.js');
const {GreeterClient} = require('./generated/helloworld/helloworld_grpc_web_pb.js');
const client = new GreeterClient('http://localhost:9000', null, null);
const request = new HelloRequest();
request.setName('World');
client.sayHello(request, {}, (err, response) => {
if (err) {
console.log(`Unexpected error for sayHello: code = ${err.code}` +
`, message = "${err.message}"`);
} else {
console.log(response.getMessage());
}
});
또한 브라우저에서 위의 설치 코드를 호출하기 위해 간단한 HTML을 설치합니다.client/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>gRPC-Web Example</title>
<script src="./dist/main.js"></script>
</head>
<body>
<p>Open up the developer console and see the logs for the output.</p>
</body>
</html>
Envoy 준비
Envoy.yaml
Envoy.yaml에서 Proxy 설정을 설명합니다.
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 9000 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
access_log:
- name: envoy.access_loggers.file
typed_config:
"@type": type.googleapis.com/envoy.config.accesslog.v2.FileAccessLog
path: "/dev/stdout"
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: greeter_service
max_grpc_timeout: 0s
cors:
allow_origin_string_match:
- prefix: "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
max_age: "1728000"
expose_headers: custom-header-1,grpc-status,grpc-message
http_filters:
- name: envoy.filters.http.grpc_web
- name: envoy.filters.http.cors
- name: envoy.filters.http.router
clusters:
- name: greeter_service
connect_timeout: 0.25s
type: logical_dns
http2_protocol_options: {}
lb_policy: round_robin
dns_lookup_family: V4_ONLY
upstream_connection_options:
tcp_keepalive:
keepalive_time: 300
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: host.docker.internal
port_value: 50051
Docker 설정
Docker를 사용하여 Envoy를 시작할 준비를 합니다.
proxy/Dockerfile
FROM envoyproxy/envoy:v1.15.0
COPY ./envoy.yaml /etc/envoy/envoy.yaml
CMD /usr/local/bin/envoy -c /etc/envoy/envoy.yaml
이어서 docker-compose.예.docker-compose.yaml
version: '3'
services:
envoy:
build:
context: ./proxy
container_name: envoy-grpc-proxy
ports:
- 9000:9000
다양한 시작 명령 준비
gRPC Server, gRPC-Web Client의 시작 명령을Makefile에 취합하면 다음과 같습니다.
Makefile
server:
cd ./server && go run main.go
client:
cd ./client && \
npx webpack --mode=development client.js && \
yarn static -p 8081
.PHONY: server client
이렇게 준비됐습니다.동작 확인
실기 한번 돌려봐.
터미널 창을 각각 열고 다음 명령을 실행합니다.
# Start gRPC Server
make server
# Start gRPC-Web Client
make client
# Start Envoy
docker-compose up
브라우저로http://localhost:8081/에 접근해 보면 gRPC 서버가 요청한 것을 알 수 있습니다.또한 Envoy 로그에서 받은 요청 정보의 출력도 확인할 수 있습니다.
Envoy를 통해 브라우저의 요청이 gRPC 서버에서 Forward에 의해 확인되었습니다.
푹 빠진 곳
우선gRPC-Web github의 샘플 코드 같은 절차를 시도했지만 자바스크립트로 실행된 gRPC 서버가 잘 작동하지 않거나 Envoy가 잘 작동하지 않습니다.yaml의 기술이 매우 낡아서 원인을 조사하는 데 많은 시간이 걸렸다😢
결과적으로 문서 Envoy를 찾아다녔습니다.yaml의 기술을 고쳐 쓰면 Go로 gRPC 서버를 다시 쓰면 잘 됩니다.
참고 자료
노드, go,protoc의 설치 완료를 전제로 합니다.↩︎
Reference
이 문제에 관하여(gRPC-웹 요청용 Envoy Proxy), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/t_horikoshi/articles/dfc2a02c7eb30f7f0819텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)