If you followed the Getting Started with Nuclio on Kubernetes or Getting Started with Nuclio on Google Kubernetes Engine (GKE) guide, you invoked functions using their HTTP interface with nuctl
and the Nuclio dashboard.
By default, each function deployed to Kubernetes declares a Kubernetes service that is responsible for routing requests to the functions' HTTP trigger port.
To invoke the function externally, using nuctl
, you probably exposed your function by using a NodePort, which is a unique cluster-wide port that is assigned to the function.
This means that if your function's HTTP trigger is configured with a NodePort
, any underlying HTTP client can call http://<your cluster IP>:<some unique port>
to reach it.
You can try this out yourself: first, find out the NodePort assigned to your function, by using the nuctl get function
command of the nuctl
CLI or the kubectl get svc
command of the Kubernetes CLI. Then, use curl
to send an HTTP request to this port.
In addition to configuring a service, Nuclio can create a Kubernetes ingress for your function's HTTP trigger, with the path specified as <function name>/latest
.
However, without an ingress controller running on your cluster, this will have no effect. An Ingress controller will listen for changed ingresses and reconfigure some type of reverse proxy to route requests based on rules specified in the ingress resource.
In this guide, you'll set up a Træfik controller, but any type of Kubernetes ingress controller should work. You can read Træfik's excellent documentation, but for the purposes of this guide you can simply run the following commands to set up the controller by using either of the following alternative methods:
-
Using
kubectl
to apply the resource YAML files. Note that this installs v1.7, and that the YAML files were removed from newer versions:kubectl apply -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/traefik-rbac.yaml kubectl apply -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/traefik-deployment.yaml
-
Using helm (provided
helm
is installed):helm install stable/traefik --name traefik --namespace kube-system
Verify that the controller is up by running the kubectl --namespace=kube-system get pods
command, and then run the kubectl describe service --namespace=kube-system traefik-ingress-service
command to get the ingress NodePort. Following is a sample output for NodePort 30019:
...
Port: web 80/TCP
TargetPort: 80/TCP
NodePort: web 30019/TCP
Endpoints: 172.17.0.8:80
Port: admin 8080/TCP
TargetPort: 8080/TCP
...
Note: You must ensure that all your requests are sent to the returned NodePort.
Run the following command to deploy the sample helloworld
function; (the command assumes the use of Minikube):
nuctl deploy -p https://raw.githubusercontent.com/nuclio/nuclio/master/hack/examples/golang/helloworld/helloworld.go --registry $(minikube ip):5000 helloworld --run-registry localhost:5000
And now, invoke the function by its path.
Replace <NodePort>
with the NodePort of your ingress controller, and replace ${minikube ip)
with your cluster IP if you are not using Minikube:
curl $(minikube ip):<NodePort>/helloworld/latest
For example, for NodePort 30019, run this command:
curl $(minikube ip):30019/helloworld/latest
By default, functions initialize the HTTP trigger and register <function name>/latest
. However, you might want to add paths for functions to organize them in namespaces/groups, or even choose through which domain your functions can be triggered. To do this, you can configure your HTTP trigger in the function's configuration. For example:
...
triggers:
http:
maxWorkers: 4
kind: "http"
attributes:
ingresses:
i1:
# this assumes that some.host.com points to <cluster ip>
host: "some.host.com"
paths:
- "/first/path"
- "/second/path"
i2:
paths:
- "/wat"
If your helloworld
function was configured in this way, and assuming that Træfik's NodePort is 30019, the function would be accessible through any of the following URLs:
<cluster ip>:30019/helloworld/latest
some.host.com:30019/helloworld/latest
some.host.com:30019/first/path
some.host.com:30019/second/path
<cluster ip>:30019/wat
some.host.com:30019/wat
Note that since the i1
configuration explicitly specifies some.host.com
as the host
for the paths, the function will not be accessible through the cluster IP; i.e., <cluster ip>:30019/first/path
will return a 404
error.
Let's put this into practice and deploy the ingress example. This is the function.yaml file for the example:
apiVersion: "nuclio.io/v1"
kind: "NuclioFunction"
spec:
runtime: "golang"
triggers:
http:
maxWorkers: 8
kind: http
attributes:
ingresses:
first:
paths:
- /first/path
- /second/path
second:
host: my.host.com
paths:
- /first/from/host
And this is the definition of the Ingress
handler function:
func Ingress(context *nuclio.Context, event nuclio.Event) (interface{}, error) {
return "Handler called", nil
}
Deploy the function with the nuctl
CLI. If you did not use Minikube, replace $(minikube ip):5000
in the following command with your cluster IP:
nuctl deploy -p https://raw.githubusercontent.com/nuclio/nuclio/master/hack/examples/golang/ingress/ingress.go --registry $(minikube ip):5000 ingress --run-registry localhost:5000 --verbose
Behind the scenes, nuctl
populates a function CR, which is picked up by the Nuclio controller
. The controller
iterates through all the triggers and looks for the required ingresses. For each ingress, the controller creates a Kubernetes Ingress object, which triggers the Træfik ingress controller to reconfigure the reverse proxy. Following are sample controller
logs:
controller.functiondep (D) Adding ingress {"function": "helloworld", "host": "", "paths": ["/helloworld/latest"]}
controller.functiondep (D) Adding ingress {"function": "helloworld", "host": "my.host.com", "paths": ["/first/from/host"]}
controller.functiondep (D) Adding ingress {"function": "helloworld", "host": "", "paths": ["/first/path", "/second/path"]
Invoke the function with nuctl
, which will use the configured NodePort:
nuctl invoke ingress
Following is a sample output for this command:
> Response headers:
Server = nuclio
Date = Thu, 02 Nov 2017 02:11:32 GMT
Content-Type = text/plain; charset=utf-8
Content-Length = 14
> Response body:
Handler called
Add my.host.com
to your local /etc/hosts file so that it resolves to your cluster IP. The following command assumes the use of Minikube:
echo "$(minikube ip) my.host.com" | sudo tee -a /etc/hosts
Now, do some invocations with curl. The following examples assume the use of Minikube (except were your configured host is used) and NodePort 30019.
Note: The parenthesized "works" and error indications at the end of each line signify the expected outcome and are not part of the command.
curl $(minikube ip):30019/ingress/latest (works)
curl my.host.com:30019/ingress/latest (works)
curl $(minikube ip):30019/first/path (works)
curl my.host.com:30019/first/path (works)
curl my.host.com:30019/first/from/host (works)
curl $(minikube ip):30019/first/from/host (404 error)