Shipping a Python service to production

Table of Contents

I have a Python service that passed all its tests and I want to ship it. The build needs compilers and dev headers to install native dependencies, but in production I want the smallest possible image — no shell, no package manager, nothing an attacker could use. This is the classic multi-stage build: build in Debian, run in distroless.

First I set up my Dagger project and install daggerlib:

dagger init --sdk=python
dagger install github.com/Konubinix/daggerlib

The following is only for testing purposes — it makes the project use the local daggerlib checkout instead of the published version:

sed -i '/pin/d; s|"github.com/Konubinix/daggerlib@main"|"../.."|; s|"\.\./\.\.",|"../.."|' dagger.json

Here is my service — it logs a startup message with timezone info:

"""Minimal service that logs a startup message with timezone info."""
from datetime import datetime

tz = datetime.now().astimezone().tzname()
print(f"service started (timezone: {tz})")

Then I write my Dagger module. The <<run-distroless>> reference is defined further below:

from typing import Annotated

import dagger
from dagger import DefaultPath, dag, function, object_type


@object_type
class ProductionService:
    @function
    async def run_distroless(self, src: Annotated[dagger.Directory, DefaultPath(".")]) -> str:
        """Run a Python service in the distroless image."""
        return await (
            dag.lib().distroless_python3_debian()
            .with_file('/app/service.py', src.file('service.py'))
            .with_exec(['python3', '/app/service.py'])
            .stdout()
        )

1. Running the service in distroless

For my Python service, I use the distroless Python image. It ships only the Python interpreter — no pip, no shell, no debugging tools. I inject my service and run it:

@function
async def run_distroless(self, src: Annotated[dagger.Directory, DefaultPath(".")]) -> str:
    """Run a Python service in the distroless image."""
    return await (
        dag.lib().distroless_python3_debian()
        .with_file('/app/service.py', src.file('service.py'))
        .with_exec(['python3', '/app/service.py'])
        .stdout()
    )
dagger call run-distroless

Author: root

Created: 2026-04-18 Sat 21:17

Validate