Running Krustlet on Kubernetes with inlets

These are steps for running a krustlet node on your own computer. You can run any kind of Kubernetes cluster you like, whether that’s local on your computer or remote in a managed Kubernetes offering.

The instructions provided in this guide were contributed by Alex Ellis. For support with the instructions, see the #inlets channel of OpenFaaS Slack or raise a GitHub issue and tag @alexellis.


There are a number of ways to give the Kubernetes API server access to the krustlet’s API. Various methods include using a VPN, a VM within the Kubernetes cluster’s private network, or a tunnel. Inlets is a popular open source service tunnel and proxy. It can be used to forward the port of the krustlet to the Kubernetes cluster so that the Kubernetes API server can access it as if it were deployed within the cluster directly.

The tunnel has two components: A client which runs on your local machine, and a server which is deployed as a Pod inside the Kubernetes cluster. The client connects to the server and provides a persistent link.

Download the latest release of the inlets binary from the project release page.

Move the binary to /usr/local/bin, or place it somewhere on your $PATH.

Step 1: Get a bootstrap config

Krustlet requires a bootstrap token and config the first time it runs. Follow the guide here to generate a bootstrap config and then return to this document. This will If you already have a kubeconfig available that you generated through another process, you can proceed to the next step. However, the credentials Krustlet uses must be part of the system:nodes group in order for things to function properly.

Step 2: Create the inlets service

In order to start Krustlet with the correct node IP address, you’ll need to create the inlets service in Kubernetes like so:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
  name: inlets
    app: inlets
  type: ClusterIP
    - port: 8000
      protocol: TCP
      targetPort: 8000
      name: control
    - port: 3000
      protocol: TCP
      targetPort: 3000
      name: data
    app: inlets

Once it has been created, run the following command to have the node IP available for next steps. This is a stable IP and won’t change.

export NODE_IP=$(kubectl get service inlets -o jsonpath="{.spec.clusterIP}")

Step 3: Run krustlet

You’ll need the certificates generated from the bootstrap process for our next steps, so go ahead and start krustlet:

$ KUBECONFIG=~/.krustlet/config/kubeconfig \
  krustlet-wasi \
  --node-ip $NODE_IP \
  --node-name=krustlet \

Then open another terminal for the next steps.

Step 4: Setup inlets server

Create a Kubernetes secret for the inlets server:

export TOKEN=$(head -c 16 /dev/urandom |shasum|cut -d- -f1)
echo $TOKEN > token.txt

kubectl create secret generic inlets-token --from-literal token=${TOKEN}

Then, create a Kubernetes secret for krustlet’s TLS certificates. These will be used by the inlets server so that the kubelet can access the tunnel using the expected TLS certificates.

kubectl create secret ghosttunnel-tls generic \
  --from-file tls.crt=~/.krustlet/config/krustlet.crt \
  --from-file tls.key=~/.krustlet/config/krustlet.key

The inlets OSS version exposes services with HTTP within the cluster, so this example uses ghosttunnel as a tiny reverse proxy to mount the krustlet’s TLS certificates so that the kubelet gets a valid HTTPS response. The service created before will expose it to the cluster

$ cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
  name: inlets
  replicas: 1
      app: inlets
        app: inlets
        - name: ghosttunnel-tls-volume
            secretName: ghosttunnel-tls
        - name: inlets-token-volume
            secretName: inlets-token
      - name: inlets
        image: inlets/inlets:2.7.0
        imagePullPolicy: Always
        command: ["inlets"]
        - "server"
        - "--token-from=/var/inlets/token"
        - "--control-port=8000"
        - "--port=3001"
          - name: inlets-token-volume
            mountPath: /var/inlets/
      - name: ghosttunnel
        image: squareup/ghostunnel:v1.5.2
        imagePullPolicy: Always
        - "server"
        - "--target="
        - "--listen="
        - "--cert=/etc/tls/tls.crt"
        - "--key=/etc/tls/tls.key"
        - "--disable-authentication"
          - name: ghosttunnel-tls-volume
            mountPath: /etc/tls

Step 5: Run the inlets client

Port-forward or expose the inlets server with:

kubectl port-forward svc/inlets 8000:8000 &

You can also expose inlets via Ingress using cert-manager to give its control-port a TLS certificate.

Run the inlets client on your computer:

inlets client \
  --upstream \
  --remote ws:// --token $(token.txt)

Step 6: Verify the node is available

Show that the krustlet node has joined the cluster:

$ kubectl get nodes -o wide
NAME                   STATUS   ROLES    AGE    VERSION   INTERNAL-IP      EXTERNAL-IP       OS-IMAGE                       KERNEL-VERSION         CONTAINER-RUNTIME
pool-3xbltttyc-3no2p   Ready    <none>   153m   v1.16.6    Debian GNU/Linux 9 (stretch)   4.19.0-0.bpo.6-amd64   docker://18.9.2
pool-3xbltttyc-3no2s   Ready    <none>   153m   v1.16.6   Debian GNU/Linux 9 (stretch)   4.19.0-0.bpo.6-amd64   docker://18.9.2
krustlet               Ready    agent    43m    v1.17.0   <none>            <unknown>                      <unknown>              mvp


Remove the port-forward for inlets OSS

We are using a port-forward to make it easier to use the tutorial. For permanent use, you will want to expose the inlets server and its control port directly. The OSS version can be configured with TLS, but this is not built-in.

You can set up an Ingress rule for the control-port of the inlets server (port 8000), and obtain a TLS certificate from LetsEncrypt.

Use inlets PRO instead

Inlets OSS is an L7 proxy that requires additional work to configure for krustlet. inlets PRO is a pure L4 TCP proxy with built-in TLS for the control-plane.

With inlets PRO you can expose the control port (8123) directly to the Internet as a NodePort, or LoadBalancer, or if you wish via an Ingress definition. The control port already has TLS configured, so won’t need additional link-layer encryption.