Skip to content

once deploy should be idempotent and support zero-downtime replacement #47

@amiorin

Description

@amiorin

Currently once deploy <image> --host <host> fails with ErrHostnameInUse if the hostname is already in use. This makes the CLI unsuitable for automated workflows (CI/CD pipelines, deployment scripts) where the same command is expected to be re-runnable safely.

The TUI already has the right behaviour: when you change settings for a running app, it performs a zero-downtime replacement — start the new container, wait for kamal-proxy to health-check it and cut over traffic, then remove the old container. The CLI should do the same.

Proposed behaviour

  • If the hostname is not in use: deploy as today (no change).
  • If the hostname is already in use by an app with the same image and settings: do nothing and exit successfully (idempotent).
  • If the hostname is already in use but the image or settings differ: perform a zero-downtime replacement using the same deployWithVolumeremoveContainersExcept flow the TUI uses.

Why this matters

  • Running once deploy from a CI pipeline on every push is the natural usage pattern, but today it requires a manual once remove first.
  • The zero-downtime logic already exists in Application.Deploy() — the CLI just needs to look up the existing app by hostname instead of failing when it finds one.
  • Idempotency also removes the footgun where a failed deploy leaves an app registered under a hostname and blocks all future deploys until manually cleaned up.

Suggested implementation sketch

In deploy.go, instead of calling ns.HostInUse(host) and returning an error, look up the existing app by host. If found, reuse its Application object (preserving the app name and volume) and call app.Deploy() with the updated settings — exactly what settings.go:handleFormSubmit does.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions