controllers/

directory
v0.0.0-...-7ce7f99 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 11, 2016 License: Apache-2.0

README

Ingress Controllers

Configuring a webserver or loadbalancer is harder than it should be. Most webserver configuration files are very similar. There are some applications that have weird little quirks that tend to throw a wrench in things, but for the most part you can apply the same logic to them and achieve a desired result. The Ingress resource embodies this idea, and an Ingress controller is meant to handle all the quirks associated with a specific "class" of Ingress (be it a single instance of a loadbalancer, or a more complicated setup of frontends that provide GSLB, DDoS protection etc).

What is an Ingress Controller?

An Ingress Controller is a daemon, deployed as a Kubernetes Pod, that watches the ApiServer's /ingresses endpoint for updates to the Ingress resource. Its job is to satisfy requests for ingress.

Writing an Ingress Controller

Writing an Ingress controller is simple. By way of example, the [nginx controller] (nginx-alpha) does the following:

  • Poll until apiserver reports a new Ingress
  • Write the nginx config file based on a go text/template
  • Reload nginx

Pay attention to how it denormalizes the Kubernetes Ingress object into an nginx config:

const (
	nginxConf = `
events {
  worker_connections 1024;
}
http {
{{range $ing := .Items}}
{{range $rule := $ing.Spec.Rules}}
  server {
    listen 80;
    server_name {{$rule.Host}};
    resolver 127.0.0.1;
{{ range $path := $rule.HTTP.Paths }}
    location {{$path.Path}} {
      proxy_set_header Host $host;
      proxy_pass http://{{$path.Backend.ServiceName}}.{{$ing.Namespace}}.svc.cluster.local:{{$path.Backend.ServicePort}};
    }{{end}}
  }{{end}}{{end}}
}`
)

You can take a similar approach to denormalize the Ingress to a haproxy config or use it to configure a cloud loadbalancer such as a GCE L7.

And here is the Ingress controller's control loop:

for {
	rateLimiter.Accept()
	ingresses, err := ingClient.List(labels.Everything(), fields.Everything())
	if err != nil || reflect.DeepEqual(ingresses.Items, known.Items) {
	    continue
	}
	if w, err := os.Create("/etc/nginx/nginx.conf"); err != nil {
		log.Fatalf("Failed to open %v: %v", nginxConf, err)
	} else if err := tmpl.Execute(w, ingresses); err != nil {
		log.Fatalf("Failed to write template %v", err)
	}
	shellOut("nginx -s reload")
}

All this is doing is:

  • List Ingresses, optionally you can watch for changes (see GCE Ingress controller for an example)
  • Executes the template and writes results to /etc/nginx/nginx.conf
  • Reloads nginx

You can deploy this controller to a Kubernetes cluster by creating an RC. After doing so, if you were to create an Ingress such as:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        backend:
          serviceName: fooSvc
          servicePort: 80
  - host: bar.baz.com
    http:
      paths:
      - path: /bar
        backend:
          serviceName: barSvc
          servicePort: 80

Where fooSvc and barSvc are 2 services running in your Kubernetes cluster. The controller would satisfy the Ingress by writing a configuration file to /etc/nginx/nginx.conf:

events {
  worker_connections 1024;
}
http {
  server {
    listen 80;
    server_name foo.bar.com;
    resolver 127.0.0.1;

    location /foo {
      proxy_pass http://fooSvc;
    }
  }
  server {
    listen 80;
    server_name bar.baz.com;
    resolver 127.0.0.1;

    location /bar {
      proxy_pass http://barSvc;
    }
  }
}

And you can reach the /foo and /bar endpoints on the publicIP of the VM the nginx-ingress pod landed on.

$ kubectl get pods -o wide
NAME                  READY     STATUS    RESTARTS   AGE       NODE
nginx-ingress-tk7dl   1/1       Running   0          3m        e2e-test-beeps-minion-15p3

$ kubectl get nodes e2e-test-beeps-minion-15p3 -o yaml | grep -i externalip -B 1
  - address: 104.197.203.179
    type: ExternalIP

$ curl --resolve foo.bar.com:80:104.197.203.179 foo.bar.com/foo

Future work

This section can also bear the title "why anyone would want to write an Ingress controller instead of directly configuring Services". There is more to Ingress than webserver configuration. Real HA usually involves the configuration of gateways and packet forwarding devices, which most cloud providers allow you to do through an API. See the GCE Loadbalancer Controller, which is deployed as a cluster addon in GCE and GKE clusters for more advanced Ingress configuration examples. Post 1.1 the Ingress resource will support at least the following:

  • TLS options (edge, passthrough, SNI etc)
  • L4 and L7 loadbalancing (it currently only supports HTTP rules)
  • Ingress Rules that are not limited to a simple path regex (eg: redirect rules, session persistence)

And is expected to be the way one configures a "frontends" that handle user traffic for a Kubernetes cluster.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL