github.com/nginxinc/kubernetes-ingress@v1.12.5/docs-web/intro/how-nginx-ingress-controller-works.md (about)

     1  # How NGINX Ingress Controller Works
     2  
     3  This document explains how NGINX Ingress Controller works. The target audience includes the following two main groups:
     4  
     5  * *Operators* who would like to know how the software works and also better understand how it can fail.
     6  * *Developers* who would like to [contribute](https://github.com/nginxinc/kubernetes-ingress/blob/master/CONTRIBUTING.md) to the project.
     7  
     8  We assume that the reader is familiar with core Kubernetes concepts, such as Pod, Deployment, Service, and Endpoints. Additionally, we recommend reading [this blog post](https://www.nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/) for an overview of the NGINX architecture.
     9  
    10  ## Contents
    11  
    12  - [How NGINX Ingress Controller Works](#how-nginx-ingress-controller-works)
    13    - [Contents](#contents)
    14    - [What is an Ingress Controller?](#what-is-an-ingress-controller)
    15    - [The Ingress Controller at a High Level](#the-ingress-controller-at-a-high-level)
    16    - [The Ingress Controller Pod](#the-ingress-controller-pod)
    17      - [Differences for NGINX Plus](#differences-for-nginx-plus)
    18    - [The Ingress Controller Process](#the-ingress-controller-process)
    19      - [Processing a New Ingress Resource](#processing-a-new-ingress-resource)
    20      - [The Ingress Controller is a Kubernetes Controller](#the-ingress-controller-is-a-kubernetes-controller)
    21    - [Ingress Controller Process Components](#ingress-controller-process-components)
    22      - [Resource Caches](#resource-caches)
    23      - [The Control Loop](#the-control-loop)
    24        - [The Controller Sync Method](#the-controller-sync-method)
    25        - [Helper Components](#helper-components)
    26          - [Configuration](#configuration)
    27          - [LocalSecretStore](#localsecretstore)
    28  
    29  ## What is an Ingress Controller?
    30  
    31  An Ingress Controller is a component in a Kubernetes cluster that configures an HTTP load balancer according to Ingress resources created by the cluster user.
    32  
    33  > If you’d like to read more about the Ingress resource, refer to [the official Kubernetes documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/).
    34  
    35  This document is specific to NGINX Ingress Controller, referred to as *Ingress Controller* or *IC*, which is built upon NGINX and NGINX Plus capabilities
    36  
    37  ## The Ingress Controller at a High Level
    38  
    39  Let’s begin with a high-level examination of the Ingress Controller (IC). The following figure depicts an example of how the IC exposes two web applications running in a Kubernetes cluster to clients on the internet:
    40  
    41  ![IC at a high level](how-nginx-ingress-controller-works-images/ic-high-level.png)
    42  
    43  The figure shows:
    44  
    45  * A *Kubernetes cluster*.
    46  * Cluster users *Admin*, *User A* and *User B*, which use the cluster via the *Kubernetes API*.
    47  * *Clients A* and *Clients B*, which connect to the *Applications A* and *B* deployed by the corresponding users.
    48  * *IC*, [deployed by *Admin*](/nginx-ingress-controller/installation/installation-with-manifests) in a pod in the namespace *nginx-ingress* and configured via the *ConfigMap nginx-ingress*. For simplicity, we depict only one IC pod; however, *Admin* typically deploys at least two pods for redundancy. The *IC* uses the *Kubernetes API* to get the latest Ingress resources created in the cluster and then configures *NGINX* according to those resources.
    49  * *Application A* with two pods deployed in the *namespace A* by *User A*. To expose the application to its clients (*Clients A*) via the host `a.example.com`, *User A* creates *Ingress A*.
    50  * *Application B* with one pod deployed in the *namespace B* by *User B*. To expose the application to its clients (*Clients B*) via the host `b.example.com`, *User B* creates *VirtualServer B*.
    51  * *Public Endpoint*, which fronts the *IC* pod(s). This is typically a TCP load balancer (cloud, software, or hardware) or a combination of such load balancer with a NodePort service. *Clients A* and *B* connect to their applications via the *Public Endpoint*.
    52  
    53  The yellow and purple arrows represent connections related to the client traffic, and the black arrows represent access to the Kubernetes API.
    54  
    55  > For simplicity, many necessary Kubernetes resources like Deployment and Services aren't shown, which Admin and the users also need to create.
    56  
    57  Next, let's explore the IC pod.
    58  
    59  ## The Ingress Controller Pod
    60  
    61  The IC pod consists of a single container, which in turn includes the following:
    62  
    63  * *IC process*, which configures NGINX according to Ingress and other resources created in the cluster.
    64  * *NGINX master process*, which controls NGINX worker processes.
    65  * *NGINX worker processes*, which handle the client traffic and load balance the traffic to the backend applications.
    66  
    67  The following is an architectural diagram that shows how those processes interact together and with some external processes/entities:
    68  
    69  ![IC pod](how-nginx-ingress-controller-works-images/ic-pod.png)
    70  
    71  For brevity, we've omitted the suffix process from the description of the processes.
    72  
    73  <!-- TO-DO: after the docs are converted to Hugo, convert this list to a markdown table>
    74  The table below describes each connection:
    75  | Connection # | Type | Description |
    76  | --- | --- | --- |
    77  -->
    78  
    79  The numbered list that follows describes each connection with its type in curly brackets:
    80  
    81  1. (HTTP) *Prometheus* fetches the IC and NGINX metrics via an HTTP endpoint that the *IC* exposes. The default is ``:9113/metrics``. **Note**: *Prometheus* is not required by the IC, the endpoint can be turned off.
    82  2. (HTTPS) The *IC* reads the *Kubernetes API* to get the latest versions of the resources in the cluster and writes to the API to update the handled resources' statuses and emit events.
    83  3. (HTTP) *Kubelet* probes the *IC* readiness probe (the default is `:8081/nginx-ready`) to consider the IC pod [ready](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-conditions).
    84  4. (File I/O) When the *IC* starts, it reads the *configuration templates* necessary for config generation from the filesystem. The templates are located in the `/` directory of the container and have the `.tmpl` extension.
    85  5. (File I/O) The *IC* writes logs to its *stdout* and *stderr*, which are collected by the container runtime.
    86  6. (File I/O) The *IC* generates NGINX *configuration* based on the resources created in the cluster (refer to [The Ingress Controller is a Kubernetes Controller](#the-ingress-controller-is-a-kubernetes-controller) section for the list of resources) and writes it on the filesystem in the `/etc/nginx` folder. The configuration files have a `.conf` extension.
    87  7. (File I/O) The *IC* writes *TLS certificates* and *keys* from any [TLS Secrets](https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets) referenced in the Ingress and other resources to the filesystem.
    88  8. (HTTP) The *IC* fetches the [NGINX metrics](https://nginx.org/en/docs/http/ngx_http_stub_status_module.html#stub_status) via the `unix:/var/lib/nginx/nginx-status.sock` UNIX socket and converts it to Prometheus format used in #1.
    89  9. (HTTP) To consider a configuration reload a success, the *IC* ensures that at least one *NGINX worker* has the new configuration. To do that, the *IC* checks a particular endpoint via the `unix:/var/lib/nginx/nginx-config-version.sock` UNIX socket.
    90  10. (N/A) To start NGINX, the *IC* runs the `nginx` command, which launches the *NGINX master*.
    91  11. (Signal) To reload NGINX, the *IC* runs the `nginx -s reload` command, which validates the configuration and sends the [reload signal](https://nginx.org/en/docs/control.html) to the *NGINX master*.
    92  12. (Signal) To shutdown NGINX, the *IC* executes `nginx -s quit` command, which sends the graceful shutdown signal to the *NGINX master*.
    93  13. (File I/O) The *NGINX master* sends logs to its *stdout* and *stderr*, which are collected by the container runtime.
    94  14. (File I/O) The *NGINX master* reads the *TLS cert and keys* referenced in the configuration when it starts or reloads.
    95  15. (File I/O) The *NGINX master* reads *configuration files* when it starts or during a reload.
    96  16. (Signal) The *NGINX master* controls the [lifecycle of *NGINX workers*](https://nginx.org/en/docs/control.html#reconfiguration) it creates workers with the new configuration and shutdowns workers with the old configuration.
    97  17. (File I/O) An *NGINX worker* writes logs to its *stdout* and *stderr*, which are collected by the container runtime.
    98  18. (UDP) An *NGINX worker* sends the HTTP upstream server response latency logs via the Syslog protocol over the UNIX socket `/var/lib/nginx/nginx-syslog.sock` to the *IC*. In turn, the *IC* analyzes and transforms the logs into Prometheus metrics.
    99  19. (HTTP,HTTPS,TCP,UDP) A *client* sends traffic to and receives traffic from any of the *NGINX workers* on ports 80 and 443 and any additional ports exposed by the [GlobalConfiguration resource](/nginx-ingress-controller/configuration/global-configuration/globalconfiguration-resource).
   100  20. (HTTP,HTTPS,TCP,UDP) An *NGINX worker* sends traffic to and receives traffic from the *backends*.
   101  21. (HTTP) *Admin* can connect to the [NGINX stub_status](http://nginx.org/en/docs/http/ngx_http_stub_status_module.html#stub_status) using port 8080 via an *NGINX worker*. **Note**: By default, NGINX only allows connections from `127.0.0.1`.
   102  
   103  ### Differences for NGINX Plus
   104  
   105  The preceding diagram depicts the IC with NGINX. The IC also supports NGINX Plus with the following important differences:
   106  
   107  * To configure NGINX Plus, in addition to configuration reloads, the IC uses the [NGINX Plus API](http://nginx.org/en/docs/http/ngx_http_api_module.html#api), which allows the IC to dynamically change the upstream servers of an upstream.
   108  * Instead of the stub status metrics, the extended metrics are used, which are available via NGINX Plus API.
   109  * In addition to TLS certs and keys, the IC writes JWKs from the secrets of the type `nginx.org/jwk`, and NGINX workers read them.
   110  
   111  ## The Ingress Controller Process
   112  
   113  This section covers the architecture of the IC process, including:
   114  
   115  * How the IC processes a new Ingress resource created by a user.
   116  * The summary of how the IC works and how it relates to Kubernetes Controllers.  
   117  * The different components of the IC process.
   118  
   119  ### Processing a New Ingress Resource
   120  
   121  The following diagram depicts how the IC processes a new Ingress resource. We represent the NGINX master and worker processes as a single rectangle *NGINX* for simplicity. Also, note that VirtualServer and VirtualServerRoute resources are processed similarly.
   122  
   123  ![IC process](how-nginx-ingress-controller-works-images/ic-process.png)
   124  
   125  Processing a new Ingress resource involves the following steps, where each step corresponds to the arrow on the diagram with the same number:
   126  
   127  1. *User* creates a new Ingress resource.
   128  2. The IC process has a *Cache* of the resources in the cluster. The *Cache* includes only the resources the IC is interested in, such as Ingresses. The *Cache* stays in sync with the Kubernetes API by [watching for changes to the resources](https://kubernetes.io/docs/reference/using-api/api-concepts/#efficient-detection-of-changes).
   129  3. Once the *Cache* has the new Ingress resource, it notifies the *Control loop* about the changed resource.
   130  4. The *Control loop* gets the latest version of the Ingress resource from the *Cache*. Because the Ingress resource references other resources, such as TLS Secrets, the *Control loop* gets the latest versions of any referenced resources as well.
   131  5. The *Control loop* generates TLS certificates and keys from the TLS Secrets and writes them to the filesystem.
   132  6. The *Control loop* generates and writes the NGINX *configuration files*, which correspond to the Ingress resource, and writes them to the filesystem.
   133  7. The *Control loop* reloads *NGINX* and waits for *NGINX* to successfully reload. As part of the reload:
   134      1. *NGINX* reads the *TLS certs and keys*.
   135      1. *NGINX* reads the *configuration files*.
   136  8. The *Control loop* emits an event for the Ingress resource and updates its status. If the reload fails, the event includes the error message.
   137  
   138  ### The Ingress Controller is a Kubernetes Controller
   139  
   140  Based on the example from the previous section, we can generalize how the IC works:
   141  
   142  *The IC constantly processes both new resources and changes to the existing resources in the cluster. As a result, the NGINX configuration stays up-to-date with the resources in the cluster.*
   143  
   144  The IC is an example of a [Kubernetes controller](https://kubernetes.io/docs/concepts/architecture/controller/): the IC runs a control loop that ensures NGINX is configured according to the desired state (Ingresses and other resources).
   145  
   146  The desired state is concentrated in the following built-in Kubernetes resources and Custom Resources (CRs):
   147  
   148  * Layer 7 Load balancing configuration:
   149    * Ingresses
   150    * VirtualServers (CR)
   151    * VirtualServerRoutes (CR)
   152  * Layer 7 policies:
   153    * Policies (CR)
   154  * Layer 4 load balancing configuration:
   155    * TransportServers (CR)
   156  * Service discovery:
   157    * Services
   158    * Endpoints
   159    * Pods
   160  * Secret configuration:
   161    * Secrets
   162  * Global Configuration:
   163    * ConfigMap (only one resource)
   164    * GlobalConfiguration (CR, only one resource)
   165  
   166  The IC can watch additional Custom Resources, which are less common and not enabled by default:
   167  
   168  * [NGINX App Protect resources](/nginx-ingress-controller/app-protect/configuration/) (APPolicies, APLogConfs, APUserSigs)
   169  * IngressLink resource (only one resource)
   170  
   171  In the next section, we examine the different components of the IC process.
   172  
   173  ## Ingress Controller Process Components
   174  
   175  In this section, we describe the components of the IC process and how they interact, including:
   176  
   177  1. How the IC watches for resources changes.
   178  1. The main components of the IC control loop.
   179  1. How those components process a resource change.
   180  1. A few additional components, which are crucial for processing changes.
   181  
   182  The IC is written in [go](https://golang.org/) and relies heavily on the [Go client for Kubernetes](https://github.com/kubernetes/client-go). In the sections next, we include links to the code on GitHub when necessary.
   183  
   184  ### Resource Caches
   185  
   186  In the section [Processing a New Ingress Resource](#processing-a-new-ingress-resource), we mentioned that the IC has a cache of the resources in the cluster that stays in sync with the Kubernetes API by watching for changes to the resources. We also mentioned that once cache is updated, it notifies the control loop about the changed resource.
   187  
   188  The cache is actually a collection of *informers*. The following diagram shows how changes to resources are processed by the IC.
   189  
   190  ![IC process components](how-nginx-ingress-controller-works-images/ic-process-components.png)
   191  
   192  * For every resource type the IC monitors, it creates an [*Informer*](https://pkg.go.dev/k8s.io/client-go@v0.21.0/tools/cache#SharedInformer). The *Informer* includes a *Store* that holds the resources of that type. To keep the *Store* in sync with the latest versions of the resources in the cluster, the *Informer* calls the Watch and List *Kubernetes APIs* for that resource type (see the arrow *1. Watch and List* on the diagram).
   193  * When a change happens in the cluster (for example, a new resource is created), the *Informer* updates its *Store* and invokes [*Handlers*](https://pkg.go.dev/k8s.io/client-go@v0.21.0/tools/cache#ResourceEventHandler) (see the arrow *2. Invoke*) for that *Informer*.
   194  * The IC registers handlers for every *Informer*. Most of the time, a *Handler* creates an entry for the affected resource in the *Workqueue* where a workqueue element includes the type of the resource and its namespace and name. (See the arrow *3. Put*.)
   195  * The *Workqueue* always tries to drain itself: if there is an element at the front, the queue will remove the element and send it to the *Controller* by calling a callback function. (See the arrow *4. Send*.)
   196  * The *Controller* is the primary component in the IC, which represents the control loop. We explain the components in [The Control Loop](#the-control-loop) section. For now, it suffices to know that to process a workqueue element, the *Controller* component gets the latest version of the resource from the *Store* (see the arrow *5. Get*), reconfigures *NGINX* according to the resource (see the arrow *6. Reconfigure*), updates the resource status, and emits an event via the *Kubernetes API* (see the arrow  *7. Update status and emit event*).
   197  
   198  ### The Control Loop
   199  
   200  This section discusses the main components of the IC, which comprise the control loop:
   201  
   202  * [Controller](https://github.com/nginxinc/kubernetes-ingress/blob/v1.11.0/internal/k8s/controller.go#L90)
   203    * Runs the IC control loop.
   204    * Instantiates *Informers*, *Handlers*, the *Workqueue* and additional helper components.
   205    * Includes the sync method (see the next section), which is called by the *Workqueue* to process a changed resource.
   206    * Passes changed resources to *Configurator* to re-configure NGINX.
   207  * [Configurator](https://github.com/nginxinc/kubernetes-ingress/blob/v1.11.0/internal/configs/configurator.go#L95)
   208    * Generates NGINX configuration files, TLS and cert keys, and JWKs based on the Kubernetes resource.
   209    * Uses *Manager* to write the generated files and reload NGINX.
   210  * [Manager](https://github.com/nginxinc/kubernetes-ingress/blob/v1.11.0/internal/nginx/manager.go#L52)
   211    * Controls the lifecycle of NGINX (starting, reloading, quitting).
   212    * Manages the configuration files, TLS keys and certs, and JWKs.
   213  
   214  The following diagram shows how the three components interact:
   215  
   216  ![Control loop](how-nginx-ingress-controller-works-images/control-loop.png)
   217  
   218  #### The Controller Sync Method
   219  
   220  The Controller [sync](https://github.com/nginxinc/kubernetes-ingress/blob/v1.11.0/internal/k8s/controller.go#L663) method is called by the *Workqueue* to process a change of a resource. The method determines the *kind* of the resource and calls the appropriate *sync* method (for example, *syncIngress* for Ingresses).
   221  
   222  Rather than show how all the various sync methods work, we focus on the most important one -- the *syncIngress* method -- and look at how it processes a new Ingress resource, illustrated in the diagram below.
   223  
   224  ![Controller sync](how-nginx-ingress-controller-works-images/controller-sync.png)
   225  
   226  1. The *Workqueue* calls the *sync* method and passes a workqueue element to it that includes the changed resource *kind* and *key* (the key is the resource namespace/name like “default/cafe-ingress”).
   227  2. Using the *kind*, the *sync* method calls the appropriate sync method and passes the resource key. For Ingresses, that method is *syncIngress*.
   228  3. *syncIngress* gets the Ingress resource from the *Ingress Store* using the key. The *Store* is controlled by the *Ingress Informer*, as mentioned in the section [Resource Caches](#resource-caches). **Note**: In the code, we use the helper *storeToIngressLister* type that wraps the *Store*.
   229  4. *syncIngress* calls *AddOrUpdateIngress* of the *Configuration*, passing the Ingress along. The [Configuration](https://github.com/nginxinc/kubernetes-ingress/blob/v1.11.0/internal/k8s/configuration.go#L320) is a component that represents a valid collection of load balancing configuration resources (Ingresses, VirtualServers, VirtualServerRoutes, TransportServers), ready to be converted to the NGINX configuration (see the [Configuration section](#configuration) for more details). *AddOrUpdateIngress* returns a list of [ResourceChanges](https://github.com/nginxinc/kubernetes-ingress/blob/v1.11.0/internal/k8s/configuration.go#L59), which must be reflected in the NGINX config. Typically, for a new Ingress resource, the *Configuration* returns only a single *ResourceChange*.
   230  5. *syncIngress* calls *processChanges*, which processes the single Ingress *ResourceChange*.
   231      1. *processChanges* creates an extended Ingress resource (*IngressEx*) that includes the original Ingress resource and its dependencies, such as Endpoints and Secrets, to generate the NGINX configuration. For simplicity, we don’t show this step on the diagram.
   232      2. *processChanges* calls *AddOrUpdateIngress* of the *Configurator* and passes the extended Ingress resource.
   233  6. *Configurator* generates an NGINX configuration file based on the extended Ingress resource and then:
   234      1. Calls *Manager’s CreateConfig()* to  update the config for the Ingress resource.
   235      2. Calls *Manager’s Reload()* to reload NGINX.
   236  7. The reload status is propagated from *Manager* to *processChanges*. The status is either a success or a failure with an error message.
   237  8. *processChanges* calls *updateRegularIngressStatusAndEvent* to update the status of the Ingress resource and emit an event with the status of the reload. Both involve making an API call to the Kubernetes API.
   238  
   239  Notes:
   240  
   241  * Some details weren't discussed for simplicity. You can view the source code if you want a fuller picture.
   242  * The *syncVirtualServer*, *syncVirtualServerRoute*, and *syncTransportServer* methods are similar to syncIngress. The other sync methods are different. However, those methods typically involve finding the affected Ingress, VirtualServer, and TransportServer resources and regenerating a configuration for them.
   243  * The *Workqueue* has only a single worker thread that calls the sync method synchronously. This means that the control loop processes only one change at a time.
   244  
   245  #### Helper Components
   246  
   247  There are two additional helper components crucial for processing changes: *Configuration* and *LocalSecretStore*.
   248  
   249  ##### Configuration
   250  
   251  [*Configuration*](https://github.com/nginxinc/kubernetes-ingress/blob/v1.11.0/internal/k8s/configuration.go#L320) holds the latest valid state of the IC load balancing configuration resources: Ingresses, VirtualServers, VirtualServerRoutes, TransportServers, and GlobalConfiguration.
   252  
   253  The *Configuration* supports add (for add/update) and delete operations on the resources. When you add/update/delete a resource in the Configuration, it performs the following:
   254  
   255  1. Validates the object (for add/update)
   256  2. Calculates the changes to the affected resources that are necessary to propagate to the NGINX config, returning the changes to the caller.
   257  
   258  For example, when you add a new Ingress resource, the *Configuration* returns a change requiring the IC to add the configuration for that Ingress to the NGINX config files. Another example: if you make an existing Ingress resource invalid, the *Configuration* returns a change requiring the IC to remove the configuration for that Ingress from the NGINX config files.
   259  
   260  Additionally, the *Configuration* ensures that only one Ingress/VirtualServer/TransportServer (TLS Passthrough) holds a particular host (for example, cafe.example.com) and only one TransportServer (TCP/UDP) holds a particular listener (for example, port 53 for UDP). This ensures that no host or listener collisions happen in the NGINX config.
   261  
   262  Ultimately, the IC ensures the NGINX config on the filesystem reflects the state of the objects in the *Configuration* at any point in time.
   263  
   264  ##### LocalSecretStore
   265  
   266  [*LocalSecretStore*](https://github.com/nginxinc/kubernetes-ingress/blob/v1.11.0/internal/k8s/secrets/store.go#L32) (of the *SecretStore* interface) holds the valid Secret resources and keeps the corresponding files on the filesystem in sync with them. Secrets are used to hold TLS certificates and keys (type `kubernetes.io/tls`), CAs (`nginx.org/ca`), JWKs (`nginx.org/jwk`), and client secrets for an OIDC provider (`nginx.org/oidc`).
   267  
   268  When *Controller* processes a change to a configuration resource like Ingress, it creates an extended version of a resource that includes the dependencies -- such as Secrets -- necessary to generate the NGINX configuration. *LocalSecretStore* allows *Controller* to get a reference on the filesystem for a secret by the secret key (namespace/name).