Skip to content

Commit

Permalink
Support Class Field in VS/VSR
Browse files Browse the repository at this point in the history
Co-authored-by: Raúl <Rulox@users.noreply.github.com>
Co-authored-by: Michael Pleshakov <pleshakov@users.noreply.github.com>
  • Loading branch information
3 people committed Jun 26, 2020
1 parent 9bc383c commit 3428be3
Show file tree
Hide file tree
Showing 15 changed files with 236 additions and 49 deletions.
4 changes: 2 additions & 2 deletions cmd/nginx-ingress/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ var (

ingressClass = flag.String("ingress-class", "nginx",
`A class of the Ingress controller. The Ingress controller only processes Ingress resources that belong to its class
- i.e. have the annotation "kubernetes.io/ingress.class" equal to the class. Additionally,
- i.e. have the annotation "kubernetes.io/ingress.class" or the "ingressClassName" field in VirtualServer/VirtualServerRoute equal to the class. Additionally,
the Ingress controller processes Ingress resources that do not have that annotation,
which can be disabled by setting the "-use-ingress-class-only" flag`)

useIngressClassOnly = flag.Bool("use-ingress-class-only", false,
`Ignore Ingress resources without the "kubernetes.io/ingress.class" annotation`)
`Ignore Ingress resources without the "kubernetes.io/ingress.class" annotation or the "ingressClassName" field in VirtualServer/VirtualServerRoute`)

