Skip to content

AppGroup Class

The AppGroup class manages multiple related services and provides cross-service configuration capabilities for complex applications.

Overview

from celestra import AppGroup, App, StatefulApp

# Basic usage
platform = AppGroup("ecommerce")
platform.add_services([
    StatefulApp("database").image("postgres:14"),
    App("api").image("api:latest"),
    App("web").image("web:latest")
])

Functions

Add Service

Add a single service to the group.

# Add individual services
platform = AppGroup("myapp")
platform.add_service(App("api").image("api:latest"))
platform.add_service(StatefulApp("db").image("postgres:14"))
platform.add_service(App("web").image("web:latest"))

Add Services

Add multiple services to the group at once.

# Add multiple services
api = App("api").image("api:latest")
db = StatefulApp("db").image("postgres:14")
web = App("web").image("web:latest")

platform = AppGroup("myapp").add_services([api, db, web])

Remove Service

Remove a service from the group by name.

# Remove a service
platform = AppGroup("myapp")
platform.add_service(App("api").image("api:latest"))
platform.add_service(App("web").image("web:latest"))
platform.remove_service("api")  # Remove the API service

Get Service

Get a service by name.

# Get a specific service
platform = AppGroup("myapp")
platform.add_service(App("api").image("api:latest"))

api_service = platform.get_service("api")
if api_service:
    api_service.port(8080)

Add Shared Secret

Add a secret that will be shared across all services in the group.

# Add shared secret
shared_secret = Secret("shared-secret").add("api_key", "shared-key")
platform = AppGroup("myapp").add_shared_secret(shared_secret)

# All services in the group will have access to this secret

Add Shared Config

Add a ConfigMap that will be shared across all services in the group.

# Add shared configuration
shared_config = ConfigMap("shared-config").add("environment", "production")
platform = AppGroup("myapp").add_shared_config(shared_config)

# All services in the group will have access to this configuration

Configure Networking

Configure networking policies for the group.

# Basic internal communication
platform = AppGroup("myapp").configure_networking(allow_internal_communication=True)

# With external access restrictions
platform = AppGroup("myapp").configure_networking(
    allow_internal_communication=True,
    deny_external_access_except=["api", "web"]
)

# With service mesh
platform = AppGroup("myapp").configure_networking(
    service_mesh=True,
    mesh_config={"type": "istio", "version": "1.18"}
)

Configure Monitoring

Configure monitoring for the group.

# Basic monitoring
platform = AppGroup("myapp").configure_monitoring()

# Custom monitoring setup
platform = AppGroup("myapp").configure_monitoring(
    prometheus_enabled=True,
    grafana_enabled=True,
    jaeger_enabled=True,
    custom_metrics=["business_metrics", "user_activity"]
)

Configure Security

Configure security policies for the group.

# Basic security
platform = AppGroup("myapp").configure_security()

# Advanced security
platform = AppGroup("myapp").configure_security(
    rbac_enabled=True,
    pod_security_policy="restricted",
    network_policies=True,
    security_context={
        "runAsNonRoot": True,
        "runAsUser": 1000
    }
)

Set Dependencies

Set service dependencies for deployment ordering.

# Set multiple dependencies
dependencies = {
    "api": ["database"],
    "web": ["api"],
    "worker": ["database", "cache"]
}
platform = AppGroup("myapp").set_dependencies(dependencies)

Add Dependency

Add a dependency for a specific service.

# Single dependency
platform = AppGroup("myapp").add_dependency("api", "database")

# Multiple dependencies
platform = AppGroup("myapp").add_dependency("worker", ["database", "cache", "kafka"])

For Environment

Create environment-specific configuration for the group.

# Development environment
dev_platform = AppGroup("myapp").for_environment("development", {
    "replicas": 1,
    "resources": {"cpu": "100m", "memory": "256Mi"}
})

# Production environment
prod_platform = AppGroup("myapp").for_environment("production", {
    "replicas": 5,
    "resources": {"cpu": "500m", "memory": "1Gi"}
})

