# How Dewy Achieves Zero-Downtime Rolling Updates for Containers: A Deep Dive into the Source Code

> Discover how Dewy implements zero-downtime rolling updates for containers. Explore the source code and its innovative three-phase deployment with continuous traffic routing.

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

---

**Dewy achieves zero-downtime rolling updates by orchestrating a three-phase deployment (pull, replace, clean-up) while a TCP proxy continuously routes traffic to healthy containers, ensuring at least one replica is always serving requests.**

The open-source deployment tool [linyows/dewy](https://github.com/linyows/dewy) implements a sophisticated container orchestration strategy that eliminates service interruptions during application updates. By combining incremental container replacement with dynamic proxy reconfiguration, Dewy ensures that incoming requests are never dropped during deployments. This article examines the specific implementation details in the Go source code that enable these zero-downtime rolling updates for containers.

## The Three-Phase Rolling Update Architecture

Dewy's deployment logic in [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) implements a strict sequence that maintains service availability throughout the update process. The architecture separates concerns into distinct phases: pre-deployment preparation, incremental replacement, and post-deployment cleanup.

### Phase 1: Pre-deployment Image Pulling

Before any running containers are touched, Dewy fetches the new image to ensure the update can proceed without delay:

```go
// Pull the new image first
d.logger.Info("Pulling new image", slog.String("image", imageRef))
if err := dockerRuntime.Pull(ctx, imageRef); err != nil {
    return 0, fmt.Errorf("pull failed: %w", err)
}

```

*Source: [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) lines 774-778*

This approach ensures that the existing application version remains fully operational during the potentially slow image download process. If the pull fails, the deployment aborts before any containers are affected.

### Phase 2: Incremental Container Replacement

After resolving port mappings and discovering existing containers, Dewy enters the core rolling update loop:

```go
for i := 0; i < replicas; i++ {
    containerID, mappedPorts, err := d.startSingleContainer(...)
    // on error → rollback the ones already started
    d.addProxyBackend("localhost", mappedPort, proxyPort) // add to load balancer
}

```

*Source: [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) lines 905-945*

Each iteration performs three critical actions:

1. **Container Creation**: `startSingleContainer` invokes `dockerRuntime.Run` to create and start a new container instance
2. **Health Verification**: Before traffic admission, Dewy executes health checks via `createHealthCheckFunc`, retrying HTTP requests to `http://localhost:<mappedPort><healthPath>` until the container reports healthy
3. **Proxy Registration**: Only after passing health checks does `addProxyBackend` register the container with the TCP proxy, making it eligible to receive traffic

This sequential approach ensures that the total number of healthy replicas never drops below the configured count, maintaining continuous service availability.

### Phase 3: Graceful Cleanup of Legacy Containers

Once all new replicas are healthy and receiving traffic, Dewy removes the old containers in a controlled manner:

```go
for i, oldContainerID := range existingContainers {
    // detach from proxy first
    d.removeProxyBackend("localhost", oldPort, mapping.ProxyPort)
    dockerRuntime.Stop(ctx, oldContainerID, 10*time.Second)
    dockerRuntime.Remove(ctx, oldContainerID)
}

```

*Source: [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) lines 945-975*

The critical sequence here is **proxy removal before container termination**. By calling `removeProxyBackend` before `dockerRuntime.Stop`, Dewy ensures that no new requests are routed to the container before it receives the shutdown signal. The 10-second grace period allows in-flight requests to complete before the container is forcibly removed.

## TCP Proxy and Traffic Management

The zero-downtime guarantee relies heavily on Dewy's internal TCP proxy implementation, which decouples traffic routing from container lifecycle management.

### Dynamic Backend Registration

The proxy maintains a dynamic list of active backends that can be modified without restarting the proxy process. When `addProxyBackend` is called during the rolling update, the new container's port is immediately added to the proxy's routing table, allowing it to receive a share of incoming traffic while old containers continue serving existing connections.

### Health-Check Gating Before Traffic Admission

Dewy implements strict health-check gating to prevent premature traffic routing:

```go
// Health check function creation
healthCheck := d.createHealthCheckFunc(...)
// Retries HTTP endpoint until healthy or timeout

```

*Source: [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) lines 886-910*

The health check function performs HTTP GET requests to the container's health endpoint, retrying several times before declaring the container ready. Only after passing this verification does the container join the proxy's backend pool, ensuring that users never see connection errors from partially initialized application instances.

## Failure Handling and Rollback Mechanisms

Dewy's rolling update implementation includes robust failure handling to maintain service stability when deployments go wrong. If `startSingleContainer` fails during the rolling loop, Dewy immediately invokes `rollbackContainers` to remove any newly created containers and their proxy backends:

```go
// Rollback on error
rollbackContainers(newContainerIDs...)

```

*Source: [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) lines 1015-1035*

This rollback mechanism ensures that if a new image fails to start or pass health checks, the deployment aborts without affecting the currently running containers. The original application version continues serving traffic uninterrupted, allowing operators to investigate the failure without service degradation.

## Key Source Files and Implementation Details

Understanding Dewy's zero-downtime rolling updates requires familiarity with several key source files:

| File | Role |
|------|------|
| **[`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go)** | Core deployment logic including the three-phase update sequence, health-check coordination, and proxy backend management. Contains `startSingleContainer`, `rollbackContainers`, and the main rolling loop. |
| **[`container/docker.go`](https://github.com/linyows/dewy/blob/main/container/docker.go)** / **[`container/podman.go`](https://github.com/linyows/dewy/blob/main/container/podman.go)** | Runtime abstractions that interface with container engines. Implements `Pull`, `Run`, `Stop`, and `Remove` operations used during the update phases. |
| **[`proxy.go`](https://github.com/linyows/dewy/blob/main/proxy.go)** (TCP proxy section) | Implements `tcpProxy`, `addProxyBackend`, and `removeProxyBackend`. Manages the dynamic routing table that enables traffic shifting between old and new containers. |
| **[`config.go`](https://github.com/linyows/dewy/blob/main/config.go)** | Defines replica counts, port mappings, health-check paths, and grace periods that control the rolling update behavior. |
| **[`README.md`](https://github.com/linyows/dewy/blob/main/README.md)** | Documents high-level configuration options and deployment workflows for operators. |

These components work together to implement a rolling update strategy that maintains continuous service availability while replacing container instances.

## Summary

Dewy achieves zero-downtime rolling updates through a carefully orchestrated deployment process that maintains service availability at every stage:

- **Pre-deployment image pulling** ensures new containers can start immediately without waiting for downloads, keeping old containers operational during the transfer.
- **Incremental container replacement** starts new replicas one-by-one, verifying health before adding them to the proxy pool, ensuring replica count never drops below configured levels.
- **Proxy-driven traffic management** uses a TCP proxy with dynamic backend registration to shift traffic instantly between old and new containers without connection drops.
- **Graceful cleanup** removes old containers only after they are detached from the proxy, with configurable grace periods allowing in-flight requests to complete.
- **Automatic rollback** aborts deployments and removes partial containers if any replica fails to start or pass health checks, preserving the original running version.

## Frequently Asked Questions

### How does Dewy ensure no requests are lost during container replacement?

Dewy uses a TCP proxy that manages traffic independently of container lifecycles. When replacing containers, Dewy first registers new containers with the proxy only after they pass health checks, then removes old containers from the proxy **before** stopping them. This ensures active connections complete during the grace period while new requests route only to healthy instances.

### What happens if a new container fails to start during a rolling update?

If any container fails to start or pass health checks during the rolling update loop, Dewy immediately triggers a rollback mechanism. The `rollbackContainers` function removes any newly created containers and their proxy backends, leaving the original containers untouched and continuing to serve traffic. This prevents partial deployments from causing service degradation.

### Can Dewy perform rolling updates with multiple replicas?

Yes, Dewy supports configurable replica counts via [`config.go`](https://github.com/linyows/dewy/blob/main/config.go) and processes them sequentially in the rolling update loop. The system starts new containers one-by-one, adding each to the proxy pool after health verification, ensuring the total number of healthy replicas never drops below the configured count. This sequential approach maintains service availability even with single-replica deployments.

### How does Dewy handle port mapping during updates?

Dewy automatically resolves port mappings through the `resolvePortMappings` function in [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go), which detects exposed ports from the container image or uses explicit configuration from [`config.go`](https://github.com/linyows/dewy/blob/main/config.go). During the rolling update, each new container receives its mapped ports, which are then registered with the TCP proxy via `addProxyBackend`, ensuring traffic routes to the correct dynamic ports without manual intervention.