Architecture

Understanding the design and components of Swiftdock.

System Overview

CLI (swiftdock)

↓ HTTP (localhost:8080) ↓

Daemon (swiftdockd)

Runtime + ImageStore

~/.swiftdock/

Components

1. CLI (apps/cli)

Command-line interface that users interact with. Built with ArgumentParser.

2. Daemon (apps/daemon)

HTTP server that manages containers and images. Built with Hummingbird.

3. Core Packages

Common (packages/Common)

RegistryClient (packages/RegistryClient)

ImageStore (packages/ImageStore)

Runtime (packages/Runtime)

Data Flow

Pulling an Image

  1. User runs swiftdock pull alpine:latest
  2. CLI sends POST /images/pull to daemon
  3. Daemon uses RegistryClient to fetch manifest
  4. RegistryClient downloads layers from Docker Hub
  5. ImageStore verifies and stores blobs
  6. ImageStore unpacks layers to rootfs
  7. Daemon returns success to CLI

Running a Container

  1. User runs swiftdock run alpine -- echo "hi"
  2. CLI sends POST /containers/create
  3. Daemon creates container metadata and rootfs
  4. CLI sends POST /containers/:id/start
  5. ContainerHost spawns Process() with command
  6. Process runs in container rootfs directory
  7. stdout/stderr captured to std.log
  8. CLI polls until container exits
  9. CLI fetches and displays logs

Storage Layout

~/.swiftdock/
├── blobs/
│   └── sha256:abc123...  # Compressed layer data
├── images/
│   └── alpine_latest/
│       └── rootfs/        # Unpacked filesystem
│           ├── bin/
│           ├── etc/
│           └── ...
└── containers/
    └── <uuid>/
        ├── config.json    # Container metadata
        ├── rootfs/        # Copy of image rootfs
        └── std.log        # stdout/stderr

Design Decisions

Why HTTP API?

Why Process() instead of namespaces?

Why Copy-on-Run?