Kubernetes Camp

Learn Kubernetes on your Coffee Break

3. Accessing your application

So far we’ve installed Kubernetes, run our first app, and learned how to scale that app. However still haven’t made the application accessible.

Do

We can make it accessible by creating a Service which we can do with the kubectl expose command like so:

$ kubectl expose deployment first --type=LoadBalancer --port 80
service/first exposed

After a few moments we can check what resources are now running in Kubernetes with kubectl get all:

$ kubectl get all
NAME                         READY   STATUS    RESTARTS   AGE
pod/first-765d49ddcb-92vv9   1/1     Running   0          20h
pod/first-765d49ddcb-f6hb4   1/1     Running   0          20h
pod/first-765d49ddcb-gcgkn   1/1     Running   0          20h

NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/first        LoadBalancer   10.108.204.60   <pending>     80:31063/TCP   2m4s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/first   3/3     3            3           41h

NAME                               DESIRED   CURRENT   READY   AGE
replicaset.apps/first-765d49ddcb   3         3         3       20h

You can see we now have a new Service resource of type LoadBalancer. On cloud providers that support Load Balancers this would have wired up a Load Balancer to provide access to your application. Minikube does not have a Load Balancer and instead provides makes your application available via minikube service.

$ minikube service first --url
http://192.168.99.107:32183

Note: if you omit the --url part of the command it will automatically open your preferred browser to the URL.

You can then use curl or a web browser to access that URL:

$ curl -s `minikube service first --url` | head -n 4
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

Learn

Service

For a more in-depth look at services see the official Kubernetes Documentation.

Services are an abstract way to expose applications running on sets of Pods as a network service.

Services achieve this by watching Pods for specific metadata and coordinating with kube-proxy to make them accessible, and kube-dns for service discovery.

Services can be exposed in various ways depending on the access required.

Cluster IP

The default service type is clusterIP which simply provides an IP address that is accessible on every worker node that forwards each request to one of the Pods being managed by the service.

This IP is only accessible inside the cluster and is perfect for Pod to Pod communication. The obvious use case here is for a web Pod to connect to a database backend pod.

Node Port

When you want to provide external access to a service you set the type to nodePort which will forward an specific port from every worker node into the service. Armed with the IP address of a worker node, and the specified port you can access your service from outside of the cluster.

Load Balancer

Having to know the IP and Port of a nodePort service can be painful. Since Kubernetes is already tracking this information when you set the service type to loadBalancer it [the Cloud Controller Manager] will actually go out and configure a Load Balancer in your infrastructure with this information and will keep it up to date.

This means that as long as you know the IP address of your Load Balancer (will be provided by Kubernetes) you can access your application via a set IP or Vanity URL.

Kubernetes Network Proxy (kube-proxy)

kube-proxy runs on each worker node and provides the network skaffolding for services. It can do simple TCP, UDP, and SCTP stream forwarding or round robin TCP, UDP, and SCTP forwarding across a set of backends.

Kubernetes Service Discovery (kube-dns)

Kubernetes provides service discovery for services running in the cluster. It does this via three primary mechanisms; API Queries, DNS, Environment variables.

API Queries

This is the least used method as it requires you to known the Kubernetes API and query it appropriately for sets of Pods or Services.

Environment Variables

When running a Pod the Kubelet adds a set of environment variables for each active service. These environment variables can be used by your application to configure itself. However they are statically created when the Pod is launched. An example of this would be:

$ kubectl exec -ti first-765d49ddcb-wtp5k -- env | grep KUBERNETES
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443

Note: above we used the kubectl exec command which is a way to execute arbitrary commands in an existing pod. By default Kubernetes provides a service called kubernetes for the Kubernetes API, so we can grep for the service name in environment variables to see what is exposed.

Kube DNS

kube-dns A cluster aware DNS server watches the Kubernetes API and modifies DNS records as Services are created or modified.

Our service named first had a DNS record registered for it. Pods running in the same namespace can access it simply by the short name first. Pods in another namespace can access it via first.default (since we haven’t yet specified namespaces, we’re using the default).

Kubernetes also supports DNS SRV (Service) records for named ports. We don’t have a named port for the first service but if we did you could do a DNS SRV query for _http._tcp.my-service.my-ns to discover the port number for “http”, as well as the IP address.

is even more useful than environment variables. and will resolve DNS inside the cluster. For example our first service will be accessible via first.svc.default.kubernetes.local.

Kube DNS is designed purely for use inside the cluster to allow cross Pod communication. External service discovery needs to be solved with additional tooling.