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