[DO NOT MERGE] Demo Go code based Inventory with WorkloadSpec customizations
What does this MR do?
Based on Add WorkloadSpec and ManagedContainerSpec API t... (!129 - merged)
This MR introduces two changes to ManagedContainerSpec:
-
Addition of a
Namefield: This allows us to identify the corresponding container and reuse existing logic effectively. -
Distinction between
ImageandImageReference: To leverage strategic merging for customizations, theImageReferencefield avoids using theimageJSON name.
Assuming a component CR should be like:
spec:
workloadSpec:
...
managedContainerSpec: # an array of ManagedContainerSpec
- name: "puma"
image: ...
- name: "workhorse"
image: ...
replicas: 1
...
For reviewers
The WorkloadSpec is a key motivator for implementing Kubernetes objects using Go code.
A complete example can be found here: !135 (diffs)
Most of the design is inspired by the openTelemetry-operator, and it is just an initial idea.
Why Go for Kubernetes Objects?
Templates, while powerful and k8s yaml alike, can become cumbersome when overloaded with logic and nesting, I especially don't like the idea mixing codes with data (yaml). This makes them harder to reuse and maintain. While partials aim to improve reusability, I feel they often introduce manageability challenges.
For ConfigMaps (which typically serve as holders for large YAML data), templates work well.
However, for constructing other Kubernetes objects, Go code offers significant advantages, including better type checking, logic centralization, and reusability.
I think both methods can coexist.
Inventory
An example of an Inventory implementation can be found here:
Currently, it only builds a Deployment, and many variables in this example are placeholders or "dummies" cuz we do not have ApplicationServer and GitLabInstance CR.
I think components can follow the idempotent pattern to reconcile:
- Create ConfigMaps/Secrets from CR and
ApplicationConfig. - Calculate configuration digest.
- Build Deployments, Services, and other related resources.
- Update the resource status.
Hence it also introduces a ManifestFactory/Build design, we can simplify the workflow:
-
BuildConfig(), and apply - calculate digest
-
Build(), and apply - update resource status from observation.
And I think we should try to avoid accessing the Context (k8s client operations) within the Inventory, so we have better decoupled and easily testable codes. Any information needed from the k8s should be retrieved separately and put into parameters.
WorkloadSpec
The WorkloadSpec relies on strategic patching, as demonstrated here:
The patchStrategy:"merge" patchMergeKey:"name" tag has been reused to facilitate this.
We just happened to be able to reuse that or is it by design?
Alternatively, we can adopt a fully manual approach to control the logic, as shown here, which is not preferable:
Summary
Implementing Deployments in Go does not necessarily lead to more verbose code compared to templates.
Instead, IMO it offers significant benefits such as type safety, reusable functions, and more manageable logic.
Worst scenario, we can convert some of the functions into template functions.
Author's Checklist
For anything in this list which will not be completed, please provide a reason in the MR discussion.
Required
-
Ensure a release milestone is set. -
MR title and description are up to date, accurate, and descriptive. -
MR targeting the appropriate branch. -
MR has a green pipeline on GitLab.com. -
When ready for review, MR is labeled workflowready for review per the MR workflow.
Expected
-
Test plan indicating conditions for success has been posted and passes. -
Documentation is created or updated. -
Tests are added.