Skip to main content
Type: rvn-eks-worker · Latest version: 0.4.0

Dependencies and consumers

Every dependency input can be specified manually to reference existing external infrastructure rather than a Ravion module.

Readme

Background worker on EKS for running a long-lived private process with no exposed port, and no Kubernetes manifests or Helm charts to write.

Overview

EKS Worker runs queue consumers, event processors, and other long-lived background processes on an existing Ravion EKS cluster. Point it at a Git repository or an image you already have, set the start command, resources, and pod count in a form, and Ravion builds the image and keeps the process running on your cluster. There are no Kubernetes manifests to write and no Helm charts to maintain. Under the hood, each deploy installs a Helm chart that Ravion maintains - a packaged template of the Kubernetes resources a worker needs. The rvn-eks-worker chart renders the Deployment that runs your pods, a ServiceAccount, an optional HorizontalPodAutoscaler, and, when the module declares runtime secrets, an ExternalSecret. Each release runs helm upgrade --install --atomic, so a failed deploy rolls back to the previous revision on its own. The chart deliberately includes no Service, no container port, and no probes. A worker is reached by nothing; it reaches out. The Terraform stack creates the ECR repository that Dockerfile and Railpack builds push to and, when Fargate is selected, a workload-specific EKS Fargate profile and pod execution role. On the Pull from image registry path with automatic or EC2 compute, the stack creates no AWS resources. Everything else the module needs - cluster endpoint, certificate authority data, private subnet IDs, and the Ravion Runner role - comes from the selected EKS Cluster module. Chart source: ravionhq/modules/charts/rvn-eks-worker Terraform source: ravionhq/modules/compute/eks_service

Use cases

Prerequisites

  • An EKS Cluster module.
  • The External Secrets Operator add-on on that cluster, if the worker uses Runtime secrets.

Build and image options

For Dockerfile and Railpack builds, provide Git repository and optionally Source base path. The stack creates an ECR repository named after the worker, Ravion pushes each build to it, and the chart deploys the resulting digest. Nodes pull from same-account ECR with their own credentials, so no pull secret is involved. A worker built with Railpack often shares a repository with the web service in front of it. Railpack’s detected start command is rarely the worker’s command, so set the worker’s entrypoint below rather than relying on the image default. Use Build environment variables for values the build itself needs - a private registry token, a NODE_ENV that changes what gets compiled. Values can be plain strings or references loaded from Parameter Store or Secrets Manager. For Dockerfile builds, turn on Inject environment variables in Dockerfile to pass them to the build as Docker build arguments; without it they are visible to the builder but not to docker build. These are separate from Runtime environment variables further down, and deliberately so: a credential needed to install dependencies has no business being in the running pod’s environment. Anything both halves need has to be set in both places. For Pull from image registry, provide the Image repository without a tag, and use Image pull secret names for a private registry - each entry names a Kubernetes Secret of type kubernetes.io/dockerconfigjson that already exists in the release namespace. Whichever source you choose, the deploy takes an Image tag or digest. A value beginning with sha256: is used as a digest and everything else as a tag. Workers usually need a command: use Start command to override the image entrypoint and Start command arguments to override its default arguments. For example, entrypoint bundle with arguments exec sidekiq.

Builder settings

Builder settings apply to Dockerfile and Railpack builds only. Scan images on push asks ECR to run its basic vulnerability scan on every pushed image. Force delete image repository lets the repository be destroyed while it still holds images; without it, destroying the module fails until the repository is emptied.

Resources and scaling

Kubernetes schedules on requests and enforces on limits. CPU is measured in cores or millicores: 1 is one vCPU and 100m is a tenth of one. Memory uses binary units: 256Mi, 1Gi (1024Mi). Fargate creates a dedicated profile matching this worker’s namespace and standard app instance label. Fargate pods launch only in the selected cluster’s private subnets and use on-demand capacity; EKS Fargate does not offer Spot pricing. Choose EC2 Spot instead when interruption tolerance and lower compute cost matter more than serverless pod placement. Autoscaling is off by default, unlike the web module. CPU utilization is a poor proxy for worker demand: a worker blocked on a queue poll uses almost no CPU no matter how deep the backlog. Enable it when the work is genuinely CPU-bound, and prefer a fixed pod count otherwise. Shutdown grace period (secs) is the window a pod gets after SIGTERM to finish in-flight work before it is killed. The default of 30 seconds suits short tasks. Raise it to at least the length of your longest job, or a rollout will kill work mid-flight.

