Generating Kubernetes Manifests
Now that we have created a new Anemos project, let's write the code to generate Kubernetes manifests for our application.
Main Script
Anemos has already created a main script for us, which contains a basic example of how to use Anemos to generate Kubernetes manifests. Let's take a look at the code:
- TypeScript
- JavaScript
import * as anemos from "@ohayocorp/anemos";
This line imports the Anemos library using TypeScript's standard import
syntax. Although
imported like any other JavaScript library, the core library is implemented in native code,
eliminating the need for dependencies.
const anemos = require("@ohayocorp/anemos");
This line imports the Anemos library using JavaScript's CommonJS require
syntax. Although
imported like any other JavaScript library, the core library is implemented in native code,
eliminating the need for dependencies.
- TypeScript
- JavaScript
const builder = new anemos.Builder("1.31", anemos.KubernetesDistribution.Minikube, anemos.EnvironmentType.Development);
const builder = new anemos.Builder("1.31", anemos.KubernetesDistribution.Minikube, anemos.EnvironmentType.Development);
Here, we instantiate the anemos.Builder
class. The Builder
takes information about the target
Kubernetes cluster and the deployment environment (e.g., development, staging, production). This context
allows Anemos packages to tailor the generated manifests. For instance, they might generate OpenShift Route
s
instead of standard Ingress
' if the distribution is OpenShift, or adjust replica counts based on
the environment type.
Anemos generates manifests based only on the information provided to the Builder
. It does not
interact with or require access to an actual Kubernetes cluster during generation.
- TypeScript
- JavaScript
builder.addDocument(
`pod.yaml`,
`
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: default
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
`);
builder.addDocument(
`pod.yaml`,
`
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: default
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
`);
The template generated by anemos new
includes a basic example of adding a simple
Nginx Pod manifest using builder.addDocument()
. This demonstrates a simple mechanism for adding
resources. For our application, however, we'll replace this Pod definition with a Deployment
and a Service
.
- TypeScript
- JavaScript
builder.build();
builder.build();
This line invokes the build
method, which orchestrates the manifest generation process based on
the components and actions added to the builder instance. We'll explore the components and actions
in the next section.
Generating the Manifests
The simplest way to define the manifests is using the builder.addDocument()
method. This method accepts a Document
object (or a path and a YAML string) (or a path and a JavaScript object),
which represents a single Kubernetes manifest file (like a Deployment
or a Service
).
Let's create a Deployment
and a Service
for a sample Nginx application.
First, define some constants for reuse within our manifests:
- TypeScript
- JavaScript
const name = "example-app";
const namespace = "default";
const image = "nginx";
const replicas = 1;
const name = "example-app";
const namespace = "default";
const image = "nginx";
const replicas = 1;
Next, add the Deployment
document using builder.addDocument()
:
- TypeScript
- JavaScript
builder.addDocument(
`deployment.yaml`,
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: ${name}
namespace: ${namespace}
spec:
replicas: ${replicas}
selector:
matchLabels:
app: ${name}
template:
metadata:
labels:
app: ${name}
spec:
containers:
- name: app
image: ${image}
ports:
- containerPort: 80
`);
builder.addDocument(
`deployment.yaml`,
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: ${name}
namespace: ${namespace}
spec:
replicas: ${replicas}
selector:
matchLabels:
app: ${name}
template:
metadata:
labels:
app: ${name}
spec:
containers:
- name: app
image: ${image}
ports:
- containerPort: 80
`);
The builder.addDocument()
function creates a Document
object by parsing a YAML string.
- The first argument (
`deployment.yaml`
) specifies the filename for the generated manifest. - The second argument is a YAML string defining the resource.
This approach leverages JavaScript template literals (backticks ``
) for easy variable injection
(${name}
, ${replicas}
, etc.) directly into the YAML structure.
Note the indentation in the YAML string. Anemos automatically removes common leading whitespace from each line before parsing, allowing you to format the YAML for readability within your code.
Now, let's add the Service
document by passing a JavaScript object to builder.addDocument()
:
- TypeScript
- JavaScript
builder.addDocument(
`service.yaml`,
{
apiVersion: "v1",
kind: "Service",
metadata: {
name: name,
namespace: namespace,
},
spec: {
selector: {
app: name
},
ports: [
{
protocol: "TCP",
port: 80,
targetPort: 80
}
]
}
});
builder.addDocument(
`service.yaml`,
{
apiVersion: "v1",
kind: "Service",
metadata: {
name: name,
namespace: namespace,
},
spec: {
selector: {
app: name
},
ports: [
{
protocol: "TCP",
port: 80,
targetPort: 80
}
]
}
});
Here, instead of a YAML string, we pass:
- The desired filename (
`service.yaml`
). - A standard JavaScript object representing the Kubernetes Service resource.
This method offers a more structured way to define resources. For enhanced type safety and IDE autocompletion, consider using libraries like kubernetes-models or kubernetes-types to define these objects (package management will be covered later).
When creating a Document
with a JavaScript object, Anemos converts the object into its YAML
representation internally. Subsequent modifications to the original JavaScript object will not
automatically update the Document
instance.
That's it! To generate the manifests, run the Anemos CLI (or press Ctrl+F5
in VSCode if you have added the keybinding):
- TypeScript
- JavaScript
anemos build --tsc . dist/index.js
This command executes the dist/index.js
file, which is generated by compiling index.ts
file, processes the added documents,
and writes the resulting deployment.yaml
and service.yaml
files to the output/manifests
directory.
anemos build index.js
This command executes the index.js
file, processes the added documents, and writes the resulting deployment.yaml
and service.yaml
files to the output/manifests
directory.
Below are the complete source files and the generated manifests:
- TypeScript
- JavaScript
import * as anemos from "@ohayocorp/anemos";
const builder = new anemos.Builder("1.31", anemos.KubernetesDistribution.Minikube, anemos.EnvironmentType.Development);
const name = "example-app";
const namespace = "default";
const image = "nginx";
const replicas = 1;
builder.addDocument(
`deployment.yaml`,
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: ${name}
namespace: ${namespace}
spec:
replicas: ${replicas}
selector:
matchLabels:
app: ${name}
template:
metadata:
labels:
app: ${name}
spec:
containers:
- name: app
image: ${image}
ports:
- containerPort: 80
`);
builder.addDocument(
`service.yaml`,
{
apiVersion: "v1",
kind: "Service",
metadata: {
name: name,
namespace: namespace,
},
spec: {
selector: {
app: name
},
ports: [
{
protocol: "TCP",
port: 80,
targetPort: 80
}
]
}
});
builder.build();
const anemos = require("@ohayocorp/anemos");
const builder = new anemos.Builder("1.31", anemos.KubernetesDistribution.Minikube, anemos.EnvironmentType.Development);
const name = "example-app";
const namespace = "default";
const image = "nginx";
const replicas = 1;
builder.addDocument(
`deployment.yaml`,
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: ${name}
namespace: ${namespace}
spec:
replicas: ${replicas}
selector:
matchLabels:
app: ${name}
template:
metadata:
labels:
app: ${name}
spec:
containers:
- name: app
image: ${image}
ports:
- containerPort: 80
`);
builder.addDocument(
`service.yaml`,
{
apiVersion: "v1",
kind: "Service",
metadata: {
name: name,
namespace: namespace,
},
spec: {
selector: {
app: name
},
ports: [
{
protocol: "TCP",
port: 80,
targetPort: 80
}
]
}
});
builder.build();
- deployment.yaml
- service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-app
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: example-app
template:
metadata:
labels:
app: example-app
spec:
containers:
- name: app
image: nginx
ports:
- containerPort: 80
apiVersion: v1
kind: Service
metadata:
name: example-app
namespace: default
spec:
selector:
app: example-app
ports:
- protocol: TCP
port: 80
targetPort: 80