Web Relay Ingress with Docker for Mac

By Karolis Rusenas · Jan 8, 2018

Docker for Mac now supports Kubernetes

Kubernetes became available in Docker for Mac 17.12 CE Edge. Kubernetes in the last year showed that it’s the most flexible and reliable option to run container workloads, all the major cloud providers now offer or are planning to offer a managed Kubernetes service to their customers:

And some great companies that help you deploy and run your own cluster:

After visiting last KubeCon in Austin I have seen a huge increase in the number of companies that specialize in Kubernetes consulting. This list could go on and on :)

In this article we will:

  • Enable Kubernetes support in your Docker for Mac.
  • Create and deploy an example Node.js application.
  • Use Web Relay ingress controller to share that app running inside our Mac to the world :)

Ingress with Docker for Mac

Prerequisites:

  • Docker for Mac 17.12 CE Edge.
  • Webhook Relay account and relay client command.
  • kubectl, the Kubernetes client command. It should be included and configured by the Docker for Mac.

If you are not using Mac or Docker for Mac you can still follow this tutorial step-by-step, just skip the “Enable Kubernetes in your Docker for Mac” section. This tutorial will work for ANY Kubernetes cluster as long as it has an Internet connectivity.

Getting started

Time to get our hands dirty! Feel free to skip a few things like enabling Kubernetes if you have already done it.

Enable Kubernetes in your Docker for Mac

To enable Kubernetes support inside your Docker for Mac, select Enable Kubernetes and click the Apply and restart button:

Kubernetes in Docker for Mac

It should take a bit of time depending on the available Internet bandwidth and once it is done, it should report that the installation is complete. If you have any problems with this step, it might make sense to visit Docker documentation on this matter.

Unlike Minikube, Docker for Mac doesn’t hijack kubectl context, so you have to set it:

kubectl config use-context docker-for-desktop

Check whether your kubectl is using the docker-for-desktop context.

$ kubectl config get-contexts
CURRENT   NAME                                                         CLUSTER                                                      AUTHINFO                                                     NAMESPACE          
          minikube                                                     minikube                                                     minikube
*         docker-for-desktop                                           docker-for-desktop-cluster                                   docker-for-desktop          

Add ingress controller to your Docker for Mac Kubernetes

Add ingress controller:

relay ingress init

Output:

$ relay ingress init
using manifest from 'https://raw.githubusercontent.com/webrelay/ingress/master/deployment/deployment-rbac.yaml'...
namespace "webrelay-ingress" created
serviceaccount "webrelay" created
deployment "webrelay" created
clusterrolebinding "webrelay" created
clusterrole "webrelay" created
ingress added to the cluster, configuring authentication...
key and secret not supplied, generating new access credentials...
secret "webrelay-credentials" created

Yeah, some of you are probably now like:

Back in my day we used helm

But hold on, this command creates RBAC-enabled ingress controller in webrelay-ingress namespace with already configured credentials for your account. You can read more about Web Relay ingress controller here.

Create your Node.js application

The next step is to write the application. Create a new directory named hello with the filename server.js:

var http = require('http');
var port = 8080
var handleRequest = function(request, response) {
  console.log('Received request for URL: ' + request.url);
  response.writeHead(200);
  response.end('Hello Internet!');
};
var www = http.createServer(handleRequest);
console.log('Listening on http://localhost:' + port);
www.listen(port);

To run the application:

node server.js

You should be able to see your “Hello World!” message at http://localhost:8080/.

Stop the running Node.js server by pressing Ctrl-C.

The next step is to package your application in a Docker container.

Put your application into a Docker container

Create a file, also in the hello directory, named Dockerfile. A Dockerfile describes the image that you want to build. You can build a Docker container image by extending an existing image. The image in this tutorial extends an existing Node.js image.

FROM node:9.2.0
EXPOSE 8080
COPY server.js .
CMD node server.js

This Dockerfile starts from the official Node.js image found in the Docker registry, exposes port 8080, copies your server.js file to the image and starts the Node.js server.
Build your Docker image:

docker build -t hello-node:v1 .

What is really nice about Docker for Mac with Kubernetes is that you can easily run locally built Docker images inside Kubernetes cluster. No need to change Docker daemons or push images to the public repositories just to test them out. Now Docker for Mac Kubernetes can run the image you built.

Create Deployment and Service

Kubernetes Deployments checks on the health of the Pods and restarts the Pod’s container if it terminates. Pod can consist of more than one containers but in this example we will only have one:

kubectl run hello-node --image=hello-node:v1 --port=8080

To view Deployments:

kubectl get deployments

Output:

$ kubectl get deployments
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-node   1         1         1            1           8s

Since by default Pod is only accessible by its internal IP address within the Kubernetes cluster, we need to expose it. Create a Service:

kubectl expose deployment hello-node --type=ClusterIP

To view created services:

kubectl get svc

Output:

$ kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
hello-node   ClusterIP   10.102.194.95   <none>        8080/TCP   1m

Define ingress and expose your app to the Internet

Things get interesting

Ingresses in Kubernetes provide an easy way to define routing rules between hostnames and services. Let’s get our public endpoint with relay command client by creating a tunnel:

relay tunnel create --group webrelay-ingress hellonode

Output:

$ relay tunnel create --group webrelay-ingress hellonode
pis9izc72c1wd9i21gxqxm.webrelay.io<---->http://127.0.0.1

Parameter –group webrelay-ingress is required to let our ingress controller know which tunnels it can manage.

Note that users with paid plans can specify any custom subdomain (as long as it is not taken) without creating a tunnel first. This allows to just easily define ingress.yaml and ingress controller wil create a tunnel for it.

We are only interested in this pis9izc72c1wd9i21gxqxm.webrelay.io (host) part. Every user gets a unique link to their tunnel. Edit this code with your tunnel hostname and save it in a folder named hello with the filename ingress.yml:

# ingress.yml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: webrelay # other ingress classes will be ignored
  name: relay-ingress
  namespace: default
spec:
  rules:
    - host: pis9izc72c1wd9i21gxqxm.webrelay.io # <- host has to match tunnel host
      http:
        paths:
        - path: /
          backend:
            serviceName: hello-node
            servicePort: 8080

Create it:

kubectl create -f ingress.yml

Output:

$ kubectl create -f ingress.yml
ingress "relay-ingress" created

Your application is now exposed to the public Internet. See next section how to access or just enter that hostname into your browser.

Accessing your application through the Internet

To view existing ingresses:

relay ingress ls

Output:

relay ingress ls
ID                                     NAME                                                  HOST                                 BACKENDS                  CRYPTO              AUTH                AGE
58f26c61-8e42-45f4-a982-4cb70990d7e2   webrelay-ingress-pis9izc72c1wd9i21gxqxm.webrelay.io   pis9izc72c1wd9i21gxqxm.webrelay.io   default/hello-node/8080   off                 -                   2 seconds

Backends column should show <namespace>/<service>/<port> of the exposed service. You can access http://pis9izc72c1wd9i21gxqxm.webrelay.io with your browser (just change the link to your own tunnel address).

You can also use web UI at https://my.webhookrelay.com/tunnels to view your ingresses:

Ingress table in web UI

Wrapping up

In this article we created, deployed and exposed an app to the Internet that is running locally on our laptops. Some people say that this is an “actual hello world” application and not just the usual “hello localhost”.

With Docker for Mac Kubernetes support it’s now a lot easier to develop and test our applications. Build locally, run locally and demo locally. I hope Web Relay ingress controller will serve you great in developing, testing and running your apps.

As always, if you have any questions, feel free to contact me.