Skip to content

Commit cba0838

Browse files
committed
fix: stuff
1 parent dc694f3 commit cba0838

File tree

7 files changed

+430
-66
lines changed

7 files changed

+430
-66
lines changed

.github/workflows/setup_test_env.yml

Lines changed: 0 additions & 33 deletions
This file was deleted.

ReadMe.md

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,35 @@
1-
# Experimental repo, will be updated - ignore all documentation and readme for now
1+
# Flipper Zero Kubernetes-inspired Containerization (Experimental)
22

3-
# Flipper Zero Firmware
3+
> **NOTICE:** This is an experimental fork exploring containerization concepts for Flipper Zero.
4+
> This is NOT the official Flipper Zero firmware repository.
45
5-
- [Flipper Zero Official Website](https://flipperzero.one). A simple way to explain to your friends what Flipper Zero can do.
6-
- [Flipper Zero Firmware Update](https://flipperzero.one/update). Improvements for your dolphin: latest firmware releases, upgrade tools for PC and mobile devices.
7-
- [User Documentation](https://docs.flipper.net). Learn more about your dolphin: specs, usage guides, and anything you want to ask.
8-
- [Developer Documentation](https://developer.flipper.net/flipperzero/doxygen). Dive into the Flipper Zero Firmware source code: build system, firmware structure, and more.
6+
This project implements a lightweight containerization system for Flipper Zero, inspired by Kubernetes
7+
but designed specifically for highly constrained microcontroller environments.
8+
9+
## Key Features
10+
11+
- **Container Runtime**: Lightweight container lifecycle management
12+
- **Pod Manifests**: Declarative application deployment
13+
- **Service Registry**: Efficient service discovery
14+
- **Resource Limits**: Memory and CPU quota enforcement
15+
16+
## Hardware Constraints
17+
18+
This implementation takes into account Flipper Zero's limited resources:
19+
- ~256KB RAM
20+
- ARM Cortex-M4 @ 64MHz
21+
- Limited flash storage
22+
- Battery-powered operation
23+
24+
## Getting Started
25+
26+
See the [Containerization Documentation](/documentation/Containerization.md) for details
27+
on how to use this system.
28+
29+
## Original Project
30+
31+
This is based on the [official Flipper Zero firmware](https://github.com/flipperdevices/flipperzero-firmware).
32+
Please refer to the official repository for the latest stable firmware.
933

1034
# Contributing
1135

documentation/Containerization.md

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,21 @@ The containerization system implements several critical optimizations for resour
2121
- **Hash-Based Service Lookups**: O(1) service discovery with hash-based optimization
2222
- **Lazy Loading**: Resources are loaded only when needed to minimize memory footprint
2323
- **Zero-Copy IPC**: Communication between containers uses shared memory references when possible
24+
- **Static Pre-allocation**: Critical resources are pre-allocated to avoid heap fragmentation
25+
- **Scheduled Health Checks**: Health checks are performed at timed intervals, not continuously
26+
27+
## Resource Constraints
28+
29+
Flipper Zero has extremely limited resources compared to typical container environments:
30+
31+
| Resource | Limit | Notes |
32+
|----------|-------|-------|
33+
| RAM | ~256KB | Shared between system and all containers |
34+
| CPU | 64MHz | ARM Cortex-M4 |
35+
| Storage | ~2MB | Available for all container images |
36+
| Power | Battery | Energy efficiency is critical |
37+
38+
Containers must be designed with these constraints in mind. Typical containers use 2-10KB of RAM.
2439

2540
## Usage Examples
2641

@@ -56,16 +71,21 @@ if(service) {
5671

5772
## Best Practices
5873

59-
1. Always specify resource limits in pod manifests
60-
2. Keep container count low - optimal performance with 3-5 containers
61-
3. Use service registry for interface discovery rather than direct references
62-
4. Implement graceful shutdown in containers to prevent resource leaks
63-
5. Prefer static allocation over dynamic when possible
74+
1. **Resource Planning**: Always specify reasonable resource limits in pod manifests
75+
2. **Container Count**: Keep container count very low - optimal performance with 2-3 containers
76+
3. **Service Discovery**: Use service registry for interface discovery rather than direct references
77+
4. **Static Allocation**: Prefer static allocation over dynamic whenever possible
78+
5. **Lazy Initialization**: Initialize resources only when needed, not at startup
79+
6. **Garbage Collection**: Implement proper cleanup to prevent memory leaks
80+
7. **Health Checks**: Use periodic health checks with reasonable intervals (5-10s)
81+
8. **Namespaces**: Organize services into namespaces for better isolation
82+
9. **Minimal Containers**: Keep container images as small as possible
6483

6584
## Future Improvements
6685

86+
- Resource quotas at namespace level
6787
- Container networking with virtual interfaces
6888
- Volume mounts for shared persistent storage
69-
- Container health checks and self-healing
89+
- Improved health checks and self-healing mechanisms
7090
- Configuration maps for environment variables
7191

furi/containerization/container_runtime.c

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
#define TAG "ContainerRT"
1414

1515
// Reduced maximum number of containers to conserve memory
16-
#define MAX_CONTAINERS 8
16+
#define MAX_CONTAINERS 5 // Reduced from 8 to save memory
17+
#define CONTAINER_POOL_SIZE 3 // Pre-allocated container handles
1718

1819
typedef struct Container {
1920
ContainerConfig config;
2021
ContainerStatus status;
2122
void* app_handle;
23+
uint32_t last_health_check; // Timestamps to avoid checking too frequently
2224
} Container;
2325

2426
struct ContainerRuntime {
@@ -29,10 +31,19 @@ struct ContainerRuntime {
2931
uint8_t active_container_count; // Track running containers separately
3032
bool running;
3133
ContainerHandle* recycled_container_pool; // Memory pool for container handles
34+
ContainerHandle container_handle_pool[CONTAINER_POOL_SIZE]; // Static allocation
35+
uint8_t next_free_handle_index;
3236
};
3337

34-
// Ultra-minimal container health checker - just checks if the underlying app is still running
38+
// Memory-efficient container health checker - check less frequently
3539
static void container_check_health(Container* container) {
40+
// Only check every 5 seconds to reduce CPU usage
41+
uint32_t current_time = furi_get_tick();
42+
if(current_time - container->last_health_check < 5000) {
43+
return;
44+
}
45+
container->last_health_check = current_time;
46+
3647
if(!container || container->status.state != ContainerStateRunning) {
3748
return;
3849
}
@@ -198,6 +209,25 @@ static Container* container_find_free_slot(ContainerRuntime* runtime) {
198209
return NULL;
199210
}
200211

212+
// Preflight check for resources - fail early if not enough memory
213+
bool container_runtime_can_start_container(ContainerRuntime* runtime, const ContainerConfig* config) {
214+
// Calculate system's free memory - simplified example
215+
size_t free_mem = furi_get_free_heap_size();
216+
size_t required_mem = config->resource_limits.max_memory;
217+
218+
// Add 20% overhead for container management
219+
required_mem = required_mem * 1.2;
220+
221+
// Check if there's enough memory
222+
if(free_mem < required_mem) {
223+
FURI_LOG_W(TAG, "Not enough memory to start container %s", config->name);
224+
FURI_LOG_W(TAG, "Required: %d, Available: %d", required_mem, free_mem);
225+
return false;
226+
}
227+
228+
return true;
229+
}
230+
201231
Container* container_create(ContainerRuntime* runtime, const ContainerConfig* config) {
202232
furi_assert(runtime);
203233
furi_assert(config);
@@ -224,6 +254,12 @@ Container* container_create(ContainerRuntime* runtime, const ContainerConfig* co
224254
return NULL;
225255
}
226256

257+
// Check available resources before proceeding
258+
if(!container_runtime_can_start_container(runtime, config)) {
259+
furi_mutex_release(runtime->mutex);
260+
return NULL;
261+
}
262+
227263
// Find unused container slot
228264
Container* container = container_find_free_slot(runtime);
229265
if(!container) {
@@ -392,7 +428,7 @@ uint16_t container_runtime_get_running_count(ContainerRuntime* runtime) {
392428
return count;
393429
}
394430

395-
// Memory optimization - reuse container objects where possible
431+
// Optimize memory allocation with static pool
396432
ContainerHandle* container_runtime_allocate_handle(ContainerRuntime* runtime) {
397433
furi_assert(runtime);
398434

@@ -401,10 +437,16 @@ ContainerHandle* container_runtime_allocate_handle(ContainerRuntime* runtime) {
401437
furi_mutex_acquire(runtime->mutex, FuriWaitForever);
402438

403439
if(runtime->recycled_container_pool) {
440+
// Reuse from linked list if available
404441
handle = runtime->recycled_container_pool;
405442
runtime->recycled_container_pool = handle->next;
406443
memset(handle, 0, sizeof(ContainerHandle));
444+
} else if(runtime->next_free_handle_index < CONTAINER_POOL_SIZE) {
445+
// Use from static pool if available
446+
handle = &runtime->container_handle_pool[runtime->next_free_handle_index++];
447+
memset(handle, 0, sizeof(ContainerHandle));
407448
} else {
449+
// Fall back to malloc only if necessary
408450
handle = malloc(sizeof(ContainerHandle));
409451
if(handle) {
410452
memset(handle, 0, sizeof(ContainerHandle));

furi/containerization/pod_manifest.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,46 @@ bool pod_manifest_validate(PodManifest* manifest);
8888
*/
8989
bool pod_manifest_validate_optimized(const PodManifest* manifest);
9090

91+
/**
92+
* @brief Pod manifest validator with resource constraints check
93+
*
94+
* Validates that required resources are available and pod can be scheduled.
95+
* Similar to Kubernetes admission controllers.
96+
*
97+
* @param manifest Pod manifest to validate
98+
* @param runtime Container runtime for resource checks
99+
* @return bool true if manifest is valid and can be scheduled
100+
*/
101+
bool pod_manifest_validate_resources(const PodManifest* manifest, ContainerRuntime* runtime);
102+
103+
/**
104+
* @brief Apply taints and tolerations to pod scheduling
105+
*
106+
* Controls which pods can run on particular nodes/apps,
107+
* similar to Kubernetes taints and tolerations.
108+
*
109+
* @param manifest The pod manifest to update
110+
* @param taints Array of taint specifications
111+
* @param taint_count Number of taints in array
112+
* @return bool true if successful
113+
*/
114+
bool pod_manifest_apply_taints(PodManifest* manifest, const PodTaint* taints, size_t taint_count);
115+
116+
/**
117+
* @brief Memory-optimized pod manifest loading
118+
*
119+
* Uses streaming JSON parser to minimize memory usage while loading manifests.
120+
*
121+
* @param path Path to manifest file
122+
* @param buffer Working buffer for parsing
123+
* @param buffer_size Size of working buffer
124+
* @return PodManifest* Newly created pod manifest or NULL on failure
125+
*/
126+
PodManifest* pod_manifest_load_from_file_buffered(
127+
const char* path,
128+
char* buffer,
129+
size_t buffer_size);
130+
91131
/**
92132
* @brief Batch apply multiple pod manifests
93133
* Similar to 'kubectl apply -f' with multiple files in Kubernetes.

0 commit comments

Comments
 (0)