Intro
Operators who treat the Kubernetes API server as a black box often discover that small misconfigurations can take down workloads, block deployments, or expose cluster data. This guide moves beyond basic kubectl get pods usage and explains how the API server actually works, how to verify its behavior, and how to recover from common failure modes safely. You will learn to observe before changing, limit blast radius, and use concrete commands with expected outputs.
Throughout this article, replace placeholders like CLUSTER_CONTROL_PLANE_HOST with values from your own environment. Never paste real credentials, tokens, or private keys into commands or configuration files.
Version and Environment Inventory
Start any API server investigation by establishing the installed version, deployment topology, and current state. This information determines which flags are supported, how the control plane is laid out, and what recovery actions are possible.
Step 1: Identify the Kubernetes version and API server image
Run on any machine with kubectl access:
kubectl version --short
Expected output looks like:
Client Version: v1.28.2
Server Version: v1.28.2
If the server version is older than expected, plan upgrades carefully. The API server version defines the available feature gates and flags. For example, the --service-account-issuer flag became stable in v1.22 and expects a URL; earlier versions accepted a string without validation.
Next, identify the API server pods and their images:
kubectl get pods -n kube-system -l component=kube-apiserver -o wide
Expected output shows control plane nodes and pod status:
NAME READY STATUS RESTARTS AGE IP NODE
kube-apiserver-node1 1/1 Running 2 10d 10.0.0.1 node1
Check the image tag:
kubectl get pod -n kube-system kube-apiserver-node1 -o jsonpath='{.spec.containers[0].image}'
Example output: registry.k8s.io/kube-apiserver:v1.28.2. This tag must match the server version; a mismatch indicates a partial upgrade.
Step 2: Understand deployment topology
Determine whether the cluster is managed (e.g., EKS, GKE, AKS) or self-managed. On a self-managed cluster, the API server runs as static pods defined in /etc/kubernetes/manifests/kube-apiserver.yaml. To view the current manifest without changing it:
sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml
On managed clusters, you may not have direct access to the control plane nodes. Instead, retrieve the API server configuration through the cloud provider's CLI or console. For example, on EKS:
aws eks describe-cluster --name my-cluster --query 'cluster.kubernetesVersion'
Step 3: Capture baseline metrics
Before making any change, record current request rates, latency, and error rates. If you have Prometheus, run queries like:
sum(rate(apiserver_request_total[5m])) by (verb, resource)
Otherwise, use kubectl get --raw /metrics to scrape metrics directly from the API server:
kubectl get --raw /metrics | grep apiserver_request_total
Save this output to a file for later comparison:
kubectl get --raw /metrics > baseline-metrics.txt
Operational safety checklist for inventory
- [ ] Version captured and recorded in a runbook.
- [ ] Deployment topology identified (static pod, managed, or other).
- [ ] Baseline metrics saved with timestamp.
- [ ] No secrets have been printed to terminal logs or stored in plain text.
Safe Configuration Path
The API server has dozens of flags that can alter authentication, authorization, admission, and storage behavior. The safe path is to understand each flag, test in a non-production cluster first, and make one change at a time with verification.
Common flags and their impact
Below is a table of frequently used flags with their purpose and a safe example value. Values depend on your cluster setup.
| Flag | Purpose | Example safe value | Verification signal |
|---|---|---|---|
--authorization-mode | Defines how requests are authorized (e.g., RBAC, Node, Webhook) | RBAC,Node | kubectl auth can-i list pods --as=system:serviceaccount:default:test returns yes or no as expected |
--enable-admission-plugins | Enables admission controllers that validate or mutate requests | NamespaceLifecycle,LimitRanger,ServiceAccount | kubectl get validatingwebhookconfigurations shows registered webhooks |
--service-account-issuer | Sets the issuer for service account tokens | https://kubernetes.default.svc.cluster.local | kubectl get --raw /.well-known/openid-configuration returns JSON with the issuer |
--etcd-servers | Specifies etcd endpoints for storage | https://127.0.0.1:2379 | kubectl get events returns events without etcd errors |
--tls-cert-file and --tls-private-key-file | Paths to serving certificate and key | /etc/kubernetes/pki/apiserver.crt, /etc/kubernetes/pki/apiserver.key | openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout shows correct DNS names and validity |
Step-by-step configuration change example: enabling an admission plugin
Suppose you need to enable the PodSecurityPolicy admission plugin on a test cluster. Process:
- Read current flags from the API server pod spec:
kubectl get pod -n kube-system kube-apiserver-node1 -o jsonpath='{.spec.containers[0].command}' | tr ' ' '\n' | grep enable-admission
Output might be empty or show current plugins.
- Edit the manifest on the control plane node:
sudo cp /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.bak
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
- Add the flag within the container command:
- --enable-admission-plugins=NodeRestriction,PodSecurityPolicy
- Apply and wait for the API server to restart (kubelet restarts static pods automatically). Verify readiness:
kubectl wait --for=condition=Ready pod -n kube-system -l component=kube-apiserver --timeout=60s
Expected output:
pod/kube-apiserver-node1 condition met
- Verify the plugin is active by attempting to create a pod that violates a PodSecurityPolicy. The request should be denied with an error message mentioning the policy.
- Roll back if needed: If the API server fails to start, copy the backup manifest back and restart kubelet:
sudo cp /etc/kubernetes/manifests/kube-apiserver.yaml.bak /etc/kubernetes/manifests/kube-apiserver.yaml
sudo systemctl restart kubelet
Controlling blast radius
- Make configuration changes during a maintenance window, even in test environments.
- Use a canary node: Apply the change to one control plane node if you have multiple, then verify before rolling to others.
- Always have a rollback plan: Copy the original manifest file to a timestamped backup before editing.
Verification and Diagnostics
Knowing what healthy looks like is essential. This section provides commands to verify API server health, inspect logs, and diagnose common issues.
Health and readiness endpoints
The API server exposes /healthz, /livez, and /readyz endpoints. Use curl from a control plane node or via kubectl get --raw:
kubectl get --raw '/healthz?verbose'
Healthy output includes:
[+]ping ok
[+]log ok
[+]etcd ok
[+]poststarthook/start-kube-apiserver-admission-initializer ok
healthz check passed
If any check fails, the output shows a minus sign and an error. For example:
[-]etcd failed: reason withheld
healthz check failed
This indicates an etcd connectivity issue. Check etcd status and network.
Inspecting API server logs
On a self-managed cluster, logs are written to files like /var/log/kube-apiserver.log or captured by journald. Use:
sudo journalctl -u kube-apiserver -n 100 --no-pager
On managed clusters, use cloud provider log collection. For example, on GKE:
gcloud logging read "resource.type=k8s_cluster AND logName=projects/my-project/logs/kube-apiserver" --limit=50
Filter for common issues:
sudo journalctl -u kube-apiserver | grep -i "error\|failed\|denied"
Sample of a TLS certificate error:
E1010 10:00:00.123456 1 authentication.go:63] Unable to authenticate the request due to an error: x509: certificate has expired or is not yet valid
Diagnosing request failures
When a kubectl command fails with The connection to the server ... was refused, check the API server pod status:
kubectl get pods -n kube-system -l component=kube-apiserver
If the pod is CrashLoopBackOff, inspect the previous container logs:
kubectl logs -n kube-system kube-apiserver-node1 --previous
Look for exit messages such as missing files, invalid flag values, or port conflicts.
Profiling API server performance
To diagnose latency, enable the --profiling flag and use pprof endpoints (only in non-production). Example:
kubectl get --raw '/debug/pprof/goroutine?debug=1' | head -20
This outputs stack traces. Analyze with go tool pprof if needed.
Failure Modes and Recovery
This section describes common failure scenarios, their symptoms, and recovery steps.
Failure 1: API server cannot reach etcd
Symptom: kubectl commands hang or return etcdserver: request timed out. Healthz endpoint shows etcd failed.
Diagnosis: Check etcd pod status and logs:
kubectl get pods -n kube-system -l component=etcd
kubectl logs -n kube-system etcd-node1 --tail=50
Also verify network connectivity from the API server container to etcd endpoints.
Recovery: If etcd is down, restart etcd. If network is the issue, restore connectivity or update --etcd-servers to correct endpoints. In extreme cases, restore etcd from a backup.
Failure 2: Certificate expiration
Symptom: API server fails to start with x509: certificate has expired, or clients get TLS errors.
Diagnosis: Check certificate expiry dates:
sudo openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -dates
Output shows notBefore and notAfter. If current date is past notAfter, certificate is expired.
Recovery: Renew the certificate. If using kubeadm, run kubeadm certs renew apiserver and then restart the API server. For clusters with cert-manager or external PKI, trigger renewal according to your setup. After renewal, verify with openssl x509 -dates and restart affected components.
Failure 3: Misconfigured admission webhook
Symptom: API server hangs on object creation or returns InternalError with webhook timeout.
Diagnosis: Check webhook configuration:
kubectl get validatingwebhookconfigurations
Test webhook reachability from API server using curl to the webhook service URL.
Recovery: Temporarily disable the webhook by deleting or editing its configuration to set failurePolicy: Ignore. Fix the webhook service, then re-enable. If the webhook is critical and cannot be fixed quickly, consider rolling back the admission plugin change that introduced it.
Failure 4: Too many open file descriptors
Symptom: API server logs show too many open files and some requests fail.
Diagnosis: Check the process limits:
sudo cat /proc/$(pgrep kube-apiserver)/limits | grep "Max open files"
Recovery: Increase the system limit for the kube-apiserver service. For systemd-managed API server, edit the unit file to set LimitNOFILE=65536 (or higher), then restart. For static pods, ensure the kubelet has high enough limits.
General recovery principles
- Always back up configuration files and etcd data before making changes.
- Use
kubectl drainto isolate a control plane node (if applicable) before maintenance to prevent request disruption. - Document the exact change, expected behavior, and rollback steps in a runbook.
Operations Checklist
Use this checklist for any API server maintenance or troubleshooting session. Assign a single owner to each item and revisit weekly or after each change.
| # | Item | Owner | Frequency | Verification method |
|---|---|---|---|---|
| 1 | Verify API server version and image tag match expected | Platform Engineer (e.g., Priya Shah) | Monthly | kubectl version --short and pod image check |
| 2 | Review API server logs for errors and warnings | SRE Lead (e.g., Marcus Chen) | Weekly | journalctl -u kube-apiserver --since "1 week ago" |
| 3 | Check health endpoints /healthz, /readyz | On-call engineer | Daily (automated) | Monitoring alert if endpoint returns non-200 |
| 4 | Validate certificate expiry dates (API server, etcd) | Security Engineer (e.g., Elena Rodriguez) | Monthly | openssl x509 -dates or cert-manager status |
| 5 | Test admission webhooks with a canary object | Application team lead | Before each major change | Create a test pod in a dedicated namespace and observe |
| 6 | Review etcd backups and test restore procedure | Infrastructure Manager (e.g., David Kim) | Quarterly | Run etcd restore in a sandbox and verify data integrity |
| 7 | Update API server configuration documentation | API Platform Owner (e.g., Sarah Johnson) | After every change | Documentation review by a peer |
When an item fails verification, the owner must open an incident ticket and follow the recovery procedures in the previous section.
Common Pitfalls and How to Avoid Them
Many API server issues stem from avoidable mistakes. Here are frequent pitfalls, why they happen, and how to prevent or recover from them.
Pitfall 1: Ignoring version skew
Why it happens: Teams upgrade worker nodes but forget control plane components, or vice versa. Kubernetes supports a maximum version skew between API server and kubelet of one minor version.
How to avoid: Always check kubectl version before and after upgrades. Use a cluster lifecycle tool like kubeadm or managed upgrade features to keep versions aligned.
Recovery: If skew is too large, upgrade or downgrade components to within the supported range. Rolling back may require etcd snapshot restore if the API server has already written incompatible data.
Pitfall 2: Making multiple flag changes at once
Why it happens: Efficiency desire leads to editing several lines in the manifest simultaneously.
How to avoid: Change one flag, restart, verify health, and only then move to the next. Use git to version-control manifest files and track changes.
Recovery: If multiple changes cause an unrecoverable state, restore the previous manifest from backup (or git) and restart. Then reapply changes one by one.
Pitfall 3: Hard-coding IP addresses in --etcd-servers
Why it happens: Copying configuration from a specific cluster without generalizing.
How to avoid: Use environment-specific templating (e.g., Helm values, kustomize) to inject correct endpoints. Prefer localhost for etcd on the same node, or use service names within the cluster.
Recovery: Update the flag with correct values and restart API server. If etcd moved, ensure connectivity and DNS resolution.
Pitfall 4: Not testing admission webhooks before production rollout
Why it happens: Teams assume the webhook behaves as documented.
How to avoid: Deploy webhooks to a staging environment with realistic workloads first. Use failurePolicy: Fail and timeoutSeconds appropriate for your latency tolerance, but also test with simulated webhook downtime to see how the API server behaves.
Recovery: If a production webhook fails, change failurePolicy to Ignore if the webhook is not security-critical, or quickly fix the webhook service.
Pitfall 5: Overlooking certificate renewal
Why it happens: Certificates have long validity (e.g., one year) and renewal processes are forgotten.
How to avoid: Set up monitoring alerts for certificate expiry at least 30 days in advance. Automate renewal with cert-manager or kubeadm's built-in renewal command.
Recovery: Renew certificates manually using kubeadm certs renew all (for kubeadm clusters) or your PKI system, then restart control plane components.
Conclusion
A solid operational approach to the Kubernetes API server requires understanding its internal components, configuration surface, and failure modes. By consistently applying the practices in this guide, you can reduce downtime, improve security, and make changes with confidence.
As a next step, choose one verification from the Operations Checklist, such as checking API server health endpoints or certificate expiry. Perform the check in your environment, compare the result with the expected signal, and document any discrepancies. Then, review your current configuration against the Safe Configuration Path to identify any risky flags.
Remember: observe first, make small reversible changes, verify with explicit commands, and always have a rollback plan.