The external address of a Kubernetes LoadBalancer Service can change when you re-create the Service or change its configuration. To get a stable human-readable address for publicly exposed Services, request a fully qualified domain name (FQDN) or wildcard record for your LoadBalancer Service. This page shows cluster operators how to request a name, how the resulting FQDN is constructed, and how to view the allocated record.
Overview
The FQDN allocation workflow has the following steps:
- To allocate an FQDN for your
LoadBalancer Service, set the service.beta.kubernetes.io/external-hostname annotation in your manifest using short, long, or wildcard format.
- In response, the External Hostname Controller creates a corresponding record in the
.coreweave.app domain, which you can inspect with kubectl.
Update (August 25, 2025)The controller’s handling of the annotation changed as follows:
-
Before August 25, 2025: The controller mutated the
service.beta.kubernetes.io/external-hostname annotation to long format if you specified it in short format.
-
Now: The controller no longer mutates the annotation. Instead, the controller sets the FQDN and its allocation status in the
.status.conditions field on the Service object, specifically under the ExternalRecords type.
You don’t need to change your manifests or annotations. Only the method for retrieving the name has changed. Both short and long formats are still acceptable in the annotation.
To create a public FQDN for a LoadBalancer Service, set the service.beta.kubernetes.io/external-hostname annotation in your manifest with the desired hostname.
This manifest uses the short format to create the hostname foo for the LoadBalancer Service. The service.beta.kubernetes.io/external-hostname and service.beta.kubernetes.io/coreweave-load-balancer-type annotations control the FQDN allocation.
loadbalancer-with-DNS-example.yaml
apiVersion: v1
kind: Service
metadata:
annotations:
service.beta.kubernetes.io/external-hostname: foo
service.beta.kubernetes.io/coreweave-load-balancer-type: public
name: example-sshd
spec:
type: LoadBalancer
externalTrafficPolicy: Local
ports:
- name: sshd
port: 22
protocol: TCP
targetPort: sshd
selector:
app.kubernetes.io/name: sshd
The Service’s FQDN follows this pattern, combining the hostname, the organization’s Org ID, and the cluster name:
[HOSTNAME].[ORG-ID]-[CLUSTER-NAME].coreweave.app
For example, assume the following values:
- An Org ID of
abc123
- A cluster named
mycluster
- An annotation of
service.beta.kubernetes.io/external-hostname set to foo
The preceding manifest creates this FQDN:
foo.abc123-mycluster.coreweave.app
You can set the annotation using the long format (full FQDN) only if it exactly follows the preceding pattern and matches the Org ID and cluster name.
For Org ID abc123 and cluster mycluster, these two hostname formats produce the same FQDN:
external-hostname annotation | Format | FQDN |
|---|
foo | Short format | foo.abc123-mycluster.coreweave.app |
foo.abc123-mycluster.coreweave.app | Long format | foo.abc123-mycluster.coreweave.app |
However, if the Org ID and cluster name in the annotation don’t match the actual values, the controller treats the annotation as short format.
Consider this erroneous scenario with the following values:
- Org ID
abc123
- Cluster
mycluster
- Annotation set to
foo.xyz456-mycluster.coreweave.app
Because the Org ID in the annotation (xyz456) doesn’t match the actual Org ID (abc123), the controller treats the entire annotation as short format.
The resulting FQDN is foo.xyz456-mycluster.coreweave.app.abc123-mycluster.coreweave.app, which is unintended.
To create a wildcard DNS record for a LoadBalancer Service, set the service.beta.kubernetes.io/external-hostname annotation to *.
The controller creates a wildcard DNS record for the Service in the format *.abc123-mycluster.coreweave.app.
loadbalancer-wildcard-example.yaml
apiVersion: v1
kind: Service
metadata:
annotations:
service.beta.kubernetes.io/external-hostname: "*"
service.beta.kubernetes.io/coreweave-load-balancer-type: public
name: example-sshd
spec:
type: LoadBalancer
externalTrafficPolicy: Local
ports:
- name: sshd
port: 22
protocol: TCP
targetPort: sshd
selector:
app.kubernetes.io/name: sshd
Secure the endpoint with TLS
Assigning a public DNS name to a Service doesn’t automatically issue a TLS certificate. To secure the endpoint, use cert-manager to obtain and manage a certificate for the FQDN or wildcard record.
View the allocated record
To view the allocated FQDN for a Service, inspect the Service status conditions:
kubectl get svc [MY-SERVICE] -o=jsonpath='{.status.conditions[?(@.type=="ExternalRecords")].message}'
Replace [MY-SERVICE] with the name of your Service, such as example-sshd from the example manifest.
Observe the allocation through events and status
Beyond retrieving the FQDN itself, you can inspect Service events and status conditions to confirm that allocation succeeded or to diagnose problems. Services expose events and status conditions with information about DNS record allocation.
To view events and status conditions for a Service named [MY-SERVICE]:
kubectl describe svc [MY-SERVICE]
The output includes:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal IPAMIPAllocationSet 3s ipamOperator IPAllocation created for Service: example-sshd
Warning DomainNotAllowed 3s external-hostname-controller Domain foo is not allowed, appending orgid-cluster-name.coreweave.app
Normal DNSRecordUpdated 3s external-hostname-controller Updated DNS record for service default/example-sshd
To see the status conditions for the Service, look for the status.conditions field in the output:
kubectl get svc [MY-SERVICE] -o yaml
The output includes:
status:
conditions:
- lastTransitionTime: "2025-08-18T16:07:35Z"
message: successfully created ip allocations
reason: IPAllocationSuccess
status: "True"
type: CoreWeaveLoadBalancerReady
- lastTransitionTime: "2025-08-18T16:07:35Z"
message: foo.orgid-cluster-name.coreweave.app
reason: EndpointsUpdated
status: "True"
type: ExternalRecords
- lastTransitionTime: "2025-08-18T16:07:35Z"
message: 12.34.56.78
reason: EndpointsUpdated
status: "True"
type: ExternalTargets
If any errors occur during record allocation, the controller reflects them in an event:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning HostnameConflict 1s (x2 over 1s) external-hostname-controller Skipping record creation - conflicting hostname orgid-cluster-name.coreweave.app found in service: default/example-sshd
The controller also creates a corresponding False status condition:
status:
conditions:
- lastTransitionTime: "2025-08-18T16:13:54Z"
message: ""
reason: EndpointsUpdated
status: "False"
type: ExternalRecords
- lastTransitionTime: "2025-08-18T16:13:54Z"
message: ""
reason: EndpointsUpdated
status: "False"
type: ExternalTargets
Last modified on May 29, 2026