# How Dewy's Pull-Based Deployment Works: A Complete Technical Guide

> Explore Dewy's pull-based deployment. Learn how it fetches Docker images, validates metadata, authenticates, and performs zero-downtime blue/green rollouts using Docker or Podman.

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

---

**Dewy's pull-based deployment fetches Docker images from registries using `Dewy.RunContainer`, validates slot metadata, authenticates with the registry, and executes zero-downtime blue/green rollouts through Docker or Podman runtimes.**

Dewy is an open-source deployment tool written in Go that implements a pull-based model for containerized applications. Unlike push-based systems that require external triggers, Dewy actively queries registries for new artifacts and pulls them to the target host, ensuring the latest version is always running.

## The Pull-Based Deployment Workflow

The deployment process orchestrated by `Dewy.RunContainer` in [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) follows a strict sequence to ensure reliable container updates.

### Step 1: Fetching Artifact Metadata from the Registry

Dewy begins by contacting the configured registry (OCI, S3, GitHub Releases, etc.) via `registry.New(...).Current`. The response contains the image URL, tag, digest, and optional slot (blue/green) information.

In [`registry/registry.go`](https://github.com/linyows/dewy/blob/main/registry/registry.go) (lines 29-45), the `Current` method retrieves this metadata, which serves as the source of truth for the deployment.

### Step 2: Slot Filtering for Blue/Green Deployments

If the user supplied a `--slot` flag, Dewy checks the artifact's `Slot` field and aborts the deployment when it does not match. This logic in [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) (lines 85-92) ensures that only artifacts built for the specific environment (e.g., "blue" or "green") are deployed.

### Step 3: Resolving the Image Reference

The URL returned by the registry has the form `img://registry/repo:tag`. Dewy strips the `img://` prefix in [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) (lines 94-96) to obtain a Docker-compatible image reference that can be passed to the container runtime.

### Step 4: Creating the OCI Artifact Object

`artifact.New` selects the appropriate implementation based on the URL scheme. For OCI images, it returns an `OCI` struct as defined in [`artifact/artifact.go`](https://github.com/linyows/dewy/blob/main/artifact/artifact.go) (lines 31-38). This abstraction allows Dewy to handle different artifact types uniformly.

### Step 5: Pulling the Image with Docker or Podman

`OCI.Download` executes `docker pull` (or `podman pull` via the runtime) to fetch the image into the local daemon's store. The implementation in [`artifact/oci.go`](https://github.com/linyows/dewy/blob/main/artifact/oci.go) (lines 36-44) first verifies that the Docker binary exists, then executes the pull command and logs the result.

### Step 6: Executing Pre-Deploy Hooks and Notifications

After a successful pull, Dewy sends a "pull notification" and runs any user-specified *before-deploy* hook. This occurs in [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) (lines 43-55), allowing users to perform health checks or database migrations before the new container goes live.

### Step 7: Deploying the Container with Runtime Abstraction

`Dewy.deployContainer`, called from `RunContainer` in [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) (lines 56-64), uses the selected runtime (`Docker` or `Podman`). The runtime first checks whether the image already exists locally, then proceeds with the deployment.

### Step 8: Blue/Green Rollout Strategy

If a slot is defined, the new container starts with a temporary alias while the old one remains running. The alias switches atomically to complete the zero-downtime deployment. This logic resides in `deployContainerInternal` within the runtime implementations, specifically in [`container/docker.go`](https://github.com/linyows/dewy/blob/main/container/docker.go) (lines 340-460).

### Step 9: Reporting Deployment Status

After the rollout completes, Dewy calls `registry.Report` to inform the upstream registry about the deployment outcome. This final step in [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) (lines 79-87) closes the feedback loop, allowing registries to track which versions are running in production.

## Key Implementation Details in the Dewy Source Code

The pull-based deployment relies on several critical components within the `linyows/dewy` repository:

- **[`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go)**: Contains the main orchestration logic including `RunContainer`, slot validation, and the deployment sequence.
- **[`registry/registry.go`](https://github.com/linyows/dewy/blob/main/registry/registry.go)**: Defines the `Registry` interface and implementations for OCI, S3, and GitHub Releases, providing the `Current` method for metadata retrieval.
- **[`artifact/oci.go`](https://github.com/linyows/dewy/blob/main/artifact/oci.go)**: Implements the `OCI` artifact type with the `Download` method that triggers the actual `docker pull` command.
- **[`container/docker.go`](https://github.com/linyows/dewy/blob/main/container/docker.go)**: Provides the Docker runtime implementation with robust pull logic including authentication retry and blue/green deployment in `deployContainerInternal`.
- **[`container/podman.go`](https://github.com/linyows/dewy/blob/main/container/podman.go)**: Offers equivalent functionality for Podman users, maintaining the same pull-based deployment interface.

## Practical Examples of Pull-Based Deployment

### CLI Deployment with Slot Specification

Deploy the latest image for the "myapp" container using the green slot for zero-downtime rollout:

```bash
dewy \
  --registry img://ghcr.io/example/myapp \
  --name myapp \
  --slot green \
  server

```

- `--registry` points to an OCI image using the `img://` scheme.
- `--slot` ensures the deployment only proceeds when the artifact's build metadata matches "green", enabling blue/green deployment strategies.

### Programmatic Deployment in Go

Trigger the same pull-based deployment flow programmatically using Dewy's Go API:

```go
package main

import (
	"context"
	"log"

	"github.com/linyows/dewy"
	"github.com/linyows/dewy/config"
)

func main() {
	// Configure the deployment
	cfg := &config.Config{
		Registry:   "img://ghcr.io/example/myapp",
		Command:    config.Server,
		Container:  config.ContainerConfig{Name: "myapp"},
		Slot:       "green",
		Notifier:   "null://",
		BeforeDeployHook: "",
		AfterDeployHook:  "",
	}

	// Initialize Dewy
	d, err := dewy.New(cfg)
	if err != nil {
		log.Fatalf("init: %v", err)
	}

	// Execute the pull-based container deployment
	if err := d.RunContainer(); err != nil {
		log.Fatalf("deploy failed: %v", err)
	}
}

```

The `RunContainer` method orchestrates the complete workflow: fetching registry metadata, pulling the image, executing hooks, and performing the blue/green container swap.

### Docker Runtime Pull Logic with Retry Mechanism

The Docker runtime implements robust pull logic with authentication retry and fallback to local images. This excerpt from [`container/docker.go`](https://github.com/linyows/dewy/blob/main/container/docker.go) demonstrates the key steps:

```go
func (d *Docker) Pull(ctx context.Context, imageRef string) error {
	// Check local cache first
	if _, err := d.execCommandOutput(ctx, "image", "inspect", imageRef); err == nil {
		d.logger.Info("Image already exists locally, pulling to check for updates")
	}

	// Attempt registry login if not already authenticated
	reg := extractRegistry(imageRef)
	if !d.loggedInRegistries[reg] {
		_ = d.Login(ctx, reg) // Continue even if login fails
	}

	// Pull the image
	output, err := d.pullImage(ctx, imageRef)

	// Retry on authentication errors
	if err != nil && isAuthError(output) {
		delete(d.loggedInRegistries, reg)
		if loginErr := d.Login(ctx, reg); loginErr == nil {
			_, err = d.pullImage(ctx, imageRef)
		}
	}

	// Fallback to local image if pull fails but local copy exists
	if err != nil && localErr == nil {
		d.logger.Warn("Failed to pull image, but local image exists – using local version")
		return nil
	}
	return err
}

```

See the full implementation at **[Docker.Pull](https://github.com/linyows/dewy/blob/main/container/docker.go#L64-L90)**.

## Summary

- **Pull-based architecture**: Dewy actively queries registries via `registry.New(...).Current` and pulls images using `OCI.Download`, ensuring the target host always runs the latest artifact.
- **Registry abstraction**: Supports OCI, S3, and GitHub Releases through a unified interface in [`registry/registry.go`](https://github.com/linyows/dewy/blob/main/registry/registry.go).
- **Slot-based filtering**: The `--slot` flag enables blue/green deployments by validating artifact metadata before deployment in [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go).
- **Robust runtime handling**: Both Docker and Podman implementations include authentication retry logic, local image fallback, and zero-downtime container swapping in `deployContainerInternal`.
- **Hook integration**: Supports `BeforeDeployHook` and `AfterDeployHook` for custom automation during the deployment lifecycle.

## Frequently Asked Questions

### What makes Dewy's deployment model "pull-based"?

Dewy uses a pull-based model where the deployment agent on the target host actively queries the configured registry for new artifacts using `registry.New(...).Current`, rather than waiting for external push notifications. The agent then pulls the Docker image locally using `docker pull` or `podman pull` before starting the container, ensuring the host always has the latest version without requiring external orchestrators to push updates.

### How does Dewy handle authentication failures during image pulls?

The Docker runtime in [`container/docker.go`](https://github.com/linyows/dewy/blob/main/container/docker.go) implements a resilient authentication retry mechanism. When `Docker.Pull` encounters an authentication error, it attempts to re-login to the registry and retries the pull operation. If the pull continues to fail but a local copy of the image exists, Dewy logs a warning and falls back to the local image, allowing deployments to proceed even during temporary registry connectivity issues.

### Can Dewy deploy containers using Podman instead of Docker?

Yes, Dewy supports both Docker and Podman as container runtimes. The [`container/podman.go`](https://github.com/linyows/dewy/blob/main/container/podman.go) file provides equivalent functionality to [`container/docker.go`](https://github.com/linyows/dewy/blob/main/container/docker.go), implementing the same pull-based deployment interface including image pulling, authentication handling, and blue/green rollout strategies. Users can configure their preferred runtime through Dewy's configuration options.

### What is the purpose of the slot flag in Dewy deployments?

The `--slot` flag enables blue/green deployment strategies by allowing users to specify which deployment environment (e.g., "blue" or "green") should receive the update. Before deploying, Dewy checks the artifact's `Slot` field retrieved from the registry in [`dewy.go`](https://github.com/linyows/dewy/blob/main/dewy.go) (lines 85-92). If the slot doesn't match the flag value, the deployment aborts, preventing accidental deployments to the wrong environment and enabling safe zero-downtime rollouts.