@datocms/cubo
v0.2.55
Published
An Heroku-like CLI wrapper over kubectl on AWS
Keywords
Readme
Cubo CLI
Cubo is an opinionated CLI designed to simplify the deployment and management of containerized applications on AWS EKS. It serves as a local or CI/CD automation tool—your cluster remains lean, running only plain Kubernetes resources and your app.
With a "convention over configuration" approach, Cubo reads a single JSON manifest (cubo.json5) to:
- Build and deploy your app:
- Support multiple environments targeting different clusters
- Choose between rolling or recreate deployment strategies
- Wrap common
kubectlcommands with a Heroku-like developer experience:- Run remote commands (
cubo runandcubo run:detached) - Toggle maintenance mode (
cubo maintenance:onandcubo maintenance:off) - Manage processes (
cubo ps:scale,cubo ps:restart, etc.) - Manage environment variables (
cubo config:set,cubo config:unset, etc.) - View/filter logs (
cubo logs)
- Run remote commands (
Cronjobs do not have a timeout (NEED CHECK)
One-off jobs (cubo run) have a timeout of 2 hours by default (look at src/subcommands/run.ts)
Detached one-off jobs (cubo run:detached) have a timeout of 5 hours by default (look at src/subcommands/run:detached.ts)
How a deploy works
In one sentence: cubo deploy pushes the image to your registry, then declares a Deployment (pointing at that image's digest) to the EKS API server via kubectl apply; Kubernetes then pulls the image onto its own nodes and rolls out new pods to match.
Cubo's machine (your laptop or a CI runner) only ever builds + pushes to the registry and sends manifests to the API server. The cluster does the actual pulling and running — so the deploy never depends on the machine that triggered it once the push is done. The steps:
- Build & push — builds the image and
docker pushes it to the registry, then resolves its immutablesha256:…digest. - Authenticate —
aws eks update-kubeconfigwrites a temporary kubeconfig; the caller's AWS IAM identity is what grants access to the cluster. - Render manifests — builds typed Kubernetes resources (Deployment, Service, Ingress, ConfigMap, secrets, HPA, …) with the container
imagepinned to the digest from step 1. - Apply —
kubectl apply --prunestores them as the cluster's new desired state (and removes cubo-managed resources no longer present). - Reconcile — Kubernetes sees the changed pod template, and each node's kubelet pulls the image (using the registry-credential secret) and rolls out new pods per the chosen strategy.
- Wait & tag —
kubectl rollout statusblocks until the rollout is healthy, then thelatest-<env>/previous-<env>registry tags are updated.
K8S requirements
To support Cubo deployments, your EKS Kubernetes cluster must have the following components installed:
- KEDA: Enables event-driven autoscaling based on external metrics.
- External Secrets: Manages secrets by syncing them from AWS Secrets Manager.
What You Can Do
Cubo allows you to define and manage different types of workloads:
- HTTP servers: Exposed via AWS ALB, with optional autoscaling (CPU or queue-time based)
- Workers: Long-running services with autoscaling (CPU or custom metrics, like queue latency)
- Cron jobs: Schedule recurring tasks with safe concurrency controls
- TCP/UDP servers: Exposed via AWS NLB for lower-level protocols
Installation
$ npm i --save-dev @datocms/cubo
$ cubo --helpConfiguration via cubo.json5
All configuration for your deployment is handled through a single cubo.json5 file. This file defines how your services are built, deployed, and scaled.
To see all available configuration options and their structure, refer to the JSON Schema:
{
"$schema": "https://unpkg.com/@datocms/cubo@<VERSION>/schemas/cubo-config-schema.json",
// ...
}Secrets Management
Cubo integrates AWS Secrets Manager and the External Secrets Operator to keep your environment variables secure and out of your codebase.
- Create an AWS Secret with the exact name of your Kubernetes namespace (as defined by
environment.kubernetes.namespacein your Cubo config). - Store your environment variables as a top-level JSON object in the secret.
- Include a
.dockerconfigjsonkey with your Docker auth JSON if pulling from private registries.
queueTime Scale Strategy
For deployments classified as web, you can implement a scaling strategy based on request queue times. When a request reaches your application, it will include the X-Request-Start header, indicating when the request first entered the proxy queue.
Your application must respond with an X-Queue-Time header. This value should represent the time difference between the current server time and the timestamp provided in X-Request-Start, effectively measuring how long the request waited in the queue.
These queue times are emitted as a StatsD metric via UDP, using the following format:
cloudwatch.cubo.http_queue_time.namespace.${environment.kubernetes.namespace}.deployment.${deploymentName}.storage-resolution.1The StatsD server aggregates these values into a 30-second average, and forwards the result to CloudWatch. From there, a KEDA ScaledObject uses the queue time data to automatically scale your application based on traffic pressure.
api Scale Strategy
For deployments classified as background, you can implement a scaling strategy based on custom application metrics (such as queue latency). Your application must expose a JSON endpoint that provides the relevant metric.
A KEDA ScaledObject will periodically query this endpoint and use the reported value to drive autoscaling decisions, allowing your background processes to scale dynamically in response to workload demands.
Deploying from your machine
Deploys normally run from CI, but you can run cubo deploy from your own machine (e.g. to ship a hotfix when CI is down). It's a real deploy: it pushes to the shared registry and rolls out to the cluster, exactly like CI.
Prerequisites:
- Required tools on your
PATH:aws(AWS CLI),kubectl, anddocker(with buildx). The AWS CLI is used both to generate the kubeconfig and to mint a token on everykubectlcall (the kubeconfig embeds anaws eks get-tokenexec plugin), so it must stay available throughout the deploy. - AWS credentials with EKS access (cubo runs
aws eks update-kubeconfigunder the hood). - Registry login so the
docker pushsucceeds, e.g.docker login ghcr.io. - A
GITHUB_SHAenv var. CI sets this automatically; locally you provide it. It is only used as a label in the image tag — it does not control what gets built (the build context is your working directory, including uncommitted changes), so make sure your tree is clean if you want the tag to be truthful.
$ GITHUB_SHA="$(git rev-parse HEAD)" cubo deploy \
--env staging3 --strategy rolling --no-cache-storagePass --no-cache-storage so the build skips the local-dir buildx cache backend, which would otherwise require the docker-container buildx driver (CI sets that up; a default local Docker install does not). See How a deploy works for what happens after the push.
Development
To publish a new cubo version:
$ npTo test the current code, run
$ npm run build && \
rm -rf /Users/<USER>/<SITE_API_REPO>/node_modules/@datocms/cubo/dist && \
cp -rf dist /Users/<USER>/<SITE_API_REPO>/node_modules/@datocms/cubo && \
cp -f bin/cubo.mjs /Users/<USER>/<SITE_API_REPO>/node_modules/@datocms/cubo/bin/Then cd into the /Users/<USER>/<SITE_API_REPO> path and to test a deploy command on staging3 (for instance):
$ cubo deploy --env staging3 --release-tag latest-staging3 --skip-tagging