Skip to content

Knative Serving⚓︎

This guide covers the prokube-specific parts of deploying a plain Knative Serving service. For the full Knative API and concepts, use the upstream documentation:

When to use Knative directly⚓︎

Use Knative directly when you want to run a serverless HTTP service on Kubernetes and do not need KServe's model-serving abstractions. For model inference, KServe is usually the better starting point because it already integrates model runtimes, model storage, inference protocols, and the prokube /serving/<namespace>/<name>/... URL convention.

The important prokube-specific difference is exposure:

  • KServe InferenceService resources are automatically exposed through the prokube /serving/<namespace>/<name>/... path.
  • Plain Knative Service resources are not automatically exposed through that path.
  • To call a plain Knative service from outside the cluster, create an Istio VirtualService that forwards a chosen external path to the Knative local gateway.

Deploy a Knative Service⚓︎

Create a Knative Service in your namespace. The container must listen on the port declared by the PORT environment variable, which Knative sets automatically.

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: my-service
  namespace: my-namespace
spec:
  template:
    spec:
      containers:
        - image: ghcr.io/example/my-service:latest
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: "500m"
              memory: 512Mi
            limits:
              cpu: "1"
              memory: 1Gi

Apply it with:

kubectl apply -f my-service.yaml

Check that Knative made the service ready:

kubectl get ksvc my-service -n my-namespace

The URL shown by kubectl get ksvc is the Knative route host. In prokube, this route is usually useful inside the cluster, but it is not automatically reachable from the public prokube domain.

Expose the Knative Service⚓︎

To expose the service externally under the prokube /serving path, create a VirtualService in your namespace. This example exposes my-service in namespace my-namespace as:

https://prokube.example.com/serving/my-namespace/my-service
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: my-service
  namespace: my-namespace
spec:
  gateways:
    - istio-system/cluster-local-gateway
  hosts:
    - prokube.example.com
  http:
    - headers:
        request:
          set:
            Host: my-service.my-namespace.svc.cluster.local
      match:
        - uri:
            exact: /serving/my-namespace/my-service
        - uri:
            prefix: /serving/my-namespace/my-service/
      rewrite:
        uri: /
      route:
        - destination:
            host: knative-local-gateway.istio-system.svc.cluster.local
            port:
              number: 80

Apply it with:

kubectl apply -f my-service-virtualservice.yaml

Replace the placeholders as follows:

Placeholder Meaning
my-service Name of your Knative Service
my-namespace Your prokube/Kubeflow profile namespace
prokube.example.com Public hostname of your prokube cluster
/serving/my-namespace/my-service External path you want users or clients to call
my-service.my-namespace.svc.cluster.local Internal Knative route host for your service

The Host header is required because Knative routes requests based on the HTTP host. The request is routed to knative-local-gateway, which then forwards it to the correct Knative revision.

Access Notes⚓︎

Inside the cluster, you can call the Knative service directly through its internal Knative URL or Kubernetes service address, depending on where the client runs. This does not require the external prokube /serving/... route.

From outside the cluster, or when using the external prokube URL, requests to /serving/* currently need an API key in the x-api-key header:

curl \
  -H "x-api-key: ${API_KEY}" \
  https://prokube.example.com/serving/my-namespace/my-service

Ask your administrator for an API key that is valid for your namespace and use case. Do not commit API keys to source control or hardcode them into application images.

Common Adjustments⚓︎

If your application expects the full path, remove the rewrite block so it receives /serving/my-namespace/my-service/....

If you want to expose a different public path than the Knative service name, change only the match paths. Keep the Host header pointing to the actual Knative service host.

If your prokube cluster has multiple public hostnames, list all allowed hostnames under spec.hosts.

If the service should not scale to zero, add Knative autoscaling annotations to the service template. For example:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: my-service
  namespace: my-namespace
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/min-scale: "1"
    spec:
      containers:
        - image: ghcr.io/example/my-service:latest

See the Knative autoscaling documentation for more options.

Troubleshooting⚓︎

Check the Knative service status:

kubectl describe ksvc my-service -n my-namespace

Check the created revision and pods:

kubectl get revision -n my-namespace
kubectl get pods -n my-namespace

Check application logs:

kubectl logs -n my-namespace -l serving.knative.dev/service=my-service

If the external URL returns 404, verify that the VirtualService path matches the request path and that the Host header points to the Knative route host.

If the external URL returns 403 or 401, check whether the cluster requires API keys for /serving/* and whether the key is valid for the namespace in the path.

If the Knative service never becomes ready, start with the pod events and logs. Most failures are image pull errors, missing environment variables or secrets, insufficient resources, or the container not listening on the expected port.