Skip to content

A lightweight container orchestrator built from scratch in Go. Inspired by Kubernetes, it features a master controller with a REST API, worker agents that manage containers via Docker.

License

Notifications You must be signed in to change notification settings

danpasecinic/podling

Repository files navigation

Podling

CI Go Report Card

A lightweight, educational container orchestrator built from scratch in Go. Inspired by Kubernetes, it features a master controller with REST API, worker agents that manage containers via Docker, and a CLI tool.

ZCsgkeEZ

Features

  • Master-Worker Architecture: Distributed container management
  • Multi-Container Pods: Kubernetes-style pods with shared lifecycle
  • REST API: Echo-based HTTP server for control plane
  • Web Dashboard: Modern React UI with real-time monitoring
  • Persistent Storage: PostgreSQL or in-memory state store
  • Health Checks: Liveness and readiness probes (HTTP, TCP, Exec)
  • Hot Reloading: Air integration for rapid development
  • Production Patterns: Following golang-standards/project-layout

Quick Start

Prerequisites

  • Go 1.25 or later
  • Docker Engine
  • Node.js 18+ (for web dashboard)
  • Make (optional, for convenience)
  • PostgreSQL 12+ (optional, for persistent storage)

Installation

# Clone the repository
git clone https://github.com/danpasecinic/podling.git
cd podling

# Install dependencies
go mod download

# Install development tools (Air, linters)
make install-tools

Running with PostgreSQL (Recommended)

# Start PostgreSQL using docker-compose
docker-compose up -d

# Configure via .env file (easiest method)
cp .env.example .env
# Edit .env to set STORE_TYPE=postgres
make run

The master automatically loads .env if present, so no need to export variables manually.

Development

# Run with hot reloading
make dev

# Or run directly
make run

# Run tests
make test

# Run tests with coverage
make test-coverage

# Run tests with race detector
make test-race

# Run PostgreSQL tests (requires running database)
export TEST_DATABASE_URL="postgres://podling:podling123@localhost:5432/podling?sslmode=disable"
go test ./internal/master/state/

Project Structure

Following the golang-standards/project-layout:

podling/
├── cmd/                    # Main applications
│   ├── master/            # Master controller entry point
│   ├── worker/            # Worker agent entry point
│   └── podling/           # CLI tool entry point
├── internal/               # Private application code
│   ├── types/             # Core data models
│   │   ├── task.go        # Task model and status
│   │   ├── pod.go         # Pod and Container models
│   │   └── node.go        # Node model and status
│   ├── master/            # Master controller internals
│   │   ├── api/           # HTTP API handlers (Echo)
│   │   ├── scheduler/     # Task and pod scheduling logic
│   │   └── state/         # State management
│   │       └── migrations/ # Database migrations
│   └── worker/            # Worker agent internals
│       ├── agent/         # Worker agent and pod executor
│       ├── docker/        # Docker SDK integration
│       └── health/        # Health check implementations
├── web/                   # Web dashboard (React)
│   ├── src/
│   │   ├── api/           # API client and types
│   │   ├── components/    # UI components
│   │   ├── hooks/         # React Query hooks
│   │   ├── pages/         # Page components
│   │   └── lib/           # Utilities
│   └── package.json
├── docs/                  # Documentation
│   ├── postman/           # Postman collection for API testing
│   ├── POSTMAN_GUIDE.md   # API testing guide
│   └── SESSION_STATE.md   # Development session tracking
├── .air.toml              # Air hot reload configuration
├── Makefile               # Development commands
└── go.mod                 # Go module definition

Architecture

Components

Component Responsibility Port
Master Task scheduling, API server, state management 8080
Worker Container execution, status reporting, heartbeats 8081+
CLI User interface for task submission and monitoring -
Dashboard Web UI for monitoring and management 5173

Technology Stack

Backend:

  • Language: Go 1.25
  • Web Framework: Echo v4 - High performance, minimalist
  • Container Runtime: Docker Engine API
  • Hot Reload: Air - Live reload for Go apps
  • Testing: Go's built-in testing with race detector

Frontend:

  • Framework: React 19 with TypeScript
  • Build Tool: Vite - Next generation frontend tooling
  • UI Components: shadcn/ui - Beautifully designed components
  • Styling: Tailwind CSS v4 - Utility-first CSS
  • Data Fetching: TanStack Query - Powerful async state management

API Documentation

The master controller exposes a RESTful API for managing tasks and worker nodes.

Running the Master

# Build and run the master
go build -o bin/podling-master ./cmd/master
./bin/podling-master

# Or use Make
make build && ./bin/podling-master

The master will start on http://localhost:8080 with the following endpoints:

Testing with Postman