Set Resource Quotas

Set resource quotas for the namespace.

# Set resource quotas
platform = AppGroup("myapp").set_resource_quotas(
    cpu_limit="10",
    memory_limit="20Gi",
    storage_limit="100Gi",
    pod_limit=50
)

Configure Namespace

Configure the namespace for the group.

# Basic namespace
platform = AppGroup("myapp").configure_namespace()

# Custom namespace configuration
platform = AppGroup("myapp").configure_namespace(
    create_namespace=True,
    namespace_labels={
        "environment": "production",
        "team": "platform"
    },
    namespace_annotations={
        "description": "E-commerce platform"
    }
)

Get Service Names

Get the names of all services in the group.

platform = AppGroup("myapp")
platform.add_services([
    App("api").image("api:latest"),
    StatefulApp("db").image("postgres:14"),
    App("web").image("web:latest")
])

service_names = platform.get_service_names()
# Returns: ["api", "db", "web"]

Get Service Count

Get the number of services in the group.

platform = AppGroup("myapp")
platform.add_services([
    App("api").image("api:latest"),
    StatefulApp("db").image("postgres:14")
])

count = platform.get_service_count()  # Returns: 2

Complete Example

#!/usr/bin/env python3
"""
Complete AppGroup Example - E-commerce Platform
"""

import os
from celestra import AppGroup, App, StatefulApp, Secret, ConfigMap, KubernetesOutput

def load_config(config_path: str) -> str:
    """Load configuration from external file."""
    with open(f"configs/{config_path}", "r") as f:
        return f.read()

def create_ecommerce_platform():
    """Create a complete e-commerce platform."""

    # Load external configurations
    nginx_config = load_config("application/nginx.conf")
    postgres_config = load_config("database/postgres.conf")

    # Create shared secrets
    shared_secret = (Secret("shared-secret")
        .add("jwt_secret", "jwt-signing-key")
        .add("stripe_key", "sk_live_...")
        .mount_as_env_vars(prefix="SHARED_"))

    # Create shared configurations
    shared_config = (ConfigMap("shared-config")
        .add("environment", "production")
        .add("log_level", "info")
        .add_json("features", {
            "new_ui": True,
            "beta_features": False
        }))

    # Create services
    database = (StatefulApp("postgres")
        .image("postgres:14")
        .port(5432)
        .storage("50Gi", "fast-ssd")
        .resources(cpu="2", memory="4Gi")
        .replicas(3)
        .add_secret(Secret("db-secret").add("password", "secure-password")))

    cache = (StatefulApp("redis")
        .image("redis:7-alpine")
        .port(6379)
        .storage("10Gi", "fast-ssd")
        .resources(cpu="1", memory="2Gi")
        .replicas(3))

    api = (App("api")
        .image("api:v2.1.0")
        .port(8080)
        .replicas(5)
        .resources(cpu="500m", memory="1Gi")
        .add_secret(Secret("api-secret").add("api_key", "api-key-123")))

    web = (App("web")
        .image("web:v2.1.0")
        .port(8080)
        .replicas(3)
        .resources(cpu="300m", memory="512Mi")
        .add_config(ConfigMap("nginx-config").add_data("nginx.conf", nginx_config)))

    worker = (App("worker")
        .image("worker:v2.1.0")
        .port(8080)
        .replicas(2)
        .resources(cpu="200m", memory="512Mi"))

    # Create the platform
    platform = (AppGroup("ecommerce")
        .add_services([database, cache, api, web, worker])
        .add_shared_secret(shared_secret)
        .add_shared_config(shared_config)
        .configure_networking(
            allow_internal_communication=True,
            deny_external_access_except=["api", "web"]
        )
        .configure_monitoring(
            prometheus_enabled=True,
            grafana_enabled=True,
            jaeger_enabled=True
        )
        .configure_security(
            rbac_enabled=True,
            pod_security_policy="restricted",
            network_policies=True
        )
        .set_dependencies({
            "api": ["postgres", "redis"],
            "web": ["api"],
            "worker": ["postgres", "redis"]
        })
        .set_resource_quotas(
            cpu_limit="20",
            memory_limit="40Gi",
            storage_limit="200Gi",
            pod_limit=100
        )
        .configure_namespace(
            create_namespace=True,
            namespace_labels={
                "environment": "production",
                "team": "ecommerce"
            }
        ))

    return platform

