Skip to content

Commit

Permalink
update to our cross-namespace routing guide
Browse files Browse the repository at this point in the history
  • Loading branch information
mark-church committed Jul 27, 2021
1 parent 0b10955 commit e16a549
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 35 deletions.
19 changes: 19 additions & 0 deletions examples/cross-namespace-routing/gateway.yaml
@@ -0,0 +1,19 @@
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: shared-gateway
namespace: infra
spec:
gatewayClassName: acme-lb
listeners:
- hostname:
- foo.example.com
protocol: HTTPS
port: 443
routes:
kind: HTTPRoute
namespaces:
from: "All"
tls:
certificateRef:
name: foo-example-com
38 changes: 38 additions & 0 deletions examples/cross-namespace-routing/site-route.yaml
@@ -0,0 +1,38 @@
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: home
namespace: site
spec:
gateways:
allow: FromList
gatewayRefs:
- name: shared-gateway
namespace: infra
rules:
- forwardTo:
- serviceName: home
port: 8080
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: login
namespace: site
spec:
gateways:
allow: FromList
gatewayRefs:
- name: shared-gateway
namespace: infra
rules:
- matches:
- path:
value: /login
forwardTo:
- serviceName: login-v1
port: 8080
weight: 90
- serviceName: login-v2
port: 8080
weight: 10
18 changes: 18 additions & 0 deletions examples/cross-namespace-routing/store-route.yaml
@@ -0,0 +1,18 @@
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: store
namespace: store
spec:
gateways:
allow: FromList
gatewayRefs:
- name: shared-gateway
namespace: infra
rules:
- matches:
- path:
value: /store
forwardTo:
- serviceName: store
port: 8080
2 changes: 1 addition & 1 deletion mkdocs.yml
Expand Up @@ -26,7 +26,7 @@ nav:
- Simple Gateway: guides/simple-gateway.md
- HTTP routing: guides/http-routing.md
- HTTP traffic splitting: guides/traffic-splitting.md
- Multiple namespaces and routes: guides/multiple-ns.md
- Cross-Namespace routing: guides/multiple-ns.md
- TLS: guides/tls.md
- TCP routing: guides/tcp.md
- References:
Expand Down
188 changes: 154 additions & 34 deletions site-src/guides/multiple-ns.md
@@ -1,38 +1,158 @@
# Routes in multiple namespaces

With the Gateway API, a single Gateway can target routes across multiple
namespaces.

This guide assumes that you have installed Gateway API CRDs and a conformant
controller.

In the following example:

- `acme-lb` GatewayClass: The GatewayClass responsible for satisfying Gateway
and Route resources.
- `multi-ns-gateaway` Gateway: The Gateway is configured with a single listener
on port 80 which selects routes that have the label `product: baz` in any
namespace. Notice how the `routes.namespaces.from` field in the listener is
set to `All`.
- `gateway-api-example-ns1` and `gateway-api-example-ns2` Namespaces: These
are the namespaces in which route resources are instantiated.
- `http-app-1` and `http-app-2` HTTPRoutes: These are two resources that are
installed in separate namespaces. These routes will be bound to Gateway
`multi-ns-gateway` for the following reasons:
- Both have the `product: baz` label on them.
- `http-app-1` HTTPRoute has `spec.gateways.allow` set to `All`. The route
owner has opted to allow **all** Gateways in the cluster to bind to this
Route.
- `http-app-2` HTTPRoute has `spec.gateways.allow` set to `FromList` and
contains a reference to the `multi-ns-gateway` in `default` namespace.
This means that only the specified Gateway resource can bind to this
route. Additional Gateways may be added to this list to allow them to
bind to this route.
# Cross-Namespace routing

