Repository navigation
Feature request: ClusterIP-only exposure without LoadBalancer or ingress resources #918
Description
Use case
Allow a CrateDB cluster to serve clients exclusively inside its Kubernetes
cluster, through an ordinary ClusterIP Service, without provisioning a cloud
load balancer or creating ingress resources.
This would avoid unnecessary infrastructure, cost and exposure for in-cluster
applications, and avoid requiring cloud load-balancer provisioning permissions
when external access is not wanted.
Current behavior
The operator's cluster exposure API currently offers loadbalancer and
traefik:
- Omitting
spec.cluster.exposuredefaults toloadbalancer. The data Service
hastype: LoadBalancer; for AWS, the operator adds the NLB annotation. traefikproduces a ClusterIP data Service, but also creates Traefik
IngressRouteTCP resources and requiresspec.cluster.externalDNS.- Neither mode expresses "ClusterIP only, no external routing".
This behavior is present in operator 2.63.0 and remains in the current master
sources inspected on 2026-10-14. This is a feature request, not a report that
the cloud controller should provision load balancers without authorization.
Environment and observed impact
- CrateDB Kubernetes Operator: 2.63.0 for the original test.
- CrateDB: 6.2.11 for the original test.
- Platform: Kubernetes on AWS EKS.
- Kubernetes: 1.34 (reported for the original test; current test-cluster
control-plane version independently confirmed through the read-only EKS
DescribeCluster API on 2026-10-14).
In the original test, clients could use the generated Service's ClusterIP,
but the cloud controller attempted unnecessary LB provisioning. Missing AWS
permissions prevented provisioning and later blocked Service cleanup.
These were cloud-controller IAM failures, not operator Kubernetes RBAC failures.
They illustrate the motivation for internal-only exposure, rather than a
request to change AWS authorization behavior.
No raw logs or stack traces are included in this report. The feature gap can
also be established from the CRD and Service/exposure implementation linked
below; the reproduction instructions are not a claim of a new test run.
How to observe the current behavior
In an isolated test environment:
-
Create an otherwise valid CrateDB resource, omitting
spec.cluster.exposureandspec.cluster.externalDNS. -
Inspect its generated data Service:
kubectl -n <namespace> get service crate-<cluster-name> \ -o jsonpath='{.spec.type}{"\n"}'
-
Observe
LoadBalancer. On AWS, this requests cloud LB provisioning even
if clients only use the Service's in-cluster address. -
Choosing
traefikinstead is not an internal-only alternative: it requires
externalDNS and attempts to create Traefik routing resources.
Do not run this reproduction on a live environment merely to report the
feature: it can provision billable resources.
Requested behavior
Please consider an explicit opt-in internal-only mode, for example:
spec:
cluster:
exposure: clusteripclusterip is a proposed name, not an existing supported value. An equivalent
maintainer-preferred API would be welcome.
In this mode:
- Keep the data Service as ClusterIP, with its HTTP/PostgreSQL ports and
selectors, and retain normal cluster discovery. - Do not request a LoadBalancer or generate Traefik/other ingress routes,
ingress middleware, or external-DNS hostname annotations. - Do not require an external hostname, ingress controller or its CRDs.
- Preserve existing defaults and behavior for
loadbalancerandtraefik. - Preserve the selected mode through restart/resume and Service recreation.
Optional follow-up: exposure transitions
Creation, restart/resume and Service recreation in internal-only mode are the
core requirement. General transitions between exposure modes can be delivered
separately if that keeps the initial contribution small.
For that follow-up:
- Transitioning to internal-only removes operator-owned external routes and
lets the cloud controller clean up any existing LB correctly. - Preserve AWS LB-identification annotations required for cleanup; see Fix orphaned AWS NLB on exposure loadbalancer->traefik switch #851.
- Preserve the existing data Service/ClusterIP where feasible.
- Returning to an existing exposure mode restores its current behavior.
Selecting internal-only cannot bypass permissions needed to clean up a
previously provisioned LB; newly created internal-only clusters should not
require those provisioning permissions.
Scope and implementation discussion
This request concerns spec.cluster.exposure for the database client Service,
not a new Grand Central routing mode.
Would you accept this capability upstream, and is an explicit third exposure
mode the preferred API? If the change is reasonably small, we would be
interested in discussing a contribution after agreement on the behavior.
Any contribution would follow the repository's developer guide, including its
CLA requirement, a feature branch based on current upstream master, applicable
tests and pre-commit checks. This issue does not promise an implementation or
assert that the CLA has already been completed.
Using a dummy ingress is not an equivalent supported contract: missing Traefik
CRDs can fail resource creation, while an absent ingress controller can leave
unused routing objects that may become active if a controller is installed
later.
Activity
Support traceable local patched operator image builds
WalBeh commentedon Oct 20, 2026
Implemented in #920 as
spec.cluster.exposure: clusterip:crate-<name>is a plain ClusterIP: no LB annotations, no external-dns hostname, no Traefik resources,externalDNSnot needed.loadbalancerstill needs the cloud controller's permissions to delete the existing LB.clusterip, so the ClusterIP survives suspend/resume.allowedCIDRshas no effect withclusterip.Notes for clients:
crate-<name>.<namespace>.crate-discovery-<name>is headless and also resolves to dedicated master nodes.--policy=upsert-only, switching toclusteripleaves the old DNS record behind.Could you try the branch on EKS? We can't reproduce the IAM side on minikube.