Zone placement

Worker pods are spread across the cluster’s availability zones with a soft topology.kubernetes.io/zone spread constraint, so a small cluster never leaves pods pending. Combined with the zone-local routing the EKS Web Service and EKS Cluster modules apply, a worker’s calls to other services and to DNS stay inside its own zone whenever a destination pod exists there, which keeps AWS cross-AZ data transfer charges off that traffic.

Application configuration

Use Runtime environment variables for plain values, as an array of {name, value} objects. Use Runtime secrets for sensitive values, as an array of {name, value_from} objects - the same shape as ECS. value_from must be a full Secrets Manager or SSM Parameter Store ARN, including the JSON-key extraction suffix when you want a single key out of a JSON secret. Ravion never reads these values. The ARNs travel to the chart as references, the chart renders an ExternalSecret, and the External Secrets Operator materializes the Kubernetes Secret in the cluster. No secret value reaches Ravion, the Helm values document, or the Helm release history.

Deployment

Every deploy runs helm upgrade --install --atomic, so a release either lands completely or leaves the cluster on the previous revision. Pods roll with the chart’s RollingUpdate strategy, which surges 25% and keeps zero pods unavailable. Deployments collapse: if several are queued, only the newest runs.

Metrics and logs

The Metrics and Logs tabs follow the providers selected on the EKS add-ons module referenced above. You configure observability once, on that module, and every workload attached to it follows; there is nothing to set here. Without an add-ons reference both tabs stay empty. Where several providers can serve the same signal they form a fallback chain, not a merge. The tab reads the first store that can answer right now and moves to the next when it cannot, saying which store it ended up using. Reading two stores at once would draw every line twice. The practical effect is that the in-cluster store’s one weakness stops being fatal. Loki is reached through the Ravion Operator, so with the agent offline those logs are unavailable - but if CloudWatch Logs is also selected, the tab shows CloudWatch and says so, then switches back when the agent returns. Charts are the same five golden signals whichever store answers: CPU, memory working set, container restarts, network in, and network out. Two things differ on the CloudWatch link of the chain, and are worth knowing before you read a number off it:
  • Container Insights reports per pod, Prometheus reports across pods. A CloudWatch chart is an average over the worker’s pods; the Prometheus charts sum them. Same shape, different magnitude.
  • It needs enhanced observability, which the add-ons module turns on with CloudWatch by default. Without it, CPU and memory come back empty.
Replicas available and desired have no CloudWatch equivalent. Container Insights’ nearest metric counts pods behind a Kubernetes Service, and a worker renders no Service, so with CloudWatch as the only metrics provider those two charts are empty while the pod charts still work. A provider that ships to a vendor rather than rendering in Ravion - Datadog, Grafana Cloud, New Relic, OpenSearch, Splunk, or a custom OTLP endpoint - adds an Open in … action to the tab, pointing at this worker rather than at the vendor’s front page. Turning a signal off on the add-ons module empties the matching tab here.

Configuration

Design decisions

  • Terraform owns AWS-side workload infrastructure. The worker itself is Helm-owned; the stack creates an ECR repository when Ravion builds the image and a dedicated EKS Fargate profile when Fargate is selected. With a pulled image and automatic or EC2 compute, it creates nothing.
  • No Nixpacks. ECS still carries a Nixpacks build source for services created before Railpack existed. EKS has no such history, so Dockerfile and Railpack are the only builders.
  • No Service and no probes. A worker exposes no port, so there is nothing to route to and no HTTP endpoint to check. Liveness for a worker is better expressed by letting the process exit on a fatal error and letting Kubernetes restart it.
  • Autoscaling defaults off. CPU utilization rarely tracks worker demand. Turning it on by default would produce autoscaling that looks configured but never fires.
  • Name and namespace are fixed after creation. Together they identify the Helm release that rollback and history target.
  • Pod Identity, not IRSA. The chart emits a stable ServiceAccount name and no role annotation, so an aws_eks_pod_identity_association can bind an IAM role to it by namespace and name.

Learn more

Inputs reference

All inputs for rvn-eks-worker version 0.4.0. Use the name shown for each field as the input key in module config.

EKS cluster

$ref:rvn-eks-cluster
required
Cluster.
  • Immutable after creation
$ref:rvn-eks-addons
EKS add-ons. Select the EKS Add-ons module attached to the cluster above to use its observability providers in the Metrics and Logs tabs.

Worker service

