diff --git a/docs/manuals/spaces/howtos/self-hosted/ingress-nginx-migration.md b/docs/manuals/spaces/howtos/self-hosted/ingress-nginx-migration.md new file mode 100644 index 000000000..34ecfaa4f --- /dev/null +++ b/docs/manuals/spaces/howtos/self-hosted/ingress-nginx-migration.md @@ -0,0 +1,667 @@ +--- +title: Migrate away from ingress-nginx +sidebar_position: 7 +description: A guide on how to migrate from ingress-nginx +tier: "business" +--- + +import GlobalLanguageSelector, { CodeBlock } from '@site/src/components/GlobalLanguageSelector'; + + + +`ingress-nginx` is deprecated and will reach end-of-life in March 2026. This +guide covers migration options for existing Spaces deployments. + +For help choosing an exposure method, see [Exposing Spaces Externally][expose]. + + + +## Prerequisites + + +Set environment variables used throughout this guide: + +```bash +export SPACES_VERSION= # Example: 1.16.0 +export SPACES_ROUTER_HOST= # Example: proxy.example.com +``` + +Export your current Helm values to a file (or use an existing version-controlled +file): + +```bash +helm get values spaces -n upbound-system -o yaml > values.yaml +``` + +You'll merge new configuration into this file throughout the migration. + + + +## Migrate current Spaces version before March 2026 + + +Choose your migration option: + +| Option | When to use | +|--------|-------------| +| [Gateway API](#gateway-api-spaces-110) | Already using Gateway API or need shared gateway | +| [Traefik](#traefik-or-alternative-ingress-controller) | Migrate from nginx Ingress to alternative controller | + +Export your current Helm values to a file (or use your existing values file if +stored in Git): + +```bash +helm get values spaces -n upbound-system -o yaml > values.yaml +``` + + +### Gateway API (Spaces 1.10+) + + +Gateway API support has been available since Spaces 1.10. See [Gateway API +Configuration][gateway-api-config] for detailed setup instructions. + +:::note +Pre-1.16 Spaces doesn't support running Ingress and Gateway API +simultaneously. This migration requires switching over in a single upgrade, +which causes brief downtime during DNS propagation. +::: + +**1. Remove existing ingress resources** + +Delete the Ingress resource and ingress-nginx controller: + +```bash +kubectl -n upbound-system delete ingress mxe-router-ingress +helm -n ingress-nginx delete ingress-nginx +``` + +:::warning +This step forces downtime for API access through spaces-router until the +Gateway API configuration is complete. +::: + +**2. Install a gateway API controller** + +Install a Gateway API implementation that supports TLS passthrough and +`TLSRoute`. + +The following example uses Envoy Gateway: + +```bash +export ENVOY_GATEWAY_VERSION= # Example: v1.2.4 + +helm -n envoy-gateway-system upgrade --install --wait --wait-for-jobs \ + --timeout 300s --create-namespace envoy-gateway \ + oci://docker.io/envoyproxy/gateway-helm \ + --version "${ENVOY_GATEWAY_VERSION}" +``` + +**3. Create GatewayClass resource** + +Create a `GatewayClass` resource. + + +```bash +kubectl apply -f - --server-side < +Configure Traefik's Service with NLB annotations. See +[Cloud-specific annotations][expose-annotate]. + + +**2. Validate before switching DNS** + +```bash +# Get Traefik load balancer address +TRAEFIK_LB=$(kubectl get svc -n traefik traefik -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') + +# Test connectivity using --connect-to to route to Traefik +curl --connect-to "${SPACES_ROUTER_HOST}:443:${TRAEFIK_LB}:443" "https://${SPACES_ROUTER_HOST}/version" +# Expected: 401 Unauthorized (routing works, auth required) +``` + +**3. Update DNS to point to Traefik** + +```bash +kubectl get svc -n traefik traefik -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' +``` + +Update your DNS record to this address. For gradual migration, use weighted DNS routing. + +**4. Preserve the nginx IngressClass before uninstalling ingress-nginx** + +```bash +helm upgrade ingress-nginx ingress-nginx \ + --repo https://kubernetes.github.io/ingress-nginx \ + --namespace ingress-nginx \ + --reuse-values \ + --set-json 'controller.ingressClassResource.annotations={"helm.sh/resource-policy": "keep"}' +``` + +**5. Uninstall ingress-nginx** + +```bash +helm uninstall ingress-nginx --namespace ingress-nginx +``` + +Keep `ingress.provision: true` so the Spaces chart continues to manage the +Ingress resource. Traefik picks it up via the nginx provider. + + +## Verification + +After migration, verify connectivity: + +```bash +curl -v "https://${SPACES_ROUTER_HOST}/version" +# Expected: 401 Unauthorized +``` + +[envoy-install]: https://gateway.envoyproxy.io/docs/install/ +[spaces-install]: /manuals/spaces/howtos/self-hosted/self-hosted-spaces-deployment/ +[traefik-migrate]: https://doc.traefik.io/traefik/migrate/nginx-to-traefik/ +[spaces-deploy]: /manuals/spaces/howtos/self-hosted/self-hosted-spaces-deployment/ +[k8s-announce]: https://www.kubernetes.dev/blog/2025/11/12/ingress-nginx-retirement/ +[expose]: /manuals/spaces/howtos/self-hosted/ingress/ +[expose-annotate]: /manuals/spaces/howtos/self-hosted/ingress/#cloud-specific-annotations +[gateway-api]: https://gateway-api.sigs.k8s.io/ +[gateway-api-config]: /manuals/spaces/howtos/self-hosted/ingress/#gateway-api diff --git a/docs/manuals/spaces/howtos/self-hosted/ingress.md b/docs/manuals/spaces/howtos/self-hosted/ingress.md new file mode 100644 index 000000000..44b47a773 --- /dev/null +++ b/docs/manuals/spaces/howtos/self-hosted/ingress.md @@ -0,0 +1,137 @@ +--- +title: Exposing Spaces externally +sidebar_position: 5 +description: Options for exposing Spaces externally +--- + +import { CodeBlock } from '@site/src/components/GlobalLanguageSelector'; + + +You can expose Spaces externally using of three options: + +| Option | When to use | +|--------|-------------| +| LoadBalancer Service | Simplest setup, recommended for most deployments | +| Gateway API | Organization already using Gateway API, or need shared gateway across services | +| Ingress | Organization already using Ingress, or need shared load balancer across services | + +## LoadBalancer Service + + +Upbound recommends a LoadBalancer Service to expose `spaces-router`. + + +:::important +Use a Network Load Balancer (L4), not an Application Load Balancer (L7). Spaces +uses long-lived connections for watch traffic that L7 load balancers may +timeout. +::: + +### Configuration + +```yaml +externalTLS: + host: proxy.example.com # Externally routable hostname for TLS certificates + +router: + proxy: + service: + type: LoadBalancer + annotations: + # AWS NLB (see Cloud-Specific Annotations for other clouds) + service.beta.kubernetes.io/aws-load-balancer-type: external + service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing + service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip +``` + +See [Cloud-Specific Annotations](#cloud-specific-annotations) for GCP and Azure. + + +### Get the LoadBalancer address + + +After installation: + +```bash +kubectl get svc -n upbound-system spaces-router \ + -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' +``` + +Create or update a DNS record pointing your `externalTLS.host` to this address. + +## Ingress + +Use Ingress if you need to share a load balancer across multiple services or +have specific networking requirements. + +### Requirements + +- TLS passthrough support in your Ingress controller +- Network Load Balancer (L4) strongly recommended for long-lived connections + +Configure your Ingress controller's Service with [NLB annotations](#cloud-specific-annotations). + + +### Configuration + +```yaml +ingress: + provision: true + host: proxy.example.com + ingressClassName: "" + # Annotations to add to the Ingress resource + annotations: {} + # Pod labels of the Ingress controller - used for network policy + podLabels: {} + # Namespace labels of the Ingress controller - used for network policy + namespaceLabels: {} +``` + +### Traefik (with nginx provider) + +Traefik can use the [kubernetesIngressNGINX provider][traefik-provider] to +handle nginx-style Ingress resources with TLS passthrough. + +```yaml +ingress: + provision: true + host: proxy.example.com + ingressClassName: nginx + annotations: + nginx.ingress.kubernetes.io/ssl-passthrough: "true" + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" + podLabels: + app.kubernetes.io/name: traefik + namespaceLabels: + kubernetes.io/metadata.name: traefik +``` + +## Gateway API + +Spaces supports the [Gateway API][gateway-api-docs]. Use this option if your +organization is already using Gateway API or needs a shared gateway across +multiple services. + +### Requirements + +- A Gateway API controller (for example, Envoy Gateway, Cilium, or Traefik) +- Gateway API CRDs installed in your cluster +- TLS passthrough support +- Network Load Balancer (L4) strongly recommended + +## Cloud-specific annotations + +Network Load Balancers (L4) are strongly recommended. Spaces uses long-lived +watch connections (hours or days) for kubectl and ArgoCD. L7 load balancers may +timeout these connections. Use these annotations on the LoadBalancer Service +(spaces-router, Ingress controller, or Gateway). + +| Cloud | Annotations | +|-------|-------------| +| **AWS** | `service.beta.kubernetes.io/aws-load-balancer-type: external`
`service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing`
`service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip` | +| **GCP** | `cloud.google.com/l4-rbs: enabled` | +| **Azure** | None required (L4 by default) | + + +[traefik-provider]: https://doc.traefik.io/traefik/reference/install-configuration/providers/kubernetes/kubernetes-ingress-nginx/ +[gateway-api-docs]: https://gateway-api.sigs.k8s.io/ diff --git a/docs/manuals/spaces/howtos/self-hosted/self-hosted-spaces-deployment.md b/docs/manuals/spaces/howtos/self-hosted/self-hosted-spaces-deployment.md index e549e3939..e24b95ab8 100644 --- a/docs/manuals/spaces/howtos/self-hosted/self-hosted-spaces-deployment.md +++ b/docs/manuals/spaces/howtos/self-hosted/self-hosted-spaces-deployment.md @@ -1,7 +1,7 @@ --- title: Deployment Workflow sidebar_position: 3 -description: A quickstart guide for Upbound Spaces +description: A quickstart guide for Upbound Spaces tier: "business" --- import GlobalLanguageSelector, { CodeBlock } from '@site/src/components/GlobalLanguageSelector'; @@ -249,59 +249,135 @@ helm install aws-load-balancer-controller aws-load-balancer-controller --namespa -### Install ingress-nginx +### Install Envoy Gateway -Starting with Spaces v1.10.0, you need to configure the ingress-nginx -controller to allow SSL-passthrough mode. You can do so by passing the -`--enable-ssl-passthrough=true` command-line option to the controller. -The following Helm install command enables this with the `controller.extraArgs` -parameter: +Starting with Spaces v1.10.0, Upbound recommends using the [Gateway API] for +routing traffic to Spaces. Gateway API is the official Kubernetes standard for +ingress and replaces the legacy Ingress API. + +This guide uses Envoy Gateway as the Gateway API controller and replaces +ingress-nginx previously recommended. + +:::info +If you need to continue to use ingress-nginx temporarily, use the [ingress-nginx +migration guide][migration guide]. + +The Kubernetes community announced that ingress-nginx will be retired in March +2026 and you should plan to migrate to Gateway API before then. +::: + + +First, install Envoy Gateway with Helm: + +```bash +helm -n envoy-gateway-system upgrade --install --wait --wait-for-jobs \ + --timeout 360s --create-namespace envoy-gateway \ + oci://docker.io/envoyproxy/gateway-helm \ + --version "v1.2.4" +``` + +Next, create the Gateway API resources for your cloud provider: +Create EnvoyProxy configuration for AWS load balancer + ```bash -helm upgrade --install ingress-nginx ingress-nginx \ - --create-namespace --namespace ingress-nginx \ - --repo https://kubernetes.github.io/ingress-nginx \ - --version 4.12.1 \ - --set 'controller.service.type=LoadBalancer' \ - --set 'controller.extraArgs.enable-ssl-passthrough=true' \ - --set 'controller.service.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-type=external' \ - --set 'controller.service.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-scheme=internet-facing' \ - --set 'controller.service.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-nlb-target-type=ip' \ - --set 'controller.service.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-healthcheck-protocol=http' \ - --set 'controller.service.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-healthcheck-path=/healthz' \ - --set 'controller.service.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-healthcheck-port=10254' \ - --wait +kubectl apply -f - --server-side < +```bash +Create EnvoyProxy configuration for Azure load balancer: ```bash -helm upgrade --install ingress-nginx ingress-nginx \ - --create-namespace --namespace ingress-nginx \ - --repo https://kubernetes.github.io/ingress-nginx \ - --version 4.12.1 \ - --set 'controller.service.type=LoadBalancer' \ - --set 'controller.extraArgs.enable-ssl-passthrough=true' \ - --set 'controller.service.annotations.service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path=/healthz' \ - --wait +kubectl apply -f - --server-side < +Create GatewayClass: ```bash -helm upgrade --install ingress-nginx ingress-nginx \ - --create-namespace --namespace ingress-nginx \ - --repo https://kubernetes.github.io/ingress-nginx \ - --version 4.12.1 \ - --set 'controller.service.type=LoadBalancer' \ - --set 'controller.extraArgs.enable-ssl-passthrough=true' \ - --wait +kubectl apply -f - --server-side < @@ -375,7 +451,10 @@ kubectl get ingress \ -If the preceding command doesn't return a load balancer address then your provider may not have allocated it yet. Once it's available, add a DNS record for the `ROUTER_HOST` to point to the given load balancer address. If it's an IPv4 address, add an A record. If it's a domain name, add a CNAME record. +If the preceding command doesn't return a load balancer address then your +provider may not have allocated it yet. Once it's available, add a DNS record +for the `ROUTER_HOST` to point to the given load balancer address. If it's an +IPv4 address, add an A record. If it's a domain name, add a CNAME record. ## Configure the up CLI @@ -435,7 +514,12 @@ kubectl wait controlplane ctp1 --for condition=Ready=True --timeout=360s ## Connect to your control plane -Connect to your control plane with the `up ctx` command. With your kubeconfig still pointed at the Kubernetes cluster where you installed the Upbound Space, run the following: + +Connect to your control plane with the up ctx command. With your kubeconfig +still pointed at the Kubernetes cluster where you installed the Upbound Space, +run the following: + + ```bash up ctx ./default/ctp1 diff --git a/utils/vale/styles/Upbound/spelling-exceptions.txt b/utils/vale/styles/Upbound/spelling-exceptions.txt index 80f6e139c..ec6468956 100644 --- a/utils/vale/styles/Upbound/spelling-exceptions.txt +++ b/utils/vale/styles/Upbound/spelling-exceptions.txt @@ -37,6 +37,7 @@ configmaps CRDs Crossplane Crossplane's +ctx Datadog declaratively downscaling @@ -144,4 +145,12 @@ XRDs XRs Zendesk Upjet +GCP +nginx +Traefik +Traefik's +hostname +HTTPRoute +TLSRoute +passthrough