KEP-4762: Allows setting arbitrary FQDN as the pod's hostname

Implementation History
STABLE Implementable
Created 2024-07-16
Latest v1.37
Milestones
Alpha v1.34
Beta v1.35
Stable v1.37
Ownership
Owning SIG
SIG Network
Participating SIGs
Primary Authors

KEP-4762: Allows setting arbitrary FQDN as the pod’s hostname

Release Signoff Checklist

Items marked with (R) are required prior to targeting to a milestone / release.

  • (R) Enhancement issue in release milestone, which links to KEP dir in kubernetes/enhancements (not the initial KEP PR)
  • (R) KEP approvers have approved the KEP status as implementable
  • (R) Design details are appropriately documented
  • (R) Test plan is in place, giving consideration to SIG Architecture and SIG Testing input (including test refactors)
    • e2e Tests for all Beta API Operations (endpoints)
    • (R) Ensure GA e2e tests meet requirements for Conformance Tests
    • (R) Minimum Two Week Window for GA e2e tests to prove flake free
  • (R) Graduation criteria is in place
  • (R) Production readiness review completed
  • (R) Production readiness review approved
  • “Implementation History” section is up-to-date for milestone
  • User-facing documentation has been created in kubernetes/website , for publication to kubernetes.io
  • Supporting documentation—e.g., additional design documents, links to mailing list discussions/SIG meetings, relevant PRs/issues, release notes

Summary

This proposal allows users to set arbitrary Fully Qualified Domain Name (FQDN) as the hostname of a pod, introduces a new field hostnameOverride for the podSpec, which, if set, once the API is GA will always be respected by the Kubelet (otherwise it will fall back to legacy behavior), and no longer cares about the hostname as well as the subdomain values.

Motivation

This feature will allow some traditional applications to join kubernetes in a more friendly way. Some older services may use hostname to determine permissions or service operations. When migrating services to k8s, the migration path will become confusing due to the hostname restrictions of the pod itself, because when we try to add a Fully Qualified Domain Name (FQDN) hostname to the pod, it will inevitably always carry the cluster-suffix, which will never be possible for services that expect to use DNS to match the hostname.

Goals

  • Allow users to set any arbitrary FQDN as pod hostname.
  • Write the FQDN set by the user to /etc/hosts in the pod.

Non-Goals

  • Add DNS records for the FQDN set by the user.

Proposal

We add a new field called hostnameOverride to podSpec, of type string. When the value of the hostnameOverride field is not an empty string, it always overrides the values of the setHostnameAsFQDN, subdomain, and hostname fields in podSpec to become the hostname of the pod, and only allow the value of setHostnameAsFQDN to be nil.

User Stories (Optional)

Story 1

As a Kubernetes administrator, I want the Kerberos replication daemon (kpropd) to accurately handle hostname resolution for authentication.

In a Kubernetes environment, kpropd on the receiving end uses the hostname to determine the appropriate service credential for authentication purposes (e.g., foo-0.default.pod.cluster-local). However, on the sending side, kpropd uses the hostname it is connecting to (e.g., kdc1.example.com) to generate the cryptographic secret for secure communication. These hostnames must match to ensure that the cryptographic process can generate consistent data on both ends. Any discrepancy between these hostnames can result in authentication failure due to mismatched cryptographic data.

Notes/Constraints/Caveats (Optional)

Risks and Mitigations

The Linux kernel limits the hostname field to 64 bytes (see sethostname(2) ). If a hostname reaches this 64 byte kernel hostname limit, Kubernetes will fail to create the Pod Sandbox, causing the Pod to remain indefinitely in the ContainerCreating state.

To mitigate this issue, we will implement a validation during resource creation to check whether the value of hostnameOverride exceeds 64 bytes. Creation requests exceeding this limit will be denied.

After enabling this feature, if users utilize it to create a group of Pods via Deployment or StatefulSet, multiple Pods with identical names may concentrate on a single node. This could lead to unintended consequences, though we haven’t identified specific potential issues at this time.

Design Details

We are introducing a new feature gate called HostnameOverride. When this feature gate is enabled, users can add the hostnameOverride field in the podSpec.

