Awesome
Jawlb
Jawlb (pronounced jolp) is an unsophisticated grpclb implementation for things running in Kubernetes talking to gRPC services within that same Kubernetes cluster.
This load balancer performs service discovery via the Kubernetes API and announces any changes it sees via the grpclb protocol to its clients.
Building
You'll want to push the result of docker build -f Dockerfile .
into your registry.
grpclb
The grpclb Go implementation (others maybe too) requires you to define a SRV record for the loadbalancer.
The easy solution is to define a Kubernetes service with a port named grpclb
and you're all set.
Example
The example shows a load balancer setup that'll forward requests to myservice:grpc
.
We assume that RBAC isn't required.
Load Balancer Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: myservice-lb
spec:
selector:
matchLabels:
app: jawlb
service: myservice
replicas: 3
template:
metadata:
labels:
app: jawlb
service: myservice
spec:
restartPolicy: Always
containers:
- image: "your.regist.ry/jawlb:yolo"
name: jawlb
ports:
- containerPort: 8000
name: grpclb
readinessProbe:
tcpSocket:
port: grpclb
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: grpclb
initialDelaySeconds: 15
periodSeconds: 60
env:
# The name of the upstream service we want
# to balance
- name: JAWLB_SERVICE
value: "myservice"
# The name of the port exposed by this service
# which we want to forward to
- name: JAWLB_TARGETPORT
value: "grpc"
# The namespace in which jawlb performs the lookup
# and we use the current one simply
- name: JAWLB_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
Load Balancer Service
apiVersion: v1
kind: Service
metadata:
name: myservice-lb
labels:
app: jawlb
service: myservice
spec:
# Make this a headless service because we'll have to use
# the dns:// resolver in the Go client
clusterIP: None
ports:
# The port MUST be named grpclb in order to create
# the proper DNS SRV entry
- name: grpclb
port: 8000
targetPort: grpclb
selector:
app: jawlb
service: myservice
gRPC Client
import _ "google.golang.org/grpc/balancer/grpclb"
// When dialing, gRPC's DNS resolver will issue a SRV lookup and
// because we're so nice to provide the grpclb entry, everything
// works as expected
//
// If no SRV record exists, gRPC will fall back to a vanilla connection
// without the loadbalancer.
conn, err := grpc.Dial(
"dns:///myservice-lb", // must use the dns resolver
grpc.WithInsecure())
// ... magic 🧙♀️
Configuration
Everything is passed via environment variables.
JAWLB_NAMESPACE
in which namespace service lookup is performed, default"default"
JAWLB_SERVICE
the name of the Kubernetes service to balance, requiredJAWLB_TARGETPORT
the name(!) of the target port on that service, default"grpc"
JAWLB_LABELSELECTOR
an additional label selector, default""
JAWLB_HOST
the hostname to listen on, default""
JAWLB_PORT
port to listen on, default8000
JAWLB_SHUTDOWNGRACEPERIOD
Grace period for open connections during shutdown, default"25s"
What's missing
- Potentially some actual load balancing
- Implementation of LoadReporter service
- Readiness Probe
- Health Check