Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/_data/series.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,6 @@ mcp-acls:
mesh-get-started-universal:
title: Get started with {{site.mesh_product_name}} on Universal
url: /mesh/get-started/universal/install/
operator-multi-tenancy:
title: Deploy multiple isolated gateways on the same cluster
url: /operator/dataplanes/how-to/multi-tenancy/setup/
147 changes: 147 additions & 0 deletions app/_how-tos/operator/operator-multi-tenancy-1-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
---
title: Install {{ site.operator_product_name }} for multi-tenancy
description: "Create tenant namespaces, install {{ site.operator_product_name }} scoped to those namespaces, and apply a KongLicense."
content_type: how_to

permalink: /operator/dataplanes/how-to/multi-tenancy/setup/
series:
id: operator-multi-tenancy
position: 1

breadcrumbs:
- /operator/
- index: operator
group: Gateway Deployment
- index: operator
group: Gateway Deployment
section: "How-To"

products:
- operator

works_on:
- on-prem

min_version:
operator: '2.0'

related_resources:
- text: "Multi-tenancy reference"
url: /operator/reference/multi-tenancy/
- text: "Limiting namespaces watched by ControlPlane"
url: /operator/reference/control-plane-watch-namespaces/

tldr:
q: How do I set up {{ site.operator_product_name }} for multi-tenancy?
a: |
Install {{ site.operator_product_name }} with `env.watch_namespace` scoped to your
tenant namespaces, then apply a single `KongLicense` in `kong-system`.

prereqs:
skip_product: true
inline:
- title: "{{site.ee_product_name}} license"
icon_url: /assets/icons/key.svg
content: |
Save your {{site.ee_product_name}} license as `license.json` in your current working directory. If you don't have a license, contact your Kong representative.
---

This series deploys two independent {{ site.base_gateway }} instances — one public-facing, one private — on the same cluster using a single {{ site.operator_product_name }} installation. Each gateway is scoped to its own namespace so that its in-memory {{ site.kic_product_name_short }} only processes routes from that namespace.

The following diagram shows the end state you'll build across this series:

<!--vale off-->
{% mermaid %}
flowchart TB
subgraph cluster["Kubernetes Cluster"]
subgraph sys["kong-system"]
KO["{{ site.operator_product_name }}\n(KongLicense)"]
end

subgraph pub["kong-gw-public"]
ConfigPub["GatewayConfiguration\nwatchNamespaces: own"]
GWPub["Gateway: gw-public"]
DPPub["Data plane Pod"]
SvcPub["echo service\nHTTPRoute /echo"]
end

subgraph priv["kong-gw-private"]
ConfigPriv["GatewayConfiguration\nwatchNamespaces: own"]
GWPriv["Gateway: gw-private"]
DPPriv["Data plane Pod"]
SvcPriv["echo service\nHTTPRoute /echo"]
end

KO -->|manages| GWPub
KO -->|manages| GWPriv
ConfigPub -.->|configures| GWPub
ConfigPriv -.->|configures| GWPriv
GWPub -->|provisions| DPPub
GWPriv -->|provisions| DPPriv
DPPub -->|routes traffic to| SvcPub
DPPriv -->|routes traffic to| SvcPriv
end
{% endmermaid %}
<!--vale on-->

## Create namespaces

Create the system namespace and the two tenant namespaces:

```bash
kubectl create namespace kong-system
kubectl create namespace kong-gw-public
kubectl create namespace kong-gw-private
```
Comment on lines +91 to +95

## Install {{ site.operator_product_name }}

1. Add the Kong Helm chart repository:

```bash
helm repo add kong https://charts.konghq.com
helm repo update
```
Comment on lines +101 to +104

1. Install {{ site.operator_product_name }} scoped to the two tenant namespaces. The `watch_namespace` value prevents the operator from reconciling resources in any other namespace.

```bash
helm upgrade --install kong-operator kong/kong-operator \
-n kong-system \
--create-namespace \
--set image.tag={{ site.data.operator_latest.release }} \
--values - <<EOF
env:
watch_namespace: kong-gw-public,kong-gw-private
EOF
```

