This is an automated email from the ASF dual-hosted git repository.
mfordjody pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-kubernetes.git
The following commit(s) were added to refs/heads/master by this push:
new 2ef28fc4 Configure proxyless keepalive from control plane (#920)
2ef28fc4 is described below
commit 2ef28fc479fa0269fb6e6635bedd65b2a189a781
Author: mfordjody <[email protected]>
AuthorDate: Fri Jun 19 00:29:00 2026 +0800
Configure proxyless keepalive from control plane (#920)
---
.../pkg/bootstrap/proxyless_grpc_controller.go | 50 +++++++++++++++-------
.../bootstrap/proxyless_grpc_controller_test.go | 24 +++++++++++
.../charts/dubbod/files/grpc-engine.yaml | 8 ++++
go.mod | 2 +-
go.sum | 2 +
pkg/dubboagency/grpcxds/grpc_bootstrap.go | 20 +++++++++
pkg/dubboagency/grpcxds/grpc_bootstrap_test.go | 15 +++++++
pkg/kube/inject/proxyless.go | 33 ++++++++------
pkg/kube/inject/proxyless_test.go | 12 ++++++
pkg/kube/inject/webhook.go | 16 +++++++
10 files changed, 152 insertions(+), 30 deletions(-)
diff --git a/dubbod/discovery/pkg/bootstrap/proxyless_grpc_controller.go
b/dubbod/discovery/pkg/bootstrap/proxyless_grpc_controller.go
index 422e2807..f153ab06 100644
--- a/dubbod/discovery/pkg/bootstrap/proxyless_grpc_controller.go
+++ b/dubbod/discovery/pkg/bootstrap/proxyless_grpc_controller.go
@@ -361,6 +361,7 @@ type proxylessGRPCRuntimeConfig struct {
Env map[string]string `json:"env"`
Bootstrap proxylessGRPCBootstrapRuntimeConfig `json:"bootstrap"`
Certificates proxylessGRPCCertRuntimeConfig `json:"certificates"`
+ Keepalive proxylessGRPCKeepaliveRuntimeConfig `json:"keepalive"`
Workload proxylessGRPCWorkloadRuntimeConfig `json:"workload"`
Services []proxylessGRPCServiceRuntimeConfig
`json:"services,omitempty"`
Routes []proxylessGRPCRouteRuntimeConfig
`json:"routes,omitempty"`
@@ -380,6 +381,13 @@ type proxylessGRPCCertRuntimeConfig struct {
RootCert string `json:"rootCert"`
}
+type proxylessGRPCKeepaliveRuntimeConfig struct {
+ Enabled bool `json:"enabled"`
+ Time string `json:"time"`
+ Timeout string `json:"timeout"`
+ PermitWithoutStream bool `json:"permitWithoutStream"`
+}
+
type proxylessGRPCWorkloadRuntimeConfig struct {
NodeID string `json:"nodeId"`
PodName string `json:"podName"`
@@ -632,22 +640,26 @@ func buildRuntimeConfigJSON(workload
*proxylessGRPCWorkloadContext, services []p
Version: proxylessGRPCRuntimeConfigVersion,
Mode: "proxyless-grpc",
Env: map[string]string{
- "GRPC_XDS_BOOTSTRAP":
inject.ProxylessGRPCBootstrapPath,
- inject.ProxylessGRPCConfigEnvName:
inject.ProxylessGRPCConfigPath,
- "GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT": "true",
- "DUBBO_GRPC_XDS_CREDENTIALS": "true",
- "DUBBO_GRPC_XDS_RESOLVER": "xds:///",
- "DUBBO_META_GENERATOR": "grpc",
- "DUBBO_META_CLUSTER_ID":
workload.clusterID,
- "DUBBO_META_NAMESPACE":
workload.podNamespace,
- "DUBBO_META_MESH_ID":
workload.trustDomain,
- "TRUST_DOMAIN":
workload.trustDomain,
- "POD_NAME":
workload.podName,
- "POD_NAMESPACE":
workload.podNamespace,
- "INSTANCE_IP":
workload.podIP,
- "SERVICE_ACCOUNT":
workload.serviceAccount,
- inject.ProxylessXDSAddressEnvName:
workload.discoveryAddress,
- "CA_ADDRESS":
workload.caAddress,
+ "GRPC_XDS_BOOTSTRAP":
inject.ProxylessGRPCBootstrapPath,
+ inject.ProxylessGRPCConfigEnvName:
inject.ProxylessGRPCConfigPath,
+ "GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT":
"true",
+ "DUBBO_GRPC_XDS_CREDENTIALS":
"true",
+ "DUBBO_GRPC_XDS_RESOLVER":
"xds:///",
+ inject.ProxylessGRPCKeepaliveEnvName:
inject.ProxylessGRPCKeepaliveValue,
+ inject.ProxylessGRPCKeepaliveTimeEnv:
inject.ProxylessGRPCKeepaliveTime,
+ inject.ProxylessGRPCKeepaliveTimeoutEnv:
inject.ProxylessGRPCKeepaliveTimeout,
+ inject.ProxylessGRPCKeepalivePermitWithoutStreamEnv:
inject.ProxylessGRPCKeepaliveValue,
+ "DUBBO_META_GENERATOR":
"grpc",
+ "DUBBO_META_CLUSTER_ID":
workload.clusterID,
+ "DUBBO_META_NAMESPACE":
workload.podNamespace,
+ "DUBBO_META_MESH_ID":
workload.trustDomain,
+ "TRUST_DOMAIN":
workload.trustDomain,
+ "POD_NAME":
workload.podName,
+ "POD_NAMESPACE":
workload.podNamespace,
+ "INSTANCE_IP":
workload.podIP,
+ "SERVICE_ACCOUNT":
workload.serviceAccount,
+ inject.ProxylessXDSAddressEnvName:
workload.discoveryAddress,
+ "CA_ADDRESS":
workload.caAddress,
},
Bootstrap: proxylessGRPCBootstrapRuntimeConfig{
Path: inject.ProxylessGRPCBootstrapPath,
@@ -661,6 +673,12 @@ func buildRuntimeConfigJSON(workload
*proxylessGRPCWorkloadContext, services []p
PrivateKey: inject.ProxylessXDSMountPath + "/" +
constants.KeyFilename,
RootCert: inject.ProxylessXDSMountPath + "/" +
constants.CACertNamespaceConfigMapDataName,
},
+ Keepalive: proxylessGRPCKeepaliveRuntimeConfig{
+ Enabled: true,
+ Time: inject.ProxylessGRPCKeepaliveTime,
+ Timeout:
inject.ProxylessGRPCKeepaliveTimeout,
+ PermitWithoutStream: true,
+ },
Workload: proxylessGRPCWorkloadRuntimeConfig{
NodeID: workload.nodeID,
PodName: workload.podName,
diff --git a/dubbod/discovery/pkg/bootstrap/proxyless_grpc_controller_test.go
b/dubbod/discovery/pkg/bootstrap/proxyless_grpc_controller_test.go
index 44dc8c9e..4165c7fe 100644
--- a/dubbod/discovery/pkg/bootstrap/proxyless_grpc_controller_test.go
+++ b/dubbod/discovery/pkg/bootstrap/proxyless_grpc_controller_test.go
@@ -174,6 +174,30 @@ func TestBuildRuntimeConfigJSON(t *testing.T) {
if got.Env["DUBBO_META_CLUSTER_ID"] != workload.clusterID {
t.Fatalf("DUBBO_META_CLUSTER_ID = %q, want %q",
got.Env["DUBBO_META_CLUSTER_ID"], workload.clusterID)
}
+ if got.Env[inject.ProxylessGRPCKeepaliveEnvName] !=
inject.ProxylessGRPCKeepaliveValue {
+ t.Fatalf("%s = %q, want %q",
inject.ProxylessGRPCKeepaliveEnvName,
got.Env[inject.ProxylessGRPCKeepaliveEnvName],
inject.ProxylessGRPCKeepaliveValue)
+ }
+ if got.Env[inject.ProxylessGRPCKeepaliveTimeEnv] !=
inject.ProxylessGRPCKeepaliveTime {
+ t.Fatalf("%s = %q, want %q",
inject.ProxylessGRPCKeepaliveTimeEnv,
got.Env[inject.ProxylessGRPCKeepaliveTimeEnv],
inject.ProxylessGRPCKeepaliveTime)
+ }
+ if got.Env[inject.ProxylessGRPCKeepaliveTimeoutEnv] !=
inject.ProxylessGRPCKeepaliveTimeout {
+ t.Fatalf("%s = %q, want %q",
inject.ProxylessGRPCKeepaliveTimeoutEnv,
got.Env[inject.ProxylessGRPCKeepaliveTimeoutEnv],
inject.ProxylessGRPCKeepaliveTimeout)
+ }
+ if got.Env[inject.ProxylessGRPCKeepalivePermitWithoutStreamEnv] !=
inject.ProxylessGRPCKeepaliveValue {
+ t.Fatalf("%s = %q, want %q",
inject.ProxylessGRPCKeepalivePermitWithoutStreamEnv,
got.Env[inject.ProxylessGRPCKeepalivePermitWithoutStreamEnv],
inject.ProxylessGRPCKeepaliveValue)
+ }
+ if !got.Keepalive.Enabled {
+ t.Fatalf("keepalive enabled = false, want true")
+ }
+ if got.Keepalive.Time != inject.ProxylessGRPCKeepaliveTime {
+ t.Fatalf("keepalive time = %q, want %q", got.Keepalive.Time,
inject.ProxylessGRPCKeepaliveTime)
+ }
+ if got.Keepalive.Timeout != inject.ProxylessGRPCKeepaliveTimeout {
+ t.Fatalf("keepalive timeout = %q, want %q",
got.Keepalive.Timeout, inject.ProxylessGRPCKeepaliveTimeout)
+ }
+ if !got.Keepalive.PermitWithoutStream {
+ t.Fatalf("keepalive permitWithoutStream = false, want true")
+ }
if got.Env[inject.ProxylessXDSAddressEnvName] !=
workload.discoveryAddress {
t.Fatalf("%s = %q, want %q", inject.ProxylessXDSAddressEnvName,
got.Env[inject.ProxylessXDSAddressEnvName], workload.discoveryAddress)
}
diff --git a/dubboinstaller/charts/dubbod/files/grpc-engine.yaml
b/dubboinstaller/charts/dubbod/files/grpc-engine.yaml
index cf51ca7a..997497cd 100644
--- a/dubboinstaller/charts/dubbod/files/grpc-engine.yaml
+++ b/dubboinstaller/charts/dubbod/files/grpc-engine.yaml
@@ -31,6 +31,14 @@ spec:
value: "true"
- name: DUBBO_GRPC_XDS_RESOLVER
value: "xds:///"
+ - name: DUBBO_GRPC_KEEPALIVE
+ value: "true"
+ - name: GRPC_KEEPALIVE_INTERVAL
+ value: "30s"
+ - name: GRPC_KEEPALIVE_TIMEOUT
+ value: "10s"
+ - name: GRPC_KEEPALIVE_PERMIT_WITHOUT_STREAM
+ value: "true"
- name: DUBBO_META_GENERATOR
value: "grpc"
- name: DUBBO_META_CLUSTER_ID
diff --git a/go.mod b/go.mod
index 906e9b28..b83c0bc8 100644
--- a/go.mod
+++ b/go.mod
@@ -55,7 +55,7 @@ require (
github.com/heroku/color v0.0.6
github.com/kdubbo/api v0.0.0-20260514125132-e21515234c56
github.com/kdubbo/client-go v0.0.0-20260514125254-aa566bd2f6d5
- github.com/kdubbo/xds-api v0.0.0-20260514125138-34014b8f6d6b
+ github.com/kdubbo/xds-api v0.0.0-20260618162542-05a9fbb3210d
github.com/moby/term v0.5.2
github.com/ory/viper v1.7.5
github.com/pkg/errors v0.9.1
diff --git a/go.sum b/go.sum
index bf3c44b1..c8c4ffe6 100644
--- a/go.sum
+++ b/go.sum
@@ -341,6 +341,8 @@ github.com/kdubbo/client-go
v0.0.0-20260514125254-aa566bd2f6d5 h1:ynMV7FtdzoEMBG
github.com/kdubbo/client-go v0.0.0-20260514125254-aa566bd2f6d5/go.mod
h1:NYuRXnoNWCR5uZLjLmWi1ACz+GYFHjckMtLJHWRI4VU=
github.com/kdubbo/xds-api v0.0.0-20260514125138-34014b8f6d6b
h1:uTmLpp65pCWvCh5yxqKXd95GoXAn13IwMRhrmIJXCqU=
github.com/kdubbo/xds-api v0.0.0-20260514125138-34014b8f6d6b/go.mod
h1:o2HDUgL1ntaDbWomZ4cD2tt8jBamuG2qRtjXOa1zZ0Q=
+github.com/kdubbo/xds-api v0.0.0-20260618162542-05a9fbb3210d
h1:9bB9M26QrBUrb59DMiWy/uAzkWITIVOC+xmLIjSDiq8=
+github.com/kdubbo/xds-api v0.0.0-20260618162542-05a9fbb3210d/go.mod
h1:o2HDUgL1ntaDbWomZ4cD2tt8jBamuG2qRtjXOa1zZ0Q=
github.com/kevinburke/ssh_config v1.2.0
h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod
h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/errcheck v1.5.0/go.mod
h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
diff --git a/pkg/dubboagency/grpcxds/grpc_bootstrap.go
b/pkg/dubboagency/grpcxds/grpc_bootstrap.go
index bdc7ffa8..9755d7f4 100644
--- a/pkg/dubboagency/grpcxds/grpc_bootstrap.go
+++ b/pkg/dubboagency/grpcxds/grpc_bootstrap.go
@@ -37,12 +37,15 @@ const (
ServerListenerNamePrefix = "xds.dubbo.apache.org/grpc/lds/inbound/"
ServerListenerNameTemplate = ServerListenerNamePrefix + "%s"
FileWatcherCertProviderName = "file_watcher"
+ DefaultKeepaliveTime = 30 * time.Second
+ DefaultKeepaliveTimeout = 10 * time.Second
)
type Bootstrap struct {
XDSServers []XdsServer
`json:"xds_servers,omitempty"`
Node *core.Node
`json:"node,omitempty"`
CertProviders map[string]CertificateProvider
`json:"certificate_providers,omitempty"`
+ Keepalive *KeepaliveConfig
`json:"dubbo_grpc_keepalive,omitempty"`
ServerListenerNameTemplate string
`json:"server_listener_resource_name_template,omitempty"`
}
@@ -76,6 +79,22 @@ type XdsServer struct {
ServerFeatures []string `json:"server_features,omitempty"`
}
+type KeepaliveConfig struct {
+ Enabled bool `json:"enabled"`
+ Time string `json:"time"`
+ Timeout string `json:"timeout"`
+ PermitWithoutStream bool `json:"permit_without_stream"`
+}
+
+func DefaultKeepaliveConfig() *KeepaliveConfig {
+ return &KeepaliveConfig{
+ Enabled: true,
+ Time: DefaultKeepaliveTime.String(),
+ Timeout: DefaultKeepaliveTimeout.String(),
+ PermitWithoutStream: true,
+ }
+}
+
func GenerateBootstrap(opts GenerateBootstrapOptions) (*Bootstrap, error) {
xdsMeta, err := extractMeta(opts.Node)
if err != nil {
@@ -122,6 +141,7 @@ func GenerateBootstrap(opts GenerateBootstrapOptions)
(*Bootstrap, error) {
Locality: opts.Node.Locality,
Metadata: xdsMeta,
},
+ Keepalive: DefaultKeepaliveConfig(),
ServerListenerNameTemplate: ServerListenerNameTemplate,
}
diff --git a/pkg/dubboagency/grpcxds/grpc_bootstrap_test.go
b/pkg/dubboagency/grpcxds/grpc_bootstrap_test.go
index f9d15fe9..4b0c1fd0 100644
--- a/pkg/dubboagency/grpcxds/grpc_bootstrap_test.go
+++ b/pkg/dubboagency/grpcxds/grpc_bootstrap_test.go
@@ -40,6 +40,21 @@ func TestGenerateBootstrapUsesTLSForDirectDiscovery(t
*testing.T) {
if got, want := bootstrap.XDSServers[0].ServerFeatures[0], "xds_v3";
got != want {
t.Fatalf("server feature = %q, want %q", got, want)
}
+ if bootstrap.Keepalive == nil {
+ t.Fatalf("keepalive config is nil")
+ }
+ if !bootstrap.Keepalive.Enabled {
+ t.Fatalf("keepalive enabled = false, want true")
+ }
+ if got, want := bootstrap.Keepalive.Time,
DefaultKeepaliveTime.String(); got != want {
+ t.Fatalf("keepalive time = %q, want %q", got, want)
+ }
+ if got, want := bootstrap.Keepalive.Timeout,
DefaultKeepaliveTimeout.String(); got != want {
+ t.Fatalf("keepalive timeout = %q, want %q", got, want)
+ }
+ if !bootstrap.Keepalive.PermitWithoutStream {
+ t.Fatalf("keepalive permit_without_stream = false, want true")
+ }
cfg, ok :=
bootstrap.XDSServers[0].ChannelCreds[0].Config.(FileWatcherCertProviderConfig)
if !ok {
diff --git a/pkg/kube/inject/proxyless.go b/pkg/kube/inject/proxyless.go
index 3c53c77a..350041b9 100644
--- a/pkg/kube/inject/proxyless.go
+++ b/pkg/kube/inject/proxyless.go
@@ -26,19 +26,26 @@ import (
)
const (
- ProxylessGRPCTemplateName = "grpc-engine"
- ProxylessXDSVolumeName = "dubbo-xds"
- ProxylessXDSMountPath = "/etc/dubbo/proxy"
- ProxylessGRPCBootstrapFileName = "grpc-bootstrap.json"
- ProxylessGRPCBootstrapPath = ProxylessXDSMountPath + "/" +
ProxylessGRPCBootstrapFileName
- ProxylessXDSAddressEnvName = "XDS_ADDRESS"
- ProxylessGRPCConfigEnvName = "DUBBO_GRPC_XDS_CONFIG"
- ProxylessGRPCConfigFileName = "dubbo-grpc-xds.json"
- ProxylessGRPCConfigPath = ProxylessXDSMountPath + "/" +
ProxylessGRPCConfigFileName
- ProxylessXServerContainerName = "dubbo-xserver"
- ProxylessXServerPort = 15080
- ProxylessManagedLabel = "proxyless.dubbo.apache.org/managed"
- ProxylessManagedLabelValue = "true"
+ ProxylessGRPCTemplateName = "grpc-engine"
+ ProxylessXDSVolumeName = "dubbo-xds"
+ ProxylessXDSMountPath = "/etc/dubbo/proxy"
+ ProxylessGRPCBootstrapFileName = "grpc-bootstrap.json"
+ ProxylessGRPCBootstrapPath = ProxylessXDSMountPath +
"/" + ProxylessGRPCBootstrapFileName
+ ProxylessXDSAddressEnvName = "XDS_ADDRESS"
+ ProxylessGRPCConfigEnvName = "DUBBO_GRPC_XDS_CONFIG"
+ ProxylessGRPCKeepaliveEnvName = "DUBBO_GRPC_KEEPALIVE"
+ ProxylessGRPCKeepaliveTimeEnv = "GRPC_KEEPALIVE_INTERVAL"
+ ProxylessGRPCKeepaliveTimeoutEnv = "GRPC_KEEPALIVE_TIMEOUT"
+ ProxylessGRPCKeepalivePermitWithoutStreamEnv =
"GRPC_KEEPALIVE_PERMIT_WITHOUT_STREAM"
+ ProxylessGRPCKeepaliveValue = "true"
+ ProxylessGRPCKeepaliveTime = "30s"
+ ProxylessGRPCKeepaliveTimeout = "10s"
+ ProxylessGRPCConfigFileName = "dubbo-grpc-xds.json"
+ ProxylessGRPCConfigPath = ProxylessXDSMountPath +
"/" + ProxylessGRPCConfigFileName
+ ProxylessXServerContainerName = "dubbo-xserver"
+ ProxylessXServerPort = 15080
+ ProxylessManagedLabel =
"proxyless.dubbo.apache.org/managed"
+ ProxylessManagedLabelValue = "true"
)
var ProxylessInjectTemplatesAnnoName =
annotation.OrgApacheDubboInjectTemplates.Name
diff --git a/pkg/kube/inject/proxyless_test.go
b/pkg/kube/inject/proxyless_test.go
index 4cee4167..6b381172 100644
--- a/pkg/kube/inject/proxyless_test.go
+++ b/pkg/kube/inject/proxyless_test.go
@@ -185,6 +185,18 @@ func assertDirectXDSConnection(t *testing.T, pod
*corev1.Pod, containerName, sec
if !hasEnv(container.Env, "DUBBO_GRPC_XDS_CREDENTIALS", "true") {
t.Fatalf("DUBBO_GRPC_XDS_CREDENTIALS env missing")
}
+ if !hasEnv(container.Env, ProxylessGRPCKeepaliveEnvName,
ProxylessGRPCKeepaliveValue) {
+ t.Fatalf("%s env missing", ProxylessGRPCKeepaliveEnvName)
+ }
+ if !hasEnv(container.Env, ProxylessGRPCKeepaliveTimeEnv,
ProxylessGRPCKeepaliveTime) {
+ t.Fatalf("%s env missing", ProxylessGRPCKeepaliveTimeEnv)
+ }
+ if !hasEnv(container.Env, ProxylessGRPCKeepaliveTimeoutEnv,
ProxylessGRPCKeepaliveTimeout) {
+ t.Fatalf("%s env missing", ProxylessGRPCKeepaliveTimeoutEnv)
+ }
+ if !hasEnv(container.Env, ProxylessGRPCKeepalivePermitWithoutStreamEnv,
ProxylessGRPCKeepaliveValue) {
+ t.Fatalf("%s env missing",
ProxylessGRPCKeepalivePermitWithoutStreamEnv)
+ }
if !hasEnv(container.Env, "CA_ADDRESS",
"dubbod.dubbo-system.svc:26012") {
t.Fatalf("CA_ADDRESS env missing")
}
diff --git a/pkg/kube/inject/webhook.go b/pkg/kube/inject/webhook.go
index 153ac4a0..71114d8c 100644
--- a/pkg/kube/inject/webhook.go
+++ b/pkg/kube/inject/webhook.go
@@ -559,6 +559,22 @@ func addApplicationContainerConfig(pod *corev1.Pod, req
InjectionParameters) err
Name: "DUBBO_GRPC_XDS_RESOLVER",
Value: "xds:///",
})
+ container.Env = ensureEnvVar(container.Env, corev1.EnvVar{
+ Name: ProxylessGRPCKeepaliveEnvName,
+ Value: ProxylessGRPCKeepaliveValue,
+ })
+ container.Env = ensureEnvVar(container.Env, corev1.EnvVar{
+ Name: ProxylessGRPCKeepaliveTimeEnv,
+ Value: ProxylessGRPCKeepaliveTime,
+ })
+ container.Env = ensureEnvVar(container.Env, corev1.EnvVar{
+ Name: ProxylessGRPCKeepaliveTimeoutEnv,
+ Value: ProxylessGRPCKeepaliveTimeout,
+ })
+ container.Env = ensureEnvVar(container.Env, corev1.EnvVar{
+ Name: ProxylessGRPCKeepalivePermitWithoutStreamEnv,
+ Value: ProxylessGRPCKeepaliveValue,
+ })
container.Env = ensureEnvVar(container.Env, corev1.EnvVar{
Name: "DUBBO_META_GENERATOR",
Value: "grpc",