forked from cloudfoundry/docs-cloudfoundry-concepts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
http-routing.html.md.erb
203 lines (130 loc) · 13.6 KB
/
http-routing.html.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
---
title: HTTP Routing
owner: Routing
---
<strong><%= modified_date %></strong>
This topic describes how the Gorouter, the main component in Cloud Foundry's [routing](./architecture/#routing) tier, routes HTTP traffic within Cloud Foundry (CF).
## <a id="http-headers"></a>HTTP Headers ##
HTTP traffic passed from the Gorouter to an app includes the following HTTP headers:
* `X-Forwarded-Proto` gives the scheme of the HTTP request from the client. The scheme is HTTP if the client made an insecure request or HTTPS if the client made a secure request. Developers can configure their apps to reject insecure requests by inspecting the HTTP headers of incoming traffic and rejecting traffic that includes `X-Forwarded-Proto` with the scheme of HTTP.
* `X-Forwarded-For` gives the IP address of the client originating the request.
If your load balancer terminates TLS upstream from the Gorouter, it must append these headers to requests forwarded to the Gorouter. <%= vars.http_routing %>
### <a id="zipkin-headers"></a> Zipkin Tracing in HTTP Headers
Zipkin is a tracing system that enables app developers to troubleshoot failures or latency issues. Zipkin provides the ability to trace requests and responses across distributed systems. See [Zipkin.io](http://zipkin.io/) for more information.
<%= vars.zipkin_enable_link %>
* If the `X-B3-TraceId` and `X-B3-SpanId` HTTP headers are not present in the request, the Gorouter generates values for these and inserts the headers into the request forwarded to an application. These values are also found in the Gorouter access log message for the request: `x_b3_traceid` and `x_b3_spanid`.
* If both `X-B3-TraceId` and `X-B3-SpanId` HTTP headers are present in the request, the Gorouter forwards the same value for `X-B3-TraceId`, generates a new value for `X-B3-SpanId`, and adds the `X-B3-ParentSpan` header, and sets to the value of the span id in the request. In addition to these trace and span ids, the Gorouter access log message for the request includes `x_b3_parentspanid`.
Developers can then add Zipkin trace IDs to their application logging in order to trace app requests and responses in Cloud Foundry.
After adding Zipkin HTTP headers to app logs, developers can use `cf logs myapp` to correlate the trace and span ids logged by the Gorouter with the trace ids logged by their app. To correlate trace IDs for a request through multiple apps, each app must forward appropriate values for the headers with requests to other applications.
### <a id="app-instance-routing"></a> App Instance Routing in HTTP Headers
Developers who want to obtain debug data for a specific instance of an app can use the HTTP header `X-CF-APP-INSTANCE` to make a request to an app instance.
Perform the following steps to make an HTTP request to a specific app instance:
1. Obtain the GUID of your app:
<pre class="terminal">$ cf app YOUR-APP --guid</pre>
1. List your app instances and retrieve the index number of the instance you want to debug:
<pre class="terminal">$ cf app YOUR-APP</pre>
1. Make a request to the app route using the HTTP header `X-CF-APP-INSTANCE` set to the concatenated values of the app GUID and the instance index:
<pre class="terminal">$ curl app.example.com -H "X-CF-APP-INSTANCE":"YOUR-APP-GUID:YOUR-INSTANCE-INDEX"</pre>
### <a id="forward-client-cert"></a> Forward Client Certificate to Applications
Applications that require mutual TLS (mTLS) need metadata from client certificates to authorize requests. Cloud Foundry supports this use case without bypassing layer-7 load balancers and the Gorouter.
The HTTP header `X-Forwarded-Client-Cert` (XFCC) may be used to pass the originating client certificate along the data path to the application. Each component in the data path must trust that the downstream component has not allowed the header to be tampered with.
If you configure the load balancer to terminate TLS and set the XFCC header from the received client certificate, then you must also configure the load balancer to strip this header if it is present in client requests. This configuration is required to prevent spoofing of the client certificate.
The following sections describe supported deployment configurations.
<% if vars.product_name == 'CF' %>
<%= partial 'oss_xfcc_loadbalancer' %>
<% else %>
<%= partial '../console/xfcc_loadbalancer' %>
<% end %>
<% if vars.product_name == 'CF' %>
<% else %>
<%= partial '../console/xfcc_haproxy' %>
<% end %>
<% if vars.product_name == 'CF' %>
<%= partial 'oss_xfcc_router' %>
<% else %>
<%= partial '../console/xfcc_router' %>
<% end %>
## <a id="tls"></a>SSL/TLS Termination
Depending on your needs, you can configure your deployment to terminate SSL/TLS at the Gorouter, at the Gorouter and the load balancer, or at the load balancer only. <%= vars.http_routing %>
## <a id="apps"></a>Routing to App Instances
As CF manages and balances apps, routes to app instances change. To keep the Gorouter's routing tables current, a route emitter on each Diego cell updates NATS with new app instance locations.
Upstream, the Gorouter subscribes to the NATS updates to keep its route information current. But network partitions can cause the Gorouter's routing tables to fall out of sync.
You can configure the Gorouter to direct traffic to app instances in two modes, with or without TLS enabled to containers:
<table border="1" id="gorouter-modes" class="nice">
<tr><th>Gorouter mode:</th>
<th>How Gorouter sends traffic to Diego cells:</th>
<th>How Gorouter updates its routing table:</th>
</tr><tr>
<td><a href="#with-tls"><strong>With TLS Enabled</strong></a></td>
<td>Secured, over TLS</td>
<td>Prunes routes with instance identity mismatch; see <a href="#when-tls-prune">Gorouter TLS pruning behavior</a></td>
</tr><tr>
<td><a href="#without-tls"><strong>Without TLS Enabled</strong></a></td>
<td>Unsecured</td>
<td>Prunes routes that do not update for time-to-live (TTL), which defaults to 120 seconds.</td>
</tr>
</table>
The first mode is newer and improves route availability and security. Both modes are described below.
### <a id="with-tls"></a>With TLS Enabled
In this mode, each app instance has its own GUID and identity credentials for TLS verification. The Gorouter's routing table includes a GUID for each app instance, along with its address and port.
Before routing traffic to an app instance, the Gorouter checks whether the instance is still running at the address and port in its routing table. It initiates a TLS handshake with an [Envoy](https://www.envoyproxy.io/) proxy that runs in each app container and listens on port 8443.
If the Envoy proxy confirms the correct GUID identity of the app instance, Gorouter sends the traffic to port 8080 of the container. If the instance identities do not match, the Gorouter temporarily stops traffic to the container by pruning it from the routing table, and re-tries with another instance of the app.
The following table explains how the Gorouter uses app instance validation to keep its routing table current:
<table border="1" id="when-tls-prune" class="nice">
<tr><th>Gorouter pruning behavior with TLS enabled</th>
<th>TLS handshake succeeds and app instance matches routing table</th>
<th>TLS handshake fails; app instance mismatch</th>
</tr><tr>
<th>Time to Live (TTL) has expired</th>
<td>Do not prune the route</td>
<td>Prune the route and re-try with another instance of the app</td>
</tr><tr>
<th>TTL has not expired</th>
<td>Do not prune the route</td>
<td>Do not prune the route, but mark container ineligible for requests for next 30 seconds and re-try with another instance of the app</td>
</tr>
</table>
#### <a id="app-valid-tls-config"></a>Configure App Instance Validation with TLS
<% if vars.product_name == 'CF' %>
<%= partial 'router_app_tls_oss' %>
<% else %>
<%= partial '../console/router_app_tls_pcf' %>
<% end %>
### <a id="without-tls"></a>Without TLS Enabled
In this mode, the Gorouter's routing table lists a name, address, and port for each app instance, but it does not include GUIDs for the app instances.
Route Emitters on each cell issue a "heartbeat" to NATS by sending the cell's route information every 20 seconds. Upstream, the Gorouter subscribes to NATS to receive route updates. If the Gorouter does not receive an app instance route for the time-to-live (TTL) interval, which defaults to 120 seconds, it prunes the route from its table.
This pruning method was developed before app instances had identity credentials.
<% if vars.product_name.include? "CF" %>
### <a id="multiple"></a>Gorouter Behavior with Multiple Runtimes
The Gorouter can [validate app instances over TLS](#with-tls) only with Diego cells that support [app instance identity credentials](../security/networking/tls-info.html#container-creds) and TLS.
If cells do not support TLS validation and routing, the Gorouter falls back to its [without TLS mode](#without-tls) of pruning routes based on TTL and sending unsecured traffic to the cells.
PCF operators can configure Linux cells, but not Windows cells, to support TLS validation and routing. With Windows apps, the Gorouter sends unsecured traffic and prunes stale routes.
Diego cells are configured through the runtime or isolation segment that they run in, so Gorouter behavior can differ for cells in different runtimes. For example, the Gorouter can use TLS to validate app instances within a PAS deployment, but send unsecured traffic and prune stale routes to apps running in an [Isolation Segment](../adminguide/isolation-segments.html) or on Windows cells.
<% end %>
## <a id="transparent"></a>Transparent Retries
If the Gorouter cannot establish a TCP connection with a selected application instance, the Gorouter considers the instance ineligible for requests for 30 seconds, and the Gorouter transparently attempts to connect to another application instance. Once the Gorouter has established a TCP connection with an application instance, the Gorouter forwards the HTTP request.
See the <a href="#round-robin">Round-Robin Load Balancing</a> section below for more information about how the Gorouter forwards requests to application instances.
## <a id="round-robin"></a>Round-Robin Load Balancing
The Gorouter uses the round-robin algorithm for load balancing incoming requests to application instances. The Gorouter maintains a dynamically updated list of application instances for each route, and forwards each request for a given route to the next application instance in the list.
## <a id="sockets"></a>WebSockets
WebSockets is a protocol providing bi-directional communication over a single, long-lived TCP connection, commonly implemented by web clients and servers. WebSockets are initiated through HTTP as an upgrade request. The Gorouter supports this upgrade handshake, and will hold the TCP connection open with the selected application instance. <%= vars.port_limitations_1 %>
## <a id="sessions"></a>Session Affinity
The Gorouter supports session affinity, or _sticky sessions_, for incoming HTTP requests to compatible apps.
With sticky sessions, when multiple instances of an app are running on CF, requests from a particular client always reach the same app instance. This allows apps to store session data specific to a user session.
* To support sticky sessions, configure your app to return a `JSESSIONID` cookie in responses. The app generates a `JSESSIONID` as a long hash in the following format:
<pre class="terminal">
1A530637289A03B07199A44E8D531427
</pre>
* If an app returns a `JSESSIONID` cookie to a client request, the CF routing tier generates a unique `VCAP_ID` for the app instance based on its GUID in the following format:
<pre class="terminal">
323f211e-fea3-4161-9bd1-615392327913
</pre>
* On subsequent requests, the client must provide both the `JSESSIONID` and `VCAP_ID` cookies.
The CF routing tier uses the `VCAP_ID` cookie to forward client requests to the same app instance every time. The `JSESSIONID` cookie is forwarded to the app instance to enable session continuity. If the app instance identified by the `VCAP_ID` crashes, the Gorouter attempts to route the request to a different instance of the app. If the Gorouter finds a healthy instance of the app, it initiates a new sticky session.
<p class="note"><strong>Note</strong>: CF does not persist or replicate HTTP session data across app instances. If an app instance crashes or is stopped, session data for that instance is lost. If you require session data to persist across crashed or stopped instances, or to be shared by all instances of an app, store session data in a CF marketplace service that offers data persistence.</p>
## <a id="keepalive"></a>Keepalive Connections
### From Frontend Clients
The Gorouter supports keepalive connections from clients; it will not close the TCP connection with clients immediately after returning an HTTP response. It is up to clients to close these connections.
### To Backend Servers
By default, the Gorouter closes the TCP connection with an app instance or system component after receiving an HTTP response.
When Keepalive Connections is enabled Gorouter will maintain established TCP connections to backends, with a configurable maximum that limits the number of total idle connections from each Gorouter. The Gorouter will reuse idle connections for routing of subsequent requests if one exists for the selected backend, lowering latency and increasing throughput. If no idle connection exists, a new connection will be established, and if the Gorouter limit has not been reached that connection will be maintained. The number of idle connections from each Gorouter to an individual backend is limited to 100. <% if vars.product_name == 'CF' || vars.product_name == 'PCF' %> <%= vars.keepalive %> <% else %> <% end %>