string
required
Service name. Name for the Helm release and the Kubernetes objects it creates.
  • Default: <<project.given_id>>-<<environment.given_id>>-<<module.given_id>>
  • Immutable after creation
  • Pattern: ^[a-z0-9]([a-z0-9-]{0,51}[a-z0-9])?$ — 1-53 lowercase letters, numbers, and hyphens. Start and end with a letter or number.
string
required
Namespace. Kubernetes namespace the release installs into.
  • Default: <<project.given_id>>-<<environment.given_id>>
  • Immutable after creation
  • Pattern: ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ — 1-63 lowercase letters, numbers, and hyphens. Start and end with a letter or number.
boolean
Create namespace. Create the namespace if it does not already exist. Turn off when the namespace is managed elsewhere.
  • Default: true

Build config

string
required
Build source.
  • Default: dockerfile
  • Allowed values: dockerfile (Dockerfile), railpack (Railpack), image_registry (Pull from image registry)
gitrepo
required
Git repository. Repository containing the application source for Dockerfile or Railpack builds.
  • Shown when: {"build_source":["dockerfile","railpack"]}
string
Source base path. Repository-relative source and build root.
  • Default: .
  • Shown when: {"build_source":["dockerfile","railpack"]}
object
Build environment variables. Environment variables available during builds. Values can be plain strings or references loaded from Parameter Store or Secrets Manager.
  • Shown when: {"build_source":["dockerfile","railpack"]}

Docker

string
Dockerfile path. Path to the Dockerfile to use for the build, relative to the repository root or configured source base path.
  • Shown when: {"build_source":"dockerfile"}
string
Docker build context path. Directory to use as the Docker build context, relative to the repository root or configured source base path.
  • Shown when: {"build_source":"dockerfile"}
boolean
Inject environment variables in Dockerfile. Pass build environment variables into Dockerfile builds as build arguments.
  • Default: false
  • Shown when: {"build_source":"dockerfile"}

Railpack

string
Railpack version. Optional Railpack version to use for the build. Leave blank to use the Ravion default.
  • Pattern: ^(|latest|v?[0-9]+\.[0-9]+\.[0-9]+(?:[-+][0-9A-Za-z.-]+)?)$ — Leave blank, use latest, a semantic version like 0.29.0, or a v-prefixed version like v0.29.0.
  • Shown when: {"build_source":"railpack"}
string
Install command. Optional dependency installation command. Leave blank to use Railpack detection.
  • Shown when: {"build_source":"railpack"}
string
Build command. Optional application build command. Leave blank to use Railpack detection.
  • Shown when: {"build_source":"railpack"}
string
Start command.
  • Shown when: {"build_source":"railpack"}

Image

string
required
Image repository. Image repository without a tag, such as 123456789012.dkr.ecr.us-east-1.amazonaws.com/api. The tag or digest is supplied at deploy time.
  • Shown when: {"build_source":"image_registry"}
string_array
Image pull secret names. Names of existing kubernetes.io/dockerconfigjson Secrets in the release namespace, for private registries.
  • Shown when: {"build_source":"image_registry"}
string_array
Start command. Overrides the image entrypoint. Leave empty to use the image default.
string_array
Start command arguments. Overrides the image default arguments. Leave empty to use the image default.

Resources

string
required
Compute target. Choose whether Kubernetes schedules this workload automatically, on a specific EC2 capacity type, or on a dedicated EKS Fargate profile. EKS Fargate capacity is on-demand only.
  • Default: any
  • Allowed values: any (Automatic), on_demand (EC2 on-demand), spot (EC2 Spot), fargate (Fargate)
string
required
CPU request. CPU reserved for the pod and its guaranteed share under load. 1 is one vCPU; m is thousandths of a core, so 100m is a tenth. Autoscaling CPU targets are a percentage of this value.
  • Default: 100m
  • Pattern: ^[0-9]+(\.[0-9]+)?m?$ — A CPU quantity such as 100m, 0.5, or 2.
string
CPU limit. Optional CPU ceiling, in the same units. Leave blank to let a pod burst into spare node CPU.
  • Pattern: ^[0-9]+(\.[0-9]+)?m?$ — A CPU quantity such as 100m, 0.5, or 2.
string
required
Memory request. Memory reserved for the pod, in binary units such as 256Mi or 1Gi (1024Mi). Set this close to steady-state usage.
  • Default: 256Mi
  • Pattern: ^[0-9]+(\.[0-9]+)?(Ki|Mi|Gi|Ti|k|M|G|T)?$ — A memory quantity such as 256Mi, 1Gi, or 512M.
