Merge pull request #192 from bprashanth/custom_controller_example

Add a custom controller example
This commit is contained in:
Manuel Alejandro de Brito Fontes 2017-01-31 15:50:53 -03:00 committed by GitHub
commit aa7b2b6302
9 changed files with 231 additions and 1 deletions

View file

@ -2,4 +2,6 @@
This is a non-comprehensive list of existing ingress controllers.
* [Dummy controller backend](/examples/custom-controller)

View file

@ -1,3 +1,4 @@
# Writing Ingress controllers
This doc outlines the basic steps needed to write an Ingress controller.
If you want the tl;dr version, skip straight to the [example](/examples/custom-controller).

View file

@ -85,7 +85,7 @@ as well as in [this](/examples/pipeline) example.
First check the [catalog](#is-there-a-catalog-of-existing-ingress-controllers), to make sure you really need to write one.
1. Write a [generic backend](https://github.com/kubernetes/ingress/blob/master/core/pkg/ingress/doc.go)
1. Write a [generic backend](/examples/custom-controller)
2. Keep it in your own repo, make sure it passes the [conformance suite](https://github.com/kubernetes/kubernetes/blob/master/test/e2e/ingress_utils.go#L112)
3. Submit an example(s) in the appropriate subdirectories [here](/examples/README.md)
4. Add it to the catalog

View file

@ -69,4 +69,10 @@ Websockets | websockets loadbalancing | nginx | Intermediate
HTTP/2 | HTTP/2 loadbalancing | * | Intermediate
Proxy protocol | leverage the proxy protocol for source IP | nginx | Advanced
## Custom controllers
Name | Description | Platform | Complexity Level
-----| ----------- | ---------- | ----------------
Dummy | A simple dummy controller that logs updates | * | Advanced

View file

@ -0,0 +1,20 @@
# Copyright 2017[<0;55;12M The Kubernetes Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# TODO(ingress#191): Change this to something more appropriate, like busybox
From ubuntu:15.10
MAINTAINER Prashanth B <beeps@google.com>
RUN apt-get update && apt-get install ssl-cert -y
COPY server /
ENTRYPOINT ["/server"]

View file

@ -0,0 +1,39 @@
# Copyright 2017 The Kubernetes Authors All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Build the default backend binary or image for amd64, arm, arm64 and ppc64le
#
# Usage:
# [PREFIX=gcr.io/google_containers/dummy-ingress-controller] [ARCH=amd64] [TAG=1.1] make (server|container|push)
all: push
TAG=0.1
PREFIX?=bprashanth/dummy-ingress-controller
ARCH?=amd64
GOLANG_VERSION=1.6
TEMP_DIR:=$(shell mktemp -d)
server: server.go
CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) GOARM=6 godep go build -a -installsuffix cgo -ldflags '-w' -o server ./server.go
container: server
docker build --pull -t $(PREFIX)-$(ARCH):$(TAG) .
push: container
gcloud docker push $(PREFIX)-$(ARCH):$(TAG)
clean:
rm -f server

View file

@ -0,0 +1,29 @@
# Dummy controller
This example contains the source code of a simple dummy controller. If you want
more details on the interface, or what the generic controller is actually doing,
please read [this doc](/docs/dev/devel.md). You can deploy the controller as
follows:
```console
$ kubectl create -f deployment.yaml
service "default-backend" created
deployment "dummy-ingress-controller" created
$ kubectl get po
NAME READY STATUS RESTARTS AGE
dummy-ingress-controller-3685541482-082nl 1/1 Running 0 10m
$ kubectl logs dummy-ingress-controller-3685541482-082nl
I0131 02:29:02.462123 1 launch.go:92] &{dummy 0.0.0 git-00000000 git://foo.bar.com}
I0131 02:29:02.462513 1 launch.go:221] Creating API server client for https://10.0.0.1:443
I0131 02:29:02.494571 1 launch.go:111] validated default/default-backend as the default backend
I0131 02:29:02.503180 1 controller.go:1038] starting Ingress controller
I0131 02:29:02.513528 1 leaderelection.go:247] lock is held by dummy-ingress-controller-3685541482-50jh0 and has not yet expired
W0131 02:29:03.510699 1 queue.go:87] requeuing kube-system/kube-scheduler, err deferring sync till endpoints controller has synced
W0131 02:29:03.514445 1 queue.go:87] requeuing kube-system/node-controller-token-826dl, err deferring sync till endpoints controller has synced
2017/01/31 02:29:12 Received OnUpdate notification
2017/01/31 02:29:12 upstream-default-backend: 10.180.1.20
```

View file

@ -0,0 +1,51 @@
apiVersion: v1
kind: Service
metadata:
name: default-backend
namespace: default
labels:
name: default-backend
app: dummy-ingress-controller
spec:
ports:
- port: 80
targetPort: 10254
selector:
# Point back the the dummy controller's
# healthz port
app: dummy-ingress-controller
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: dummy-ingress-controller
namespace: default
labels:
app: dummy-ingress-controller
spec:
selector:
matchLabels:
app: dummy-ingress-controller
template:
metadata:
labels:
app: dummy-ingress-controller
spec:
containers:
- name: server
image: bprashanth/dummy-ingress-controller-amd64:0.1
imagePullPolicy: Always
ports:
- containerPort: 10254
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
args:
- /server
- --default-backend-service=$(POD_NAMESPACE)/default-backend

View file

@ -0,0 +1,82 @@
package main
import (
"log"
"net/http"
"os/exec"
"strings"
nginxconfig "k8s.io/ingress/controllers/nginx/pkg/config"
"k8s.io/ingress/core/pkg/ingress"
"k8s.io/ingress/core/pkg/ingress/controller"
"k8s.io/ingress/core/pkg/ingress/defaults"
"k8s.io/kubernetes/pkg/api"
)
func main() {
dc := newDummyController()
ic := controller.NewIngressController(dc)
defer func() {
log.Printf("Shutting down ingress controller...")
ic.Stop()
}()
ic.Start()
}
func newDummyController() ingress.Controller {
return &DummyController{}
}
type DummyController struct{}
func (dc DummyController) SetConfig(cfgMap *api.ConfigMap) {
log.Printf("Config map %+v", cfgMap)
}
func (dc DummyController) Reload(data []byte) ([]byte, bool, error) {
out, err := exec.Command("echo", string(data)).CombinedOutput()
if err != nil {
log.Printf("Reloaded new config %s", out)
} else {
return out, false, err
}
return out, true, err
}
func (dc DummyController) Test(file string) *exec.Cmd {
return exec.Command("echo", file)
}
func (dc DummyController) OnUpdate(updatePayload ingress.Configuration) ([]byte, error) {
log.Printf("Received OnUpdate notification")
for _, b := range updatePayload.Backends {
eps := []string{}
for _, e := range b.Endpoints {
eps = append(eps, e.Address)
}
log.Printf("%v: %v", b.Name, strings.Join(eps, ", "))
}
return []byte(`<string containing a configuration file>`), nil
}
func (dc DummyController) BackendDefaults() defaults.Backend {
// Just adopt nginx's default backend config
return nginxconfig.NewDefault().Backend
}
func (n DummyController) Name() string {
return "dummy Controller"
}
func (n DummyController) Check(_ *http.Request) error {
return nil
}
func (dc DummyController) Info() *ingress.BackendInfo {
return &ingress.BackendInfo{
Name: "dummy",
Release: "0.0.0",
Build: "git-00000000",
Repository: "git://foo.bar.com",
}
}