Skip to content

Image Management

Build and push the flaude Docker image to Fly.io's container registry.

ensure_image async

ensure_image(app_name, *, tag=DEFAULT_TAG, token=None, docker_context=None, build_timeout=600, push_timeout=600)

Build, authenticate, and push the flaude Docker image in one call.

This is the high-level convenience function that orchestrates the full image lifecycle: build → login → push.

Parameters:

Name Type Description Default
app_name str

The Fly.io app name.

required
tag str

Image tag. Defaults to latest.

DEFAULT_TAG
token str | None

Explicit Fly API token for registry auth.

None
docker_context Path | None

Override the Docker build context directory.

None
build_timeout float

Max seconds for the build step.

600
push_timeout float

Max seconds for the push step.

600

Returns:

Type Description
str

The full image reference (e.g. registry.fly.io/my-app:latest).

Raises:

Type Description
ImageBuildError

If any step in the pipeline fails.

Source code in flaude/image.py
async def ensure_image(
    app_name: str,
    *,
    tag: str = DEFAULT_TAG,
    token: str | None = None,
    docker_context: Path | None = None,
    build_timeout: float = 600,
    push_timeout: float = 600,
) -> str:
    """Build, authenticate, and push the flaude Docker image in one call.

    This is the high-level convenience function that orchestrates the full
    image lifecycle: build → login → push.

    Args:
        app_name: The Fly.io app name.
        tag: Image tag. Defaults to ``latest``.
        token: Explicit Fly API token for registry auth.
        docker_context: Override the Docker build context directory.
        build_timeout: Max seconds for the build step.
        push_timeout: Max seconds for the push step.

    Returns:
        The full image reference (e.g. ``registry.fly.io/my-app:latest``).

    Raises:
        ImageBuildError: If any step in the pipeline fails.
    """
    image = await docker_build(
        app_name, tag=tag, docker_context=docker_context, timeout=build_timeout
    )
    await docker_login_fly(token=token)
    await docker_push(app_name, tag=tag, timeout=push_timeout)
    return image

docker_build async

docker_build(app_name, *, tag=DEFAULT_TAG, platform='linux/amd64', docker_context=None, timeout=600)

Build the flaude Docker image and tag it for Fly's registry.

Parameters:

Name Type Description Default
app_name str

The Fly.io app name (used in the image tag).

required
tag str

Image tag. Defaults to latest.

DEFAULT_TAG
platform str

Target platform for the image. Defaults to linux/amd64 (required by Fly.io).

'linux/amd64'
docker_context Path | None

Path to the directory containing the Dockerfile. Defaults to the flaude/ directory in the project root.

None
timeout float

Max seconds to wait for the build. Defaults to 600 (10 min).

600

Returns:

Type Description
str

The full image reference (e.g. registry.fly.io/my-app:latest).

Raises:

Type Description
ImageBuildError

If the docker build command fails.

Source code in flaude/image.py
async def docker_build(
    app_name: str,
    *,
    tag: str = DEFAULT_TAG,
    platform: str = "linux/amd64",
    docker_context: Path | None = None,
    timeout: float = 600,
) -> str:
    """Build the flaude Docker image and tag it for Fly's registry.

    Args:
        app_name: The Fly.io app name (used in the image tag).
        tag: Image tag. Defaults to ``latest``.
        platform: Target platform for the image. Defaults to ``linux/amd64``
            (required by Fly.io).
        docker_context: Path to the directory containing the Dockerfile.
            Defaults to the ``flaude/`` directory in the project root.
        timeout: Max seconds to wait for the build. Defaults to 600 (10 min).

    Returns:
        The full image reference (e.g. ``registry.fly.io/my-app:latest``).

    Raises:
        ImageBuildError: If the docker build command fails.
    """
    context = docker_context or _DEFAULT_DOCKER_CONTEXT
    image = _image_ref(app_name, tag)

    if not Path(context).is_dir():
        raise ImageBuildError(
            f"Docker context directory does not exist: {context}",
            returncode=None,
            stderr="",
        )

    dockerfile = Path(context) / "Dockerfile"
    if not dockerfile.is_file():
        raise ImageBuildError(
            f"Dockerfile not found at: {dockerfile}",
            returncode=None,
            stderr="",
        )

    logger.info(
        "Building Docker image %s from %s (platform=%s)", image, context, platform
    )
    await _run_subprocess(
        ["docker", "build", "--platform", platform, "-t", image, "."],
        cwd=context,
        timeout=timeout,
    )

    logger.info("Docker image built: %s", image)
    return image

docker_push async

docker_push(app_name, *, tag=DEFAULT_TAG, timeout=600)

Push the flaude Docker image to Fly.io's container registry.

The image must already be built (via :func:docker_build).

Parameters:

Name Type Description Default
app_name str

The Fly.io app name.

required
tag str

Image tag. Defaults to latest.

DEFAULT_TAG
timeout float

Max seconds to wait for the push. Defaults to 600 (10 min).

600

Returns:

Type Description
str

The full image reference that was pushed.

Raises:

Type Description
ImageBuildError

If the docker push command fails.

Source code in flaude/image.py
async def docker_push(
    app_name: str,
    *,
    tag: str = DEFAULT_TAG,
    timeout: float = 600,
) -> str:
    """Push the flaude Docker image to Fly.io's container registry.

    The image must already be built (via :func:`docker_build`).

    Args:
        app_name: The Fly.io app name.
        tag: Image tag. Defaults to ``latest``.
        timeout: Max seconds to wait for the push. Defaults to 600 (10 min).

    Returns:
        The full image reference that was pushed.

    Raises:
        ImageBuildError: If the docker push command fails.
    """
    image = _image_ref(app_name, tag)

    logger.info("Pushing Docker image %s", image)
    await _run_subprocess(
        ["docker", "push", image],
        timeout=timeout,
    )

    logger.info("Docker image pushed: %s", image)
    return image

docker_login_fly async

docker_login_fly(*, token=None)

Authenticate Docker to Fly.io's container registry.

Uses flyctl auth docker which configures Docker credentials for registry.fly.io. Requires FLY_API_TOKEN to be set or passed.

Parameters:

Name Type Description Default
token str | None

Explicit Fly API token. If not provided, uses FLY_API_TOKEN from the environment.

None

Raises:

Type Description
ImageBuildError

If authentication fails.

Source code in flaude/image.py
async def docker_login_fly(*, token: str | None = None) -> None:
    """Authenticate Docker to Fly.io's container registry.

    Uses ``flyctl auth docker`` which configures Docker credentials for
    ``registry.fly.io``. Requires FLY_API_TOKEN to be set or passed.

    Args:
        token: Explicit Fly API token. If not provided, uses FLY_API_TOKEN
            from the environment.

    Raises:
        ImageBuildError: If authentication fails.
    """
    env: dict[str, str] = {}
    if token:
        env["FLY_API_TOKEN"] = token

    logger.info("Authenticating Docker with Fly.io registry")
    await _run_subprocess(["flyctl", "auth", "docker"], env=env)
    logger.info("Docker authenticated with registry.fly.io")

ImageBuildError

ImageBuildError(message, returncode=None, stderr='')

Bases: Exception

Raised when the Docker image build or push fails.

Attributes:

Name Type Description
returncode

The process exit code from the failed command, or None if the failure occurred before the process started (e.g. missing file).

stderr

Captured stderr output from the failed command (may be empty).

Source code in flaude/image.py
def __init__(self, message: str, returncode: int | None = None, stderr: str = ""):
    self.returncode = returncode
    self.stderr = stderr
    super().__init__(message)