Minikube is a convenient tool for developing cloud services on your laptop, but how can you access them from your IoT device? In this article, we'll walk through deploying the drogue-cloud project on minikube and then use some drogue crates to post data to its knative endpoint via an ESP8266 WiFi module.

tl;dr

We'll cover the gory details below, but the crux of the biscuit for accessing any knative service on minikube from a remote device is to first set up a port-forward on your laptop, and then override the Host header when connecting to that port from your device.

On your laptop, forward HTTP requests on port 8080 to knative's ingress running on minikube...

kubectl port-forward --address 0.0.0.0 svc/kourier -n kourier-system 8080:80

On your device, connect to your laptop's IP address on port 8080, but set the HTTP Host header to match the URL of the knative endpoint...

kubectl get ksvc -n drogue-iot http-endpoint -o jsonpath='{.status.url}'

It's this Host header that ensures your request is routed to the proper service.

And now, as promised, the details...

Configure Minikube

You're gonna need a lot of RAM! Like, at least 10 GB. And let's say double that amount of disk...

Still reading? Great!

The drogue-cloud repo is a bit of a playground. We include a lot of resource-hungry services such as knative -- both serving and eventing -- and strimzi.

Instructions for starting minikube with the required resources, versions, and addons are here. Essentially, you'll run this:

minikube start --cpus 4 --memory 10240 --disk-size 20gb --addons ingress

In addition, you'll need to fire up minikube tunnel in a separate shell to enable LoadBalancer type services.

minikube tunnel

Deploy drogue-cloud

With minikube up and running, installing drogue-cloud should be as simple as this:

git clone https://github.com/drogue-iot/drogue-cloud
cd drogue-cloud
./hack/drogue.sh

If it fails, it's likely because it can't find one of these. You can safely restart it after installing the one it's complaining about as the drogue.sh script is idempotent.

It will take a few minutes to finish. When it finally does, you should see output similar to this:

==========================================================================================
 Base:
==========================================================================================

SSO:
  url:      http://172.17.0.3
  user:     admin
  password: admin123456

Console:
  url:      http://172.17.0.3:30046
  user:     admin
  password: admin123456

------------------------------------------------------------------------------------------
Examples
------------------------------------------------------------------------------------------

View the dashboard:
---------------------

* Login to Grafana:
    url:      http://172.17.0.3:32656
    username: admin
    password: admin123456
* Try this link: http://172.17.0.3:32656/d/YYGTNzdMk/
* Or search for the 'Knative test' dashboard

Publish data:
----------------

At a shell prompt, try these commands:

  http POST http://http-endpoint.drogue-iot.10.96.168.111.nip.io/publish/device_id/foo temp:=44
  mqtt pub -v -h 172.17.0.3.nip.io -p 31677 -s --cafile tls.crt -t temp -m '{"temp":42}' -V 3

This shows the URL's for the drogue-cloud services specific to your minikube. You can generate this output at any time with this script:

./hack/status.sh

Configure your device

That http POST ... example command near the end of the above output is what you'll use in your device code to set the Host header.

An extremely rudimentary application based on the RTIC framework demonstrates the posting of a single piece of data to the http-endpoint using the drogue_esp8266, drogue_network, and drogue_http_client crates.

Relevant sections of the code -- replicated below -- include configuring the app for your local network and minikube, creating the correct IP address, and finally the HTTP POST request.

const HOST: &str = "192.168.0.110";    // laptop IP
const HOST_HEADER: &str = "http-endpoint.drogue-iot.10.96.168.111.nip.io";
  ...
let socket_addr = HostSocketAddr::new(
    HostAddr::from_str(HOST).unwrap(),
    8080,
);
  ...
let mut req = con
    .post("/publish/esp8266/dummy")
    .headers(&[("Host", HOST_HEADER),
               ("Content-Type", "text/json")])
    .handler(handler)
    .execute_with::<_, U512>(&mut tcp, Some(data.as_bytes()));

Obviously, unless you happen to have an STM32F401 board connected to an ESP8266 module via USART6, this code is not going to work out of the box.

But hopefully we've at least shown it's possible to combine the conveniences of Minikube for your cloud services work with Rust for your IoT development.