string
required
Memory limit. Memory ceiling, in the same units. Exceeding it terminates the container with OOMKilled, so set it above the worst legitimate spike.
  • Default: 512Mi
  • Pattern: ^[0-9]+(\.[0-9]+)?(Ki|Mi|Gi|Ti|k|M|G|T)?$ — A memory quantity such as 256Mi, 1Gi, or 512M.

Scaling

boolean
Autoscaling. Scale pods with a HorizontalPodAutoscaler. Requires the metrics server or an equivalent metrics API in the cluster.
  • Default: false
number
Minimum pods.
  • Default: 1
  • Min: 1
  • Max: 1000
  • Shown when: {"autoscaling_enabled":true}
number
Maximum pods.
  • Default: 3
  • Min: 1
  • Max: 1000
  • Shown when: {"autoscaling_enabled":true}
number
CPU target (%). Average CPU utilization, as a percentage of the CPU request, the autoscaler aims to hold.
  • Default: 70
  • Min: 1
  • Max: 100
  • Shown when: {"autoscaling_enabled":true}
number
Memory target (%). Optional average memory utilization target, as a percentage of the memory request. Leave blank to scale on CPU alone.
  • Min: 1
  • Max: 100
  • Shown when: {"autoscaling_enabled":true}
number
Pods. Number of worker pods to run when autoscaling is disabled.
  • Default: 1
  • Min: 0
  • Max: 1000
  • Shown when: {"autoscaling_enabled":false}
number
Shutdown grace period (secs). Seconds a pod has to finish in-flight work after SIGTERM before it is killed. Raise this for workers with long-running jobs.
  • Default: 30
  • Min: 0
  • Max: 3600

Environment variables

array
Runtime environment variables. Plain environment variables passed to the container, as an array of {name, value} objects.
array
Runtime secrets. Secret references injected at runtime, as an array of {name, value_from} objects. value_from must be a full Secrets Manager or SSM Parameter Store ARN. Ravion never reads these values; the External Secrets Operator resolves them inside the cluster.

Builder config

string
required
Builder capacity type. Use on-demand EC2 for predictable availability or EC2 Spot for lower cost with possible capacity delays or interruption.
  • Default: ec2
  • Allowed values: ec2 (EC2), ec2-spot (EC2 spot)
  • Shown when: {"build_source":["dockerfile","railpack"]}
string
required
Builder instance type. EC2 instance type for builds. Start with the default value, then increase or decrease it based on the resource usage report at the end of builds.
  • Default: c7a.4xlarge
  • Shown when: {"build_source":["dockerfile","railpack"]}
string
Builder execution environment. Optional execution environment ID or given ID for builds. Defaults to the module Terraform execution environment.
  • Shown when: {"build_source":["dockerfile","railpack"]}
string
Builder AMI. Optional AMI ID for build runners. Leave empty to use the default runner image.
  • Shown when: {"build_source":["dockerfile","railpack"]}
boolean
Include default build policies. The step’s built-in policies (ECR/S3 access, CloudWatch agent) stay attached alongside your Builder IAM policies. Turn off to run the build with only the policies listed below.
  • Default: true
  • Shown when: {"build_source":["dockerfile","railpack"]}
string_array
Builder IAM policies. IAM managed policy ARNs for the EC2 build runner role, applied for the duration of each build.
  • Default: []
  • Shown when: {"build_source":["dockerfile","railpack"]}

Image registry lifecycle

boolean
Scan images on push. Ask ECR to run its basic vulnerability scan whenever a new image is pushed. Keep this on for early dependency and OS package findings; disable only if another scanner owns image scanning or duplicate findings are noisy.
  • Default: true
  • Shown when: {"build_source":["dockerfile","railpack"]}
boolean
Force delete image repository. Allow the ECR repository to be deleted even when it contains images. Use with care.
  • Default: false
  • Shown when: {"build_source":["dockerfile","railpack"]}

Misc

keyvalue
Tags. A map of tags to assign to all resources. Default tags are Owner, ProjectGivenId, EnvironmentGivenId, ModuleGivenId, ModuleId

Terraform settings

string
OpenTofu version override. Override the environment’s default version for this module
string
Ravion Terraform workspace name. Override Terraform state backend workspace name. Defaults to project + environment + module given ids.
  • Immutable after creation
object
Advanced Terraform variables. Optional raw Terraform variable overrides for advanced module inputs or one-off overrides. Values here override the generated variables above.
  • Default: {}