The Gateway API has core support for cross Namespace routing. This is useful
when more than one user or team is sharing underlying networking infrastructure,
yet control and configuration must be segmented to minimize security and fault
domains. Gateways and Routes can be deployed into different Namespaces and bind
with each other across Namespace boundaries. This allows differing user access
and roles (RBAC) to be applied to separate Namespaces, effectively controlling
who has access to different parts of the cluster-wide routing configuration. The
ability for Routes to bind with Gateways across Namespace boundaries is goverend
by [_Route binding_](/guides/multiple-ns#cross-namespace-route-binding), which
is explored in this guide. The guide shows how two independent teams can safely
share the same Gateway from different Namespaces.

In this guide there are two independent teams, _store_ and _site_, operating
in the same Kubernetes cluster in the `store` and `site` Namespaces. These are
their requirements:

- The site team has two applications, _home_ and _login_, that are running
behind `foo.example.com`. They want to isolate access and configuration across
their apps as much as possible to minimize security and failure domains.
They use separate HTTPRoutes for each app, to isolate app routing configurations
such as canary rollouts. but share the same load balancer
IP, port, domain, and TLS certificate.
- The store team has a single Service called _store_ that they have deployed
in the `store` Namespace.
- The Foobar Corporation operates behind the `foo.example.com` domain so they
would like to host all applications on the same Gateway resource. This is
controlled by a central infrastructure team, operating in the `infra` Namespace.
- Lastly, the security team controls the certificate for `foo.example.com`.
By managing this certificate through the single shared Gateway they are able
to centrally control security without directly involving application teams.

The logical relationship between the Gateway API resources looks like this:

![Cross-Namespace routing](/images/cross-namespace-routing.svg)

## Cross-namespace Route binding

[Route binding](/concepts/api-overview/#route-binding) is an important concept
that dictates how Routes and Gateways select each other to apply routing
configuration to a Gateway. It is especially relevant when there are multiple
Gateways and multiple Namespaces in a cluster. Gateway and Route binding is
bidirectional - a binding can only exist if the Gateway owner and Route owner
owner both agree to the relationship. This bi-directional relationship exists
for two reasons:

- Route owners don't want to overexpose their applications and don't want
their apps to be accessible through paths they are not aware of.
- Gateway owners don't want apps using certain Gateways they should not be
using. An internal application shouldn't be exposed through a public Gateway
for example.


As a result, Gateways and Routes have independent control to determine which
resources they permit binding with. It is a handshake between the infra owners
and the application owners that allows them to be independent actors.
Route-owners can specify that they will bind with all Gateways in the cluster,
or only Gateways from a specific Namespace, with a specific label selector, or
an individual Gateway. Similarly, Gateways provide the same level of control.
This allows a cluster to be more self-governed, which requires less central
administration to ensure that Routes are not over-exposed.

## Resource Deployment

The infrastructure team deploys the `shared-gateway` Gateway into the `infra`
Namespace.

```yaml
{% include 'cross-namespace-routing/gateway.yaml' %}
```

A few notes about this Gateway:

- It is matching for the `foo.example.com` domain. This is configured on the
Gateway so that each HTTPRoute does not also have to configure hostname matching,
since they are all using the same domain. This also allows these HTTPRoute
manifests to be reused across production and dev environments where the dev
environment might be hosted at `foo.dev.corp.example.com`.
- The Gateway is configured for HTTPS and references the `foo-example-com` Secret.
This allows the certificate to be managed centrally for all applications which
are using this Gateway.
- It allows any Route in the cluster to use this Gateway because `namespaces.from = All`.
This is a permissive method of Route selection since the Routes are given
full control to select this Gateway. There are more restrictive forms of Route
selection that allow selection on a per-Namespace basis, detailed
in [Route binding](/concepts/api-overview/#route-binding). The following block
specifies how this Gateway allows HTTPRoutes from all Namespaces in the
cluster to bind to it:

```yaml
routes:
kind: HTTPRoute
namespaces:
from: "All"
```

Meanwhile, the store team deploys their route for the `store` Service in the
`store` Namespace:

```yaml
{% include 'cross-namespace-routing/store-route.yaml' %}
```

This Route has straightforward routing logic as it just matches for
`/store` traffic which it sends to the `store` Service. The following snippet
of the [`gateways` field](/references/spec/#networking.x-k8s.io/v1alpha1.RouteGateways)
controls which Gateways this Route can bind to:

```yaml
gateways:
allow: FromList
gatewayRefs:
- name: shared-gateway
namespace: infra
```
{% include 'routes-in-multiple-namespaces.yaml' %}

`gateways.allow` can be configured for Gateways in the same Namespace as the
Route (the default), all Gateways, or a list of specific Gateways. In this
example the store and site teams decide to reference a specific Gateway. This is
the least permissive choice which ensures that other Gateways in the cluster
(perhaps created in the future at some point) will not bind with these Routes.
If cluster administrators have full control over how Gateways are deployed in a
cluster then a more permissive binding option could be configured on Routes. The
less permissive the Gateway selection is, the less that application owners need
to know about which Gateways are deployed.

The site team now deploys Routes for their applications. They deploy two
HTTPRoutes into the `site` Namespace:

- The `home` HTTPRoute acts as a default routing rule, matching for all traffic
to `foo.example.com/*` not matched by an existing routing rule and sending it to
the `home` Service.
- The `login` HTTPRoute routes traffic for `foo.example.com/login` to
`service/login-v1` and `service/login-v2`. It uses weights to granularly
control traffic distribution between them.

Both of these Routes use the same Gateway binding configuration which specifies
`gateway/shared-gateway` in the `infra` Namespace as the only Gateway that these
Routes can bind with.

```yaml
{% include 'cross-namespace-routing/site-route.yaml' %}
```

Please note that this guide illustrates this feature for HTTPRoute resource
only as an example. The same can be accomplished with other route types as
well.
After these three Routes are deployed, they will all be bound to the
`shared-gateway` Gateway. The Gateway merges its bound Routes into a single flat
list of routing rules. [Routing
precedence](/references/spec/#networking.x-k8s.io/v1alpha1.HTTPRouteRule)
between the flat list of routing rules is determined by most specific match and
conflicts are handled according to [conflict
resolution](/concepts/guidelines#conflicts). This provides predictable and
deterministic merging of routing rules between independent users.

Thanks to cross-Namespace routing, the Foobar Corporation can distribute
ownership of their infrastructure more evenly, while still retaining centralized
control. This gives them the best of both worlds, all delivered through
declarative and open source APIs.
1 change: 1 addition & 0 deletions site-src/images/cross-namespace-routing.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit e16a549

Please sign in to comment.