The hostnameOverride field has a length limitation of 64 characters and must adhere to the DNS subdomain names standard defined in RFC 1123 .

Additionally, in the generatePodSandboxConfig method of kubelet, the pod’s hostname will always be overridden with the value of hostnameOverride, and it will be written in the pod’s /etc/hosts.

For Windows containers, we only set the container’s hostname and do not create an /etc/hosts file for it (as we have previously made it clear that we do not create an /etc/hosts file for Windows containers).

If both setHostnameAsFQDN and hostnameOverride fields are set, or if both hostNetwork and hostnameOverride fields are set, we will reject the creation of the resource and return an error indicating that these fields are mutually exclusive with the hostnameOverride field.

Based on the above design, after the KEP is implemented, we can achieve the following results.

#.hostname.subdomain.setHostnameAsFQDN.hostnameOverride.hostNetwork$(hostname)$(hostname -f)DNS (assuming service exists)
0<pod-name><pod-name>
1aaaaaa
2bb<pod-name><pod-name>.bb.<ns>.svc.<zone><pod-name>.bb.<ns>.svc.<zone>
3aabbaaaa.bb.<ns>.svc.<zone>aa.bb.<ns>.svc.<zone>
4true<pod-name><pod-name>
5aatrueaaaa
6bbtrue<pod-name>.bb.<ns>.svc.<zone><pod-name>.bb.<ns>.svc.<zone><pod-name>.bb.<ns>.svc.<zone>
7aabbtrueaa.bb.<ns>.svc.<zone>aa.bb.<ns>.svc.<zone>aa.bb.<ns>.svc.<zone>
8xx.yy.zzxx.yy.zzxx.yy.zz
9aaxx.yy.zzxx.yy.zzxx.yy.zz
10bbxx.yy.zzxx.yy.zzxx.yy.zz<pod-name>.bb.<ns>.svc.<zone>
11aabbxx.yy.zzxx.yy.zzxx.yy.zzaa.bb.<ns>.svc.<zone>
12truexx.yy.zzINVALIDINVALIDINVALID
13aatruexx.yy.zzINVALIDINVALIDINVALID
14bbtruexx.yy.zzINVALIDINVALIDINVALID
15aabbtruexx.yy.zzINVALIDINVALIDINVALID
16true<same-as-node><same-as-node>
17aatrue<same-as-node><same-as-node>
18bbtrue<same-as-node><same-as-node><pod-name>.bb.<ns>.svc.<zone>
19aabbtrue<same-as-node><same-as-node>aa.bb.<ns>.svc.<zone>
20truetrue<same-as-node><same-as-node>
21aatruetrue<same-as-node><same-as-node>
22bbtruetrue<same-as-node><same-as-node><pod-name>.bb.<ns>.svc.<zone>
23aabbtruetrue<same-as-node><same-as-node>aa.bb.<ns>.svc.<zone>
24xx.yy.zztrueINVALIDINVALIDINVALID
25aaxx.yy.zztrueINVALIDINVALIDINVALID
26bbxx.yy.zztrueINVALIDINVALIDINVALID
27aabbxx.yy.zztrueINVALIDINVALIDINVALID
28truexx.yy.zztrueINVALIDINVALIDINVALID
29aatruexx.yy.zztrueINVALIDINVALIDINVALID
30bbtruexx.yy.zztrueINVALIDINVALIDINVALID
31aabbtruexx.yy.zztrueINVALIDINVALIDINVALID

As shown in the table, setting hostnameOverride will only change the hostname inside the pod and will not modify the DNS records in Kubernetes.

Test Plan

Prerequisite testing updates
Unit tests
  • Add kubelet unit tests to verify that container hostnames are correctly generated: k8s.io/kubernetes/pkg/kubelet/kuberuntime: 2025-06-06 - 69.0%
  • Add API validation unit tests to ensure all field combinations yield correct results: k8s.io/kubernetes/pkg/apis/core/validation : 2025-06-06 - 84.7%
Integration tests
  • N/A
e2e tests
  • Add a conformance test to test/e2e that verifies our implementation conforms to the expectation defined in the table within the #Design Details section.

Graduation Criteria

Alpha

