Skip to content

Commit aef1a18

Browse files
authored
Debulleting Porch Architecture & Components - Porch API server (#1041)
* Debulleting Porch Architecture & Components - Porch API server Signed-off-by: Dominika Schweier <dominika.schweier@nokia.com> * Correcting copilot comments Signed-off-by: Dominika Schweier <dominika.schweier@nokia.com> * Adding review comments Signed-off-by: Dominika Schweier <dominika.schweier@nokia.com> --------- Signed-off-by: Dominika Schweier <dominika.schweier@nokia.com>
1 parent d617e09 commit aef1a18

3 files changed

Lines changed: 106 additions & 417 deletions

File tree

docs/content/en/docs/5_architecture_and_components/porch-apiserver/design.md

Lines changed: 37 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,11 @@ See [Functionality]({{% relref "/docs/5_architecture_and_components/porch-apiser
1212

1313
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.
1414

15-
**Storage interface characteristics:**
16-
- Implements standard Kubernetes storage.Interface
17-
- Provides CRUD operations (Create, Get, List, Update, Delete)
18-
- Supports Watch for real-time change notifications
19-
- Delegates all operations to CaD Engine
20-
- No direct etcd storage - packages stored in Git
21-
22-
**Storage implementations:**
23-
- **packageRevisions**: Manages PackageRevision resources
24-
- **packageRevisionResources**: Manages PackageRevisionResources (package content)
25-
- **packages**: Manages Package resources
15+
The Storage Interface implements standard Kubernetes storage. It provides CRUD operations (Create, Get, List, Update, Delete), supports Watch for real-time change notifications and delegates all operations to CaD Engine. However, it has no direct etcd storage, as the packages are stored in Git.
16+
17+
- **packageRevisions** manage PackageRevision resources
18+
- **packageRevisionResources** manage PackageRevisionResources (package content)
19+
- **packages** manage Package resources.
2620

2721
## Strategy Pattern
2822

@@ -32,31 +26,15 @@ The API Server uses Kubernetes' strategy pattern to customize resource behavior:
3226

3327
### Validation Strategy
3428

35-
**Purpose**: Validates resource specifications before persistence
36-
37-
**Validation types:**
38-
- **Create validation**: Ensures required fields present, lifecycle constraints enforced
39-
- **Update validation**: Validates resource version, lifecycle transitions, immutability rules
40-
- **Status validation**: Validates status subresource updates
29+
The purpose of the this strategy is to validate resource specifications before persistence. It has three types: create, update and status. The create validation ensures that the fields present and the lifecycle constraints enforced. The update validation checks resource version, lifecycle transitions and immutability rules. And the status validation checks status subresource updates.
4130

4231
### Admission Strategy
4332

44-
**Purpose**: Applies admission control policies and defaults
45-
46-
**Admission operations:**
47-
- **PrepareForCreate**: Sets defaults, generates names, initializes status
48-
- **PrepareForUpdate**: Validates resource version, enforces immutability
49-
- **Canonicalize**: Normalizes resource representation
33+
The purpose of this strategy is to apply admission control policies and defaults. There are three admission operations: PrepareForCreate, PrepareForUpdate and Canonicalize. PrepareForCreate sets defaults, generates names and initializes status. PrepareForUpdate validates resource version and enforces immutability. Canonicalize normalizes resource representation.
5034

5135
### Table Conversion Strategy
5236

53-
**Purpose**: Converts resources to table format for kubectl display
54-
55-
**Table conversion:**
56-
- Defines columns for kubectl output (Name, Package, Workspace, Revision, Lifecycle)
57-
- Extracts values from resource specifications
58-
- Formats data for human-readable display
59-
- Supports both list and individual resource views
37+
The purpose of the table conversion strategy is to convert resources to table format for `kubectl` display. The table conversion defines columns for `kubectl` output (Name, Package, Workspace, Revision, Lifecycle), extracts values from resource specifications, and formats data for human-readable display. It supports both list and individual resource views.
6038

6139
## API Groups
6240

@@ -69,33 +47,19 @@ The Porch API Server registers two API groups with Kubernetes:
6947
- **PackageRevisionResources**: Contains the actual resource content of a package revision
7048
- **Package**: Represents a package across all its revisions
7149

72-
**Versions:**
73-
- v1alpha1: Current version with all resources
50+
**Versions:** v1alpha1: Current version with all resources
7451

75-
**Characteristics:**
76-
- Primary API group for package management
77-
- All resources namespaced
78-
- Served via Kubernetes API aggregation (not CRDs)
79-
- Supports full CRUD and Watch operations
80-
- Integrates with Engine for all operations
81-
- Uses custom REST storage (Git-backed, not etcd)
52+
**Characteristics:** The porch.kpt.dev API group is the primary API group for package management, and all its resources are namespaced. It is served via Kubernetes API aggregation, not CRDs, and supports full CRUD and Watch operations. This group integrates with Engine for all operations and uses custom REST storage, which is Git-backed, not etcd.
8253

8354
### config.porch.kpt.dev API Group (CRDs)
8455

8556
**Resources:**
8657
- **Repository**: Configures Git repositories for package storage
8758
- **PackageRev**: Internal metadata resource for tracking package revisions
8859

89-
**Versions:**
90-
- v1alpha1: Current version for all resources
60+
**Versions:** v1alpha1: Current version for all resources
9161

92-
**Characteristics:**
93-
- Configuration API group for repository management
94-
- All resources are namespaced
95-
- Implemented as standard Kubernetes CRDs
96-
- Managed by separate controllers, not directly by API server
97-
- Stored in etcd (standard Kubernetes CRD storage)
98-
- PackageRev is an internal resource used for metadata tracking
62+
**Characteristics:** The config.porch.kpt.dev API group serves as the configuration API group for repository management, with all its resources being namespaced. It is implemented as standard Kubernetes CRDs and is managed by separate controllers, not directly by the API server. Its data is stored in etcd, which is the standard Kubernetes CRD storage. Within this group, PackageRev is used an internal resource specifically for metadata tracking.
9963

10064
## Background Operations
10165

@@ -107,105 +71,52 @@ See [Functionality]({{% relref "/docs/5_architecture_and_components/porch-apiser
10771

10872
### REST Storage vs etcd
10973

110-
**Decision**: Implement custom REST storage that delegates to Engine instead of using etcd.
74+
Instead of using etcd, custom REST storage is implemented that delegates to Engine.
11175

112-
**Rationale:**
113-
- Package data naturally lives in Git repositories
114-
- etcd not suitable for large package content
115-
- Engine provides necessary abstraction over Git
116-
- Enables draft-commit workflow for package modifications
76+
Package data naturally lives in Git repositories, and etcd is not suitable for storing large package content. The Engine provides the necessary abstraction over Git, which enables a draft-commit workflow for package modifications.
11777

118-
**Alternatives considered:**
119-
- **Store in etcd**: Would require duplicating package content, large storage overhead
120-
- **Hybrid approach**: Metadata in etcd, content in Git - adds complexity
78+
Using etcd would require duplicating package content, causing large storage overhead. As an alternative, a hybrid approach was considered as well. Metadata would be stored in etcd, content in Git. However, that would add complexity.
12179

122-
**Trade-offs:**
123-
- Custom storage more complex than standard etcd
124-
- Enables Git-native package management
125-
- Better scalability for large packages
80+
This decision has some trade-offs. Custom storage, while more complex than standard etcd, offers the significant advantages of enabling Git-native package management and providing better scalability for large packages.
12681

12782
### Strategy-Based Validation
12883

129-
**Decision**: Use Kubernetes strategy pattern for validation and admission control.
84+
Kubernetes strategy pattern for validation and admission control is used.
13085

131-
**Rationale:**
132-
- Follows Kubernetes conventions
133-
- Separates validation logic from storage logic
134-
- Enables reuse across different storage implementations
135-
- Provides consistent validation behavior
86+
Following Kubernetes conventions, this approach separates validation logic from storage logic, which enables reuse across different storage implementations and provides consistent validation behavior.
13687

137-
**Alternatives considered:**
138-
- **Validation in Engine**: Would duplicate validation logic
139-
- **Webhook-based validation**: Adds network overhead and complexity
88+
Two alternatives were considered. Either validate in engine or webhook-based validation. However, validation in engine duplicated validation logic, while webhook-based validation adds network overhead and complexity.
14089

141-
**Trade-offs:**
142-
- Strategy pattern adds abstraction layer
143-
- Provides clean separation of concerns
144-
- Enables testing validation independently
90+
This decision has some trade-offs. The strategy pattern, while adding an abstraction layer, provides a clean separation of concerns and enables independent testing of validation.
14591

14692
### Watch via WatcherManager
14793

148-
**Decision**: Implement watch streams using Engine's WatcherManager.
94+
Watch streams using Engine's WatcherManager is implemented.
14995

150-
**Rationale:**
151-
- Engine knows when package revisions change
152-
- WatcherManager provides efficient fan-out to multiple watchers
153-
- Avoids polling or etcd watch overhead
154-
- Enables real-time notifications
96+
The engine knows when package revisions change. Combined with the WatcherManager's efficient fan-out, this solution enables real-time notifications while avoiding the overhead of polling or etcd watches.
15597

156-
**Alternatives considered:**
157-
- **etcd watch**: Would require storing all data in etcd
158-
- **Polling**: Inefficient and high latency
98+
Two alternatives were considered, either etcd watch or polling. However, etcd watch requires storing all data in etcd, while polling is inefficient and causes high latency.
15999

160-
**Trade-offs:**
161-
- Custom watch implementation more complex
162-
- Provides efficient real-time updates
163-
- Scales to many concurrent watchers
100+
This decision has some trade-offs. A custom watch implementation, while more complex to develop, offers efficient real-time updates and scales effectively to support many concurrent watchers.
164101

165102
### Repository Management Pattern
166103

167-
**Decision**: Extract repository synchronization into a dedicated Repository Controller using controller-runtime framework.
168-
169-
**Rationale:**
170-
- Separates concerns: API server handles requests, controller manages repository lifecycle
171-
- Controller-runtime provides proven patterns (watch management, work queues, leader election)
172-
- Better scalability with concurrent reconciliation and rate limiting
173-
- Independent deployment and scaling of repository management
174-
- Cleaner shutdown and error handling
175-
176-
**Alternatives considered:**
177-
- **Background goroutines in API server**: Mixes request handling with background sync logic
178-
- **Sync on demand**: Would add latency to API requests
179-
- **Custom controller implementation**: Reinvents controller-runtime features
180-
181-
**Trade-offs:**
182-
- Additional deployment component (Repository Controller)
183-
- Better separation of concerns and operational flexibility
184-
- Improved observability with controller metrics and status
185-
186-
**Implementation:**
187-
The Repository Controller manages Repository CRs through standard Kubernetes reconciliation:
188-
- Watches Repository resources for spec changes
189-
- Performs health checks and full syncs on configurable schedules
190-
- Updates repository status with sync results and package metadata
191-
- Handles repository deletion and cache cleanup
192-
- See [Repository Controller]({{% relref "/docs/5_architecture_and_components/controllers/repository-controller/_index.md" %}}) for details
104+
Repository synchronization is extracted into a dedicated Repository Controller using `controller-runtime` framework.
105+
106+
This design separates concerns by dedicating the API server to request handling and the controller to managing the repository lifecycle. Leveraging `controller-runtime` provides proven patterns for watch management, work queues, and leader election, leading to better scalability through concurrent reconciliation and rate limiting. This architecture also allows for independent deployment and scaling of repository management, and facilitates cleaner shutdown and error handling.
107+
108+
Three alternatives were considered: background goroutines in the API server, sync on demand or the implementation of custom controller. However, background goroutines mix request handling with background sync logic, sync on demand adds latency to API requests and custom controller implementation reinvents controller-runtime features.
109+
110+
This decision has some trade-offs. The introduction of a dedicated Repository Controller as an additional deployment component offers significant advantages, including a better separation of concerns, enhanced operational flexibility, and improved observability through specialized controller metrics and status reporting.
111+
112+
The Repository Controller manages Repository CRs through standard Kubernetes reconciliation to manage Repository Custom Resources (CRs). Its core functions include watching for changes in Repository specifications, conducting scheduled health checks and full synchronizations, updating the repository status with synchronization results and package metadata, and managing repository deletion and cache cleanup. For more information, see [Repository Controller]({{% relref "/docs/5_architecture_and_components/controllers/repository-controller/_index.md" %}}).
193113

194114
### Dependency Injection
195115

196-
**Decision**: Configure Engine, Cache, and clients through dependency injection.
116+
Engine, Cache, and clients are configured through dependency injection.
197117

198-
**Rationale:**
199-
- Enables testing with mock implementations
200-
- Provides flexible configuration
201-
- Separates construction from usage
202-
- Supports different deployment scenarios
118+
This approach is justified by its ability to enable testing with mock implementations, provide flexible configuration options, separate the construction of components from their usage, and support various deployment scenarios.
203119

204-
**Alternatives considered:**
205-
- **Global singletons**: Hard to test and configure
206-
- **Service locator**: Hides dependencies
120+
Two alternatives were considered. Either global singletons or a service locator. However, global singletons are hard to test and configure, and a service locator hides dependencies.
207121

208-
**Trade-offs:**
209-
- Requires explicit wiring during initialization
210-
- Provides clear dependency graph
211-
- Enables flexible testing and configuration
122+
This decision has some trade-offs. While it requires explicit wiring during initialization, it offers the significant benefits of a clear dependency graph and enables flexible testing and configuration.

0 commit comments

Comments
 (0)