Status: implemented
Creation date: 2022-11-10
Last update: 2022-11-10
Provide a mechanism by which Pipelines can target the correct manifest to effect a promotion, and make the appropriate change, when using the pull-request strategy.
RFC 0003 describes the general promotion flow and defines the possibility for several distinct promotion strategies to be implemented. One of these promotion strategies further described in this document of the same RFC is one that creates a PR for promoting an app version to the next environment. For this to work the implementation will need to determine which field in which YAML manifest file in the repository contains the app version. One such approach is described herein.
- Define a means for discovering a specific field in one or more YAML files located in a particular directory hierarchy.
- Define a way to update that field in-place in all of the relevant files.
Similar to what Flux offers with image update automations this RFC proposes to use well-formatted YAML comments for discovering and updating fields pertaining to a certain Pipeline's application. Here is an example of such a comment:
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
spec:
postBuild:
substitute:
podinfoVersion: 6.2.0 # {"$promotion": "default:podinfo:prod"}
[...]
This comment is a JSON object comprised of the following parts:
- The key
$promotion
designates it as pertaining to pipeline promotions. - The value
default:podinfo:prod
refers to the environment called "prod" in the Pipeline resource named "podinfo" in the Kubernetes Namespace "default".
An implementation of this RFC has the following inputs and outputs:
- A Pipeline that a particular promotion is supposed to represent
- An environment name. This can either be the target environment name ("prod" in the example above) or an environment preceeding the target environment (e.g. "dev"). In the latter case the implementation would have to fetch the Pipeline from the Kubernetes API and determine the target environment by itself.
- A field value that is used to update the field targeted by the given promotion. This can be a Helm chart version, a Git commit SHA, an image tag or any other value that makes sense in the given user scenario.
Given the inputs above an implementation is able to precisely determine which marker comment it is supposed to discover and with which value it shall update the targeted YAML field. The output of this operation is one or more modified YAML files.
- Requires update to application manifests to know about pipelines.
- Comments are often stripped by tooling
- This includes our own Templates capability currently. There is a potential enhancement to solve this but it has its own drawbacks beyond cost of implementation.
This RFC is a retroactive definition of what has been implemented in pipeline-controller. No alternatives were considered for this initial delivery, but are recorded here for potential future iteration. The initial proposed approach was deemed viable primarily given its similar use within Flux. Coupled with the desire within Weave GitOps to both build natively on top of Flux, and to optimise for velocity and iteration based on customer feedback.
Base Scenario
As to illustrate a couple of potential alternatives, the following base scenario will be used.
There is a pipeline definition like the following.
apiVersion: pipelines.weave.works/v1alpha1
kind: Pipeline
metadata:
name: podinfo-01
namespace: flux-system
spec:
appRef:
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
name: podinfo
environments:
- name: dev
targets:
- namespace: podinfo-01-dev
clusterRef:
kind: GitopsCluster
name: dev
namespace: flux-system
- name: prod
targets:
- namespace: podinfo-01-prod
clusterRef:
kind: GitopsCluster
name: prod
namespace: default
promotion:
pull-request:
url: https://github.com/weaveworks/weave-gitops-clusters
secretRef:
name: promotion-credentials
Helm releases manifests exists like
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: podinfo
spec:
interval: 5m
chart:
spec:
chart: podinfo
version: "6.0.1"
sourceRef:
kind: HelmRepository
name: podinfo
interval: 1m
This alternative solves the base scenario by allowing the pipeline owner to define based
on pipeline properties the layout of repo to use the discovery. Any of the entities within the pipeline
spec
coudl be referenced for discovery.
For example using flux ways of organise repo. A monorepo could be navigated with the following configuration:
promotion:
pull-request:
url: https://github.com/weaveworks/weave-gitops-clusters
match: "path(apps/{environment.name}/{application.name})"
secretRef:
name: promotion-credentials
- Discover the helm release manifest to promote: it will use
spec.promotion.pull-request.match
to determine the path for manifest to promote. - Discover the field to promote: not required as we could resolve it via the schema
spec.chart.spec.version
.
Pros
- Manifests discovery is an explicit strategy defined within pipeline boundaries (manifest and configuration repo).
- Loosely couple solution
- Pipeline behaviours like promotions don't impose restrictions in application manifests
- Application manifests does not know about pipelines.
Cons
- Same discovery mechanism applies to any application in any deployment target within any environment so there is a need for consistency.
- It is unlikely that a single directory-structure strategy would cover all customer scenarios. For example version set by variable and using variable substiution. It would require to either support a set of strategies or to don't support some scenarios.
This alternative tries to address the same problem using a solution based on kubernetes annotations. Similar to argocd resource tracking
An example could be
promotion:
pull-request:
url: https://github.com/weaveworks/weave-gitops-clusters
match: "labels(app.kubernetes.io/environment=environment, annotherLabel)"
match: "annotations(app.kubernetes.io/environment=environment, anotherAnnotation)"
secretRef:
name: promotion-credentials
With the resource annotated like the following
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: podinfo
annotations:
app.kubernetes.io/environment: "dev"
spec:
interval: 5m
chart:
spec:
chart: podinfo
version: "6.0.1"
sourceRef:
kind: HelmRepository
name: podinfo
interval: 1m
- Discover the helm release manifest to promote: it will use
spec.promotion.pull-request.match
to determine the resources matching by label or annotation. - Discover the field to promote: not required as we could resolve it via the schema
spec.chart.spec.version
.
Pros
- Resolution leverages a kubernetes-native metadata solution based on labels or annotations so well understood by kubernetes users and supported by standard tooling.
Cons
- Application manifests does need to know about pipelines.
- Resolution logic split between pipeline and application manifests.
- Implemented in pipeline-controller 0.0.4