# How to Deploy Containerized Applications with Dewy's Container Command: A Complete Guide

> Deploy container apps with Dewy's container command. Learn zero-downtime blue-green deployments using port mappings, registry URLs, and health checks for Docker or Podman.

- Repository: [Tomohisa Oda/dewy](https://github.com/linyows/dewy)
- Tags: how-to-guide
- Published: 2026-03-06

---

**Use `dewy container` with port mappings (`-p`), a registry URL (`--registry`), and optional health checks to perform zero-downtime blue-green deployments of Docker or Podman containers.**

Dewy is an open-source deployment tool (linyows/dewy) designed for zero-downtime application releases. The `container` subcommand orchestrates containerized deployments by managing image pulls, health checks, TCP proxying, and rolling updates—all without requiring external load balancers.

## Understanding Dewy's Container Deployment Architecture

Dewy's container deployment follows a modular architecture spanning CLI parsing, runtime abstraction, and orchestration logic.

### CLI Flag Parsing in cli.go

The `container` subcommand is configured in [`cli.go`](https://github.com/linyows/dewy/blob/main/cli.go) via the `configureContainerCommand` function. Key flags include:

- `--replicas`: Number of container instances (default: 1)
- `--health-path`: HTTP path for health checks (e.g., `/health`)
- `--health-timeout`: Health check timeout in seconds (default: 30)
- `--drain-time`: Graceful drain period after traffic switch (default: 30)
- `--runtime`: Container engine (`docker` or `podman`, default: `docker`)
- `--cmd`: Command and arguments to pass to the container
- `--admin-port`: Admin API port (default: 17539, auto-increments if in use)

The `-p` or `--port` flag is required and accepts `proxy:container` mappings or just `proxy` for auto-detection.

### Runtime Abstraction in container/container.go and docker.go

Dewy abstracts container operations through the `Runtime` interface defined in [`container/container.go`](https://github.com/linyows/dewy/blob/main/container/container.go):

```go
type Runtime interface {
    Pull(ctx context.Context, imageRef string) error
    Run(ctx context.Context, opts RunOptions) (string, error)
    Stop(ctx context.Context, containerID string, timeout time.Duration) error
    Remove(ctx context.Context, containerID string) error
    GetMappedPort(ctx context.Context, containerID string, containerPort int) (int, error)
    GetImageExposedPorts(ctx context.Context, imageRef string) ([]int, error)
    // ... additional methods for labels, listing, cleanup
}

```

The Docker implementation in [`container/docker.go`](https://github.com/linyows/dewy/blob/main/container/docker.go) provides concrete methods like `Pull` (lines 64-89), `Run` (lines 40-100), and `GetImageExposedPorts` (lines 779-830) for reading image metadata.

### Orchestration Flow in dewy.go

The `RunContainer` function (lines 668-712 in [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go)) orchestrates the deployment:

1. Fetches latest image info from the registry
2. Builds the Docker/Podman runtime
3. Pulls the image via `dockerRuntime.Pull`
4. Resolves port mappings via `resolvePortMappings` (lines 152-215)
5. Executes pre-deploy hooks
6. Deploys via `deployContainer` (lines 222-284) with rolling updates
7. Runs post-deploy hooks and cleanup

## Required Flags and Configuration

### Port Mappings (-p)

The `-p` flag is required and supports two formats:

```bash

# Explicit mapping: public port 8080 forwards to container port 80

dewy container -p 8080:80 ...

# Auto-detection: public port 8080 maps to the image's single EXPOSEd port

dewy container -p 8080 ...

```

When using auto-detection, Dewy calls `GetImageExposedPorts` and requires exactly one exposed port in the image metadata.

### Registry URL (--registry)

Specify the image source using the `img://` protocol:

```bash
--registry "img://ghcr.io/linyows/myapp:1.2.3"

```

Dewy automatically handles registry authentication when needed.

### Optional Configuration

- **Replicas**: `--replicas 3` runs three container instances behind the proxy
- **Health Checks**: `--health-path /health --health-timeout 60` ensures containers are healthy before receiving traffic
- **Runtime**: `--runtime podman` uses Podman instead of Docker
- **Drain Time**: `--drain-time 10` sets the graceful shutdown period after traffic switch

## Step-by-Step Deployment Process

### Image Pull and Port Detection

When `RunContainer` executes, it first pulls the image via `dockerRuntime.Pull`. If port mappings omit the container port, `resolvePortMappings` queries the image's exposed ports using `GetImageExposedPorts` and validates that exactly one port is exposed.

### Health Check Implementation

If `--health-path` is provided, `createHealthCheckFunc` (lines 886-931 in [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go)) builds a health check function that repeatedly performs HTTP GET requests to `http://localhost:<mappedPort>/<health-path>` until the container responds with 200 OK or the timeout expires.

### Proxy Setup and Traffic Management

Dewy starts a TCP proxy via `startProxy` (lines 442-473) that listens on each `ProxyPort`. The proxy maintains a round-robin backend list of host ports assigned by Docker (`127.0.0.1::<containerPort>`). When new containers start, `addProxyBackend` adds their ports; old containers are removed via `removeProxyBackend` before stopping.

### Rolling Update Execution

The `deployContainer` function performs rolling updates:

1. Starts new containers with unique names (`<app>-<timestamp>-<replica>`) and the label `dewy.managed=true`
2. Waits for health checks to pass
3. Adds new containers to the proxy backends
4. Removes old containers from the proxy and stops them with a 10-second timeout
5. Cleans up old images via `cleanupOldImages`

If any step fails, `rollbackContainers` stops and removes all new containers, restoring the previous state.

## Practical Usage Examples

### Basic Deployment with Explicit Ports

Deploy an image with explicit port mapping and health checks:

```bash
dewy container \
  -p 8080:80 \
  -p 8443:443 \
  --registry "img://ghcr.io/linyows/myapp:1.2.3" \
  --health-path /health \
  --replicas 2

```

### Auto-Detecting Exposed Ports

When the image has a single `EXPOSE` directive, omit the container port:

```bash
dewy container \
  -p 8080 \
  --registry "img://ghcr.io/linyows/myapp:latest" \
  --health-path /ready

```

Dewy queries the image metadata via `GetImageExposedPorts` and maps port 8080 to the exposed container port automatically.

### Blue-Green Deployments with Slots

Use the `--slot` flag for blue-green deployment strategies:

```bash
dewy container \
  -p 8080:80 \
  --registry "img://ghcr.io/linyows/myapp:${VERSION}" \
  --slot blue

```

Dewy checks the image's slot metadata and skips deployment if the slot doesn't match, enabling safe blue-green switches.

### Inspecting Running Containers

Query the admin API to view managed containers:

```bash
dewy container list

```

This command queries `http://localhost:17539/api/containers` (or the configured `--admin-port`) and displays container IDs, IP:port mappings, deployment times, and names. Internally, this uses `ListContainersByLabels` with the `dewy.managed=true` label filter.

## Summary

- **Dewy's `container` command** orchestrates zero-downtime deployments for Docker and Podman containers via `dewy container` with flags for ports, registry, and health checks.
- **Required configuration** includes port mappings (`-p`) and a registry URL (`--registry img://...`), with optional auto-detection of exposed ports via `GetImageExposedPorts`.
- **Deployment flow** pulls images, resolves ports, performs health checks via `createHealthCheckFunc`, and manages traffic through a built-in TCP proxy with rolling updates.
- **Key source files** include [`cli.go`](https://github.com/linyows/dewy/blob/main/cli.go) for flag parsing, [`container/docker.go`](https://github.com/linyows/dewy/blob/main/container/docker.go) for runtime operations, and [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) for orchestration via `RunContainer` and `deployContainer`.
- **Advanced features** support blue-green deployments with `--slot`, configurable drain times, and an admin API for container inspection.

## Frequently Asked Questions

### What container runtimes does Dewy support?

Dewy supports **Docker** and **Podman** as container runtimes. You can specify the runtime using the `--runtime` flag (e.g., `--runtime podman`), with Docker being the default. The runtime abstraction is defined in [`container/container.go`](https://github.com/linyows/dewy/blob/main/container/container.go) as the `Runtime` interface, with concrete implementations in [`container/docker.go`](https://github.com/linyows/dewy/blob/main/container/docker.go) and [`container/podman.go`](https://github.com/linyows/dewy/blob/main/container/podman.go).

### How does Dewy handle port mapping when I don't specify the container port?

When you omit the container port in the `-p` flag (e.g., `-p 8080` instead of `-p 8080:80`), Dewy automatically detects the exposed port by calling `GetImageExposedPorts` in the runtime implementation. This function inspects the image metadata (the `EXPOSE` directive in the Dockerfile). Dewy requires exactly one exposed port when using auto-detection; if multiple ports are exposed or none are found, the deployment aborts with an error.

### What happens if a health check fails during deployment?

If a health check fails, Dewy performs an automatic rollback. During the `deployContainer` execution in [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go), if the health check function (created by `createHealthCheckFunc`) fails to receive a 200 OK response within the `--health-timeout` period, Dewy triggers `rollbackContainers`. This stops and removes all newly started containers, cleans up the proxy backends, and leaves the previous containers running, ensuring zero-downtime failure recovery.

### Can I use Dewy for blue-green deployments?

Yes, Dewy supports blue-green deployments through the `--slot` flag. When you specify a slot (e.g., `--slot blue`), Dewy checks the image's slot metadata during the `RunContainer` execution. If the image's slot does not match the configured slot, Dewy logs "Deploy skipped: slot mismatch" and exits without deploying. This allows you to maintain separate blue and green environments and switch traffic between them by controlling which slot Dewy is configured to accept.