Skip to content

Commit e320d5c

Browse files
authored
Merge pull request #55 from nginxinc/ingress-class-annotation
Ingress class annotation
2 parents ce17870 + 560b7df commit e320d5c

File tree

4 files changed

+99
-4
lines changed

4 files changed

+99
-4
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ Every time the number of pods of services you expose via Ingress changes, the In
4444
NGINX Plus provides you with [advanced statistics](https://www.nginx.com/products/live-activity-monitoring/), which you can access either through the API or via the built-in dashboard. This can give you insights into how NGINX Plus and your applications are performing.
4545
* **Session Persistence** When enabled, NGINX Plus makes sure that all the requests from the same client are always passed to the same backend container using the *sticky cookie* method. Refer to the [session persistence examples](examples/session-persistence) to find out how to configure it.
4646

47+
## Using Multiple Ingress Controllers
48+
49+
You can run multiple Ingress controllers at the same time. For example, if your Kubernetes cluster is deployed in cloud, you can run the NGINX controller and the corresponding cloud HTTP load balancing controller. Refer to the [example](examples/multiple-ingress-controllers) to learn more.
50+
4751
## Advanced load balancing (beyond Ingress)
4852

4953
When your requirements go beyond what Ingress offers, you can use NGINX and
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Using Multiple Ingress Controllers
2+
3+
With the *kubernetes.io/ingress.class* annotation it is possible to smoothly run multiple Ingress controllers at the same time. This could be the case when you deploy your Kubernetes cluster in a cloud provider, for example, Google Compute Engine (GCE). A cloud provider can provide its own Ingress controller enabled by default.
4+
5+
If the annotation is not present in an Ingress resource, which is the usual case, each Ingress controller deployed in the cluster will handle that Ingress. Using the annotation you can specify which Ingress controller must handle which Ingress resource.
6+
7+
To designate that a particular Ingress resource must be handled *only* by the NGINX or NGINX Plus controller add the following annotation along with the value to the Ingress resource:
8+
```
9+
kubernetes.io/ingress.class: "nginx"
10+
```
11+
12+
In this case other Ingress controllers will ignore that Ingress.
13+
14+
To summarize, the NGINX or NGINX Plus controller *will* handle an Ingress resource, if one of the following is true:
15+
* The annotation is not present in the resource
16+
* The annotation is present and its value is either the `nginx` or the empty string
17+
18+
Any other value of the annotation, for example, `gce`, makes the NGINX or NGINX Plus controller ignore the Ingress resource.
19+
20+
Here is an example of an Ingress resource that will be handled *only* by the NGINX or NGINX Plus controller:
21+
```yaml
22+
apiVersion: extensions/v1beta1
23+
kind: Ingress
24+
metadata:
25+
name: cafe-ingress-nginx
26+
annotations:
27+
kubernetes.io/ingress.class: "nginx"
28+
spec:
29+
tls:
30+
- hosts:
31+
- cafe.example.com
32+
secretName: cafe-secret
33+
rules:
34+
- host: cafe.example.com
35+
http:
36+
paths:
37+
- path: /tea
38+
backend:
39+
serviceName: tea-svc
40+
servicePort: 80
41+
- path: /coffee
42+
backend:
43+
serviceName: coffee-svc
44+
servicePort: 80
45+
```

nginx-controller/controller/controller.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ import (
3737
"k8s.io/kubernetes/pkg/watch"
3838
)
3939

40+
const (
41+
ingressClassKey = "kubernetes.io/ingress.class"
42+
nginxIngressClass = "nginx"
43+
)
44+
4045
// LoadBalancerController watches Kubernetes API and
4146
// reconfigures NGINX via NginxController when needed
4247
type LoadBalancerController struct {
@@ -73,18 +78,28 @@ func NewLoadBalancerController(kubeClient *client.Client, resyncPeriod time.Dura
7378
ingHandlers := framework.ResourceEventHandlerFuncs{
7479
AddFunc: func(obj interface{}) {
7580
addIng := obj.(*extensions.Ingress)
81+
if !isNginxIngress(addIng) {
82+
glog.Infof("Ignoring Ingress %v based on Annotation %v", addIng.Name, ingressClassKey)
83+
return
84+
}
7685
glog.V(3).Infof("Adding Ingress: %v", addIng.Name)
7786
lbc.ingQueue.enqueue(obj)
7887
},
7988
DeleteFunc: func(obj interface{}) {
8089
remIng := obj.(*extensions.Ingress)
90+
if !isNginxIngress(remIng) {
91+
return
92+
}
8193
glog.V(3).Infof("Removing Ingress: %v", remIng.Name)
8294
lbc.ingQueue.enqueue(obj)
8395
},
8496
UpdateFunc: func(old, cur interface{}) {
97+
curIng := cur.(*extensions.Ingress)
98+
if !isNginxIngress(curIng) {
99+
return
100+
}
85101
if !reflect.DeepEqual(old, cur) {
86-
glog.V(3).Infof("Ingress %v changed, syncing",
87-
cur.(*extensions.Ingress).Name)
102+
glog.V(3).Infof("Ingress %v changed, syncing", curIng.Name)
88103
lbc.ingQueue.enqueue(cur)
89104
}
90105
},
@@ -521,3 +536,11 @@ func parseNginxConfigMaps(nginxConfigMaps string) (string, string, error) {
521536
}
522537
return res[0], res[1], nil
523538
}
539+
540+
func isNginxIngress(ing *extensions.Ingress) bool {
541+
if class, exists := ing.Annotations[ingressClassKey]; exists {
542+
return class == nginxIngressClass || class == ""
543+
}
544+
545+
return true
546+
}

nginx-plus-controller/controller/controller.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ import (
3737
"k8s.io/kubernetes/pkg/watch"
3838
)
3939

40+
const (
41+
ingressClassKey = "kubernetes.io/ingress.class"
42+
nginxIngressClass = "nginx"
43+
)
44+
4045
// LoadBalancerController watches Kubernetes API and
4146
// reconfigures NGINX via NginxController when needed
4247
type LoadBalancerController struct {
@@ -73,18 +78,28 @@ func NewLoadBalancerController(kubeClient *client.Client, resyncPeriod time.Dura
7378
ingHandlers := framework.ResourceEventHandlerFuncs{
7479
AddFunc: func(obj interface{}) {
7580
addIng := obj.(*extensions.Ingress)
81+
if !isNginxIngress(addIng) {
82+
glog.Infof("Ignoring Ingress %v based on Annotation %v", addIng.Name, ingressClassKey)
83+
return
84+
}
7685
glog.V(3).Infof("Adding Ingress: %v", addIng.Name)
7786
lbc.ingQueue.enqueue(obj)
7887
},
7988
DeleteFunc: func(obj interface{}) {
8089
remIng := obj.(*extensions.Ingress)
90+
if !isNginxIngress(remIng) {
91+
return
92+
}
8193
glog.V(3).Infof("Removing Ingress: %v", remIng.Name)
8294
lbc.ingQueue.enqueue(obj)
8395
},
8496
UpdateFunc: func(old, cur interface{}) {
97+
curIng := cur.(*extensions.Ingress)
98+
if !isNginxIngress(curIng) {
99+
return
100+
}
85101
if !reflect.DeepEqual(old, cur) {
86-
glog.V(3).Infof("Ingress %v changed, syncing",
87-
cur.(*extensions.Ingress).Name)
102+
glog.V(3).Infof("Ingress %v changed, syncing", curIng.Name)
88103
lbc.ingQueue.enqueue(cur)
89104
}
90105
},
@@ -521,3 +536,11 @@ func parseNginxConfigMaps(nginxConfigMaps string) (string, string, error) {
521536
}
522537
return res[0], res[1], nil
523538
}
539+
540+
func isNginxIngress(ing *extensions.Ingress) bool {
541+
if class, exists := ing.Annotations[ingressClassKey]; exists {
542+
return class == nginxIngressClass || class == ""
543+
}
544+
545+
return true
546+
}

0 commit comments

Comments
 (0)