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.
|
||||
|
||||
* [Dummy controller backend](/examples/custom-controller)
|
||||
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
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