1. Wait for {{ site.operator_product_name }} to be ready:

{% capture validate %}
{% include prereqs/products/operator-validate-deployment.md %}
{% endcapture %}

{{validate | indent}}

## Apply a KongLicense

Apply the license once in `kong-system`. It's shared by all gateways managed by this operator installation.

1. Apply the `KongLicense`:

```bash
echo "
apiVersion: configuration.konghq.com/v1alpha1
kind: KongLicense
metadata:
name: kong-license
rawLicenseString: '$(cat ./license.json)'
" | kubectl -n kong-system apply -f -
```

1. Wait for {{ site.operator_product_name }} to pick up the license:

```bash
kubectl wait --for=condition=Programmed=True konglicense/kong-license --timeout=60s
```
131 changes: 131 additions & 0 deletions app/_how-tos/operator/operator-multi-tenancy-2-public-gateway.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
---
title: Deploy the public gateway
description: "Create a {{ site.base_gateway }} instance scoped to the public tenant namespace."
content_type: how_to

permalink: /operator/dataplanes/how-to/multi-tenancy/public-gateway/
series:
id: operator-multi-tenancy
position: 2

breadcrumbs:
- /operator/
- index: operator
group: Gateway Deployment
- index: operator
group: Gateway Deployment
section: "How-To"

products:
- operator

works_on:
- on-prem

min_version:
operator: '2.0'

related_resources:
- text: "Multi-tenancy reference"
url: /operator/reference/multi-tenancy/
- text: "Managed Gateways"
url: /operator/dataplanes/managed-gateways/
- text: "Gateway configuration"
url: /operator/dataplanes/gateway-configuration/

tldr:
q: How do I deploy an isolated gateway for a single tenant?
a: |
Create a `GatewayConfiguration` with `controlPlaneOptions.watchNamespaces.type: own`,
then create the matching `GatewayClass` and `Gateway` in the tenant namespace.

prereqs:
skip_product: true
---

## Create a GatewayConfiguration

The `controlPlaneOptions.watchNamespaces.type: own` field restricts the in-memory {{ site.kic_product_name_short }} for this gateway to watch only the `kong-gw-public` namespace. Without this, it would watch all namespaces and process routes belonging to other tenants.

```bash
echo '
kind: GatewayConfiguration
apiVersion: gateway-operator.konghq.com/{{ site.operator_gatewayconfiguration_api_version }}
metadata:
name: gw-public
namespace: kong-gw-public
spec:
dataPlaneOptions:
deployment:
podTemplateSpec:
spec:
containers:
- name: proxy
image: kong/kong-gateway:{{ site.data.gateway_latest.release }}
controlPlaneOptions:
watchNamespaces:
type: own
' | kubectl apply -f -
```

## Create a GatewayClass

1. Create a `GatewayClass` that references the `GatewayConfiguration` above:

```bash
echo '
kind: GatewayClass
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: gw-public
spec:
controllerName: konghq.com/gateway-operator
parametersRef:
group: gateway-operator.konghq.com
kind: GatewayConfiguration
name: gw-public
namespace: kong-gw-public
' | kubectl apply -f -
```

1. Wait for {{ site.operator_product_name }} to accept the `GatewayClass`:

```bash
kubectl wait --for=condition=Accepted=True gatewayclass/gw-public --timeout=60s
```

## Create a Gateway

1. Create the `Gateway` resource in the `kong-gw-public` namespace, referencing the `GatewayClass` above:

```bash
echo '
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: gw-public
namespace: kong-gw-public
spec:
gatewayClassName: gw-public
listeners:
- name: http
protocol: HTTP
port: 80
' | kubectl apply -f -
```

1. Wait for the gateway to be programmed:

```bash
kubectl wait --for=condition=Programmed=True gateway/gw-public -n kong-gw-public --timeout=120s
```

## Validate

Verify the public gateway was reconciled successfully:

{% validation kubernetes-resource %}
kind: Gateway
name: gw-public
namespace: kong-gw-public
{% endvalidation %}
Loading
Loading