Skip to main content
RunBook Academy

KubernetesLXXIX · API DeprecationAPI deprecation

--dry-run=server for manifest review — server-side validation

Advanced⏱ ~12 minkubectl

What you'll learn

  • Use kubectl --dry-run=server to validate manifests
  • Identify server-side deprecated API warnings
  • Integrate --dry-run=server with CI/CD
  • Distinguish --dry-run=client, --dry-run=server, and live apply

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

kubectl --dry-run=server is the canonical pre-flight check for manifest review. It validates a manifest against the live apiserver without persisting the change. The mode is the cluster-side analog of kubectl apply. This lesson walks the mode, the warnings, and the CI/CD integration.

The three dry-run modes

kubectl supports three dry-run modes:

kubectl apply -f manifest.yaml --dry-run=client
kubectl apply -f manifest.yaml --dry-run=server
kubectl apply -f manifest.yaml

The modes:

  • --dry-run=client: The client validates the manifest (schema, parser) but does not contact the apiserver.
  • --dry-run=server: The client sends the manifest to the apiserver; the apiserver validates the manifest (schema, admission chain); the apiserver does not persist the change.
  • No flag: The client sends the manifest; the apiserver validates and persists.
flowchart LR
    A[manifest.yaml] --> B[kubectl apply]
    B --> C{dry-run mode?}
    C -->|client| D[Client validation only]
    C -->|server| E[Server validation]
    E --> F[No persistence]
    C -->|none| G[Server validation]
    G --> H[Persist]

The server-side validation

kubectl apply -f manifest.yaml --dry-run=server
deployment.apps/my-app created (server dry run)

The manifest is sent to the apiserver; the apiserver validates and returns the result. The cluster’s state is unchanged.

For a deprecated API:

# manifest.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
kubectl apply -f manifest.yaml --dry-run=server
Warning: extensions/v1beta1 Ingress is deprecated, use networking.k8s.io/v1 Ingress
ingress.extensions/my-ingress created (server dry run)

The warning is server-side; the apiserver is the source of the deprecation message.

The full admission chain

--dry-run=server exercises the full admission chain:

  1. Authentication. The kubectl client authenticates to the apiserver.
  2. Authorization (RBAC). The apiserver checks the client’s verb permissions.
  3. MutatingAdmissionWebhook. The mutating webhooks fire.
  4. ValidatingAdmissionWebhook. The validating webhooks fire.
  5. Built-in admission. PodSecurity, ResourceQuota, LimitRange, etc.
  6. Schema validation. The manifest’s schema is validated against the API.

The result is the same as a live apply, except the manifest is not persisted.

sequenceDiagram
    participant K as kubectl
    participant AS as apiserver
    participant W as Webhooks
    participant R as Built-in admission
    K->>AS: Apply (dry-run=server)
    AS->>AS: Authentication
    AS->>AS: RBAC
    AS->>W: Mutating webhooks
    AS->>W: Validating webhooks
    AS->>R: Built-in admission
    AS->>AS: Schema validation
    AS-->>K: Result (no persistence)

The side-by-side comparison

# Client-side validation only
kubectl apply -f manifest.yaml --dry-run=client

# Server-side validation
kubectl apply -f manifest.yaml --dry-run=server

# Live apply
kubectl apply -f manifest.yaml

The differences:

ModeValidationAdmissionPersistence
clientClient schemaNoneNo
serverServer schemaFullNo
liveServer schemaFullYes

The CI/CD integration

# .github/workflows/k8s-validate.yml
- name: Server-side validate
  run: |
    kubectl apply -f manifests/ --dry-run=server --validate=true

The CI/CD pipeline validates every manifest against the live apiserver. The pipeline fails if:

  • The manifest has a deprecated API.
  • The manifest has a removed API.
  • The manifest violates an admission policy.
  • The manifest has a schema error.
flowchart LR
    A[PR] --> B[kubectl apply --dry-run=server]
    B --> C[Validation result]
    C --> D[PR passes]
    C --> E[PR fails]
    E --> F[Block merge]

The validate flag

kubectl apply -f manifest.yaml --dry-run=server --validate=true

The --validate=true flag ensures schema validation (client-side schema check). The flag is the default.

kubectl apply -f manifest.yaml --dry-run=server --validate=false

The --validate=false flag skips client-side validation. The server-side validation still applies.

The application into the cluster

After the dry-run validation passes:

kubectl apply -f manifest.yaml

The manifest is applied. The cluster state is updated.

Cross-course references

  • The CI/CD course covers pipeline integration patterns.
  • The Linux course covers JSON schema validation.
  • The Helm course covers chart template validation.

Quiz

Knowledge check · 4 questions

  1. Q1. Which --dry-run mode exercises the full admission chain without persisting the change?

  2. Q2. kubectl --dry-run=server emits warnings for deprecated APIs.

  3. Q3. Walk the --dry-run=server validation of a manifest.

    Manifest with a deployment using `extensions/v1beta1` Ingress. The team is preparing to apply the manifest to a 1.34.x cluster.

  4. Q4. What is the difference between --dry-run=client and --dry-run=server?

Passing score: 75%. Answers are checked in this browser.

Production discipline

  • Use —dry-run=server for production manifests. The server-side validation is the source of truth.
  • Run —dry-run=server in CI/CD. The pipeline fails on warnings.
  • Address warnings before applying. Deprecation warnings are signals to update.
  • Use —validate=true with —dry-run=server. Client-side schema validation is the first check.
  • Document the dry-run in the runbook. The validation, the result, the action.

The dry-run is the canonical pre-flight check. Operating it well is using it in CI/CD and acting on the warnings.