Import the provided Postman collection to test all endpoints:

  1. Import docs/postman/Podling.postman_collection.json into Postman
  2. Import docs/postman/Podling.postman_environment.json for local environment
  3. Select "Podling - Local" environment
  4. Start testing the API

See Postman Guide for detailed testing workflow.

Running the Worker

# Build and run a worker node
go build -o bin/podling-worker ./cmd/worker
./bin/podling-worker -node-id=worker-1 -port=8081

# Or use Make
make build && ./bin/podling-worker -node-id=worker-1

# Worker configuration options:
# -node-id: Unique worker identifier (required)
# -hostname: Worker hostname (default: localhost)
# -port: Worker port (default: 8081)
# -master-url: Master API URL (default: http://localhost:8080)
# -heartbeat-interval: Heartbeat interval (default: 30s)
# -shutdown-timeout: Graceful shutdown timeout (default: 30s)

The worker will:

  • Connect to the master and send periodic heartbeats
  • Execute tasks in Docker containers
  • Report task status back to master
  • Stream container logs via API
  • Handle graceful shutdown with task cleanup

Endpoints

Health Check

GET /health

curl http://localhost:8080/health

Task Management

Create Task - Submit a new task for execution

POST /api/v1/tasks
Content-Type: application/json

{
  "name": "my-nginx-task",
  "image": "nginx:latest",
  "env": {
    "PORT": "8080"
  }
}

# Example
curl -X POST http://localhost:8080/api/v1/tasks \
  -H "Content-Type: application/json" \
  -d '{"name":"nginx-task","image":"nginx:latest"}'

List Tasks - Get all tasks

GET /api/v1/tasks

curl http://localhost:8080/api/v1/tasks

Get Task - Get specific task details

GET /api/v1/tasks/{taskId}

curl http://localhost:8080/api/v1/tasks/20250119123456-abc12345

Update Task Status - Update task execution status (typically called by workers)

PUT /api/v1/tasks/{taskId}/status
Content-Type: application/json

{
  "status": "running",
  "containerId": "docker-container-id"
}

# Example
curl -X PUT http://localhost:8080/api/v1/tasks/20250119123456-abc12345/status \
  -H "Content-Type: application/json" \
  -d '{"status":"running","containerId":"abc123"}'

Node Management

Register Node - Register a worker node

POST /api/v1/nodes/register
Content-Type: application/json

{
  "hostname": "worker-1",
  "port": 8081,
  "capacity": 10
}

# Example
curl -X POST http://localhost:8080/api/v1/nodes/register \
  -H "Content-Type: application/json" \
  -d '{"hostname":"worker-1","port":8081,"capacity":10}'

Node Heartbeat - Update node heartbeat

POST /api/v1/nodes/{nodeId}/heartbeat

curl -X POST http://localhost:8080/api/v1/nodes/20250119123456-xyz98765/heartbeat

List Nodes - Get all registered nodes

GET /api/v1/nodes

curl http://localhost:8080/api/v1/nodes

Worker Endpoints

Execute Task - Execute a task on worker (called by master)

POST /api/v1/tasks/:id/execute
Content-Type: application/json

{
  "task": {
    "taskId": "task-id",
    "name": "my-task",
    "image": "nginx:latest",
    "env": {"PORT": "8080"}
  }
}

Get Task Status - Get task execution status

GET /api/v1/tasks/:id/status

curl http://localhost:8081/api/v1/tasks/task-id/status

Get Task Logs - Stream container logs

GET /api/v1/tasks/:id/logs?tail=100

curl http://localhost:8081/api/v1/tasks/task-id/logs?tail=100

Task Status Flow

Tasks progress through the following states:

pending → scheduled → running → completed/failed
  • pending: Task created, awaiting scheduling
  • scheduled: Task assigned to a worker node
  • running: Task is executing on a worker
  • completed: Task finished successfully
  • failed: Task execution failed

Pod API Endpoints

Podling supports Kubernetes-style pods - groups of one or more containers with shared lifecycle:

Create Pod - Create a multi-container pod

POST /api/v1/pods
Content-Type: application/json

{
  "name": "my-web-app",
  "namespace": "production",
  "labels": {
    "app": "web",
    "version": "1.0"
  },
  "containers": [
    {
      "name": "app",
      "image": "myapp:1.0",
      "env": {"PORT": "8080"}
    },
    {
      "name": "sidecar",
      "image": "nginx:latest"
    }
  ]
}

# Example
curl -X POST http://localhost:8080/api/v1/pods \
  -H "Content-Type: application/json" \
  -d '{"name":"web-pod","containers":[{"name":"nginx","image":"nginx:latest"}]}'

List Pods - Get all pods

GET /api/v1/pods

curl http://localhost:8080/api/v1/pods

