For the complete documentation index, see llms.txt. This page is also available as Markdown.

Containerization

How Kitaru builds and configures container images for remote execution

When you run a flow on a remote stack (Kubernetes, Vertex AI, SageMaker, Azure ML), Kitaru packages your code into a container image automatically. The image parameter on @flow controls how that image is built.

Default behavior

With no image configuration, Kitaru:

  1. Uses a default Python base image

  2. Installs kitaru into the container

  3. Packages your project source code (detected from the .kitaru/ project root)

This is enough for simple flows with no extra dependencies.

The image parameter

Pass image to @flow, .run(), or kitaru.configure(). It accepts an ImageSettings object or a plain dictionary:

from kitaru import flow
import kitaru

@flow(
    image=kitaru.ImageSettings(
        base_image="python:3.12-slim",
        requirements=["kitaru[pydantic-ai,openai]", "httpx"],
        apt_packages=["git"],
        environment={"MY_VAR": "value"},
    ),
)
def my_agent(topic: str) -> str:
    ...

Or as a dictionary:

Available fields

Field
Type
Description

base_image

str

Docker image to start from (e.g. python:3.12-slim)

requirements

list[str]

Python packages to install (pip format)

dockerfile

str

Path to a custom Dockerfile instead of auto-building

build_context_root

str

Root directory for the Docker build context

environment

dict[str, str]

Environment variables set inside the container (non-secret values only)

secret_environment_from

list[str]

Names/IDs of ZenML secrets whose keys are exposed as runtime environment variables during step execution

apt_packages

list[str]

System packages to install via apt

replicate_local_python_environment

bool

Mirror your local pip freeze into the container

image_tag

str

Custom tag for the built image

target_repository

str

Registry repository to push the image to (e.g. my-registry/my-repo)

user

str

OS user to run as inside the container (e.g. nonroot)

platform

str

Target platform for the Docker build (e.g. linux/amd64)

Automatic Kitaru injection

Kitaru can automatically add plain kitaru to image requirements when it builds the requirements list for you. It does not infer optional extras from packages like pydantic-ai. If your code imports a Kitaru adapter, include the matching Kitaru extra explicitly, for example kitaru[pydantic-ai,openai].

If you already include kitaru (with or without a version pin or extras), it is not duplicated:

Replicating your local environment

During development, you can mirror your entire local Python environment into the container. This runs pip freeze and installs everything so the remote container matches your dev setup exactly:

This is convenient for quick iteration but produces less reproducible builds. For production, pin explicit requirements instead.

Custom Dockerfile

For full control, point to your own Dockerfile:

When using a custom Dockerfile, you are responsible for installing Python, kitaru, and any other dependencies your flow needs.

System packages

If your flow needs OS-level tools (e.g., git, ffmpeg, poppler-utils), use apt_packages:

Setting image config at different levels

The image parameter follows the same precedence rules as other execution settings. From highest to lowest priority:

Environment variables inside the container

Use environment for non-sensitive runtime configuration such as feature flags or log levels. Values listed here are treated as literal Docker build/runtime env vars, so they are not safe for API keys, tokens, or passwords:

Secret-backed environment variables

For credentials, configure secret_environment_from with a list of ZenML secret names or IDs. Every key in each referenced secret is exposed as an environment variable during step execution, and Kitaru never copies the values into Docker build metadata:

Under the hood, Kitaru forwards the list to ZenML via Pipeline.with_options(secrets=[...]). The backend resolves the secret values at runtime, so plaintext credentials never enter your image, config files, or frozen execution spec. Secret references (names/IDs) are the only thing persisted.

Current limitations:

  • The common case is that the secret's key names already match the desired environment variable names (e.g., a secret with a OPENAI_API_KEY key is read as os.environ["OPENAI_API_KEY"]). Per-key renaming or selecting a single key from a multi-key secret is not supported yet.

  • kitaru.llm() continues to auto-resolve alias-linked secrets without needing this field; use secret_environment_from when user code or a third-party SDK needs raw environment variables.

secret_environment_from merges in list-replacement style. An override layer with a non-None list replaces the inherited list (an empty [] explicitly clears inherited references).

How source code is packaged

Kitaru detects your project root from the .kitaru/ directory created by kitaru init. Everything under that root is packaged into the container image so your flow code, local modules, and utility files are available at runtime.

Make sure you have run kitaru init in your project directory before running flows on remote stacks.

Last updated

Was this helpful?