Beta

  • Make feature gate to be enabled by default.
  • Update the feature gate documentation.

GA

  • No issues reported during two releases.

Upgrade / Downgrade Strategy

API server should be upgraded before Kubelets. Kubelets should be downgraded before the API server.

Version Skew Strategy

The core implementation resides in kubelet.

Older kubelet versions will ignore the pod’s hostnameOverride field: • Newly created Pods will retain previous behavior

Older apiserver versions will similarly ignore the hostnameOverride field: • The apiserver doesn’t populate the hostnameOverride value, so newer kubelet versions will maintain legacy behavior

Production Readiness Review Questionnaire

Feature Enablement and Rollback

How can this feature be enabled / disabled in a live cluster?
  • Feature gate (also fill in values in kep.yaml)
    • Feature gate name: HostnameOverride
    • Components depending on the feature gate: kubelet, kube-apiserver
  • Other
    • Describe the mechanism:
    • Will enabling / disabling the feature require downtime of the control plane?
    • Will enabling / disabling the feature require downtime or reprovisioning of a node?
Does enabling the feature change any default behavior?

No

Can the feature be disabled once it has been enabled (i.e. can we roll back the enablement)?

Yes. Using the feature gate is the only way to enable/disable this feature.

What happens if we reenable the feature if it was previously rolled back?

There will be no impact on running Pods in the cluster. This change solely affects newly created Pods. Once enabled, you can set pod hostnames by configuring the podSpec.hostnameOverride field.

Are there any tests for feature enablement/disablement?

We have added unit tests for enabling and disabling the feature gate in: pkg/kubelet/kubelet_pods_test.go#TestGeneratePodHostNameAndDomain

Rollout, Upgrade and Rollback Planning

How can a rollout or rollback fail? Can it impact already running workloads?

No known failure modes.

What specific metrics should inform a rollback?

The kubelet_started_pods_total metrics helps determine whether enabling/disabling this feature causes abnormal pod restarts in the cluster.

kubelet_started_pods_errors_total metrics tracks if feature toggling results in pod startup failures.

kubelet_restarted_pods_total metrics monitors whether enabling/disabling triggers restarts of Static Pods.

run_podsandbox_errors_total metric helps detect if enabling the feature gate and using this functionality would cause sandbox container creation failures.

Were upgrade and rollback tested? Was the upgrade->downgrade->upgrade path tested?

Yes. The upgrade, downgrade, and upgrade path was manually tested with a local cluster by restarting the kube-apiserver and kubelet with the HostnameOverride feature gate enabled, then disabled, then enabled again. The test verified that:

  • A Pod created while HostnameOverride=true uses spec.hostnameOverride as its runtime hostname.
  • The existing Pod keeps running and keeps its hostname after the feature gate is disabled.
  • A new Pod created while HostnameOverride=false ignores spec.hostnameOverride and uses the default Pod hostname.
  • The Pod created while the feature gate was disabled keeps running and keeps the default hostname after the feature gate is re-enabled.

The script used for the manual local-up test was:

#!/usr/bin/env bash
set -euo pipefail

export GOPATH="${GOPATH:-/root/go}"
KUBE_ROOT="$GOPATH/src/k8s.io/kubernetes"
KUBECTL="$KUBE_ROOT/_output/bin/kubectl"
POD_NAME="test-pod"
OVERRIDE_HOSTNAME="test-hostname"
DEFAULT_HOSTNAME="$POD_NAME"
FEATURE_GATES_ON="HostnameOverride=true"
FEATURE_GATES_OFF="HostnameOverride=false"

cd "$KUBE_ROOT"
export PATH="$PATH:$GOPATH/bin:$KUBE_ROOT/third_party/etcd"
export KUBECONFIG="/var/run/kubernetes/admin.kubeconfig"