Get Pod - Get specific pod with container status

GET /api/v1/pods/{podId}

curl http://localhost:8080/api/v1/pods/20250119123456-pod123

Delete Pod - Delete a pod

DELETE /api/v1/pods/{podId}

curl -X DELETE http://localhost:8080/api/v1/pods/20250119123456-pod123

Pod Status Flow

Pods progress through similar states:

pending → scheduled → running → succeeded/failed
  • pending: Pod created, awaiting scheduling
  • scheduled: Pod assigned to a worker node
  • running: All containers in pod are running
  • succeeded: All containers exited with code 0
  • failed: One or more containers failed

Web Dashboard

The web dashboard provides a modern UI for monitoring and managing your Podling cluster.

Running the Dashboard

# Install dependencies (first time only)
cd web
npm install

# Start development server
npm run dev

The dashboard will be available at http://localhost:5173 and connects to the master API at http://localhost:8080.

Features

  • Overview: Cluster statistics with node, pod, task, and service counts
  • Nodes: View worker nodes with resource usage (CPU/Memory)
  • Pods: List and inspect multi-container pods
  • Tasks: Monitor single-container task execution
  • Services: View service discovery and endpoints
  • Auto-refresh: Data updates every 5 seconds

Building for Production

cd web
npm run build

The built files will be in web/dist/ and can be served by any static file server.

CLI Usage

The podling CLI provides a user-friendly interface to interact with the Podling orchestrator.

Installation

# Build the CLI
make build

# The binary will be at bin/podling
# Optionally, add it to your PATH
cp bin/podling /usr/local/bin/

Configuration

The CLI can be configured via:

  1. Command-line flags: --master http://localhost:8080
  2. Environment variables: PODLING_MASTER_URL=http://localhost:8080
  3. Config file: ~/.podling.yaml (future enhancement)

Commands

Task Commands (Single Container)

Submit a new task to run a single container:

# Basic usage
podling run my-nginx --image nginx:latest

# With environment variables
podling run my-redis --image redis:latest --env PORT=6379 --env MODE=standalone

# With custom master URL
podling --master http://production:8080 run my-task --image alpine:latest

View tasks:

# List all tasks
podling ps

# Get detailed info for a specific task
podling ps --task <task-id>
podling ps -t <task-id>

View task logs:

# Get logs (last 100 lines by default)
podling logs <task-id>

# Limit output
podling logs <task-id> --tail 50

Pod Commands (Multi-Container)

Create and manage multi-container pods:

# Create a pod with a single container
podling pod create my-web --container nginx:nginx:latest

# Create a pod with multiple containers
podling pod create my-app \
  --container app:myapp:1.0:PORT=8080,ENV=prod \
  --container sidecar:nginx:latest \
  --namespace production \
  --label app=myapp \
  --label version=1.0

# List all pods
podling pod list

# Get detailed pod information (shows all container statuses)
podling pod get <pod-id>

# Delete a pod
podling pod delete <pod-id>

Container Specification Format:

name:image[:env1=val1,env2=val2]

Examples:

  • nginx:nginx:latest - Simple container
  • app:myapp:1.0:PORT=8080,DB=postgres - With environment variables

Node Commands

View all registered worker nodes:

# List all nodes
podling nodes

# With verbose output
podling nodes --verbose

Output example:

ID          HOSTNAME    PORT   STATUS   CAPACITY   TASKS   LAST HEARTBEAT
worker-1    localhost   8081   online   10         2       30s ago
worker-2    localhost   8082   online   10         1       25s ago

Global Flags

All commands support these global flags:

  • --master string: Master API URL (default "http://localhost:8080")
  • --verbose, -v: Enable verbose output
  • --config string: Config file location (default "$HOME/.podling.yaml")
  • --help, -h: Show help for any command

Testing

# Run all tests
make test

# Run with coverage report (generates coverage.html)
make test-coverage

# Run with race detector
make test-race

# Or use go directly
go test ./...
go test -race ./...
go test -coverprofile=coverage.out ./...

Current Test Coverage:

  • State management: 94.7%
  • API handlers: 91.9%
  • Scheduler: 100%
  • Worker agent: 86.2%
  • Docker client: 73.6%
  • Overall: >85%

Code Quality

# Format code
make fmt

# Run linter (requires golangci-lint)
make lint

Building

# Build all binaries
make build

# Binaries will be in bin/
# - bin/podling-master
# - bin/podling-worker
# - bin/podling

License

See LICENSE file for details.

Acknowledgments

About

A lightweight container orchestrator built from scratch in Go. Inspired by Kubernetes, it features a master controller with a REST API, worker agents that manage containers via Docker.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Contributors 2

  •  
  •  

Languages