TT Lab
Get started
Learn Learning paths Courses

CNPE — Cloud Native Platform Engineer

Why is the app not ready after its request was saved?

Continue in TT Lab

One-line summary

A self-service API is not a button that hides an install command. It is a contract that keeps connecting a user's request to the state of the actual resources. Request acceptance, synchronization, and readiness are answers to different questions.

Why this was needed

If the platform team hand-creates a Deployment and a Service every time a developer requests "please give me a test app," omissions creep into the handoff. Some apps have no Service, and some differ only in replica count. Even if you share a template to solve this, changes and deletions after the copy become each person's responsibility again. Self-service is an approach that turns a repeated request into a simple API and has a controller keep managing the resources behind it.

But a simpler API does not remove operational responsibility. You may tell a user "your app is ready" because the HTTP request succeeded, while the container image is still being pulled. The API server stored the declaration, the controller is processing it, and the app is carrying out its own readiness procedure. Because the three tasks have different owners, their completion times differ too.

How it works

The App in this lab takes only two inputs, replicas and channel. The XRD defines this API's name, scope, and input format. replicas is from 1 to 3, and channel is stable or preview. This is not merely help text shown to people. A request above the cap must be rejected by the API server, and the rejected object must not be stored. The developer account works with App in its own namespace but is not given permission to create the child Deployment directly.

The Composition decides what actual resources the App is composed of. This time a function creates a Deployment and a Service and connects the request name to the resource names and selectors. The request's replica count is passed to the Deployment, and the channel is passed to a container environment variable. If the Service selects the labels of another app, then even if HTTP succeeds, it is not evidence that my request is ready. So you compare not only the name but also the owner UID and the Pod's ownership lineage.

Observation Fact confirmed Fact not yet confirmed
App creation succeeded The API received and stored the request Has the container started?
Synced=True The controller has processed the request Are the readiness condition and the real app healthy?
Ready=True The readiness condition defined in the configuration is met Does that condition adequately express business success?
HTTP response from that Pod The real code responded with the expected channel Are the next change or deletion also handled correctly?

What Ready means depends on how the readiness condition was written. A Deployment generally provides an Available condition, but the lab's faulty Composition looks for a Ready condition. Even if the container and HTTP are healthy, the condition it looks for is not there, so the parent App reports that it is not ready. If you remove the readiness check at this point, you can make only the display green. But next time it can show an app that is not really ready as a success, so it does not solve the problem.

What it looks like in the field

Input validity and permissions are also different things. A request that creates replicas=4 for your own team violates the schema. Conversely, even a valid replicas=1 violates permissions if it creates it for another team. If you merge both failures into a "request error," the user cannot tell whether to change the value or fix the target team. A platform engineer must check the actual response and whether it was stored, and explain the causes separately.

In the team boundary test, you send requests as a restricted service account, not as an administrator. If you see an administrator succeed and judge that users can use it too, you miss a missing permission. Conversely, if you automatically turn a failed permission query into no, you mistake a broken test tool for successful isolation. An observation failure must be recorded separately.

What to check in the next reading

The same principle is needed for changes and deletion after creation. In the next reading, you connect the observed generation, the owner UID, and the finalizer, and in the lab that follows, you compare the actual App request file with the HTTP of the relevant Pod. Think first about why you record the current resources and ownership relationships rather than submitting only the declaration file.

Official documentation