if __name__ == "__main__":
    platform = create_ecommerce_platform()

    # Generate Kubernetes resources
    output = KubernetesOutput()
    resources = platform.generate_kubernetes_resources()

    # Write to files
    for i, resource in enumerate(resources):
        output.write_resource(resource, f"ecommerce-platform/resource-{i}.yaml")

    print("✅ E-commerce platform generated!")
    print("🚀 Deploy: kubectl apply -f ecommerce-platform/")

Generated Kubernetes Resources

The AppGroup class generates the following Kubernetes resources:

  • Namespace - Dedicated namespace for the group
  • ResourceQuota - Resource limits for the namespace
  • Services - All services in the group
  • Deployments/StatefulSets - All workloads
  • ConfigMaps - Shared and service-specific configurations
  • Secrets - Shared and service-specific secrets
  • NetworkPolicies - Network security policies
  • RBAC - Role-based access control
  • Monitoring - Prometheus, Grafana, Jaeger (if enabled)

Usage Patterns

Microservices Platform

# Microservices platform
platform = AppGroup("microservices")
platform.add_services([
    StatefulApp("postgres").image("postgres:14").port(5432),
    StatefulApp("redis").image("redis:7").port(6379),
    App("user-service").image("user-service:latest").port(8080),
    App("order-service").image("order-service:latest").port(8080),
    App("payment-service").image("payment-service:latest").port(8080),
    App("notification-service").image("notification-service:latest").port(8080)
])
platform.configure_networking(allow_internal_communication=True)

Data Processing Platform

# Data processing platform
platform = AppGroup("data-platform")
platform.add_services([
    StatefulApp("kafka").image("confluentinc/cp-kafka:7.4.0").port(9092),
    StatefulApp("elasticsearch").image("elasticsearch:8.8.0").port(9200),
    App("data-ingestion").image("ingestion:latest").port(8080),
    App("data-processing").image("processing:latest").port(8080),
    App("data-visualization").image("visualization:latest").port(8080)
])
platform.configure_monitoring(prometheus_enabled=True, grafana_enabled=True)

Development vs Production

# Development environment
dev_platform = AppGroup("myapp-dev").for_environment("development", {
    "replicas": 1,
    "resources": {"cpu": "100m", "memory": "256Mi"}
})

# Production environment
prod_platform = AppGroup("myapp").for_environment("production", {
    "replicas": 5,
    "resources": {"cpu": "500m", "memory": "1Gi"}
})

Best Practices

1. Use Shared Resources

# ✅ Good: Use shared secrets and configs
platform = AppGroup("myapp")
platform.add_shared_secret(Secret("shared-secret").add("key", "value"))
platform.add_shared_config(ConfigMap("shared-config").add("env", "prod"))

# ❌ Bad: Duplicate secrets/configs for each service

2. Set Dependencies

# ✅ Good: Set proper dependencies
platform = AppGroup("myapp").set_dependencies({
    "api": ["database"],
    "web": ["api"]
})

# ❌ Bad: No dependency management

3. Configure Security

# ✅ Good: Enable security features
platform = AppGroup("myapp").configure_security(
    rbac_enabled=True,
    network_policies=True
)

# ❌ Bad: No security configuration

4. Set Resource Quotas

# ✅ Good: Set resource quotas
platform = AppGroup("myapp").set_resource_quotas(
    cpu_limit="10",
    memory_limit="20Gi"
)

# ❌ Bad: No resource limits

5. Use Environment-Specific Configs

# ✅ Good: Environment-specific configuration
dev_platform = AppGroup("myapp").for_environment("development")
prod_platform = AppGroup("myapp").for_environment("production")

# ❌ Bad: Same config for all environments