kill_local_up_components() {
  pkill -9 -f "$KUBE_ROOT/_output/local/bin/linux/arm64/kube-apiserver" >/dev/null 2>&1 || true
  pkill -9 -f "$KUBE_ROOT/_output/local/bin/linux/arm64/kube-controller-manager" >/dev/null 2>&1 || true
  pkill -9 -f "$KUBE_ROOT/_output/local/bin/linux/arm64/kube-scheduler" >/dev/null 2>&1 || true
  pkill -9 -f "$KUBE_ROOT/_output/local/bin/linux/arm64/kubelet" >/dev/null 2>&1 || true
  pkill -9 -f "$KUBE_ROOT/_output/local/bin/linux/arm64/kube-proxy" >/dev/null 2>&1 || true
  pkill -9 -f "etcd --advertise-client-urls http://127.0.0.1:2379" >/dev/null 2>&1 || true
  pkill -9 -f "bash hack/local-up-cluster.sh" >/dev/null 2>&1 || true
  sleep 2
}

component_pid() {
  pgrep -f "^$1 " | head -n 1
}

read_cmdline() {
  local pid="$1"
  local -n out="$2"
  out=()
  while IFS= read -r -d '' arg; do
    out+=("$arg")
  done <"/proc/$pid/cmdline"
}

set_feature_gates() {
  local -n cmd="$1"
  local feature_gates="$2"
  for i in "${!cmd[@]}"; do
    if [[ "${cmd[$i]}" == --feature-gates=* ]]; then
      cmd[$i]="--feature-gates=$feature_gates"
      return
    fi
    if [[ "${cmd[$i]}" == "--feature-gates" ]]; then
      cmd[$((i + 1))]="$feature_gates"
      return
    fi
  done
  cmd+=("--feature-gates=$feature_gates")
}

start_cluster() {
  local log_file="$KUBE_ROOT/_output/hostname-override-local-up.log"
  kill_local_up_components
  rm -f "$log_file"
  FEATURE_GATES="$FEATURE_GATES_ON" LOG_LEVEL=3 hack/local-up-cluster.sh >"$log_file" 2>&1 &

  until grep -q "Local Kubernetes cluster is running" "$log_file"; do
    sleep 2
  done
}

restart_apiserver_and_kubelet() {
  local feature_gates="$1"
  local apiserver_pid kubelet_pid
  local apiserver_cmd kubelet_cmd

  apiserver_pid="$(component_pid "$KUBE_ROOT/_output/local/bin/linux/arm64/kube-apiserver")"
  kubelet_pid="$(component_pid "$KUBE_ROOT/_output/local/bin/linux/arm64/kubelet")"
  read_cmdline "$apiserver_pid" apiserver_cmd
  read_cmdline "$kubelet_pid" kubelet_cmd
  set_feature_gates apiserver_cmd "$feature_gates"
  set_feature_gates kubelet_cmd "$feature_gates"

  pkill -9 -f "$KUBE_ROOT/_output/local/bin/linux/arm64/kubelet" >/dev/null 2>&1 || true
  pkill -9 -f "$KUBE_ROOT/_output/local/bin/linux/arm64/kube-apiserver" >/dev/null 2>&1 || true
  sleep 2

  "${apiserver_cmd[@]}" >"/tmp/kube-apiserver-hostname-override.log" 2>&1 &
  disown "$!"
  until "$KUBECTL" version >/dev/null 2>&1; do
    sleep 1
  done

  "${kubelet_cmd[@]}" >"/tmp/kubelet-hostname-override.log" 2>&1 &
  disown "$!"
  "$KUBECTL" wait --for=condition=Ready node/127.0.0.1 --timeout=180s >/dev/null
}

apply_pod() {
  cat <<EOF | "$KUBECTL" apply -f - >/dev/null
apiVersion: v1
kind: Pod
metadata:
  name: $POD_NAME
spec:
  hostnameOverride: $OVERRIDE_HOSTNAME
  containers:
  - name: writer-container
    image: busybox
    command: ["/bin/sh", "-c", "sleep 3600"]
EOF
}

wait_for_pod() {
  "$KUBECTL" wait --for=condition=Ready "pod/$POD_NAME" --timeout=180s >/dev/null
}

expect_hostname() {
  local message="$1"
  local expected="$2"
  local actual=""
  for _ in $(seq 1 60); do
    actual="$("$KUBECTL" exec "$POD_NAME" -- hostname 2>/dev/null || true)"
    if [[ -n "$actual" ]]; then
      break
    fi
    sleep 2
  done
  if [[ "$actual" != "$expected" ]]; then
    echo "FAIL: $message: expected hostname $expected, got $actual"
    exit 1
  fi
  echo "PASS: $message: hostname=$actual"
}

print_version() {
  echo "Cluster version:"
  "$KUBECTL" version
}

start_cluster
restart_apiserver_and_kubelet "$FEATURE_GATES_ON"
print_version
"$KUBECTL" delete "pod/$POD_NAME" --ignore-not-found --wait=true >/dev/null
apply_pod
wait_for_pod
expect_hostname "HostnameOverride=true overrides pod hostname" "$OVERRIDE_HOSTNAME"

restart_apiserver_and_kubelet "$FEATURE_GATES_OFF"
wait_for_pod
expect_hostname "existing pod keeps running after HostnameOverride=false" "$OVERRIDE_HOSTNAME"
"$KUBECTL" delete "pod/$POD_NAME" --wait=true >/dev/null
apply_pod
wait_for_pod
expect_hostname "new pod does not use hostnameOverride when HostnameOverride=false" "$DEFAULT_HOSTNAME"

restart_apiserver_and_kubelet "$FEATURE_GATES_ON"
wait_for_pod
expect_hostname "pod created while HostnameOverride=false keeps running after HostnameOverride=true" "$DEFAULT_HOSTNAME"

The test result was:

Cluster version:
Client Version: v1.36.0-1349+643e407efef84a
Kustomize Version: v5.8.1
Server Version: v1.36.0-1349+643e407efef84a
PASS: HostnameOverride=true overrides pod hostname: hostname=test-hostname
PASS: existing pod keeps running after HostnameOverride=false: hostname=test-hostname
PASS: new pod does not use hostnameOverride when HostnameOverride=false: hostname=test-pod
PASS: pod created while HostnameOverride=false keeps running after HostnameOverride=true: hostname=test-pod
Is the rollout accompanied by any deprecations and/or removals of features, APIs, fields of API types, flags, etc.?

No

Monitoring Requirements

How can an operator determine if the feature is in use by workloads?

Users can check which workloads are utilizing this feature with the following command:

kubectl get pods -A -o json | jq -r '.items[] | select(.spec.hostnameOverride != null) | "\(.metadata.namespace) \(.metadata.name) \(.spec.hostnameOverride)"'
How can someone using this feature know that it is working for their instance?

Users can use the following command to identify which workloads are using this feature and verify whether it is functioning as expected.

kubectl get pods -A -o json | jq -r '.items[] | select(.spec.hostnameOverride != null) | "\(.metadata.namespace) \(.metadata.name) \(.spec.hostnameOverride)"' | while IFS=' ' read -r ns pod ho; do actual=$(kubectl exec -n "$ns" "$pod" -- hostname 2>/dev/null); [ "$actual" = "$ho" ] && echo "$ns $pod $actual $ho"; done
What are the reasonable SLOs (Service Level Objectives) for the enhancement?

If the kubelet_started_pods_errors_total metric in a cluster remains consistently at 0, then after introducing this feature, the value of kubelet_started_pods_errors_total should similarly remain at 0.

What are the SLIs (Service Level Indicators) an operator can use to determine the health of the service?
  • Metrics
    • Metric name: run_podsandbox_errors_total, kubelet_started_pods_total, kubelet_started_pods_errors_total, kubelet_restarted_pods_total
    • [Optional] Aggregation method: A sharp increase in these metric values would indicate abnormal pod restarts or creation errors in the cluster caused by toggling the feature gate.
    • Components exposing the metric: Kubelet
  • Other (treat as last resort)
    • Details:
Are there any missing metrics that would be useful to have to improve observability of this feature?

No

Dependencies

Does this feature depend on any specific services running in the cluster?

No

Scalability

Will enabling / using this feature result in any new API calls?

No

Will enabling / using this feature result in introducing new API types?

No

Will enabling / using this feature result in any new calls to the cloud provider?

No

Will enabling / using this feature result in increasing size or count of the existing API objects?

Implementing this feature requires adding a new field to the Pod object, which will increase its size. However, we’ll limit the new field’s length to 64 bytes.

