This is a proposal that is a counterpoint to #25
It's also drawing heavily from @mattmoor and his thoughts about our next Serving API rev, even if it disagrees about this one point.
Motivation
Live your truth.
When you start using Knative, your day 1 experience probably doesn't involve a GitOps repository. On day one, you're using kn
to deploy directly, and using the etcd of your Kubernetes cluster as your source of truth about what should be serving, and at what percentages, and under what subdomains.
As you grow, you may end up setting up a github repository, and transitioning your source of truth over to that.
Both of these are valid workflows for various orgs and maturities. Transitioning between them should be smooth, and not require a phase change (@evankanderson's point 1 in #25)
Well I do declare!
The serving API a language for describing what programs you want to run, accessible under what names, with what traffic split, configured how. Knative contains a way of interpereting that language into action on a kubernetes cluster too, but the language itself is useful even without the particular controllers in the serving repo. The PodSpec-able nature of @mattmoor's proposed v1 API is great for when you want to declare the thing you run as a fully-formed image, but sometimes the image is just a sideeffect, the actual main description of the program you want to be running is a particular commit to a source git repo.
A CI/CD system, on the other hand, describes a process, not a declaration of what you want running. Each run of the CI/CD pipeline might build a thing to run, and set some percentages, but what you actually run is something like the most recent of those to complete successfully, or even worse, ill-defined.
In your declarative serving-API language, you should declare exactly what code you want to be running. It should be up to your CI system to make a tested deployable artifact for you, safely.
In your declarative serving-API language, you should declare exactly what percent of traffic should be going to your program. It should be up to your CD system to figure out how to make that so, safely.
Therefore, the serving API specifies what a CI/CD system should accomplish. The serving API knows what, the CI/CD system knows how.
Concrete v1 API suggestions
(with reference to @mattmoor v1 API principles/opinions)
Specifying source to run in the serving API language
Let Service inline the inputs
and outputs
parts of TaskRun
/PipelineRun
from the Pipelines API. This is for specifying source instead of image to run, and is how the CI system knows what to build and test. (Subresource specs can be inlined vs. embedded, [Use] [known] idioms to evoke API familiarity)
When a Service specifies source to run, the outputs
section can be considered to by default include an image in an operator-configured image repo named something sensible based on the service name, tagged with the commit hash, and the image
of the container to run is also by default that image. ([Use] defaulting to graduate complexity)
Integrating with CI/CD
This is the part where I'm suggesting we NOT invert the flow control, or at least allow a non-inverted flow control.
Service can also inline the PipelineRef
/TaskRef
field from the Pipelines API, but generalized so you could point to anything (it shouldn't have to be a Pipeline or Task, because we shouldn't limit ourselves to Pipelines as a CI/CD system). (Henceforth when I say Pipeline please read Pipeline, Task, or other CI/CD primitive; they should be pluggable)
When you specify no PipelineRef
, you get the behavior you get today for images, and an error if you attempted to specify source. Specifying a particular traffic split, Knative will immediately make the relevant route(s) reflect it.
When you specify a PipelineRef
, that pipeline is in charge of all subresource manipulations. That means that the Service is treated as the declarative goal for what should be deployed; the Pipeline is in charge of manipulating the Service's Configuration and Route(s) to match. They're still owned by the Service, but the Service's controller won't touch them directly. Instead, it'll instantiate that Pipeline , and the Pipeline will do its thing.
Regarding the pipeline doing its thing, that thing can even be manipulations to another canary Knative service, or even manipulations to another three Knative clusters. (Embrace Gitops, or die: We must anticipate workflows where the same resource definitions may be applied across multiple clusters, including release scenarios.)
Knative comes with a special ExternalOperation pipeline. When you specify your Service has that pipeline, it does nothing, and expects a human or system outside Knative to be manipulating the child Configuration and Route(s) of the service. This is the Manual Mode missing from @mattmoor 's presentation.
Example
Here's a source-based service using @mattmoor 's suggestions for v1 as a jumping-off point:
apiVersion: serving.knative.dev/v1beta1
kind: Service
metadata:
name: thingservice
spec:
inputs:
resources:
- resourceSpec:
type: git
params:
- name: url
value: https://github.com/wizzbangcorp/thing.git
- name: revision
value: lolcommithash
pipelineRef:
name: build-it-and-roll-it-out-slowly
kind: Pipeline
apiVersion: tekton.dev/v1
This specifies the source. The cluster has gcr.io/stuff configured as the image repo for this namespace, so the image is going to be by default gcr.io/stuff/thingservice:lolcommithash. The pipeline build-it-and-roll-it-out-slowly is invoked with the source input, the image output, and a reference to this Service, which will build the relevant image and then roll it out slowly on this service (or even several others!).
Transitioning from etcdops to full-on gitops
You download your services form etcd into Git. You set up your same relevant pipelines to trigger off commits to the git repo, with the extra initial Task of kubectl apply
-ing the directory. You change all the pipelineRef
fields to ExternalOperation
.
I plan to edit the above as discussion is ongoing, if we end up with discussion that would make this idea better. Please comment on anything that is either a bad idea or unclear.