convoy docs
Search

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:

  1. It fetches the source. See Sources.
  2. It reads the target Cluster, and stops if the cluster is not reachable. See Clusters.
  3. For helm content, it reads the Helm values layers.
  4. It renders the content.
  5. It runs the mutations. See Mutations.
  6. It calculates the renderRef of the result.
  7. 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.typeRenderer
helmThe Helm SDK, in-process
kustomizeThe Kustomize API, in-process
manifestsA YAML and JSON decoder
jsonnetNone. 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.

  • releaseName sets .Release.Name. The default is the chart name.
  • releaseNamespace sets .Release.Namespace. The default is default.
  • .Release.IsInstall is always true.
  • .Capabilities holds the Helm defaults, not the values of the target cluster.
  • The lookup function always returns an empty result.
  • dependencyMode: vendored is the only mode that works. All dependencies must be in charts/. resolve gives reason Unsupported.

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.

  • path is the directory of the kustomization. The default is the root of the source.
  • The directory must contain kustomization.yaml, kustomization.yml or Kustomization.
  • A kustomization can reference files outside its directory, in the same fetched tree.
  • targetNamespace sets 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 .yaml and .yml files below it, also in subdirectories.
  • . selects all .yaml and .yml files 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 typeContent of the layer
inlineThe YAML in the Release.
configMapOne key of a ConfigMap. With optional: true, a missing ConfigMap or key gives no layer.
secretOne key of a Secret. With optional: true, a missing Secret or key gives no layer.
gitRepositoryOne 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.

Values layers Pick a scenario and change the sources. Maps merge, lists replace, and a null deletes a chart default. The renderRef is an illustration: the same method, not the same bytes as convoy.
OrderLayerimage.tagreplicaCountresources.limitsargs
0Chart values.yaml6.0.01{cpu: 100m}[--a]
1inline2{memory: 128Mi}
2configMap6.1.0[--b]
3secret, optional: true, missingNo layer
Result6.1.02{cpu: 100m, memory: 128Mi}[--b]

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 reasonStageCauseRetry
SourceNotReadySourceResolutionThe source object is missing, or the fetch failed.Yes
ClusterNotReadyClusterResolutionThe Cluster is missing or not reachable.Yes
ValuesNotReadyRenderingA values ConfigMap, Secret, key or file is missing, or a values fetch failed.Yes
DeployFailedRenderingThe chart, the kustomization, the manifests or a mutation gave an error.Yes
UnsupportedSourceResolution or RenderingA 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 the renderRef.
  • 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.renderRef and status.lastSuccessful.renderRef.
  • The key of the render in the render store, and the value of a pin. See Pin and history.
  • A new renderRef starts a new rollout. See Progressive rollout.
releases/release-gitrepository-helm-in-cluster.yaml
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