@cubos/kube-templates
Biblioteca TypeScript que encapsula recursos do Kubernetes em classes tipadas e reutilizáveis.
Você descreve a aplicação em TypeScript e a biblioteca gera o YAML pronto para kubectl apply,
com autocompletar e checagem de tipos em tudo.
Mantida pela Cubos. Repositório: github.com/cubos-devops/kube-templates
(até 2026-10-27 ficava em git.cubos.io/cubos/kube-templates).
Índice
- Instalação
- Começando
- Recursos disponíveis
- Exemplos
- Deploy em pipelines (forma recomendada)
- Funções auxiliares
- Tipos do Kubernetes
- Desenvolvimento
- Publicação
Instalação
Requer Node.js 24 ou superior.
npm install @cubos/kube-templates
Começando
Todas as classes seguem o mesmo contrato: new Classe(metadata, spec) e o getter .yaml.
import { Namespace, StatelessApp } from "@cubos/kube-templates";
const namespace = new Namespace({ name: "my-app" });
const app = new StatelessApp(
{ name: "api", namespace: "my-app" },
{
image: "my-registry/my-api:latest",
replicas: 3,
cpu: { request: "100m", limit: "500m" },
memory: { request: "128Mi", limit: "512Mi" },
ports: [
{
type: "http",
port: 8080,
publicUrl: "https://api.example.com",
tlsCert: "api-tls-cert",
},
],
envs: {
NODE_ENV: "production",
DATABASE_URL: { secretName: "db-credentials", key: "url" },
},
},
);
console.log(namespace.yaml);
console.log(app.yaml);
Recursos disponíveis
Todas as classes abaixo são exportadas pelo pacote.
Recursos básicos do Kubernetes
Namespace, Deployment, StatefulSet, DaemonSet, Service, IngressV1, ConfigMap,
Secret, Job, CronJob, PersistentVolumeClaim, HorizontalPodAutoscaler,
PodDisruptionBudget, NetworkPolicy, ServiceAccount, Role, RoleBinding.
Bancos de dados
| Classe | O que gera |
|---|---|
Postgres, PostgresV1 | PostgreSQL |
PgBouncer | Pooler de conexões do PostgreSQL (com sidecar opcional de métricas Prometheus) |
StackgresCluster, StackgresInstanceProfile, StackgresPostgresConfig, StackgresBackupConfig | PostgreSQL via operador StackGres |
Redis | Redis |
Mongo | MongoDB |
MySQL, MariaDB | MySQL e MariaDB |
MSSQL | SQL Server |
Cockroach | CockroachDB |
Aplicações
| Classe | O que gera |
|---|---|
StatelessApp | Aplicação stateless completa: Deployment, Service, Ingress, HPA e PDB, conforme o spec |
Cron | CronJob com configuração simplificada |
StaticSite | Site estático |
WordPress | WordPress com banco de dados |
Escala, certificados e segredos
| Classe | O que gera |
|---|---|
ScaledObject, ScaledJob | Autoescalonamento por eventos (KEDA) |
CertManagerV1Certificate, CertificateV1 | Certificados (cert-manager) |
ReplicatedSecret | Secret replicado entre namespaces |
Exemplos
StatelessApp com autoescalonamento
replicas aceita um número fixo ou uma faixa [mínimo, máximo]. Com a faixa, a biblioteca gera
um HorizontalPodAutoscaler (e não escreve replicas no Deployment); com um número, o Deployment
fica com réplicas fixas (padrão 1). minAvailable gera um PodDisruptionBudget.
import { StatelessApp } from "@cubos/kube-templates";
const app = new StatelessApp(
{ name: "my-api", namespace: "production" },
{
image: "my-registry/api:v1.0.0",
replicas: [2, 10],
cpuUtilizationToScale: 70,
cpu: { request: "100m", limit: "1" },
memory: { request: "256Mi", limit: "512Mi" },
ports: [
{
type: "http",
port: 3000,
publicUrl: "https://api.example.com",
tlsCert: "api-tls",
timeout: 60,
maxBodySize: "10Mi",
},
],
envs: {
NODE_ENV: "production",
DATABASE_URL: { secretName: "db-secret", key: "connection-string" },
POD_NAME: { fieldPath: "metadata.name" },
},
// repassa variáveis do processo que gera o YAML (ex.: do CI). Lança erro
// se alguma não estiver definida: `Environment variable BUILD_VERSION not defined`
forwardEnvs: ["BUILD_VERSION"],
minAvailable: 1,
// CronJobs que usam a mesma imagem
crons: [
{
name: "cleanup",
schedule: "0 2 * * *",
command: ["node"],
args: ["cleanup.js"],
},
],
},
);
console.log(app.yaml);
Redis
import { Redis } from "@cubos/kube-templates";
const cache = new Redis(
{ name: "cache", namespace: "production" },
{
version: "7-alpine",
cpu: { request: "100m", limit: "500m" },
memory: "256Mi",
options: {
maxmemory: "200mb",
maxmemoryPolicy: "allkeys-lru",
},
},
);
console.log(cache.yaml);
Cron
import { Cron } from "@cubos/kube-templates";
const report = new Cron(
{ name: "daily-report", namespace: "production" },
{
schedule: "0 8 * * *",
image: "my-registry/report-generator:latest",
command: ["node"],
args: ["generate-report.js"],
cpu: { request: "100m", limit: "500m" },
memory: { request: "128Mi", limit: "256Mi" },
envs: {
REPORT_TYPE: "daily",
SMTP_PASSWORD: { secretName: "smtp", key: "password" },
},
timeoutSeconds: 3600,
},
);
console.log(report.yaml);
Os specs de cada classe (campos obrigatórios e opcionais) estão tipados: o editor mostra tudo
com autocompletar, e o código-fonte em src/ é a especificação de cada recurso.
Deploy em pipelines (forma recomendada)
A forma recomendada de aplicar recursos gerados com o kube-templates num cluster é a imagem
ghcr.io/cubos-devops/cli/k8s, do repositório
cubos-devops/cli. É uma imagem enxuta, só para deploy em
Kubernetes: traz kubectl, Node.js, ts-node, ejs-cli, o próprio @cubos/kube-templates e os
scripts cluster_from_env e deploy. Não é preciso rodar npm install no pipeline nem montar
kubeconfig à mão.
O deploy lê a pasta deploy/ do repositório da aplicação e aplica tudo com kubectl apply:
deploy/*.ts: arquivos TypeScript que exportam por padrão uma lista de recursos do kube-templates (odeployimprime o.yamlde cada item);deploy/*.yml: YAML puro, ou template EJS se tiver<% %>;deploy/*.ejs: templates EJS.
// deploy/app.ts
import { Namespace, StatelessApp } from "@cubos/kube-templates";
export default [
new Namespace({ name: "my-app" }),
new StatelessApp(
{ name: "api", namespace: "my-app" },
{
image: "my-registry/my-api:latest",
cpu: { request: "100m", limit: "500m" },
memory: { request: "128Mi", limit: "512Mi" },
ports: [{ type: "http", port: 8080 }],
},
),
];
O pacote @cubos/kube-templates é resolvido a partir da instalação que já vem na imagem, então a
versão usada no deploy é a embutida nela (definida no Dockerfile da cli).
As credenciais do cluster vêm de três variáveis com um prefixo à sua escolha (aqui CLUSTER_PRD):
CLUSTER_PRD_K8S_SERVER_URL, CLUSTER_PRD_K8S_SERVER_CA (CA em Base64) e CLUSTER_PRD_K8S_TOKEN.
Guarde-as como secrets/variáveis protegidas do CI.
GitHub Actions
A action roda cluster_from_env e depois deploy num único passo:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cubos-devops/cli@v1
with:
cluster: CLUSTER_PRD
env:
CLUSTER_PRD_K8S_SERVER_URL: ${{ secrets.CLUSTER_PRD_K8S_SERVER_URL }}
CLUSTER_PRD_K8S_SERVER_CA: ${{ secrets.CLUSTER_PRD_K8S_SERVER_CA }}
CLUSTER_PRD_K8S_TOKEN: ${{ secrets.CLUSTER_PRD_K8S_TOKEN }}
Para rodar comandos próprios contra o cluster (por exemplo kubectl get pods), use a imagem como
container do job:
jobs:
deploy:
runs-on: ubuntu-latest
container: ghcr.io/cubos-devops/cli/k8s
steps:
- uses: actions/checkout@v4
- run: |
cluster_from_env CLUSTER_PRD
deploy
env:
CLUSTER_PRD_K8S_SERVER_URL: ${{ secrets.CLUSTER_PRD_K8S_SERVER_URL }}
CLUSTER_PRD_K8S_SERVER_CA: ${{ secrets.CLUSTER_PRD_K8S_SERVER_CA }}
CLUSTER_PRD_K8S_TOKEN: ${{ secrets.CLUSTER_PRD_K8S_TOKEN }}
GitLab CI
Deploy:
stage: deploy
image: ghcr.io/cubos-devops/cli/k8s
only:
- main
script:
- cluster_from_env CLUSTER_PRD
- deploy
Todos os inputs da action e as demais imagens estão documentados no
README da cli.
Funções auxiliares
import { configFactory, env, parseMemory } from "@cubos/kube-templates";
// Lê variáveis de ambiente e lança erro descritivo se a variável não existir
const databaseUrl = env.DATABASE_URL;
// Mesmo comportamento para qualquer objeto
const config = configFactory(process.env, "Config");
const apiKey = config.API_KEY;
// Converte quantidades de memória para bytes
parseMemory("1Gi"); // 1073741824
parseMemory("256M"); // 256000000
Tipos do Kubernetes
Os tipos em src/generated são gerados a partir das especificações OpenAPI do Kubernetes e dos
CRDs usados pelas classes (npm run generate). Dá para usá-los diretamente:
import type { io } from "@cubos/kube-templates/src/generated";
const container: io.k8s.api.core.v1.Container = {
name: "my-container",
image: "nginx:latest",
};
Desenvolvimento
Pré-requisito: Node.js 24 (versão em .nvmrc).
npm ci
npm run lint # Biome
npx tsc --noEmit # checagem de tipos
npm run generate # regenera src/generated
# testes de lógica pura, sem cluster
npx vitest run tests/statelessApp tests/pgbouncer
Os demais testes (tests/cockroach, tests/postgres, tests/wordpress) são de integração:
aplicam os recursos num cluster Kubernetes local criado com kind
(tests/setup.ts lê o kind-kubeconfig e o container kube-templates-test-control-plane) e,
por isso, não rodam no CI do GitHub.
CI
O workflow ci.yml roda em pull requests e na main: lint,
type-check, testes unitários, npm audit (não bloqueante) e build.
Publicação
O pacote é publicado no npm pelo workflow publish.yml
quando uma release é publicada no GitHub:
- No GitHub, vá em Releases → Draft a new release.
- Crie uma tag no formato
vX.Y.Z(ex.:v1.1.0) apontando para amain. - Clique em Publish release.
A versão publicada no npm é a da tag, sem o v. Marcar a release como pre-release
(ex.: tag v1.2.0-rc.1) publica sob a dist-tag next em vez de latest.
A publicação usa npm Trusted Publishing (OIDC):
não há NPM_TOKEN no repositório, e cada versão sai com
provenance assinado.
Versionamento: até a migração para o GitHub as versões eram
1.0.<id do pipeline>(a última foi1.0.1153395). As versões novas seguem semver pela tag e precisam ser maiores que essa — comece emv1.1.0ou acima.