A proxy that transparently exposes gRPC Kubernetes services cluster-externally.
Using Ambassador as gRPC proxy, kruiser
watches deployment in a target namespace that are labelled with grpc=expose
. When it finds such a deployment, it creates a corresponding service of type NodePort
proxying traffic to its pods from outside the cluster.
So far, I've tested kruiser
on Minikube v0.24 with Kubernetes v1.8 and v1.9, as well as on GKE with Kubernetes v1.9 with and without RBAC.
There are two main use cases:
Imagine two or more clusters deployed within, say, a data center in an enterprise. In order for gRPC services to communicate across clusters, you need to proxy the traffic from one cluster to another.
If you want to make your gRPC service publicly available, you need to somehow expose it, routing traffic from outside the cluster to the cluster-internal service.
First, clone this repository with git clone https://github.com/mhausenblas/kruiser.git && cd kruiser
.
Creating a namespaces for related apps rather than dumping all into the default
namespace is a good practice, so let's do that first:
$ kubectl create namespace kruiser
$ go install .
The two example gRPC demo services used below are:
- A simple echo service yages.Echo available via
quay.io/mhausenblas/yages:0.1.0
- The reference helloworld.Greeter available via
quay.io/mhausenblas/grpc-gs:0.2
As a generic gRPC client we use fullstorydev/grpcurl which you can either install locally, if you have Go installed, or as a container via the quay.io/mhausenblas/gump:0.1 container image.
To expose a deployment, that is, creating an Ambassador-backed service proxying traffic to its pods from outside the cluster with kruiser
you have to do two things: 1. define the gRPC service semantics, and 2. enable/disable the proxying.
Define the gRPC service semantics on the deployment you want to expose like so:
$ kubectl -n kruiser annotate deploy/ping kruiser.kubernetes.sh/container-port='9000'
$ kubectl -n kruiser annotate deploy/ping kruiser.kubernetes.sh/fq-service-name='yages.Echo'
And now, in order to trigger the service proxy to be created, label the deployment with kruiser.kubernetes.sh/grpc=expose
, for example:
$ kubectl -n kruiser label deploy/ping kruiser.kubernetes.sh/grpc=expose
Note: use kubectl -n kruiser label deploy/ping kruiser.kubernetes.sh/grpc-
to remove the label again.
In the following, I'll walk you through how you can use kruiser
in a static manner, that is, manually exposing gRPC services cluster-externally. Along the way I explain how kruiser
works.
$ kubectl create namespace kruiser
First, install Ambassador with:
$ kubectl -n kruiser apply -f ambassador/admin.yaml
Next, deploy the two gRPC demo services:
$ kubectl -n kruiser apply -f demo-services/
Now you can invoke each of the gRPC demo services from outside Minikube like so:
$ grpcurl --plaintext $(minikube ip):31001 yages.Echo.Ping
$ grpcurl --plaintext -d '{ "name" : "Michael" }' $(minikube ip):31000 helloworld.Greeter.SayHello
Alternatively, you can access one of the gRPC services via the gRPC jump pod like so:
$ kubectl -n kruiser run -it --rm gumpod \
--restart=Never --image=quay.io/mhausenblas/gump:0.1
/go $ grpcurl --plaintext ping:9000 yages.Echo.Ping
Note that the GKE deployment in the following uses RBAC for access control.
As a preparation, you need to give your user certain rights.
$ cat ambassador/gke-crb.yaml | \
sed s/__USER__/$(gcloud projects get-iam-policy $(gcloud config get-value core/project) | grep -m 1 user | awk '{split($0,u,":"); print u[2]}')/g | \
kubectl -n kruiser apply -f -
Above, we replace the __USER__
placeholder in ambassador/gke-crb.yaml
with the value of the user name of the active GKE project before creating the respective cluster-role binding.
Next, install Ambassador with:
$ kubectl -n kruiser apply -f ambassador/admin-rbac.yaml
And now deploy the two gRPC demo services:
$ kubectl -n kruiser apply -f demo-services/
To be able to access the services from outside the GKE cluster we first have to find values for external IPs of cluster nodes (store them for example in an env var NODE_IP
):
$ kubectl get nodes --selector=kubernetes.io/role!=master \
-o jsonpath={.items[*].status.addresses[?\(@.type==\"ExternalIP\"\)].address}
Now, finally, you can invoke each of the gRPC demo services from outside the GKE cluster like so:
$ grpcurl --plaintext $(NODE_IP):31001 yages.Echo.Ping
$ grpcurl --plaintext -d '{ "name" : "Michael" }' $(NODE_IP):31000 helloworld.Greeter.SayHello
When done, clean up with:
$ kubectl delete ns kruiser