Skip to main content

Anemos vs Helm

Generating Kubernetes Manifests

Helm uses a templating engine to manage Kubernetes applications. This requires you to write YAML files with special templating syntax, which can be complex and hard to read. In addition, all the contents of a manifest must be defined in a single file, which can lead to large and unwieldy files that are difficult to maintain. The way to move parts of the manifest to separate files is to use named templates, which are essentially functions that can be reused across multiple manifests. However, defining logic in these templates is hard and readability and maintainability suffers as a result.

Anemos, on the other hand, provides an SDK for managing Kubernetes manifests using JavaScript or TypeScript. It allows template-based, object-based, and YAML node-based generation of manifests. Templates use JavaScript's template literals, which are more readable and maintainable than Helm's templating syntax. Objects allow you to define your manifests using JavaScript or TypeScript objects, which brings type safety and better tooling support. YAML node-based approach allows you to manipulate YAML documents directly, which can be useful for modifying deeply nested structures without having to write complex templates or objects.

Take a look at the following examples from HashiCorp Vault Helm chart and their equivalents in Anemos:

{{/*
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: MPL-2.0
*/}}

{{ template "vault.serverServiceAccountEnabled" . }}
{{- if .serverServiceAccountEnabled -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ template "vault.serviceAccount.name" . }}
namespace: {{ include "vault.namespace" . }}
labels:
helm.sh/chart: {{ include "vault.chart" . }}
app.kubernetes.io/name: {{ include "vault.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- if .Values.server.serviceAccount.extraLabels -}}
{{- toYaml .Values.server.serviceAccount.extraLabels | nindent 4 -}}
{{- end -}}
{{ template "vault.serviceAccount.annotations" . }}
{{ end }}
Anemos
// Compute if the server serviceaccount is enabled.
function serverServiceAccountEnabled(): boolean {
return options.server.serviceAccount.create && (options.server.enabled || options.global.enabled);
}

function addServiceAccount(context: anemos.BuildContext): void {
if (!serverServiceAccountEnabled()) {
return;
}

const document = anemos.parseDocument(
"server-serviceaccount.yaml",
`
apiVersion: v1
kind: ServiceAccount
metadata:
name: ${options.name}
namespace: ${options.namespace}
labels:
app.kubernetes.io/name: vault
app.kubernetes.io/instance: ${options.name}
app.kubernetes.io/managed-by: anemos
`
);

// You can get labels from options and pass to the document. Alternatively users themselves can set
// labels on generated documents.
document.setLabels(options.labels);

context.addDocument(document);
}

Modifying Kubernetes Manifests

Helm doesn't provide a good way to modify generated manifests. It requires you to execute other commands as post render hooks to modify the manifests, which can be cumbersome and error-prone. Since post render hooks are not practical, Helm charts often contain large amounts of boilerplate code to define parts of the manifest such as node selectors, tolerations, affinity rules, etc. Central Helm charts repo is archived, but it has a good example of how much effort goes into defining these boilerplate parts. Just searching for affinity brings up 277 pull requests, and most of them are about adding affinity rules to the charts.

Anemos supports manipulating YAML nodes directly, which can be useful for quick modifications or when you need to adapt YAML documents that are generated by another part of your codebase or by a third-party package. It allows you to centralize boilerplate code in a single place. For example, you can define a function that sets the image pull policy for all your workloads, or a function that adds common labels to all your manifests. This powerful feature allows you to modify any YAML document, without waiting for the package maintainers to add support for your use case or fix a bug in the package.

Another benefit of programmatic access to YAML nodes is that it allows you to validate and lint your manifests according to your organization's standards. This allows you to enforce best practices and avoid common pitfalls before deploying your manifests to the cluster.

Managing Multiple Applications

Helm charts mostly focus on managing a single application. While it is possible to use Helm to manage multiple applications with subcharts, they only cover the dependencies of the main chart. Unrelated applications are managed separately, which can lead to a fragmented and inconsistent configuration. Common values such as image registries or annotations are often duplicated across multiple values files.

Anemos projects are designed to manage multiple applications in a single codebase. All applications for the target cluster can be defined in a single Anemos project. It's also possible to manage multiple environments (e.g., development, staging, production) in the same project with different configurations for each environment. This allows you to manage common logic accross all environments and applications, while still being able to customize each application and environment as needed.

Third-Party Packages

Helm doesn't provide a mechanism to use third-party libraries. Reusable code is only accessible through the Helm chart itself. Code duplication is common accross charts and since everything is based on string interpolation, it is hard to define data structures or refactor code without introducing bugs.

Anemos allows you to use third-party packages from the NPM ecosystem. These packages can generate manifests, provide utilities for manipulating manifests, validate or lint manifests, generate reports, or provide any other functionality unrelated to Kubernetes manifests. For example, you can use the @grafana/grafana-foundation-sdk package to generate Grafana dashboards using staticly typed objects and embed them into your manifests. This allows you to leverage the power of the JavaScript ecosystem and use existing libraries to enhance your Anemos projects.

Applying Manifests

Helm has a built-in command to apply manifests to the cluster. This command makes it easy to quickly deploy your manifests to a cluster. Anemos, currently, does not have a built-in command to apply manifests. This may change in the future, but for now, you can use other CLI tools such as kubectl or kapp, or GitOps tools like ArgoCD or Flux to apply your manifests to the cluster.

Interoperability with Helm Charts

Anemos supports generating documents from Helm charts, allowing you to use your existing Helm charts along the migration process. Visit the Helm Interoperability page for more details on how to use Helm charts in Anemos.