feat: Add Kubernetes examples and update dependencies

- Add Kubernetes examples demonstrating deployment of various
  applications (PostgreSQL, Redis, generic). This improves the
  documentation and provides practical usage examples.
- Add `tokio` dependency for async examples. This enables the use
  of asynchronous operations in the examples.
- Add `once_cell` dependency for improved resource management in
  Kubernetes module. This allows efficient management of
  singletons and other resources.
This commit is contained in:
Mahmoud-Emad
2025-07-10 00:40:11 +03:00
parent 99e121b0d8
commit 6b12001ca2
29 changed files with 1951 additions and 482 deletions

View File

@@ -35,15 +35,96 @@ This package provides a high-level interface for managing Kubernetes clusters us
## Features
- **Application Deployment**: Deploy complete applications with a single method call
- **Environment Variables & Labels**: Configure containers with environment variables and Kubernetes labels
- **Resource Lifecycle Management**: Automatic cleanup and replacement of existing resources
- **Namespace-scoped Management**: Each `KubernetesManager` instance operates on a single namespace
- **Pod Management**: List, create, and manage pods
- **Pattern-based Deletion**: Delete resources using PCRE pattern matching
- **Namespace Operations**: Create and manage namespaces (idempotent operations)
- **Resource Management**: Support for pods, services, deployments, configmaps, secrets, and more
- **Rhai Integration**: Full scripting support through Rhai wrappers
- **Rhai Integration**: Full scripting support through Rhai wrappers with environment variables
## Core Concepts
### Labels vs Environment Variables
Understanding the difference between labels and environment variables is crucial for effective Kubernetes deployments:
#### **Labels** (Kubernetes Metadata)
- **Purpose**: Organize, select, and manage Kubernetes resources
- **Scope**: Kubernetes cluster management and resource organization
- **Visibility**: Used by Kubernetes controllers, selectors, and monitoring systems
- **Examples**: `app=my-app`, `tier=backend`, `environment=production`, `version=v1.2.3`
- **Use Cases**: Resource grouping, service discovery, monitoring labels, deployment strategies
#### **Environment Variables** (Container Configuration)
- **Purpose**: Configure application runtime behavior and settings
- **Scope**: Inside container processes - available to your application code
- **Visibility**: Accessible via `process.env`, `os.environ`, etc. in your application
- **Examples**: `NODE_ENV=production`, `DATABASE_URL=postgres://...`, `API_KEY=secret`
- **Use Cases**: Database connections, API keys, feature flags, runtime configuration
#### **Example: Complete Application Configuration**
```rust
// Labels: For Kubernetes resource management
let mut labels = HashMap::new();
labels.insert("app".to_string(), "web-api".to_string()); // Service discovery
labels.insert("tier".to_string(), "backend".to_string()); // Architecture layer
labels.insert("environment".to_string(), "production".to_string()); // Deployment stage
labels.insert("version".to_string(), "v2.1.0".to_string()); // Release version
// Environment Variables: For application configuration
let mut env_vars = HashMap::new();
env_vars.insert("NODE_ENV".to_string(), "production".to_string()); // Runtime mode
env_vars.insert("DATABASE_URL".to_string(), "postgres://db:5432/app".to_string()); // DB connection
env_vars.insert("REDIS_URL".to_string(), "redis://cache:6379".to_string()); // Cache connection
env_vars.insert("LOG_LEVEL".to_string(), "info".to_string()); // Logging config
```
## Usage
### Application Deployment (Recommended)
Deploy complete applications with labels and environment variables:
```rust
use sal_kubernetes::KubernetesManager;
use std::collections::HashMap;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let km = KubernetesManager::new("default").await?;
// Configure labels for Kubernetes resource organization
let mut labels = HashMap::new();
labels.insert("app".to_string(), "my-app".to_string());
labels.insert("tier".to_string(), "backend".to_string());
// Configure environment variables for the container
let mut env_vars = HashMap::new();
env_vars.insert("NODE_ENV".to_string(), "production".to_string());
env_vars.insert("DATABASE_URL".to_string(), "postgres://db:5432/myapp".to_string());
env_vars.insert("API_KEY".to_string(), "secret-api-key".to_string());
// Deploy application with deployment + service
km.deploy_application(
"my-app", // name
"node:18-alpine", // image
3, // replicas
3000, // port
Some(labels), // Kubernetes labels
Some(env_vars), // container environment variables
).await?;
println!("✅ Application deployed successfully!");
Ok(())
}
```
### Basic Operations
```rust
@@ -53,17 +134,17 @@ use sal_kubernetes::KubernetesManager;
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a manager for the "default" namespace
let km = KubernetesManager::new("default").await?;
// List all pods in the namespace
let pods = km.pods_list().await?;
println!("Found {} pods", pods.len());
// Create a namespace (no error if it already exists)
km.namespace_create("my-namespace").await?;
// Delete resources matching a pattern
km.delete("test-.*").await?;
Ok(())
}
```
@@ -74,14 +155,24 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create Kubernetes manager for namespace
let km = kubernetes_manager_new("default");
// List pods
// Deploy application with labels and environment variables
deploy_application(km, "my-app", "node:18-alpine", 3, 3000, #{
"app": "my-app",
"tier": "backend",
"environment": "production"
}, #{
"NODE_ENV": "production",
"DATABASE_URL": "postgres://db:5432/myapp",
"API_KEY": "secret-api-key"
});
print("✅ Application deployed!");
// Basic operations
let pods = pods_list(km);
print("Found " + pods.len() + " pods");
// Create namespace
namespace_create(km, "my-app");
// Delete test resources
namespace_create(km, "my-namespace");
delete(km, "test-.*");
```
@@ -98,6 +189,7 @@ delete(km, "test-.*");
### Kubernetes Authentication
The package uses the standard Kubernetes configuration methods:
- In-cluster configuration (when running in a pod)
- Kubeconfig file (`~/.kube/config` or `KUBECONFIG` environment variable)
- Service account tokens
@@ -144,6 +236,18 @@ The main interface for Kubernetes operations. Each instance is scoped to a singl
- `KubernetesManager::new(namespace)` - Create a manager for the specified namespace
#### Application Deployment
- `deploy_application(name, image, replicas, port, labels, env_vars)` - Deploy complete application with deployment and service
- `deployment_create(name, image, replicas, labels, env_vars)` - Create deployment with environment variables and labels
#### Resource Creation
- `pod_create(name, image, labels, env_vars)` - Create pod with environment variables and labels
- `service_create(name, selector, port, target_port)` - Create service with port mapping
- `configmap_create(name, data)` - Create configmap with data
- `secret_create(name, data, secret_type)` - Create secret with data and optional type
#### Resource Listing
- `pods_list()` - List all pods in the namespace
@@ -160,6 +264,8 @@ The main interface for Kubernetes operations. Each instance is scoped to a singl
- `pod_delete(name)` - Delete a specific pod by name
- `service_delete(name)` - Delete a specific service by name
- `deployment_delete(name)` - Delete a specific deployment by name
- `configmap_delete(name)` - Delete a specific configmap by name
- `secret_delete(name)` - Delete a specific secret by name
#### Pattern-based Operations
@@ -180,32 +286,93 @@ The main interface for Kubernetes operations. Each instance is scoped to a singl
When using the Rhai integration, the following functions are available:
**Manager Creation & Application Deployment:**
- `kubernetes_manager_new(namespace)` - Create a KubernetesManager
- `deploy_application(km, name, image, replicas, port, labels, env_vars)` - Deploy application with environment variables
**Resource Listing:**
- `pods_list(km)` - List pods
- `services_list(km)` - List services
- `deployments_list(km)` - List deployments
- `configmaps_list(km)` - List configmaps
- `secrets_list(km)` - List secrets
- `namespaces_list(km)` - List all namespaces
- `delete(km, pattern)` - Delete resources matching pattern
- `namespace_create(km, name)` - Create namespace
- `namespace_exists(km, name)` - Check namespace existence
- `resource_counts(km)` - Get resource counts
**Resource Operations:**
- `delete(km, pattern)` - Delete resources matching pattern
- `pod_delete(km, name)` - Delete specific pod
- `service_delete(km, name)` - Delete specific service
- `deployment_delete(km, name)` - Delete specific deployment
- `configmap_delete(km, name)` - Delete specific configmap
- `secret_delete(km, name)` - Delete specific secret
**Namespace Functions:**
- `namespace_create(km, name)` - Create namespace
- `namespace_exists(km, name)` - Check namespace existence
- `namespace_delete(km, name)` - Delete namespace
- `namespace(km)` - Get manager's namespace
## Examples
The `examples/kubernetes/` directory contains comprehensive examples:
The `examples/kubernetes/clusters/` directory contains comprehensive examples:
- `basic_operations.rhai` - Basic listing and counting operations
- `namespace_management.rhai` - Creating and managing namespaces
- `pattern_deletion.rhai` - Using PCRE patterns for bulk deletion
- `multi_namespace_operations.rhai` - Working across multiple namespaces
### Rust Examples
Run with: `cargo run --example <name> --features kubernetes`
- `postgres` - PostgreSQL database deployment with environment variables
- `redis` - Redis cache deployment with configuration
- `generic` - Multiple application deployments (nginx, node.js, mongodb)
### Rhai Examples
Run with: `./target/debug/herodo examples/kubernetes/clusters/<script>.rhai`
- `postgres.rhai` - PostgreSQL cluster deployment script
- `redis.rhai` - Redis cluster deployment script
### Real-World Examples
#### PostgreSQL Database
```rust
let mut env_vars = HashMap::new();
env_vars.insert("POSTGRES_DB".to_string(), "myapp".to_string());
env_vars.insert("POSTGRES_USER".to_string(), "postgres".to_string());
env_vars.insert("POSTGRES_PASSWORD".to_string(), "secretpassword".to_string());
km.deploy_application("postgres", "postgres:15", 1, 5432, Some(labels), Some(env_vars)).await?;
```
#### Redis Cache
```rust
let mut env_vars = HashMap::new();
env_vars.insert("REDIS_PASSWORD".to_string(), "redispassword".to_string());
env_vars.insert("REDIS_MAXMEMORY".to_string(), "256mb".to_string());
km.deploy_application("redis", "redis:7-alpine", 3, 6379, None, Some(env_vars)).await?;
```
## Testing
Run tests with:
### Test Coverage
The module includes comprehensive test coverage:
- **Unit Tests**: Core functionality without cluster dependency
- **Integration Tests**: Real Kubernetes cluster operations
- **Environment Variables Tests**: Complete env var functionality testing
- **Edge Cases Tests**: Error handling and boundary conditions
- **Rhai Integration Tests**: Scripting environment testing
- **Production Readiness Tests**: Concurrent operations and error handling
### Running Tests
```bash
# Unit tests (no cluster required)
@@ -216,12 +383,61 @@ KUBERNETES_TEST_ENABLED=1 cargo test --package sal-kubernetes
# Rhai integration tests
KUBERNETES_TEST_ENABLED=1 cargo test --package sal-kubernetes --features rhai
# Run specific test suites
cargo test --package sal-kubernetes deployment_env_vars_test
cargo test --package sal-kubernetes edge_cases_test
# Rhai environment variables test
KUBERNETES_TEST_ENABLED=1 ./target/debug/herodo kubernetes/tests/rhai/env_vars_test.rhai
```
## Security Considerations
### Test Requirements
- **Kubernetes Cluster**: Integration tests require a running Kubernetes cluster
- **Environment Variable**: Set `KUBERNETES_TEST_ENABLED=1` to enable integration tests
- **Permissions**: Tests require permissions to create/delete resources in the `default` namespace
## Production Considerations
### Security
- Always use specific PCRE patterns to avoid accidental deletion of important resources
- Test deletion patterns in a safe environment first
- Ensure proper RBAC permissions are configured
- Be cautious with cluster-wide operations like namespace listing
- Consider using dry-run approaches when possible
- Use Kubernetes secrets for sensitive environment variables instead of plain text
### Performance & Scalability
- Consider adding resource limits (CPU/memory) for production deployments
- Use persistent volumes for stateful applications
- Configure readiness and liveness probes for health checks
- Implement proper monitoring and logging labels
### Environment Variables Best Practices
- Use Kubernetes secrets for sensitive data (passwords, API keys)
- Validate environment variable values before deployment
- Use consistent naming conventions (e.g., `DATABASE_URL`, `API_KEY`)
- Document required vs optional environment variables
### Example: Production-Ready Deployment
```rust
// Production labels for monitoring and management
let mut labels = HashMap::new();
labels.insert("app".to_string(), "web-api".to_string());
labels.insert("version".to_string(), "v1.2.3".to_string());
labels.insert("environment".to_string(), "production".to_string());
labels.insert("team".to_string(), "backend".to_string());
// Non-sensitive environment variables
let mut env_vars = HashMap::new();
env_vars.insert("NODE_ENV".to_string(), "production".to_string());
env_vars.insert("LOG_LEVEL".to_string(), "info".to_string());
env_vars.insert("PORT".to_string(), "3000".to_string());
// Note: Use Kubernetes secrets for DATABASE_URL, API_KEY, etc.
km.deploy_application("web-api", "myapp:v1.2.3", 3, 3000, Some(labels), Some(env_vars)).await?;
```