feat(cubeproxy): add plaintext gRPC ingress on port 9090#679
feat(cubeproxy): add plaintext gRPC ingress on port 9090#679xiaojunxiang2023 wants to merge 1 commit into
Conversation
56408a9 to
fa2afd2
Compare
fa2afd2 to
3b02ba2
Compare
Code Review: PR #679 — Plaintext gRPC Ingress on Port 9090OverviewThe PR adds a plaintext HTTP/2 gRPC listener on CubeProxy port 9090 with corresponding deployment, Terraform, doc, and test changes. Overall well-structured — consistent error handling patterns, good defensive templating, and clean integration with existing code. Below are the noteworthy findings across all review dimensions. Findings1. CLB security group is missing port 9090 — feature will be unreachable (Critical)The The port 9090 rule was instead placed in the jumpserver security group (a bastion CVM), where it has no effect. An operator reading the jumpserver SG would reasonably believe the port is open while the actual traffic path silently drops it. (Inlined at main.tf:309) 2. Missing
|
3b02ba2 to
40489f5
Compare
chenhengqi
left a comment
There was a problem hiding this comment.
Please add an example. Do we need SDK side support?
40489f5 to
923eea1
Compare
Example: OK, I have added SDK: No SDK changes are required for this PR. The existing Python/Go SDK continues to use HTTP/Connect on CubeProxy HTTP/HTTPS ( |
|
cc @fslongjin @tinklone for deploy-related changes. |
| set $cube_retcode "310200"; | ||
| set $garyscale_test "none"; | ||
| set $access_time ""; | ||
| set $cache_free_space ""; |
| set $cube_admin_token ""; | ||
|
|
||
| # Mirror of the 8081 server's internal sub-location. | ||
| location = /_sidecar_resume { |
aefb163 to
ab2ca4f
Compare
Expose a dedicated HTTP/2 listener so clients can dial the proxy IP directly and route via :authority "<container_port>-<sandbox_id>" without DNS. Wire the listener through one-click deploy (CUBE_PROXY_GRPC_PORT), systemd postcheck, release bundle templating, and TKE CLB exposure. Document the access mode alongside existing Host and path-based routing. Add examples/grpc-ingress for native gRPC client usage. Signed-off-by: xiaojunxiang <xiaojunxiang@kingsoft.com>
d983241 to
c2d15f3
Compare
c2d15f3 to
d01c63c
Compare
| proxy_pass http://$cube_sidecar_addr/internal/resume?$args; | ||
| } | ||
|
|
||
| location / { |
There was a problem hiding this comment.
Missing grpc_buffering off; — streaming RPCs can exhaust memory
The HTTP server blocks explicitly disable buffering for known streaming endpoints (process.Start, Connect, WatchDir) via proxy_buffering off in envd_streaming_host_route.inc. The gRPC equivalent is grpc_buffering off, but it's absent here.
Nginx defaults grpc_buffering to on, meaning the entire upstream response is buffered in memory before any data reaches the client. For server-streaming RPCs like filesystem.Filesystem/WatchDir (a never-ending stream), this would consume memory proportional to uptime.
Recommend adding grpc_buffering off; to this location block (or separating streaming and unary methods into distinct locations as the HTTP ports do).
| location / { | ||
| include /usr/local/openresty/nginx/conf/global/global.conf; | ||
|
|
||
| grpc_connect_timeout 3s; |
There was a problem hiding this comment.
Missing grpc_set_header for client IP forwarding
The HTTP server blocks forward the client IP via proxy_set_header X-Real-IP $remote_addr and proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for (lines 343-344). The gRPC block needs grpc_set_header instead of proxy_set_header since it uses grpc_pass.
Without this, the upstream envd process receives all connections as if they originated from the nginx proxy's address rather than the actual client — degrading audit logging and preventing IP-based access control.
| set $cube_admin_token ""; | ||
|
|
||
| # Mirror of the 8081 server's internal sub-location. | ||
| location = /_sidecar_resume { |
There was a problem hiding this comment.
_sidecar_resume block is triplicated across server blocks
This same location = /_sidecar_resume { internal; ... } block now appears identically in the 8081 (line 132), 8080 (line 254), and the new 9090 server blocks. It's a maintenance hazard — any change to the sidecar resume protocol must be replicated in three places.
Consider extracting this into an included file (e.g. conf/includes/sidecar_resume.inc) and using include in all three server blocks. The location is protocol-agnostic and doesn't need to differ between HTTP and gRPC servers.
| action = "ACCEPT" | ||
| cidr_block = "0.0.0.0/0" | ||
| protocol = "TCP" | ||
| port = "9090" |
There was a problem hiding this comment.
Port 9090 is opened on the jumpserver security group but the CLB SG is missing it
The port 9090 ingress rule is added to the jumpserver security group (tencentcloud_security_group.jumpserver), which is a bastion CVM that does not run cube-proxy. Meanwhile, the CLB security group (tencentcloud_security_group_rule_set.clb, lines 420-469) lists ports 80, 443, 3000, and 8089 but not 9090.
The cube_proxy Kubernetes Service (tke-addons.tf:762) is annotated with tencentcloud_security_group.clb.id, so the CLB SG is the one that controls inbound traffic to the proxy. Without a 9090 ingress rule there, the CLB will drop all inbound traffic on port 9090.
Recommend moving this rule to the CLB SG:
ingress {
action = "ACCEPT"
cidr_block = var.enable_public_network ? "0.0.0.0/0" : "10.0.0.0/16"
protocol = "TCP"
port = "9090"
description = "Allow cube-proxy plaintext gRPC ingress"
}| options=(("grpc.default_authority", authority),), | ||
| ) | ||
| try: | ||
| grpc.channel_ready_future(channel).result(timeout=15) |
There was a problem hiding this comment.
channel_ready_future should handle connection failures gracefully
grpc.channel_ready_future(channel).result(timeout=15) raises grpc.FutureTimeoutError on connection timeout or grpc.RpcError on other failures. Neither is caught here. Consider wrapping in try/except with a user-friendly message.
Also consider documenting keepalive options (grpc.keepalive_time_ms) for production use, as gRPC streams may be dropped by intermediate network equipment with idle timeouts.
| }, var.enable_public_network ? { | ||
| "service.kubernetes.io/qcloud-loadbalancer-internet-charge-type" = "TRAFFIC_POSTPAID_BY_HOUR" | ||
| } : { | ||
| "service.cloud.tencent.com/specify-protocol" = "{\"80\":{\"protocol\":[\"TCP\"]},\"443\":{\"protocol\":[\"TCP\"]},\"9090\":{\"protocol\":[\"TCP\"]}}" |
There was a problem hiding this comment.
Port 9090 missing from specify-protocol annotation in internal mode
The base annotation (line 759) only declares ports 80 and 443. The public mode override correctly adds 9090, but the internal mode branch does not override specify-protocol — so port 9090 falls back to the base annotation without TCP protocol declaration. Recommend moving 9090 into the base annotation.
| proxy_pass http://$cube_sidecar_addr/internal/resume?$args; | ||
| } | ||
|
|
||
| location / { |
There was a problem hiding this comment.
Missing grpc_buffering off; — streaming RPCs can exhaust memory
The HTTP server blocks explicitly disable buffering for known streaming endpoints (process.Start, Connect, WatchDir) via proxy_buffering off in envd_streaming_host_route.inc. The gRPC equivalent is grpc_buffering off, but it's absent here.
Nginx defaults grpc_buffering to on, meaning the entire upstream response is buffered in memory before any data reaches the client. For server-streaming RPCs like filesystem.Filesystem/WatchDir (a never-ending stream), this would consume memory proportional to uptime.
Recommend adding grpc_buffering off; to this location block (or separating streaming and unary methods into distinct locations as the HTTP ports do).
| location / { | ||
| include /usr/local/openresty/nginx/conf/global/global.conf; | ||
|
|
||
| grpc_connect_timeout 3s; |
There was a problem hiding this comment.
Missing grpc_set_header for client IP forwarding
The HTTP server blocks forward the client IP via proxy_set_header X-Real-IP $remote_addr and proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for (lines 343-344). The gRPC block needs grpc_set_header instead of proxy_set_header since it uses grpc_pass.
Without this, the upstream envd process receives all connections as if they originated from the nginx proxy's address rather than the actual client — degrading audit logging and preventing IP-based access control.
| set $cube_admin_token ""; | ||
|
|
||
| # Mirror of the 8081 server's internal sub-location. | ||
| location = /_sidecar_resume { |
There was a problem hiding this comment.
_sidecar_resume block is triplicated across server blocks
This same location = /_sidecar_resume { internal; ... } block now appears identically in the 8081 (line 132), 8080 (line 254), and the new 9090 server blocks. It's a maintenance hazard — any change to the sidecar resume protocol must be replicated in three places.
Consider extracting this into an included file (e.g. conf/includes/sidecar_resume.inc) and using include in all three server blocks. The location is protocol-agnostic and doesn't need to differ between HTTP and gRPC servers.
Summary
Add a plaintext HTTP/2 gRPC ingress listener on CubeProxy (default port
9090) so clients can reach sandbox gRPC services without wildcard DNS or TLS on CubeProxy.Clients dial the CubeProxy IP and identify the target sandbox via the gRPC
:authoritypseudo-header, using the same<container_port>-<sandbox_id>format as host-based HTTP routing.Changes
CubeProxy/nginx.confgrpc_backendupstream and HTTP/2 server block on port9090CubeProxy/Dockerfile9090CUBE_PROXY_GRPC_PORTtemplating, startup/postcheck,env.example9090https-and-domain.md; port/config innetwork-hardening.md,self-build-deploy.md,service-management.mdtest_runtime_file_safety.shfor gRPC postcheck portMotivation
CubeProxy already supports sandbox ingress via:
<container_port>-<sandbox_id>.<domain>on ports 80/443/sandbox/<sandbox_id>/<container_port>/...gRPC clients often cannot rely on wildcard DNS or custom TLS. A dedicated plaintext HTTP/2 listener lets them connect directly to the CubeProxy IP.
Usage
Example:
See
docs/guide/https-and-domain.mdfor details.Configuration
CUBE_PROXY_GRPC_PORT9090