Will enabling / using this feature result in increasing time taken by any operations covered by existing SLIs/SLOs?

No

Will enabling / using this feature result in non-negligible increase of resource usage (CPU, RAM, disk, IO, …) in any components?

No

Can enabling / using this feature result in resource exhaustion of some node resources (PIDs, sockets, inodes, etc.)?

No

Troubleshooting

How does this feature react if the API server and/or etcd is unavailable?

No impact to the running workloads

What are other known failure modes?

No known failure modes.

What steps should be taken if SLOs are not being met to determine the problem?

If the SLO is not being met, operators should:

  1. Check whether the affected Pods use spec.hostnameOverride:

    kubectl get pods -A -o json | jq -r '.items[] | select(.spec.hostnameOverride != null) | "\(.metadata.namespace) \(.metadata.name) \(.spec.hostnameOverride)"'
    
  2. Confirm the HostnameOverride feature gate state on the kube-apiserver and kubelet. The field is accepted and used only when the feature gate is enabled in the relevant components.

  3. Inspect kubelet metrics for the affected nodes, especially kubelet_started_pods_errors_total, run_podsandbox_errors_total, kubelet_started_pods_total, and kubelet_restarted_pods_total, and compare them with the same metrics before the feature gate was enabled or before Pods using spec.hostnameOverride were created.

  4. Inspect affected Pod status, events, and kubelet logs to determine whether the failures are during Pod admission, sandbox creation, or container start:

    kubectl describe pod -n <namespace> <pod>
    kubectl get events -n <namespace> --field-selector involvedObject.name=<pod>
    
  5. Verify the runtime hostname for Pods that are Ready but suspected to be misconfigured:

    kubectl exec -n <namespace> <pod> -- hostname
    
  6. If failures correlate with enabling this feature or with Pods using spec.hostnameOverride, roll back by disabling the HostnameOverride feature gate. Existing Pods are not expected to be disrupted; newly created Pods will stop using spec.hostnameOverride while the feature gate is disabled.

Implementation History

  • 2024-07-18: Initial draft KEP
  • 2025-08-13: Align KEPs with implemented PRs and documentation.
  • 2025-10-10: Promote to beta stage
  • 2026-05-23: Promote to stable (GA) stage

Drawbacks

This is not a standard Kubernetes use case; it is undoubtedly in conflict with the current pod’s potential DNS records, and using it will bring more confusion to users. Moreover, we are not sure how much it can help traditional services that can benefit from being migrated to Kubernetes.

Alternatives

  • Configure hostnameOverride via kube-apiserver:
    • If the hostnameOverride field is set, Kubelet will always respect this field (otherwise it will revert to the old behavior). In the default or REST logic, we can see if hostnameOverride is not set, then we check the hostname, setHostnameAsFQDN, and the cluster-suffix, and write the result into hostnameOverride. If the user sets it themselves, we will retain it and treat it as an override, this can ultimately simplify Kubelet as it can remove legacy behavior, but it means teaching the kube-apiserver about the cluster-suffix, however, it is challenging to find an existing or grace way to pass the kube-apiserver’s configuration options in the REST or default logic.
  • Migrate Legacy Projects:
    • Repair the traditional projects that cannot be migrated to Kubernetes, or find alternatives.
  • Relax hostname Validation:
    • Do not add new fields, relax the validation of the hostname field in podSpec to allow it to accept strings in FQDN format, and when the hostname is set to FQDN, we will unconditionally ignore the subdomain and setHostnameAsFQDN fields, or to keep the current hostname and be able to override or omit the default.svc.cluster.local part. However, doing so will cause us to lose the DNS resolution records for the pod.
  • Custom setHostnameAsFQDN:
    • Do not add new fields, allowing the value of setHostnameAsFQDN to be set to Custom, the pod’s hostname can still meet our expectations. However, since setHostnameAsFQDN is currently a boolean type, modifying it would be disruptive to the existing API.
  • Init Container Hostname
    • We can start an init container with privileged mode and run the command hostname mypod.fqdn.com within the init container to set the Pod’s hostname to mypod.fqdn.com. This can achieve the same goal.

Infrastructure Needed (Optional)