defaultServerSecret = flag.String("default-server-tls-secret", "",
`A Secret with a TLS certificate and key for TLS termination of the default server. Format: <namespace>/<name>.
Expand Down
2 changes: 2 additions & 0 deletions deployments/common/vs-definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ spec:
properties:
host:
type: string
ingressClassName:
type: string
routes:
type: array
items:
Expand Down
2 changes: 2 additions & 0 deletions deployments/common/vsr-definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ spec:
properties:
host:
type: string
ingressClassName:
type: string
subroutes:
type: array
items:
Expand Down
4 changes: 2 additions & 2 deletions deployments/helm-chart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ Parameter | Description | Default
`controller.volumeMounts` | The volumeMounts of the Ingress controller pods. | []
`controller.resources` | The resources of the Ingress controller pods. | {}
`controller.replicaCount` | The number of replicas of the Ingress controller deployment. | 1
`controller.ingressClass` | A class of the Ingress controller. The Ingress controller only processes Ingress resources that belong to its class - i.e. have the annotation `"kubernetes.io/ingress.class"` equal to the class. Additionally, the Ingress controller processes Ingress resources that do not have that annotation which can be disabled by setting the "-use-ingress-class-only" flag. | nginx
`controller.useIngressClassOnly` | Ignore Ingress resources without the `"kubernetes.io/ingress.class"` annotation. | false
`controller.ingressClass` | A class of the Ingress controller. The Ingress controller only processes Ingress resources that belong to its class - i.e. have the annotation `"kubernetes.io/ingress.class"` or the `"ingressClassName"` field in VirtualServer/VirtualServerRoute equal to the class. Additionally, the Ingress controller processes Ingress resources that do not have that annotation which can be disabled by setting the "-use-ingress-class-only" flag. | nginx
`controller.useIngressClassOnly` | Ignore Ingress resources without the `"kubernetes.io/ingress.class"` annotation or the `"ingressClassName"` field in VirtualServer/VirtualServerRoute. | false
`controller.watchNamespace` | Namespace to watch for Ingress resources. By default the Ingress controller watches all namespaces. | ""
`controller.enableCustomResources` | Enable the custom resources. | true
`controller.enableTLSPassthrough` | Enable TLS Passthrough on port 443. Requires `controller.enableCustomResources`. | false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ spec:
description: VirtualServerSpec is the spec of the VirtualServer resource.
type: object
properties:
ingressClassName:
type: string
host:
type: string
routes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ spec:
spec:
type: object
properties:
ingressClassName:
type: string
host:
type: string
subroutes:
Expand Down
4 changes: 2 additions & 2 deletions deployments/helm-chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ controller:
replicaCount: 1

## A class of the Ingress controller. The Ingress controller only processes Ingress resources that belong to its class
## i.e. have the annotation "kubernetes.io/ingress.class" equal to the class.
## i.e. have the annotation "kubernetes.io/ingress.class" or the "ingressClassName" field in VirtualServer/VirtualServerRoute equal to the class.
## Additionally, the Ingress controller processes Ingress resources that do not have that annotation which can be disabled by setting the "-use-ingress-class-only" flag.
ingressClass: nginx

## Ignore Ingress resources without the "kubernetes.io/ingress.class" annotation.
## Ignore Ingress resources without the "kubernetes.io/ingress.class" annotation or the "ingressClassName" field in VirtualServer/VirtualServerRoute.
useIngressClassOnly: false

## Namespace to watch for Ingress resources. By default the Ingress controller watches all namespaces.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Below we describe the available command-line arguments:
.. option:: -ingress-class <string>
A class of the Ingress controller. The Ingress controller only processes Ingress resources that belong to its class (in other words, have the annotation "kubernetes.io/ingress.class").
A class of the Ingress controller. The Ingress controller only processes Ingress resources that belong to its class (i.e. have the annotation "kubernetes.io/ingress.class" or the "ingressClassName" field in VirtualServer/VirtualServerRoute").
Additionally, the Ingress controller processes Ingress resources that do not have that annotation, which can be disabled by setting the :option:`-use-ingress-class-only` flag (default "nginx").
.. option:: -ingress-template-path <string>
Expand Down Expand Up @@ -132,7 +132,7 @@ Below we describe the available command-line arguments:
.. option:: -use-ingress-class-only
Ignore Ingress resources without the "kubernetes.io/ingress.class" annotation.
Ignore Ingress resources without the "kubernetes.io/ingress.class" annotation or the "ingressClassName" field in VirtualServer/VirtualServerRoute.
.. option:: -v <value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ spec:
- A list of routes.
- `[]route <#virtualserver-route>`_
- No
* - ``ingressClassName``
- Specifies which Ingress controller must handle the VirtualServer resource.
- ``string``
- No
```
### VirtualServer.TLS
Expand Down Expand Up @@ -274,6 +278,10 @@ Note that each subroute must have a `path` that starts with the same prefix (her
- A list of subroutes.
- `[]subroute <#virtualserverroute-subroute>`_
- No
* - ``ingressClassName``
- Specifies which Ingress controller must handle the VirtualServerRoute resource. Must be the same as the ``ingressClassName`` of the VirtualServer that references this resource.
- ``string``_
- No
```
### VirtualServerRoute.Subroute
Expand Down
4 changes: 2 additions & 2 deletions docs-web/installation/installation-with-helm.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,10 @@ The following tables lists the configurable parameters of the NGINX Ingress cont
- The number of replicas of the Ingress controller deployment.
- 1
* - ``controller.ingressClass``
- A class of the Ingress controller. The Ingress controller only processes Ingress resources that belong to its class - i.e. have the annotation ``"kubernetes.io/ingress.class"`` equal to the class. Additionally, the Ingress controller processes Ingress resources that do not have that annotation which can be disabled by setting the "-use-ingress-class-only" flag.
- A class of the Ingress controller. The Ingress controller only processes Ingress resources that belong to its class - i.e. have the annotation ``"kubernetes.io/ingress.class"`` or the ``"ingressClassName"`` field in VirtualServer/VirtualServerRoute equal to the class. Additionally, the Ingress controller processes Ingress resources that do not have that annotation which can be disabled by setting the "-use-ingress-class-only" flag.
- nginx
* - ``controller.useIngressClassOnly``
- Ignore Ingress resources without the ``"kubernetes.io/ingress.class"`` annotation.
- Ignore Ingress resources without the ``"kubernetes.io/ingress.class"`` annotation or the ``"ingressClassName"`` field in VirtualServer/VirtualServerRoute.
- false
* - ``controller.watchNamespace``
- Namespace to watch for Ingress resources. By default the Ingress controller watches all namespaces.
Expand Down
20 changes: 11 additions & 9 deletions docs-web/installation/running-multiple-ingress-controllers.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,39 @@ This document explains the following topics:
* How to run NGINX Ingress Controller in the same cluster with another Ingress Controller, such as an Ingress Controller for a cloud HTTP load balancer, and prevent any conflicts between the Ingress Controllers.
* How to run multiple NGINX Ingress Controllers.

**Note**: In this document we refer to Ingress, VirtualServer and VirtualServerRoute resources as configuration resources.

## Ingress Class

The smooth coexistence of multiple Ingress Controllers in one cluster is provided by the Ingress class concept, which mandates the following:
* Every Ingress Controller must only handle Ingress resources for its particular class.
* Ingress resources should be annotated with the `kubernetes.io/ingress.class` annotation set to the value, which corresponds to the class of the Ingress Controller the user wants to use.
* VirtualServer and VirtualServerRoute resources should have the `ingressClassName` field set to the value, which corresponds to the class of the Ingress Controller the user wants to use.

### Configuring Ingress Class

The default Ingress class of NGINX Ingress Controller is `nginx`, which means that it only handles Ingress resources with the `kubernetes.io/ingress.class` annotation set to `nginx`. You can customize the class through the `-ingress-class` command-line argument.
The default Ingress class of NGINX Ingress Controller is `nginx`, which means that it only handles configuration resources with the `class` set to `nginx`. You can customize the class through the `-ingress-class` command-line argument.

**Note**: By default, if the `kubernetes.io/ingress.class` annotation is not set in an Ingress resource, the Ingress Controller will handle the resource. This is controlled via the `-use-ingress-class-only` argument.
**Note**: By default, if the `class` is not set in a configuration resource, the Ingress Controller will handle the resource. This is controlled via the `-use-ingress-class-only` argument.

## Running NGINX Ingress Controller and Another Ingress Controller

It is possible to run NGINX Ingress Controller and an Ingress Controller for another load balancer in the same cluster. This is often the case if you create your cluster through a cloud provider managed Kubernetes service that by default might include the Ingress Controller for the HTTP load balancer of the cloud provider, and you want to use NGINX Ingress Controller.

To make sure that NGINX Ingress Controller handles particular Ingress resources, annotate those Ingress resources with the `kubernetes.io/ingress.class` set to `nginx` or the value that you configured.
To make sure that NGINX Ingress Controller handles particular configuration resources, update those resources with the `class` set to `nginx` or the value that you configured.


## Running Multiple NGINX Ingress Controllers

When running NGINX Ingress Controller, you have the following options with regards to which Ingress resources it handles:
* **Cluster-wide Ingress Controller (default)**. The Ingress Controller handles Ingress resources created in any namespace of the cluster. As NGINX is a high-performance load balancer capable of serving many applications at the same time, this option is used by default in our installation manifests and Helm chart.
* **Single-namespace Ingress Controller**. You can configure the Ingress Controller to handle Ingress resources only from a particular namespace, which is controlled through the `-watch-namespace` command-line argument. This can be useful if you want to use different NGINX Ingress Controllers for different applications, both in terms of isolation and/or operation.
* **Ingress Controller for Specific Ingress Class**. This option works in conjunction with either of the options above. You can further customize which Ingress resources are handled by the Ingress Controller by configuring the class of the Ingress Controller and using that class in your Ingress resources. See the section [Configuring Ingress Class](#configuring-ingress-class).
When running NGINX Ingress Controller, you have the following options with regards to which configuration resources it handles:
* **Cluster-wide Ingress Controller (default)**. The Ingress Controller handles configuration resources created in any namespace of the cluster. As NGINX is a high-performance load balancer capable of serving many applications at the same time, this option is used by default in our installation manifests and Helm chart.
* **Single-namespace Ingress Controller**. You can configure the Ingress Controller to handle configuration resources only from a particular namespace, which is controlled through the `-watch-namespace` command-line argument. This can be useful if you want to use different NGINX Ingress Controllers for different applications, both in terms of isolation and/or operation.
* **Ingress Controller for Specific Ingress Class**. This option works in conjunction with either of the options above. You can further customize which configuration resources are handled by the Ingress Controller by configuring the class of the Ingress Controller and using that class in your configuration resources. See the section [Configuring Ingress Class](#configuring-ingress-class).

Considering the options above, you can run multiple NGINX Ingress Controllers, each handling a different set of Ingress resources.
Considering the options above, you can run multiple NGINX Ingress Controllers, each handling a different set of configuration resources.

## See Also

* [Command-line arguments](/nginx-ingress-controller/configuration/global-configuration/command-line-arguments)

**Note**: all mentioned command-line arguments are also available as the parameters in the [Helm chart](/nginx-ingress-controller/installation/installation-with-helm).

67 changes: 52 additions & 15 deletions internal/k8s/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ func (lbc *LoadBalancerController) syncEndpoint(task task) {
var mergableIngressesSlice []*configs.MergeableIngresses

for i := range ings {
if !lbc.IsNginxIngress(&ings[i]) {
if !lbc.HasCorrectIngressClass(&ings[i]) {
continue
}
if isMinion(&ings[i]) {
Expand Down Expand Up @@ -647,7 +647,7 @@ func (lbc *LoadBalancerController) GetManagedIngresses() ([]extensions.Ingress,
ings, _ := lbc.ingressLister.List()
for i := range ings.Items {
ing := ings.Items[i]
if !lbc.IsNginxIngress(&ing) {
if !lbc.HasCorrectIngressClass(&ing) {
continue
}
if isMinion(&ing) {
Expand Down Expand Up @@ -1476,6 +1476,11 @@ func (lbc *LoadBalancerController) updateVirtualServersStatusFromEvents() error
for _, obj := range lbc.virtualServerLister.List() {
vs := obj.(*conf_v1.VirtualServer)

if !lbc.HasCorrectIngressClass(vs) {
glog.V(3).Infof("Ignoring VirtualServer %v based on class %v", vs.Name, vs.Spec.IngressClass)
continue
}

events, err := lbc.client.CoreV1().Events(vs.Namespace).List(context.TODO(),
meta_v1.ListOptions{FieldSelector: fmt.Sprintf("involvedObject.name=%v,involvedObject.uid=%v", vs.Name, vs.UID)})
if err != nil {
Expand Down Expand Up @@ -1508,6 +1513,11 @@ func (lbc *LoadBalancerController) updateVirtualServerRoutesStatusFromEvents() e
for _, obj := range lbc.virtualServerRouteLister.List() {
vsr := obj.(*conf_v1.VirtualServerRoute)

if !lbc.HasCorrectIngressClass(vsr) {
glog.V(3).Infof("Ignoring VirtualServerRoute %v based on class %v", vsr.Name, vsr.Spec.IngressClass)
continue
}

events, err := lbc.client.CoreV1().Events(vsr.Namespace).List(context.TODO(),
meta_v1.ListOptions{FieldSelector: fmt.Sprintf("involvedObject.name=%v,involvedObject.uid=%v", vsr.Name, vsr.UID)})
if err != nil {
Expand Down Expand Up @@ -1599,7 +1609,7 @@ items:
continue
}

if !lbc.IsNginxIngress(&ing) {
if !lbc.HasCorrectIngressClass(&ing) {
continue
}

Expand Down Expand Up @@ -1651,7 +1661,7 @@ items:
func (lbc *LoadBalancerController) EnqueueIngressForService(svc *api_v1.Service) {
ings := lbc.getIngressesForService(svc)
for _, ing := range ings {
if !lbc.IsNginxIngress(&ing) {
if !lbc.HasCorrectIngressClass(&ing) {
continue
}
if isMinion(&ing) {
Expand Down Expand Up @@ -1879,6 +1889,11 @@ func (lbc *LoadBalancerController) getVirtualServers() []*conf_v1.VirtualServer
for _, obj := range lbc.virtualServerLister.List() {
vs := obj.(*conf_v1.VirtualServer)

if !lbc.HasCorrectIngressClass(vs) {
glog.V(3).Infof("Ignoring VirtualServer %v based on class %v", vs.Name, vs.Spec.IngressClass)
continue
}

err := validation.ValidateVirtualServer(vs, lbc.isNginxPlus)
if err != nil {
glog.V(3).Infof("Skipping invalid VirtualServer %s/%s: %v", vs.Namespace, vs.Name, err)
Expand All @@ -1897,6 +1912,11 @@ func (lbc *LoadBalancerController) getVirtualServerRoutes() []*conf_v1.VirtualSe
for _, obj := range lbc.virtualServerRouteLister.List() {
vsr := obj.(*conf_v1.VirtualServerRoute)

if !lbc.HasCorrectIngressClass(vsr) {
glog.V(3).Infof("Ignoring VirtualServerRoute %v based on class %v", vsr.Name, vsr.Spec.IngressClass)
continue
}

err := validation.ValidateVirtualServerRoute(vsr, lbc.isNginxPlus)
if err != nil {
glog.V(3).Infof("Skipping invalid VirtualServerRoute %s/%s: %v", vsr.Namespace, vsr.Name, err)
Expand Down Expand Up @@ -2193,6 +2213,12 @@ func (lbc *LoadBalancerController) createVirtualServer(virtualServer *conf_v1.Vi

vsr := obj.(*conf_v1.VirtualServerRoute)

if !lbc.HasCorrectIngressClass(vsr) {
glog.Warningf("Ignoring VirtualServerRoute %v based on class %v", vsr.Name, vsr.Spec.IngressClass)
virtualServerRouteErrors = append(virtualServerRouteErrors, newVirtualServerRouteErrorFromVSR(vsr, errors.New("VirtualServerRoute with incorrect class name")))
continue
}

err = validation.ValidateVirtualServerRouteForVirtualServer(vsr, virtualServer.Spec.Host, r.Path, lbc.isNginxPlus)
if err != nil {
glog.Warningf("VirtualServer %s/%s references invalid VirtualServerRoute %s: %v", virtualServer.Name, virtualServer.Namespace, vsrKey, err)
Expand Down Expand Up @@ -2510,16 +2536,27 @@ func (lbc *LoadBalancerController) getServiceForIngressBackend(backend *extensio
return nil, fmt.Errorf("service %s doesn't exist", svcKey)
}

// IsNginxIngress checks if resource ingress class annotation (if exists) is matching with ingress controller class
// If annotation is absent and use-ingress-class-only enabled - ingress resource would ignore
func (lbc *LoadBalancerController) IsNginxIngress(ing *extensions.Ingress) bool {
if class, exists := ing.Annotations[ingressClassKey]; exists {
if lbc.useIngressClassOnly {
return class == lbc.ingressClass
}
return class == lbc.ingressClass || class == ""
// HasCorrectIngressClass checks if resource ingress class annotation (if exists) or ingressClass string for VS/VSR is matching with ingress controller class
func (lbc *LoadBalancerController) HasCorrectIngressClass(obj interface{}) bool {
var class string
switch obj.(type) {
case *conf_v1.VirtualServer:
vs := obj.(*conf_v1.VirtualServer)
class = vs.Spec.IngressClass
case *conf_v1.VirtualServerRoute:
vsr := obj.(*conf_v1.VirtualServerRoute)
class = vsr.Spec.IngressClass
case *extensions.Ingress:
ing := obj.(*extensions.Ingress)
class = ing.Annotations[ingressClassKey]
default:
return false
}

if lbc.useIngressClassOnly {
return class == lbc.ingressClass
}
return !lbc.useIngressClassOnly
return class == lbc.ingressClass || class == ""
}

// isHealthCheckEnabled checks if health checks are enabled so we can only query pods if enabled.
Expand Down Expand Up @@ -2566,7 +2603,7 @@ func (lbc *LoadBalancerController) getMinionsForMaster(master *configs.IngressEx
var minionPaths = make(map[string]*extensions.Ingress)

for i := range ings.Items {
if !lbc.IsNginxIngress(&ings.Items[i]) {
if !lbc.HasCorrectIngressClass(&ings.Items[i]) {
continue
}
if !isMinion(&ings.Items[i]) {
Expand Down Expand Up @@ -2620,7 +2657,7 @@ func (lbc *LoadBalancerController) FindMasterForMinion(minion *extensions.Ingres
}

for i := range ings.Items {
if !lbc.IsNginxIngress(&ings.Items[i]) {
if !lbc.HasCorrectIngressClass(&ings.Items[i]) {
continue
}
if !lbc.configurator.HasIngress(&ings.Items[i]) {
Expand Down
Loading

0 comments on commit 3428be3

Please sign in to comment.