Repository navigation
Replies: 3 comments
Revision 1: in line with the walkthroughs that landedThis proposal was posted before #629's revisions 13 to 17 and before any walkthrough was built. Since then, the job walkthrough and the RabbitMQ processor walkthrough have landed, at Revision 14 says #629's points don't bind this proposal, since it is outside the waves. This revision takes them anyway, so this walkthrough is built, tested and read like the two that landed. Nine things change:
Each section below replaces or adds to the part of the same name in the post. The rest of the post stands. The note at the topThe second paragraph becomes:
"It is the first walkthrough proposed" is dropped. BackgroundThe bullet "The docs test accepts a sample only from a The application
The resource is shown bare: type DatabaseSpec struct {
Name string `json:"name"`
DeletionPolicy DeletionPolicy `json:"deletionPolicy,omitempty"`
}
type DatabaseStatus struct {
SecretName string `json:"secretName,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
}
Reconciling gains a step 3 sentence: while the PostgreSQL: the injection point bullet becomes two points of the end user's own, named as the job walkthrough's
Production-ready, as a checklistThese rows change, and the others stand:
The testsThe deployed level's row becomes:
The in-process level's k3s and PostgreSQL get passwords generated on each run. In the The alerts and the dashboardThis section is added.
Nothing is Prometheus's: there is no server, no exporter and no promtool. The deployment
The overlay,
The kind job runs it, and so does a reader. There is no compose file, and no secret is kept in the repository. The manifests, the script and the Dockerfile have no comments. The pagesThey are replaced. Each page is a list of steps: a sentence or two, then the code it arrives at. There is no history, there are no alternatives and there are no asides. The pages are in
The pages also add the walkthrough to the Walkthroughs section's index, as the billing and mailer pages did. Changes to other filesThe list becomes:
Out of scopeThe first bullet becomes the wave-6 walkthroughs, which #629 plans. #629's revision 13 put the MIGRATING.md out of scope. The last bullet becomes ko, Helm and OLM. One bullet is added: running it in production, with runbooks, as for every walkthrough. Open questions
ReferencesThese are added:
|
Revision 2: every question answeredQuestion 1 is answered with (a): the controller provisions PostgreSQL databases, as proposed. Revision 1 answered questions 2 to 4 with #629's answers. So every question is answered. Nothing else changes. The stories go in the milestone Kubernetes controller walkthrough. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Important
Revision 1 brings this proposal in line with the job and RabbitMQ processor walkthroughs that landed, and with #629's revisions 13 to 17. The walkthrough is a module of its own,
example/databases. The Walkthroughs section and the docs test's rule already exist. Its code has no comments, and its pages are code-first steps. It ships Grafana alert rules and a dashboard, with no Prometheus. Its kind overlay runs the LGTM stack, brought up byup.sh. Its probes are served over TLS. Its own points arepostgresql:provisionandpostgresql:drop. #851 and #922 are done, so nothing blocks its stories. Open questions 2 to 4 take #629's answers. Revision 2 answers question 1: the PostgreSQL database provisioner. Every question is answered.Note
A new feature for humus, with no wave. Proposal: humus on the bedrock process model plans walkthroughs in its wave 6, for features old humus had: a Kafka processor (#317) and a RabbitMQ processor (#318). This walkthrough is of a feature old humus never had, so it isn't part of that wave, and it needs no revision of the charter. It is the first walkthrough proposed.
It depends on two proposals, and its stories wait for theirs:
Summary
A walkthrough is a production-ready application, kept in this repository, with pages that walk a reader through how it was built and why. Feature docs show one package at a time. A walkthrough shows them put together: settings, telemetry, probes, failure handling, tests, deployment and failure injection, in one service an end user could run. It is built, tested and deployed in CI, so it can't drift from humus.
This proposal sets out the first one, a Kubernetes controller:
The controller provisions PostgreSQL databases.
Databasecustom resource names a database. The controller creates the database and a role that owns it in a PostgreSQL server, and writes the role's credentials to a Secret that theDatabaseowns.Readycondition.spec.deletionPolicysays.It is the kind of controller platform teams write, and it uses nearly every part of
kube:Resourceand typedRules, including a CEL rule that makes the name immutable;Ownsfor the Secret, andFinalizefor the drop;Synced, the instruments and the recovery of panics;TrustScenario, beside an injection point of its own for PostgreSQL.It is production-ready by a stated bar. Every setting is sourced and checked, and a bad one exits 78. It runs two replicas with leader election and probes, under least-privilege RBAC, and sends traces, logs and metrics over OTLP. Its failure modes are shown, not just claimed.
It is tested at three levels, with the cases written once:
The second and third run the same black-box test cases, which also run against an end user's staging cluster.
Failure injection is part of the tests. Annotating a
Databasewith a scenario makes PostgreSQL unavailable, slow, or the Secret's apply fail. The cases show that theReadycondition says why, that the controller backs off, and that it recovers once the annotation is gone.It ships with its manifests and its image: a kustomization with the CRD, RBAC, the Deployment and a PodDisruptionBudget, and a Dockerfile.
Its pages are a new Walkthroughs section of the docs site. Every code sample on them is quoted from the walkthrough's files, and a test checks it.
Background
openapi/v3and PostgreSQL, with container tests. It has no deployment, no failure injection and no pages that explain it.kube's container tests start k3s asserver --disable-agent, because rootless Podman doesn't delegate the cpuset controller (#851's Testing). A controller whose children are pods can't be shown working there. GitHub's runners have Docker, where kind runs a whole cluster, pods included._test.gofile.TestDocs_code_samplesrequires every Go sample on the site to appear, line for line, in a_test.gofile of the repository (docs_test.go#L23-L28). A walkthrough quotes the application itself.Target. The same cases run in-process in the container tests, and against a deployed environment as functional tests. Plain poll loops work in both.Proposed API
A walkthrough adds no API to humus. What it adds is an application, its manifests, its tests and its pages.
The application
It lives in the
examplemodule, beside the shoppingcart, atexample/databases. The module gainsgithub.com/z5labs/humus/kube, replaced with../kubeas the core module is.The resource:
Its rules:
Namematches^[a-z_][a-z0-9_]{0,62}$, PostgreSQL's limit for an unquoted identifier, and is immutable through a CEL rule,self == oldSelf;DeletionPolicyisRetainorDelete, and defaults toRetain, so deleting by mistake loses no data;Conditionsis a list map keyed bytype.Reconciling, level-triggered, as the Kubernetes docs page describes:
Ensure the role exists, with the password from the Secret when there is one, and a new random password when there isn't.
Ensure the database exists, owned by the role.
Apply the Secret, which the
Databasecontrols, with server-side apply:host,port,database,usernameandpassword.Set
Ready:True, reasonProvisioned;False, with a reason that says which step failed (PostgresUnavailableorSecretApplyFailed) and a stable message.An error is also returned, so the object backs off.
Deleting the Secret makes a new password, which
Ownsbrings about within a reconcile. That doubles as the walkthrough's rotation.Finalizing: with
Delete,fdrops the database, forcing out its connections, then the role. WithRetain, it drops nothing. Either way, the finalizer is removed oncefsucceeds. A failed drop keeps theDatabase, and its finalizer, until it succeeds.PostgreSQL:
s.Host.FS, from a Secret mounted as files, never from the environment.postgresql:<host>:<port>, as Proposal: failure injection #869's docs suggest naming one, before it calls the server.crypto/rand.Init:kube.Connectionfrom the service account, as Proposal: Kubernetes controllers #851's In use does, and thekube.Settings, with the Lease's namespace and identity from the downward API;httphealthService of its probes, withSyncedas readiness.Faultsbuilds failure injection withjsonscenario.TrustScenariotrusts aDatabasein a namespace whose name starts with a prefix that a setting names. The prefix is empty by default, so production trusts none. The container tests and the kind overlay set it to the cases' prefix.Production-ready, as a checklist
The walkthrough's pages close with this list, and the application meets each item:
config.Structand the packages' checkss.Host.FS; a password only in the SecretminAvailable: 1Syncedas readinessterminationGracePeriodSecondsexceeds humus's 20s gracedatabases, their status and Secrets, and a Role for Leases in the controller's namespace. A non-root, read-only containerqueue.depth, theerrorandpanicoutcomes, andreconcile.longest_unfinished_durationReadycondition's reason and messagedeletionPolicy: Retain, and an immutable nameThe tests
go test, in the Build jobObject, the Secret applied throughkubefake.NewClientset(), and PostgreSQL behind the walkthrough's own interface, faked in its test.Finalize'sfwith each policygo testdeploy/, as #851's In use showstestcontainerstag, in a CI job that isn't requiredhumus.OSHost()and humustest's process, against k3s and PostgreSQL in containersfunctionaltag, in a CI job that isn't required, and against an end user's staging clusterThe shared cases are in
cases. It imports neither the application nor humustest, so the compiler keeps them black-box. Each takes aTarget: a client-go config, a namespace prefix, the scenario annotation and codec key, a PostgreSQL DSN to verify with, and a timeout. They poll with plain loops, which work in both harnesses. The cases:DatabasebecomesReady. Its Secret's credentials connect to its database, as its owner.Delete, the database and role are gone. WithRetain, both remain, and theDatabaseis gone either way.postgresql:*:ReadyisFalsewithPostgresUnavailable, and becomesTrueonce the annotation is removed;kube:secrets:patch:ReadyisFalsewithSecretApplyFailed, then recovers;postgresql:*by 2s:Readystill becomesTrue;postgresql:*while aDeletepolicy'sDatabaseis deleted: it stays, with its finalizer, until the annotation is removed.Every case creates its own namespace under the
Target's prefix, and deletes it, so the cases can run in parallel and against a shared staging cluster. They mutate, so they never run against production.The deployment
deploy/is a kustomization:An overlay for the kind job adds PostgreSQL, and sets the trusted prefix to the cases'. The Dockerfile builds a static binary onto a distroless, non-root base.
The pages
A new section,
docs/content/walkthroughs/, opens with what a walkthrough is. This walkthrough's pages follow the order it was built in:deletionPolicy.Init, the settings, the probes, telemetry andFaults.Changes to other files
docs_test.go: a Go sample on a walkthrough's page may also quote any.gofile under its walkthrough's directory, and a YAML sample any file under itsdeploy/. Both are checked line for line, as samples are today..github/workflows/build.yaml:example/go.mod: thekubemodule, client-go and the k3s module.Design decisions
PostgresServerresource with credentials of its own would double the reconciling, and teach nothing new aboutkube.Retainby default. A controller that drops data on a mistaken delete isn't production-ready.Targetand nothing else.examplemodule. It already has pgx and PostgreSQL's testcontainers module, and isn't released. Open question 3.Testing
The walkthrough is its own test: see The tests. Nothing here was prototyped, since
kubeisn't built yet.Migration from today
Nothing migrates. The site has no Walkthroughs section yet.
Open questions
Which controller.
Recommendation: (a).
How it's packaged.
Recommendation: (a).
Where the code lives.
examplemodule, as proposed.example/databases, which keeps client-go out of the shoppingcart's module graph.Recommendation: (a).
The kind job.
Recommendation: (a).
Out of scope
References
docs_test.goAll reactions