-
Notifications
You must be signed in to change notification settings - Fork 121
RFC: Tekton DSL based on Starlark #185
Comments
The proposal is valid and definitely required IMHO for Tekton to reach wider adoption. Interacting with Tekton using K8s YAML objects is too verbose and cumbersome. Tooling can assist to an extent but there are limitations to that. However I still see benefits in providing a more compact YAML format instead. That's the approach taken by Jenkins X and frankly majority of other CI solution (GitLab, Travis CI, Circle CI, Azure Pipelines, BitBucket Pipelines, Google Build, etc) out there which has created a strong muscle memory for users. Would the benefits you described be strong enough for Tekton users to justify deviating from that muscle memory? This also reminds me of one of the downsides of Groovy syntax in Jenkins pipelines based on what we heard from our customers. That it made it more difficult for them to reason about what a pipeline does by looking at its definition due to the higher level abstractions, loops, etc. |
Yeah that's a fair question. First: I believe that Tekton's API syntax today is roughly as simple as it can get for the level of flexibility it provides, and the extent of functionality it lets you describe. If this isn't true today, we should work to make it true, and probably sooner rather than later since this complexity hurts adoption, with or without a DSL. If there are specific examples of unnecessary complexity please file bugs so we can fix them. If we assume Tekton will have a YAML API (and it will; this is Kubernetes we're talking about), and we consider this the lower-level "plumbing" API, then there's an opportunity for a higher-level "porcelean" API in addition to it, that is capable of driving the lower-level layer -- in this case, generating the lower-level API described by the higher-level API. I think it would be more confusing to users to have two levels of the API, and to have both of them be YAML. Jenkins X avoids this by completely hiding the low-level Tekton API and replacing it with their own higher-level YAML. That's perfectly fine for JX, but Tekton itself can't do this since expert users (and providers like JX!) still need that low-level API for debugging and maximum flexibility. Other providers only have the high-level YAML API, which presumably compiles to some internal format to actually execute it. I admit I don't know anything about Jenkins' use of Groovy, and I'd love to learn more from that experience. Was the Groovy the "only" API for defining the pipeline? Or did it let you generate some lower-level config that could be cracked open and debugged or manually edited if the user needed to? Basically, I think there's a nice sweet spot here for providing a higher-level config mode -- in some non-YAML language -- that generates the lower-level YAML one. Users can check in both the high-level and generated low-level configs, with presubmit checks to ensure they're in sync, so they can see diffs in both config flavors. Happy to chat more, and thanks for your input! |
This and the other examples seems very reminiscent of the test builders. I think your proposal point:
is very interesting. Should some tool be introduced to make working with Tekton easier, what does that mean for the state of the catalog? Would the catalog support both? Only one? |
If interpolation were not necessary, this seems to imply that the catalog would likely be a |
If we supported this DSL as a first-class feature of Tekton, resources in the catalog could be defined as YAML and installed using Ultimately the DSL should just be another way to express the same underlying resources and send them to the cluster, and I think it's critical that it be able to "compile down" the high-level format down to the "low-level" YAML, for debuggability, compatibility, etc. Whether the Task/Pipeline/etc was originally defined using the DSL should be irrelevant once it's installed on the cluster. I'm not sure I understand your question in #185 (comment) -- the intention of the catalog is to include common Tasks, Pipelines and Resources (once those are extensible) |
I was trying to envision what you meant by "elides the need for variable interpolation in Tekton resource strings" and incorrectly thought that Tasks were the only resource that could omit interpolation, but they also use it as current. Can you describe this point more? |
I haven't thought it all the way through yet, but I was imagining you could do something along the lines of:
This would validate that the If you only ever dealt with the DSL configuration, you'd never need to learn or know about the interpolation syntax yourself. But since it generates the YAML with placeholders, and that YAML is the source-of-truth, you can always fall back to that lower level of abstraction if you need to. This is just a strawman, but I think it should be possible if we design it carefully. |
As you note, this is a problem shared by k8s. K8s has never addressed it by introducing a first-class DSL or tooling, it has allowed an ecosystem of tools to evolve, as well as people using generic templating tools to generate json/yaml. (Keeping said tools up to date w/ evolving apis is of course a challenge, depending how much logic they include). Is there a reason a similar solution isn't appropriate/viable here? i.e. external/standalone tools that can generate tekton yaml rather than an embedded first-class choice? (And perhaps if a particular tool evolves to be universally adopted by the community, then bringing it into the tekton cli as a first class capability?) |
Yeah that's a fair question. Kubernetes is arguably more complex than Tekton, and it doesn't have a built-in opinionated YAML-generating DSL -- so why should Tekton? I think Tekton does a few things that are fairly uncommon in "vanilla" Kubernetes, which the lack of a higher-level DSL makes acutely painful. Tekton relies heavily on variable interpolation to be able to pass context from one Task to another, and this is necessary in nearly every real-world use case to be able to accomplish even simple tasks. This data isn't known at the time the pipeline is configured (e.g., test success status, built image digest, etc.), and is only derived once the pipeline is running. In Kubernetes, I don't think this is the case to nearly the same extent. Users create Deployments, put them behind Services, and hook those up to an Ingress, and so on, but ultimately each of those configurations are configurable on their own ahead of time, without much data needing to be passed between them -- a Service doesn't need to be configured with details of its Deployment's Pods derived at runtime, it just relies on label selectors. Kubernetes is actually quite a bit simpler than Tekton in this way. I think if you used Starlark to define normal Kubernetes resources, you'd probably mostly end up using loops and variables for DRY-ing (which could be helpful...), but you wouldn't use things like those described in #185 (comment) to pass dynamic data around. Users could use any of Kubernetes' many YAML-templating tools to generate Tekton configs, but they'd lack the facilities to make data passing easier, so they'd ultimately only be solving the easier part of the problem. It's possible that Tekton shouldn't bundle a DSL, and should rely on the community to build some options, and only then maybe choose one to support as first-class. I don't see any other DSLs solving Tekton's specific problems out in the community though, and I think it would take a fairly deeply involved Tekton user (or contributor) to design one. So it's a bit of a chicken-and-egg problem -- adoption is hurt because of YAML's complex usability, so nobody gains enough experience to build a more usable DSL. I think it will take Tekton itself focusing on this problem to solve it. |
@imjasonh To your point about Tekton using variable interpolation and with consideration for this issue I raised regarding Without a DSL and as current, It is my own preference to have as little indirection as possible to discern what is truly going in general, where hopefully Tekton yaml is not the inhibitor of adoption. Although a DSL does consolidate the resource definitions, I feel that this has shifted the adoption concern from understanding the API format to somewhat understanding the API format and this python (or any other) DSL. Perhaps this tooling would be used by a subset of people that much prefer this, but in general I don't know if this entirely resolves the issue. However, aside from upkeep, I can only see benefits to providing a DSL as presented above. |
This is very good point. Ideally the solution is to improve and simplify the core API and object model, to such a point that a DSL isn't necessary at all. Indeed we should also strive to simplify the underlying object model no matter what, even if there is a DSL. Removing some of the nouns, and removing variable interpolation could help, but I don't know (possibly due to my own narrowmindedness) how that can be achieved. |
The way I envision removing interpolation is to implicitly pass all parameters (as they exist current) as arguments directly into the container. I don't know all the use cases, but there are likely only a few other notable areas that would require tailored overrides like image/image tag, which could be other new inputs introduced to steps. Even if |
Just wanted to chime in with support for higher order DSL. I think it's best to get the variable interpolation out of the data format and into an appropriately sophisticated language, because it is a very slippery slope - as in the discussion at tektoncd/pipelines#850, once there's interpolation people start to need concatenation, regex, etc. By way of example, Spinnaker have gone all the way down that slippery slope, via their Pipeline Expressions feature, which provides a large number of helper expressions and indeed the ability to embed arbitrary Java code anywhere you can use a plain text field. Which is great for that project's philosophy, but I think Tekton's kubernetes lineage leads it towards wanting inputs that don't go through complex transformation steps before acting on them. $.02 FWIW YMMV etc. |
Re: concatenation, regex; I completely agree. Params today are not powerful enough, and making them more powerful invites the need for a "real programming language", and YAML doesn't cut it. I wonder whether tektoncd/pipeline#1344 (tektoncd/pipeline#781) allays this concern, since it enables steps to invoke simple scripts in some "real programming language" like Bash/Python/JavaScript given the values of interpolated variables, which gives you support for regex, et al.
Script-mode has downsides of its own of course, you end up writing Python wrapped in YAML (nested meaningful whitespace!). By the time you split the code out into a separate file you've probably been experiencing the pain of having it inline for a while. But at least we're not inventing new languages embedded in YAML. Does script-mode count as a DSL? I don't think so. But it improves intra-step programming. Now we just need to improve inter-step programming, and we're golden. :) |
Proving that there are no new problems in computer science, today I came across this bit in the Borg, Omega, and Kubernetes paper from a few years ago...
¯\(ツ)/¯ |
Thanks I hadn't seen that before, it's definitely relevant! 🤣 At the risk of spilling even more ink over this well-inked topic, I think this can be interpreted to mean: if you choose to pursue a DSL, learn from our mistakes and make sure it's a "real language" with "real development tools" (debuggers, test frameworks), and acknowledge that you'll end up with a Turing-complete language eventually, so probably just start there. If you accept that interpretation (you don't have to, it's a stretch!) then I think Starlark is a good option -- or something like it. It has a testing framework of a sort, and is similar to "real" Python, albeit stripped down for simplicity. Also of note, the goal of this DSL in my mind is not to replace static YAML config, but to make it easier to generate, so that it's entirely optional in the ecosystem -- YAML would remain the source of truth. I believe this is one way to achieve "clean separation between config and code", or at least enable it. Definitely food for thought though. Now I'm going to go read the rest of that paper. 🤔 |
Is this RFC going to move forward? Looks good to me. I would also like to point out in case you missed it that drone.io is using Starlark for their DSL as an alternative to yaml. |
There have been a few prototypes demoed in WG meetings, but I don't know of any more official experiments. I think there's broad consensus that some DSL (YAML or otherwise) would be useful. If you are reading this and have ideas feel free to share them. :) |
Dhall is another configuration language which already has strong Kubernetes bindings. It actually advertises absence of turing completeness : http://www.haskellforall.com/2020/01/why-dhall-advertises-absence-of-turing.html FWIW I was able to generate the Tekton resources types from the go source files, and here is a prototype: https://github.com/TristanCacqueray/dhall-tekton |
Issues go stale after 90d of inactivity. /lifecycle stale Send feedback to tektoncd/plumbing. |
Rotten issues close after 30d of inactivity. /close Send feedback to tektoncd/plumbing. |
Stale issues rot after 30d of inactivity. /lifecycle rotten Send feedback to tektoncd/plumbing. |
@tekton-robot: Closing this issue. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Has there been any update/progress with this? I'm somewhat of the opinion that Tekton won't achieve wide adoption until a simple DSL has been achieved. Whether it's Starlark, or whether it's a more simpler |
Problems
Proposal
tkn
CLI, and in future triggering workflows.Caveats
Simple example
Let's see some code!
This config describes a simple TaskRun that executes a single step:
CLI usage
This interprets the config, generates YAML, and kubectl-applies it
kubectl
, which it assumes you've installed)This interprets the config and emits generated YAML to stdout
This reverses the export process, converting YAML into the equivalent unoptimized config.
What did that buy us?
Not a lot really! The
.cfg
version isn't any more readable than YAML, and is quite a bit more verbose! :(Just converting YAML to this DSL has some small benefits:
tkn config
can perform type checking, but so does the K8s API server (though slower). We can validate Tekton resources, but the webhook controller will do that too (though slower)..foo.bar[2].baz should be a string
).cfg
files easilyBut wait, there's more!
Starlark gives us a Python-esque language, with many of the features of a Real Programming Language, like:
Helper Methods
This would be ~3x more lines in YAML, and harder to read.
Starlark comes bundled with a number of built-in methods for things like string manipulation (e.g., join, replace, format), list manipulation (any, all, enumerate, sorted), and more.
Users can define and share their own libraries of helper methods, including other shared files in their repository.
Tekton itself could provide a library of helper methods to make common use cases simpler to define.
Comprehensions
This would be ~10x more lines in YAML, and harder to read.
Conditional Expressions
NB: This would serve a different purpose to the conditionals work being added to Pipelines. Config conditionals would only have the context available to it at config-interpretation-time (possibly including triggering context), while conditionals would have runtime context available (e.g., whether the previous step failed).
Variables
This reduces lines of code and improves readability by aiding reuse.
This conceivably elides the need for variable interpolation in Tekton resource strings, if we're careful about how we expose Resource information in configs. It's possible that interpolation will still be necessary in YAML, but won't be necessary (and therefore should be disallowed) in the config language. More experimentation is needed.
Execution Context
The top-level
main
function takes a Context, which Tekton can populate with any information available at the time of interpretation. This could include information about the cluster in which Tekton is running, values passed from the CLI, and in the case of triggered resource creation, information about the event that triggered it.Debugging
Starlark includes a builtin
print
function which can be helpful to users debugging config interpretation. Users runningtkn
config exportmy.cfg
will see these print statements in stderr, so they don't alter the output YAML.For configs that are interpreted during triggering, Tekton will need some way to record and surface those debug logs to users.
Applicability Outside Tekton
There's nothing terribly Tekton-specific about anything above. Really at its core we're just generating builtin Starlark objects from Go structs or protobuf messages and interpreting some scripts, and printing its output as YAML. This same work could be applied to Kubernetes resources of all kinds, or YAML of all kinds, or non-YAML outputs, and so on.
I do think there's a specific need in Tekton for a simpler config format than YAML, so we should start by addressing Tekton's needs first, then see if we can extend the approach for general Kubernetes resources.
The text was updated successfully, but these errors were encountered: