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. 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 # 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).

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. 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

View file

@ -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

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",
}
}