Skip to content

Seed bind mounts from image content when host path is empty #139

@nfebe

Description

@nfebe

Problem

Bind mounts only go one way. When a host path is mounted over a container path that the image populates, the image content is obscured, never copied out (Docker docs: "the pre-existing files are obscured by the mount", https://docs.docker.com/engine/storage/bind-mounts/). Named volumes get copy-on-first-use semantics (https://docs.docker.com/engine/storage/volumes/), but FlatRun is bind-mounts only, so we lose that.

Today the agent just creates empty dirs before compose up (internal/docker/discovery.go:315-319) and only the parent dir for file mounts (internal/docker/discovery.go:306). No image-to-host seeding exists anywhere in the agent.

Why it matters

Current templates are unaffected: the WordPress, Nextcloud, and Ghost entrypoints all self-populate an empty mount. The gaps are:

  1. Single-file config mounts. Mounting ./nginx.conf:/etc/nginx/nginx.conf with no host file makes the daemon create a directory at that path ("It's always created as a directory", bind mounts doc), so the container gets a directory where a file should be and crashes.
  2. Arbitrary user compose files. Images whose entrypoints do not self-populate leave the user with an empty dir or a broken app.

Seeding also serves the flat-file philosophy: configs become visible and editable on the host.

Proposal

Opt-in per-mount seeding (seed: true in template metadata, and optionally a deploy-time flag). When the host path is empty or missing:

  1. ContainerCreate the image without starting it
  2. CopyFromContainer the container path as a tar
  3. Extract to the host path (tar preserves ownership and modes)
  4. Remove the temp container

Only seed empty targets, mirroring named-volume semantics, so existing user data is never overwritten.

Costs

One image pull plus a temp container per seeded mount; large directories double first-deploy I/O.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions