Update Deprecated API Manifests

KubernetesBeginner
Practice Now

Introduction

Kubernetes APIs evolve. A manifest that worked on an older cluster can fail on a newer cluster because an API version was removed or because fields moved to a different shape. In CKAD work, this usually appears as a practical maintenance task: read the error, identify the current API, update the manifest, and prove that the new version is accepted.

In this lab, you will migrate an old Ingress manifest from networking.k8s.io/v1beta1 to networking.k8s.io/v1. You will first create a Service for the Ingress to reference, then observe the old manifest failing, use kubectl discovery commands to inspect the current API, rewrite the manifest, and apply the corrected Ingress.

Prepare a Service Reference

In this step, you will prepare a clean namespace and a simple Service. The old and new Ingress manifests will both point to this Service, so the migration remains focused on API shape instead of Pod readiness or traffic routing.

Start in /home/labex/project:

mkdir -p /home/labex/project
cd /home/labex/project

Check that the Kubernetes API server is reachable. If the VM has just started and the node is not ready yet, wait a few seconds and run the command again.

kubectl get nodes --request-timeout=5s

Expected output includes:

NAME         STATUS   ROLES           AGE   VERSION
labex-v135   Ready    control-plane   ...   v1.35...

Create a namespace named ckad-prep-api-migration and set it as the current namespace:

kubectl create namespace ckad-prep-api-migration
kubectl config set-context --current --namespace=ckad-prep-api-migration

Create a ClusterIP Service named app-web. The --tcp=80:80 option means the Service listens on port 80 and would forward to target port 80 if matching Pods existed. For this migration lab, the Service object itself is enough because you are validating Ingress API fields, not HTTP traffic.

kubectl create service clusterip app-web --tcp=80:80

Confirm that the Service exists:

kubectl get service app-web

Expected output includes:

NAME      TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
app-web   ClusterIP   ...          <none>        80/TCP    ...

Observe a Deprecated Manifest Failure

In this step, you will create an old Ingress manifest and let the current cluster reject it. This is useful practice because the first clue in a migration task is often the API server error message.

Create old-ingress.yaml:

cat > old-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: app-web
spec:
  rules:
  - host: app.example.local
    http:
      paths:
      - path: /
        backend:
          serviceName: app-web
          servicePort: 80
EOF

Read the top of the file. The apiVersion field tells Kubernetes which API group and version should handle this object.

sed -n '1,20p' old-ingress.yaml

Expected output includes:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
...
          serviceName: app-web
          servicePort: 80

Ask the API server to validate the manifest without creating it. --dry-run=server sends the object to the API server for validation, while || true keeps the tutorial moving because this failure is expected.

kubectl apply --dry-run=server -f old-ingress.yaml || true

Expected output includes an error similar to:

error: resource mapping not found for name: "app-web" namespace: "" from "old-ingress.yaml": no matches for kind "Ingress" in version "networking.k8s.io/v1beta1"

The important evidence is no matches for kind "Ingress" in version "networking.k8s.io/v1beta1". That means the current cluster no longer serves this API version.

Discover the Current Ingress API Shape

In this step, you will inspect the current Ingress API before rewriting the file. This is the part that keeps migration work disciplined: do not guess the new fields when the cluster can show you the accepted shape.

List the served Ingress resource:

kubectl api-resources | grep -i '^ingresses'

Expected output includes:

ingresses   ing   networking.k8s.io/v1   true   Ingress

Use kubectl explain to inspect the current backend service field. The path is long because the Service backend is nested under spec.rules[].http.paths[].backend.service.

kubectl explain ingress.spec.rules.http.paths.backend.service --recursive | sed -n '1,80p'

Expected output includes:

GROUP:      networking.k8s.io
KIND:       Ingress
VERSION:    v1

FIELD: service <IngressServiceBackend>
...
  name        <string> -required-
  port        <ServiceBackendPort> -required-

Now create the migrated current-ingress.yaml. The new manifest uses networking.k8s.io/v1, adds pathType, and replaces serviceName plus servicePort with the nested service.name and service.port.number fields.

cat > current-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-web
spec:
  rules:
  - host: app.example.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-web
            port:
              number: 80
EOF

Validate the migrated manifest with a server-side dry run:

kubectl apply --dry-run=server -f current-ingress.yaml

Expected output:

ingress.networking.k8s.io/app-web created (server dry run)

Apply and Inspect the Migrated Ingress

In this step, you will create the migrated Ingress and inspect the fields stored by Kubernetes. Applying the resource is the final proof that the manifest now matches the current API server.

Apply the migrated manifest:

kubectl apply -f current-ingress.yaml

Expected output:

ingress.networking.k8s.io/app-web created

List the Ingress:

kubectl get ingress app-web

Expected output includes:

NAME      CLASS   HOSTS               ADDRESS   PORTS   AGE
app-web   ...     app.example.local    ...       80      ...

Inspect the migrated backend fields directly from the stored object:

kubectl get ingress app-web -o jsonpath='{.apiVersion}{" "}{.spec.rules[0].http.paths[0].pathType}{" "}{.spec.rules[0].http.paths[0].backend.service.name}{":"}{.spec.rules[0].http.paths[0].backend.service.port.number}{"\n"}'

Expected output:

networking.k8s.io/v1 Prefix app-web:80

This output proves three things at once: the object uses the current API version, the path has an explicit pathType, and the backend uses the nested Service reference required by networking.k8s.io/v1.

Summary

You practiced a practical API migration workflow. You created an old networking.k8s.io/v1beta1 Ingress manifest, used server-side dry run to confirm that the current cluster rejects it, inspected the served networking.k8s.io/v1 API, rewrote the backend fields with pathType and the nested Service reference, then applied and inspected the migrated Ingress.