@digifi/k8s-grpc-js-resolver
v0.1.0
Published
A grpc-js resolver that watches Kubernetes EndpointSlices for push-based service discovery.
Maintainers
Keywords
Readme
@digifi/k8s-grpc-js-resolver
A @grpc/grpc-js resolver that watches Kubernetes
EndpointSlices and pushes backend changes into grpc-js. It is intended for headless Services used
with client-side round_robin load balancing.
The stock DNS resolver may keep a subchannel for a terminating pod until the connection fails or
grpc-js asks DNS to resolve again. This package removes an endpoint as soon as Kubernetes reports
ready: false, serving: false, or terminating: true, and adds new endpoints on the watch event.
Install
npm install @digifi/k8s-grpc-js-resolver @grpc/grpc-jsThe package declares grpc-js as a peer dependency so the application and resolver share the same process-wide resolver registry.
Usage
import { credentials } from '@grpc/grpc-js';
import { resolveGrpcTargetAddress } from '@digifi/k8s-grpc-js-resolver';
const target = resolveGrpcTargetAddress('digifi-users-headless:4004');
const client = new UsersClient(target, credentials.createInsecure(), {
'grpc.service_config': JSON.stringify({
loadBalancingConfig: [{ round_robin: {} }],
}),
});Set GRPC_K8S_RESOLVER_ENABLED=true in the client workload. Recognized in-cluster Service
addresses are rewritten to k8s://<namespace>/<service>:<port>. External hosts, IP literals,
loopback addresses, and targets that already have another scheme are left unchanged.
Explicit k8s:// targets register the resolver without requiring the feature flag:
resolveGrpcTargetAddress('k8s://test4/digifi-users-headless:4004');Environment
| Variable | Default | Purpose |
| -------------------------------- | ------------------------------ | ------------------------------------------------------------- |
| GRPC_K8S_RESOLVER_ENABLED | false | Rewrites recognized in-cluster host:port targets. |
| GRPC_K8S_RESOLVER_DNS_FALLBACK | true | Uses headless DNS when initial EndpointSlice discovery fails. |
| POD_NAMESPACE | ServiceAccount namespace file | Overrides the caller pod namespace. |
| KUBERNETES_CLUSTER_DOMAIN | detected, then cluster.local | Overrides the cluster domain used by DNS fallback. |
| LogLevel | info | Controls resolver error, warn, and info output. |
DNS fallback is used only when EndpointSlice discovery is unavailable. A healthy watch reporting zero ready endpoints publishes an empty resolution so grpc-js drops stale subchannels.
Kubernetes RBAC
The caller pod's ServiceAccount must be able to read EndpointSlices in its namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: grpc-endpointslice-reader
rules:
- apiGroups: [discovery.k8s.io]
resources: [endpointslices]
verbs: [get, list, watch]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: grpc-endpointslice-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: grpc-endpointslice-reader
subjects:
- kind: ServiceAccount
name: default
namespace: test4Prefer a dedicated ServiceAccount in shared environments. The resolver keeps one watch per namespace in each Node.js process and shares it across all gRPC targets in that namespace.
Development
npm ci
npm run check
npm pack --dry-runPublishing is configured for the public @digifi scope on npm. Update package.json to the release
version, merge it, and publish a GitHub Release. The release workflow expects an NPM_AUTH_TOKEN
repository secret. A manual workflow dispatch can publish the same version under a custom npm tag.
