About images
Configure default container images for collectors, policies, and catalogers in lunar-config.yml, with override precedence rules.
Lunar supports running collectors, policies, and catalogers inside Docker containers. This provides isolation, reproducibility, and simplifies dependency management. Default images can be configured at multiple levels, with more specific settings overriding more general ones.
Image Resolution Order
The image used to run a script is determined in the following order (first match wins):
Script-level
image- Set directly on the collector, policy, or catalogerPlugin-level default - Set in
lunar-collector.yml,lunar-policy.yml, orlunar-cataloger.ymlGlobal default - Set in
lunar-config.ymlImplicit default -
native(no container)
Once an image has been resolved, the image_replace rules — if any are configured — are applied to the result.
Global Default Images
Configure default images in lunar-config.yml:
version: 0
default_image: my-custom-image:alpine-1.2.3
default_image_ci_collectors: native
default_image_non_ci_collectors: my-image:v1.0
default_image_policies: another-image:latest
default_image_catalogers: yet-another-image:v2.0
# ... rest of configurationdefault_image
lunar-config.yml -> default_imageType:
stringOptional
Default:
native
The global default image to use for all collectors, policies, and catalogers. This is overridden by the more specific default_image_* settings.
default_image_ci_collectors
lunar-config.yml -> default_image_ci_collectorsType:
stringOptional
Default: value of
default_image
The default image for CI collectors (collectors with hooks of type ci-before-command, ci-after-command, ci-before-job, ci-after-job). It is common to set this to native since CI collectors often need direct access to the CI environment.
default_image_non_ci_collectors
lunar-config.yml -> default_image_non_ci_collectorsType:
stringOptional
Default: value of
default_image
The default image for non-CI collectors (collectors with hooks of type code, cron).
default_image_policies
lunar-config.yml -> default_image_policiesType:
stringOptional
Default: value of
default_image
The default image for all policies.
default_image_catalogers
lunar-config.yml -> default_image_catalogersType:
stringOptional
Default: value of
default_image
The default image for all catalogers.
Plugin-Level Default Images
Plugins can define their own default images that override the global settings. This is useful when a plugin requires specific dependencies that are pre-installed in a custom image.
In lunar-collector.yml, lunar-policy.yml, or lunar-cataloger.yml:
The same settings are available as at the global level. Plugin-level defaults override global defaults but are overridden by script-level image settings.
Script-Level Image
Each individual collector, policy, or cataloger can specify its own image to override all defaults:
The native Value
The special value native explicitly opts out of containerized execution. When image: native is set, the script runs directly on the host system using the native runtime (Python, Bash, etc.).
This is useful when:
A default image has been configured, but a specific script needs to run natively
CI collectors need direct access to the CI environment
The script needs access to host-specific resources
Rewriting Image References
Some clusters only permit images from an approved registry. image_replace rewrites image references after they have been resolved, so you can point every image at an internal mirror without owning the plugins that declare them.
This rewrites earthly/lunar-scripts:1.1.5 to 111122223333.dkr.ecr.us-east-1.amazonaws.com/docker.io/earthly/lunar-scripts:1.1.5.
Because the rules run after resolution, they apply to every image the configuration produces — including images set by an imported plugin's default_image, which you cannot otherwise override from a consumer config.
image_replace
lunar-config.yml -> image_replaceType:
listOptional
Each entry takes:
from_pattern
A Go regular expression matched against the resolved image. Required.
to
The replacement. May reference capture groups from from_pattern as $1, $2, … A literal $ must be written $$.
Rules are evaluated in order and the first matching rule wins — later rules are not applied to an already-rewritten image, so two rules sharing a prefix cannot compound into a doubled registry path.
Patterns are unanchored, matching the other pattern-valued settings in lunar-config.yml. Anchor a registry prefix explicitly with ^:
$ means end of text in a regular expression, not "starts with". A pattern written $earthly/ is valid and will simply never match anything. Lunar logs a warning for any image_replace rule that matched no images during a pull, which is the quickest way to catch this.
The native value is never rewritten. It names an execution mode rather than an image, so a broad pattern cannot accidentally containerize a script that is meant to run natively.
image_replace may be set in only one configuration document. Because the first matching rule wins, splitting the list across multiple config files would make a rule's precedence depend on the order the files happen to merge in.
Common Configuration Pattern
A common configuration is to use containers for most scripts but run CI collectors natively:
This configuration:
Runs all policies in containers
Runs all catalogers in containers
Runs non-CI collectors (code, cron, repo hooks) in containers
Runs CI collectors natively for direct access to CI environment variables and tools
Official Image: earthly/lunar-scripts
Lunar provides an official Docker image earthly/lunar-scripts that includes:
Alpine Linux (or
-debianvariant for tools requiring glibc)Python 3 with venv
Bash
The
lunar-policyPython packageThe
lunarCLICommon tools:
jq,yq,curl,parallel,wget
Dependency Handling
The official earthly/lunar-scripts image automatically executes any requirements.txt and/or install.sh files it finds in the plugin directory as part of its entrypoint. This is a convenience feature to help you get up and running quickly during development.
For production use, we recommend baking all dependencies directly into your image. This approach provides:
Faster startup times (no runtime installation)
Reproducible builds
Better caching and smaller attack surface
Elimination of network dependencies at runtime
Recommended Approach: Custom Image Inheriting from Official
The recommended approach is to create a custom Dockerfile that inherits from the official earthly/lunar-scripts image and installs your dependencies at build time:
This pattern gives you all the benefits of the official image (Python, Bash, lunar CLI, lunar-policy package) while ensuring your dependencies are baked in for production use.
Image Entrypoint Contract
Lunar executes snippets by passing two arguments to the image's entrypoint:
$1
The snippet language
python, bash
$2
Absolute path to the main script file
/app/exec/main.py
The entrypoint is responsible for invoking the correct language runtime on the given script. The official earthly/lunar-scripts image ships an entrypoint at /app/entrypoint.sh that handles this automatically.
Requirements for Custom Images
If you build a custom image, it must meet these requirements:
Entrypoint at
/app/entrypoint.shthat accepts(language, script_path)as$1and$2. The simplest implementation:
Language runtime on
PATH— the binary matching the snippet's language must be available:
Python
python
Bash
bash
Many base images ship python3 without a python symlink. Ensure python resolves correctly (e.g., RUN ln -sf /usr/bin/python3 /usr/bin/python). The official earthly/lunar-scripts image handles this automatically.
The recommended approach is to inherit from the official image, which satisfies both requirements out of the box:
How Execution Works
Both the Docker engine (local development) and the Kubernetes operator use the same entrypoint contract. Lunar passes [language, script_path] as arguments to the container, and the image's entrypoint handles dispatching to the correct runtime.
This means a custom image tested locally via the Docker engine will behave identically when deployed to Kubernetes — the entrypoint runs in both environments with the same arguments.
Mount Points
The following directories are available inside the container in both Docker and Kubernetes execution modes:
/app/exec
Plugin directory — script and plugin files
/app/work
Working directory — the component's code (for collectors and some catalogers)
/app/lib
Library directory — bundle data for policies
The container's working directory is set to /app/work, so your scripts can access the component's files using relative paths. The LUNAR_PLUGIN_ROOT environment variable is set to /app/exec.
Private Registry Authentication
To pull images from private Docker registries, configure the following environment variables:
LUNAR_DOCKER_REGISTRY_USER- Username for Docker registry authenticationLUNAR_DOCKER_REGISTRY_PASS- Password or token for Docker registry authentication
Last updated
