Rendering
How convoy turns fetched source files into the objects of a render, and how it identifies a render.
Rendering turns the fetched source files into a list of Kubernetes objects. spec.content.type
selects the renderer. After rendering, the mutation pipeline changes the objects. The result is a
render. convoy identifies each render with a renderRef.
The render pipeline#
At each reconcile, the Release controller does these steps in this order:
- It fetches the source. See Sources.
- It reads the target
Cluster, and stops if the cluster is not reachable. See Clusters. - For
helmcontent, it reads the Helm values layers. - It renders the content.
- It runs the mutations. See Mutations.
- It calculates the
renderRefof the result. - If a pin selects a different render, it loads that render from the render store. See Pin and history.
The observer uses the same render code for /preview, /diff and health. It renders on its own.
It does not read the render of the controller-manager.
Content types#
content.type | Renderer |
|---|---|
helm | The Helm SDK, in-process |
kustomize | The Kustomize API, in-process |
manifests | A YAML and JSON decoder |
jsonnet | None. Rendering gives reason Unsupported. A Jsonnet renderer is planned. Not built |
No renderer runs an external binary. See Release for the fields of each type.
helm#
convoy loads the chart from the fetched files and renders its templates. It does not install a
Helm release, so helm list does not show it.
releaseNamesets.Release.Name. The default is the chart name.releaseNamespacesets.Release.Namespace. The default isdefault..Release.IsInstallis alwaystrue..Capabilitiesholds the Helm defaults, not the values of the target cluster.- The
lookupfunction always returns an empty result. dependencyMode: vendoredis the only mode that works. All dependencies must be incharts/.resolvegives reasonUnsupported.
convoy removes each object whose helm.sh/hook annotation contains test. convoy does not run
other Helm hooks as hooks. It applies them as normal objects of the render. For ordered actions,
use lifecycle hooks.
kustomize#
convoy copies the fetched files into an in-memory file system and builds the kustomization there. The build cannot read files of the host.
pathis the directory of the kustomization. The default is the root of the source.- The directory must contain
kustomization.yaml,kustomization.ymlorKustomization. - A kustomization can reference files outside its directory, in the same fetched tree.
targetNamespacesets the namespace with the namespace transformer of Kustomize. It replaces a namespace that the kustomization sets. It does not change known cluster-scoped kinds.
manifests#
Each entry in paths selects files:
- A path to a file selects that file, with any extension.
- A path to a directory selects all
.yamland.ymlfiles below it, also in subdirectories. .selects all.yamland.ymlfiles of the source.- Globs do not work. A path that selects no files is a render error.
convoy reads the files in path order, and sorts the files of a directory by name. A file can hold many YAML documents. convoy ignores empty documents.
manifests.targetNamespace does not change the rendered objects. As with Helm, convoy applies a namespaced
object without metadata.namespace to the default namespace.
Helm values layers#
spec.content.helm.values is an ordered list of values layers. Other content types ignore it.
Layer type | Content of the layer |
|---|---|
inline | The YAML in the Release. |
configMap | One key of a ConfigMap. With optional: true, a missing ConfigMap or key gives no layer. |
secret | One key of a Secret. With optional: true, a missing Secret or key gives no layer. |
gitRepository | One layer for each entry of paths, in order. The layer has its own ref. |
convoy merges the layers in list order. A later layer wins:
- Two maps merge key by key, at all levels.
- All other values replace the earlier value. This includes lists.
Helm then merges the result over the values.yaml of the chart. The chart defaults are the lowest
layer.
convoy reads the layers again at each reconcile. A change to a ConfigMap or a Secret does not start a reconcile. convoy uses the change at the next reconcile of the Release.
Render failures#
A render failure stops the reconcile. convoy does not apply anything, and the objects of the last
apply stay on the cluster. The Release reports Applied=False. status.lastAttempted.phase is
Failed, and status.lastAttempted.failure holds the stage and the message.
Applied reason | Stage | Cause | Retry |
|---|---|---|---|
SourceNotReady | SourceResolution | The source object is missing, or the fetch failed. | Yes |
ClusterNotReady | ClusterResolution | The Cluster is missing or not reachable. | Yes |
ValuesNotReady | Rendering | A values ConfigMap, Secret, key or file is missing, or a values fetch failed. | Yes |
DeployFailed | Rendering | The chart, the kustomization, the manifests or a mutation gave an error. | Yes |
Unsupported | SourceResolution or Rendering | A configuration that convoy does not support. Examples: jsonnet, dependencyMode: resolve, an empty inline values layer, an unknown mutation type. | At the next periodic reconcile only |
A transient failure retries with spec.syncPolicy.retryBackoff. Without a backoff, the default rate
limit applies. See Status and conditions.
renderRef#
The renderRef is a content hash of the render. convoy serializes each object of the render to
JSON, in render order, and calculates one SHA-256 over all of them. The format is
sha256:<hex>. convoy calculates it after the mutations.
These are the results:
- The same objects give the same
renderRef. A new commit or a new values layer that does not change the objects keeps therenderRef. - A change in a mutation, or in the cluster metadata that a mutation reads, can give a new
renderRef. - A change in the order of the objects gives a new
renderRef.
convoy uses the renderRef to identify a render everywhere:
status.lastAttempted.renderRefandstatus.lastSuccessful.renderRef.- The key of the render in the render store, and the value of a pin. See Pin and history.
- A new
renderRefstarts a new rollout. See Progressive rollout.
apiVersion: core.convoy.kumodo.io/v1alpha1
kind: Release
metadata:
name: podinfo-in-cluster-helm
namespace: default
mutations:
- type: syncWave
waveStrategy:
strategy: waitForHealthy
wave: 1
target:
group: ""
version: v1
kind: Service
spec:
clusterRef:
name: dev-local
source:
type: gitRepository
gitRepository:
name: podinfo
namespace: default
ref:
branch: master
content:
type: helm
helm:
path: charts/podinfo
releaseName: podinfo-helm
values:
- type: inline
inline:
image:
tag: 6.14.0
probes:
readiness:
initialDelaySeconds: 10
liveness:
initialDelaySeconds: 10
syncPolicy:
automatic: true
prune:
orphaned: false
includeCRDs: false
includeNamespaces: false
interval: 1m
healthAssessment:
globalRuleSetSelector:
matchLabels:
convoy.kumodo.io/default: "true"
deadline: 20s
failurePolicy:
rollback: OnReleaseFailure
In the code
convoy v0.9.0
internal/render.Renderinternal/render/render.go:42internal/render.renderHelminternal/render/helm.go:43internal/render.renderKustomizeinternal/render/kustomize.go:46internal/render.gatherFilesinternal/render/render.go:86internal/render.ResolveValuesinternal/render/values.go:39internal/render.mergeValueLayersinternal/render/helm.go:167internal/controller/release.(*Controller).stageRenderinternal/controller/release/controller.go:901internal/controller/release.renderRefinternal/controller/release/controller.go:1755