Design
REST Storage Interface
See Functionality for detailed CRUD operations and storage implementations.
The Porch API Server implements Kubernetes’ REST storage interface to provide custom storage backends for Porch resources. Unlike standard Kubernetes resources that store data in etcd, Porch resources delegate to the Engine which manages package data in Git repositories through the Cache.
Storage interface characteristics:
- Implements standard Kubernetes storage.Interface
- Provides CRUD operations (Create, Get, List, Update, Delete)
- Supports Watch for real-time change notifications
- Delegates all operations to CaD Engine
- No direct etcd storage - packages stored in Git
Storage implementations:
- packageRevisions: Manages PackageRevision resources
- packageRevisionResources: Manages PackageRevisionResources (package content)
- packages: Manages Package resources
Strategy Pattern
See Functionality for detailed validation rules and processes.
The API Server uses Kubernetes’ strategy pattern to customize resource behavior:
Validation Strategy
Purpose: Validates resource specifications before persistence
Validation types:
- Create validation: Ensures required fields present, lifecycle constraints enforced
- Update validation: Validates resource version, lifecycle transitions, immutability rules
- Status validation: Validates status subresource updates
Admission Strategy
Purpose: Applies admission control policies and defaults
Admission operations:
- PrepareForCreate: Sets defaults, generates names, initializes status
- PrepareForUpdate: Validates resource version, enforces immutability
- Canonicalize: Normalizes resource representation
Table Conversion Strategy
Purpose: Converts resources to table format for kubectl display
Table conversion:
- Defines columns for kubectl output (Name, Package, Workspace, Revision, Lifecycle)
- Extracts values from resource specifications
- Formats data for human-readable display
- Supports both list and individual resource views
API Groups
The Porch API Server registers two API groups with Kubernetes:
porch.kpt.dev API Group (Aggregated API)
Resources:
- PackageRevision: Represents a specific revision of a package
- PackageRevisionResources: Contains the actual resource content of a package revision
- Package: Represents a package across all its revisions
Versions:
- v1alpha1: Current version with all resources
Characteristics:
- Primary API group for package management
- All resources namespaced
- Served via Kubernetes API aggregation (not CRDs)
- Supports full CRUD and Watch operations
- Integrates with Engine for all operations
- Uses custom REST storage (Git-backed, not etcd)
config.porch.kpt.dev API Group (CRDs)
Resources:
- Repository: Configures Git repositories for package storage
- PackageRev: Internal metadata resource for tracking package revisions
Versions:
- v1alpha1: Current version for all resources
Characteristics:
- Configuration API group for repository management
- All resources are namespaced
- Implemented as standard Kubernetes CRDs
- Managed by separate controllers, not directly by API server
- Stored in etcd (standard Kubernetes CRD storage)
- PackageRev is an internal resource used for metadata tracking
Background Operations
See Functionality for detailed implementation of background operations including repository synchronization and resource cleanup.
Design Decisions
REST Storage vs etcd
Decision: Implement custom REST storage that delegates to Engine instead of using etcd.
Rationale:
- Package data naturally lives in Git repositories
- etcd not suitable for large package content
- Engine provides necessary abstraction over Git
- Enables draft-commit workflow for package modifications
Alternatives considered:
- Store in etcd: Would require duplicating package content, large storage overhead
- Hybrid approach: Metadata in etcd, content in Git - adds complexity
Trade-offs:
- Custom storage more complex than standard etcd
- Enables Git-native package management
- Better scalability for large packages
Strategy-Based Validation
Decision: Use Kubernetes strategy pattern for validation and admission control.
Rationale:
- Follows Kubernetes conventions
- Separates validation logic from storage logic
- Enables reuse across different storage implementations
- Provides consistent validation behavior
Alternatives considered:
- Validation in Engine: Would duplicate validation logic
- Webhook-based validation: Adds network overhead and complexity
Trade-offs:
- Strategy pattern adds abstraction layer
- Provides clean separation of concerns
- Enables testing validation independently
Watch via WatcherManager
Decision: Implement watch streams using Engine’s WatcherManager.
Rationale:
- Engine knows when package revisions change
- WatcherManager provides efficient fan-out to multiple watchers
- Avoids polling or etcd watch overhead
- Enables real-time notifications
Alternatives considered:
- etcd watch: Would require storing all data in etcd
- Polling: Inefficient and high latency
Trade-offs:
- Custom watch implementation more complex
- Provides efficient real-time updates
- Scales to many concurrent watchers
Background Job Pattern
Decision: Run repository synchronization and cleanup as background goroutines.
Rationale:
- Sync operations are long-running and periodic
- Should not block API requests
- Enables concurrent sync of multiple repositories
- Provides automatic cache refresh
Alternatives considered:
- Sync on demand: Would add latency to API requests
- External controller: Adds deployment complexity
Trade-offs:
- Background jobs add complexity to server lifecycle
- Provides better user experience (no sync delays)
- Enables automatic cache consistency
Dependency Injection
Decision: Configure Engine, Cache, and clients through dependency injection.
Rationale:
- Enables testing with mock implementations
- Provides flexible configuration
- Separates construction from usage
- Supports different deployment scenarios
Alternatives considered:
- Global singletons: Hard to test and configure
- Service locator: Hides dependencies
Trade-offs:
- Requires explicit wiring during initialization
- Provides clear dependency graph
- Enables flexible testing and configuration