sal/kubernetes/README.md
Mahmoud-Emad 6b12001ca2 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.
2025-07-10 00:40:11 +03:00

16 KiB

SAL Kubernetes (sal-kubernetes)

Kubernetes cluster management and operations for the System Abstraction Layer (SAL).

Installation

Add this to your Cargo.toml:

[dependencies]
sal-kubernetes = "0.1.0"

⚠️ IMPORTANT SECURITY NOTICE

This package includes destructive operations that can permanently delete Kubernetes resources!

  • The delete(pattern) function uses PCRE regex patterns to bulk delete resources
  • Always test patterns in a safe environment first
  • Use specific patterns to avoid accidental deletion of critical resources
  • Consider the impact on dependent resources before deletion
  • No confirmation prompts - deletions are immediate and irreversible

Overview

This package provides a high-level interface for managing Kubernetes clusters using the kube-rs SDK. It focuses on namespace-scoped operations through the KubernetesManager factory pattern.

Production Safety Features

  • Configurable Timeouts: All operations have configurable timeouts to prevent hanging
  • Exponential Backoff Retry: Automatic retry logic for transient failures
  • Rate Limiting: Built-in rate limiting to prevent API overload
  • Comprehensive Error Handling: Detailed error types and proper error propagation
  • Structured Logging: Production-ready logging for monitoring and debugging

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 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

// 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

Deploy complete applications with labels and environment variables:

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

use sal_kubernetes::KubernetesManager;

#[tokio::main]
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(())
}

Rhai Scripting

// Create Kubernetes manager for namespace
let km = kubernetes_manager_new("default");

// 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");

namespace_create(km, "my-namespace");
delete(km, "test-.*");

Dependencies

  • kube: Kubernetes client library
  • k8s-openapi: Kubernetes API types
  • tokio: Async runtime
  • regex: Pattern matching for resource deletion
  • rhai: Scripting integration (optional)

Configuration

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

Production Safety Configuration

use sal_kubernetes::{KubernetesManager, KubernetesConfig};
use std::time::Duration;

// Create with custom configuration
let config = KubernetesConfig::new()
    .with_timeout(Duration::from_secs(60))
    .with_retries(5, Duration::from_secs(1), Duration::from_secs(30))
    .with_rate_limit(20, 50);

let km = KubernetesManager::with_config("my-namespace", config).await?;

Pre-configured Profiles

// High-throughput environment
let config = KubernetesConfig::high_throughput();

// Low-latency environment
let config = KubernetesConfig::low_latency();

// Development/testing
let config = KubernetesConfig::development();

Error Handling

All operations return Result<T, KubernetesError> with comprehensive error types for different failure scenarios including API errors, configuration issues, and permission problems.

API Reference

KubernetesManager

The main interface for Kubernetes operations. Each instance is scoped to a single namespace.

Constructor

  • 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
  • services_list() - List all services in the namespace
  • deployments_list() - List all deployments in the namespace
  • configmaps_list() - List all configmaps in the namespace
  • secrets_list() - List all secrets in the namespace

Resource Management

  • pod_get(name) - Get a specific pod by name
  • service_get(name) - Get a specific service by name
  • deployment_get(name) - Get a specific deployment by name
  • 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

  • delete(pattern) - Delete all resources matching a PCRE pattern

Namespace Operations

  • namespace_create(name) - Create a namespace (idempotent)
  • namespace_exists(name) - Check if a namespace exists
  • namespaces_list() - List all namespaces (cluster-wide)

Utility Functions

  • resource_counts() - Get counts of all resource types in the namespace
  • namespace() - Get the namespace this manager operates on

Rhai Functions

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
  • 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/clusters/ directory contains comprehensive examples:

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

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

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

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

# Unit tests (no cluster required)
cargo test --package sal-kubernetes

# Integration tests (requires cluster)
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

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
  • 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

// 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?;