Kubernetes 1.23 makes dual-stack networking a stable explicit choice
Dual-stack networking reaches general availability in Kubernetes 1.23 without making every Service dual-stack. Service policy, network prerequisites, and the distinction between preferred and required address families remain explicit.
Supporting two address families does not require every workload to use both. Kubernetes 1.23 makes IPv4/IPv6 dual-stack networking stable while retaining single-stack defaults for Pods and Services. The operational decision remains explicit in network configuration and in the Service API.
The 7 December release announcement removes the IPv6DualStack feature gate. It explains that support has been enabled by default since 1.21, but that using dual-stack still requires appropriate infrastructure and configuration. General availability changes the maturity of the capability without manufacturing the network underneath it.
I value Kubernetes most where its API makes an operating choice explicit. Dual-stack Service policy is useful because it distinguishes a preference from a requirement. Those are different deployment contracts, especially when the same manifests can reach clusters with different network capabilities.
The network must support both families
The release announcement identifies concrete prerequisites. Nodes need routable IPv4 and IPv6 interfaces. The CNI plugin must support dual-stack, and Pods need dual-stack configuration. Services must request either PreferDualStack or RequireDualStack through their IP family policy.
These requirements belong to different layers. An API-server capability does not make node interfaces routable. A Service requesting two families does not add missing support to a CNI plugin. The feature coordinates a supported configuration across those layers.
That distinction helps explain why single-stack defaults remain useful. Existing workloads do not have to acquire a second address family merely because the cluster software can represent one. The stable mechanism permits adoption where the infrastructure and workload requirements justify it.
The removal of the feature gate also changes how the capability is expressed operationally. It is no longer an experimental switch to enable in 1.23. The remaining choices concern the configured network and the workload's request, which are separate from the maturity switch.
A Service can prefer or require dual-stack
The Service API definition in 1.23.0 describes three policy values. SingleStack requests a single family and is the default when no policy is provided.
PreferDualStack requests two families on a dual-stack cluster but accepts one on a single-stack cluster. RequireDualStack requires two and fails when the cluster cannot supply them. The difference is observable at resource creation, not merely a comment about a preferred deployment environment.
This example requires a cluster capable of allocating both families. The selector represents an application whose Pods have been configured for the network being used.
apiVersion: v1
kind: Service
metadata:
name: inventory
spec:
ipFamilyPolicy: RequireDualStack
ipFamilies:
- IPv4
- IPv6
selector:
app: inventory
ports:
- name: http
port: 80
targetPort: 8080
The manifest leaves address allocation to the cluster. It names the desired families and requires both, without hard-coding addresses that may be outside a particular cluster's allocation ranges.
Changing the policy to PreferDualStack would change the accepted result. A deployment could then succeed with a single family on a single-stack cluster. That is appropriate when dual-stack is optional, but it does not prove that the workload has exercised both families.
A requirement that silently falls back is difficult to distinguish from a preference. The Service API avoids that ambiguity by giving the two behaviors separate values. The choice belongs in the declared configuration because downstream automation needs to know which outcome is acceptable.
Address ordering is part of the API contract
The Service has both the older clusterIP field and the clusterIPs list. Its API definition requires the first list entry and the singular field to agree when both are specified. At most two entries can appear in the list.
The ipFamilies list corresponds to those addresses. Its entries can be IPv4 and IPv6 in either order, with the policy governing how the request is interpreted. This lets the API preserve a primary family while representing the second family explicitly.
The definition permits adding or removing a secondary family under its rules, but it does not permit changing the primary family through that field. An update that looks like reordering a short list can therefore have more meaning than cosmetic YAML organization.
This is relevant to clients that process a Service response. Reading only the singular address omits the additional family. Reading the plural field without preserving its relationship to ipFamilies discards information about what each entry represents.
The stable API also applies the family information to headless Services where appropriate, while ExternalName has different rules and clears the relevant fields. Dual-stack should therefore be understood through the Service type and its documented fields, not as an independent list of arbitrary addresses.
Other stable APIs address workload lifecycle
Kubernetes 1.23 also promotes the HorizontalPodAutoscaler autoscaling/v2 API to stable and deprecates autoscaling/v2beta2. This is a separate API graduation. It should not be read as changing the network prerequisites for dual-stack or as requiring every workload to use autoscaling.
Generic ephemeral volumes reach stable as well. The announcement says an existing storage driver with dynamic provisioning can provide an ephemeral volume whose lifecycle follows the Pod. StorageClass parameters and PersistentVolumeClaim-supported functionality remain available through that mechanism.
The useful distinction is lifecycle ownership. A volume can use the provisioning machinery of persistent storage while being scoped to a Pod's lifetime. Ephemeral describes that relationship, so it does not mean that the storage driver stops performing provisioning or loses its supported parameters.
The release also stabilizes the policy that can skip recursive permission changes when mounting a volume. That can reduce Pod startup work. The announcement separately identifies CSI drivers' declaration of support for fsGroup-based permissions as another graduation.
These changes concern how workloads acquire resources and begin execution. They extend stable behavior around storage without requiring an operator to interpret every release feature as part of one coordinated migration.
Pod security becomes available by default as a beta capability
PodSecurity admission moves to beta, and its feature gate becomes enabled by default. The controller enforces Pod Security Standards according to labels on a namespace. The announcement presents it as the replacement for deprecated PodSecurityPolicy.
Enabling a capability is distinct from selecting a namespace's enforcement policy. The release identifies labels as the mechanism for choosing the enforcement level. Operators need to reason about those labels and their intended restrictions when introducing enforcement.
That resembles the dual-stack distinction in a limited but useful way. Software support can be enabled while the effective behavior remains a declared configuration choice. Neither maturity status alone nor the presence of a controller describes the complete policy applied to a particular workload.
My preference is for these choices to remain visible in the API. A namespace label can express a security level, just as a Service policy can express whether a second address family is optional. Their mechanisms differ, but both allow reviewers to inspect the intended behavior.
Server-side validation begins to expose ignored input
An alpha server-side field validation feature addresses another API concern. Previously, unknown fields and all but the last occurrence of duplicate fields could be dropped. With the feature enabled, the server can warn about that input, and a request can select its behavior through the fieldValidation parameter.
The announcement lists Ignore, Warn, and Strict behaviors. Strict rejects the request, while Warn reports the problem without applying that rejection policy. Because this capability remains alpha and depends on its feature gate, it must not be confused with a universal validation change across every 1.23 cluster.
The mechanism matters to declarative configuration because a submitted field can look intentional while the server does not recognize it. Reporting that mismatch makes the accepted object easier to compare with the submitted request.
Release artifacts acquire provenance records
The announcement also reports SLSA Level 1 compliance in the release process. Kubernetes now generates provenance attestation files describing staging and release phases, and artifacts are verified as they move between those phases.
This is a statement about the release process and its recorded provenance. It should not be expanded into a claim that every dependency is free of vulnerabilities or every possible compromise is prevented. The described improvement is the production and checking of evidence about how release artifacts progress through the process.
For consumers, that evidence complements the API-level changes. Stable dual-stack support describes what Kubernetes can configure, while provenance records describe part of how its distributable artifacts are produced. They answer different operational questions.
The central network choice in 1.23 remains explicit. A Service can accept single-stack operation, prefer two families, or require both. The stable release preserves those different outcomes in ipFamilyPolicy, and the cluster must still supply the routable interfaces, CNI support, and Pod configuration that make the selected outcome possible.