Merge pull request #192 from bprashanth/custom_controller_example
Add a custom controller example
This commit is contained in:
commit
aa7b2b6302
9 changed files with 231 additions and 1 deletions
|
@ -2,4 +2,6 @@
|
||||||
|
|
||||||
This is a non-comprehensive list of existing ingress controllers.
|
This is a non-comprehensive list of existing ingress controllers.
|
||||||
|
|
||||||
|
* [Dummy controller backend](/examples/custom-controller)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
# Writing Ingress controllers
|
# Writing Ingress controllers
|
||||||
|
|
||||||
This doc outlines the basic steps needed to write an Ingress controller.
|
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).
|
||||||
|
|
|
@ -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.
|
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)
|
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)
|
3. Submit an example(s) in the appropriate subdirectories [here](/examples/README.md)
|
||||||
4. Add it to the catalog
|
4. Add it to the catalog
|
||||||
|
|
|
@ -69,4 +69,10 @@ Websockets | websockets loadbalancing | nginx | Intermediate
|
||||||
HTTP/2 | HTTP/2 loadbalancing | * | Intermediate
|
HTTP/2 | HTTP/2 loadbalancing | * | Intermediate
|
||||||
Proxy protocol | leverage the proxy protocol for source IP | nginx | Advanced
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
20
examples/custom-controller/Dockerfile
Normal file
20
examples/custom-controller/Dockerfile
Normal 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"]
|
39
examples/custom-controller/Makefile
Normal file
39
examples/custom-controller/Makefile
Normal 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
|
||||||
|
|
29
examples/custom-controller/README.md
Normal file
29
examples/custom-controller/README.md
Normal 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
|
||||||
|
```
|
||||||
|
|
||||||
|
|
51
examples/custom-controller/deployment.yaml
Normal file
51
examples/custom-controller/deployment.yaml
Normal 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
|
82
examples/custom-controller/server.go
Normal file
82
examples/custom-controller/server.go
Normal 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",
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue