Expose Harbor with Envoy Gateway
TOC
OverviewArchitecturePrerequisitesStep 1: Create the GatewayStep 2: Deploy HarborOption A: Use theHarbor High Availability (Envoy Gateway) TemplateOption B: Deploy from YAMLStep 3: VerifyTLS ConfigurationCross-namespace GatewayTroubleshootingAccess without a LoadBalancerOverview
Envoy Gateway is a Gateway API-based L7 ingress and load balancer built on Envoy Proxy. In environments that do not provide an IngressClass — or where external traffic routing prefers Gateway API (for example, on Alauda Container Platform 4.3+ with the Envoy Gateway Operator) — Harbor cannot rely on Ingress resources, because Envoy Gateway does not process the Kubernetes Ingress API.
Instead, Harbor is exposed through an HTTPRoute (Gateway API). The Harbor Helm chart renders the HTTPRoute natively when expose.type is set to route, attaching it to a user-created Gateway managed by Envoy Gateway.
Architecture
- TLS is terminated at the Gateway listener, not by Harbor's Nginx.
- The Harbor Registry API (
/v2/) is routed toharbor-core, sodocker login/push/pullwork through the Gateway.
Prerequisites
- Envoy Gateway is installed on the cluster.
- On Alauda Container Platform 4.3+, install it through the platform's Envoy Gateway Operator. Creating the default
EnvoyGatewayCtlinstance (cpaas-defaultin theenvoy-gateway-operatornamespace) automatically generates theGatewayClassenvoy-gateway-operator-cpaas-default. - On other clusters, install upstream Envoy Gateway and create a
GatewayClassyourself.
- On Alauda Container Platform 4.3+, install it through the platform's Envoy Gateway Operator. Creating the default
- A
Gatewayresource exists (see Step 1: Create the Gateway). - The domain name resolves to the Envoy Gateway external address.
- For high availability deployments, the same external dependencies as the standard HA mode are required (HA Redis/PostgreSQL, HA load balancer, more than 2 nodes). See Harbor Instance Deployment.
Step 1: Create the Gateway
Create the Gateway in the same namespace as the Harbor instance to keep the deployment simple (no ReferenceGrant required). For a cross-namespace Gateway, see Cross-namespace Gateway.
Notes:
- Replace
gatewayClassNamewith theGatewayClassgenerated by yourEnvoyGatewayCtlinstance. The default on ACP 4.3 isenvoy-gateway-operator-cpaas-default; GatewayClass names follow the<namespace>-<name>pattern of theEnvoyGatewayCtl. - The
HTTPSlistener requires a TLS certificateSecretin the same namespace as the Gateway (see TLS Configuration). - You can also create the Gateway from the Web Console: Networking → Gateway API Gateway, which automatically creates a companion
EnvoyProxyresource. - If you also need plain HTTP access (e.g., for a registry without TLS), add an
HTTPlistener on port80.
Step 2: Deploy Harbor
Option A: Use the Harbor High Availability (Envoy Gateway) Template
Select the Harbor High Availability (Envoy Gateway) template from the Harbor deployment wizard and fill in:
Option B: Deploy from YAML
The equivalent Harbor instance configuration is:
After the instance is deployed, the operator renders an HTTPRoute (named harbor-route by default) that attaches to the referenced Gateway.
Step 3: Verify
-
Check the
HTTPRouteis accepted by the Gateway:
The route conditions should show Accepted: True and ResolvedRefs: True.
-
Access the Harbor UI:
https://harbor.example.com -
Verify the registry API with a Docker client (in a test environment without DNS, map the domain with
--add-host):
TLS Configuration
In route mode, TLS is terminated at the Gateway, so the certificate is configured on the Gateway listener instead of on the Harbor instance:
-
Create the TLS certificate
Secretin the Gateway's namespace: -
Reference it in the Gateway's
HTTPSlistener (see Step 1). -
Keep Harbor's own
expose.tls.enabledasfalseand setexternalURLtohttps://<domain>.
When the certificate is renewed, update the Secret; the Gateway listener picks up the new certificate without redeploying Harbor.
Cross-namespace Gateway
If the Gateway lives in a different namespace than the Harbor instance:
-
The Gateway listener must allow routes from the Harbor namespace, e.g.:
-
Create a
ReferenceGrantin the Gateway's namespace that permits the Harbor namespace:
Troubleshooting
Access without a LoadBalancer
On bare-metal or air-gapped clusters without MetalLB or a cloud LoadBalancer, the Envoy proxy Service defaults to type: LoadBalancer and stays Pending, so the Gateway never gets an external address. Create an EnvoyProxy (referenced from the Gateway via infrastructure.parametersRef) and set its envoyService.type to NodePort, then access Harbor via https://<nodeIP>:<nodePort>.
This is a generic Envoy Gateway capability; see the Envoy Gateway documentation for the full EnvoyProxy configuration reference:
- Customize EnvoyProxy — operational guide
- EnvoyProxy API reference —
envoyService.type(valid options:ClusterIP,LoadBalancer,NodePort)