Skip to content

Architecture

System architecture, components, and data flows.

System architecture

Playpen runs on a local Kubernetes cluster with two main namespaces:

  • playpen-platform: Platform services (Jenkins, Nexus, Dex, PostgreSQL)
  • playpen-apps: User applications
graph TB
    subgraph Dev["Developer Workstation"]
        direction LR
        DevTools["kubectl<br/>Docker<br/>Helm"]
    end

    subgraph K8s["Kubernetes Cluster"]
        direction TB

        subgraph Platform["playpen-platform Namespace"]
            direction TB
            Jenkins["Jenkins<br/>CI/CD Controller<br/>:8080"]
            Nexus["Nexus Repository<br/>Maven & Docker<br/>:8081"]
            Dex["Dex OIDC Provider<br/>Authentication<br/>:5556"]
            Postgres["PostgreSQL<br/>Database<br/>:5432"]
        end

        subgraph Apps["playpen-apps Namespace"]
            direction TB
            App1["Python Apps"]
            App2["ML Services"]
            App3["GenAI Apps"]
        end

        subgraph Storage["Storage Layer"]
            direction LR
            PV["Persistent Volumes<br/>local-path-provisioner"]
        end
    end

    Dev -->|kubectl apply| K8s
    Dev -->|port-forward| Platform
    Platform -->|deploy| Apps
    Platform -->|store| Storage
    Apps -->|authenticate| Dex
    Apps -->|query| Postgres
    Apps -->|pull images| Nexus
    Jenkins -->|build & push| Nexus
    Jenkins -->|deploy| Apps

Component architecture

Platform services deployment

graph TB
    subgraph Platform["playpen-platform Namespace"]
        direction TB

        subgraph JenkinsBox["Jenkins CI/CD"]
            JCtrl["Jenkins Controller<br/>StatefulSet<br/>Port: 8080<br/>Storage: 20Gi"]
            JAgents["Ephemeral Agents<br/>• Kaniko (Docker builds)<br/>• Maven (Java builds)<br/>• Python (Python builds)"]
            JCtrl --> JAgents
        end

        subgraph NexusBox["Nexus Repository"]
            NexusPod["Nexus Pod<br/>Deployment<br/>Ports: 8081, 5000<br/>Storage: 20Gi"]
            MavenRepo["Maven Repositories<br/>• maven-releases<br/>• maven-snapshots"]
            DockerRepo["Docker Registry<br/>Port: 5000"]
            NexusPod --> MavenRepo
            NexusPod --> DockerRepo
        end

        subgraph DexBox["Dex OIDC Provider"]
            DexPod["Dex Pod<br/>Deployment<br/>Port: 5556<br/>Stateless"]
            DexConfig["OIDC Configuration<br/>• Azure Entra Compatible<br/>• Static Users<br/>• Client Credentials"]
            DexPod --> DexConfig
        end

        subgraph PostgresBox["PostgreSQL Database"]
            PGStateful["PostgreSQL<br/>StatefulSet<br/>Port: 5432<br/>Storage: 10Gi"]
            PGDB["Databases<br/>• playpen (app data)<br/>• dex (auth data)"]
            PGStateful --> PGDB
        end
    end

Data flows

CI/CD pipeline flow

sequenceDiagram
    participant Dev as Developer
    participant Git as Git Repository
    participant Jenkins as Jenkins
    participant Kaniko as Kaniko Agent
    participant Nexus as Nexus Registry
    participant K8s as Kubernetes

    Dev->>Git: git push
    Git->>Jenkins: Webhook trigger
    Jenkins->>Kaniko: Create build pod
    Kaniko->>Kaniko: Build Docker image
    Kaniko->>Nexus: Push image to registry
    Jenkins->>K8s: Deploy to playpen-apps
    K8s->>K8s: Create/update pods
    K8s-->>Dev: Application running

Authentication flow

sequenceDiagram
    participant User as User/App
    participant App as Application
    participant Dex as Dex OIDC
    participant DB as PostgreSQL

    User->>App: Access request
    App->>Dex: OIDC token request
    Dex->>DB: Validate credentials
    DB-->>Dex: User data
    Dex->>Dex: Generate token
    Dex-->>App: OIDC token
    App->>App: Validate token
    App-->>User: Authorized response

Networking

Service discovery

All services are accessible via Kubernetes DNS: - Jenkins: jenkins.playpen-platform.svc.cluster.local:8080 - Nexus: nexus.playpen-platform.svc.cluster.local:8081 - Dex: dex.playpen-platform.svc.cluster.local:5556 - PostgreSQL: postgres.playpen-platform.svc.cluster.local:5432

External access

Services use ClusterIP and are accessed via port-forwarding for local development: - Jenkins: localhost:8080 - Nexus: localhost:8081 - Dex: localhost:5556 - PostgreSQL: localhost:5432

Storage architecture

graph TB
    subgraph Storage["Storage Infrastructure"]
        direction TB

        SC["StorageClass<br/>local-path"]

        subgraph PVs["Persistent Volumes"]
            J_PV["Jenkins PVC<br/>20Gi<br/>Job History"]
            N_PV["Nexus PVC<br/>20Gi<br/>Artifacts"]
            P_PV["PostgreSQL PVC<br/>10Gi<br/>Database"]
        end

        subgraph Provisioner["local-path-provisioner"]
            ProvisionerPod["Provisioner Pod"]
            HostPath["Host Path<br/>/opt/local-path-provisioner"]
        end
    end

    SC --> ProvisionerPod
    ProvisionerPod --> HostPath
    J_PV --> SC
    N_PV --> SC
    P_PV --> SC

Security model

Service accounts

  • jenkins-agent: Minimal permissions for Jenkins agents
  • platform-services: Read access to configs/secrets

Secrets management

  • Kubernetes Secrets for credentials
  • No hard-coded secrets
  • Placeholder patterns for OIDC, DB, Nexus

Network policies

  • Optional network policies for isolation
  • Not enforced by default (for simplicity)

Resource requirements

Minimum

  • CPU: 4 cores
  • Memory: 8GB RAM
  • Disk: 50GB free
  • CPU: 8 cores
  • Memory: 16GB RAM
  • Disk: 100GB free

Scalability

Playpen is designed for local development, not production scale: - Single-node Kubernetes cluster - No multi-region support - No high availability - Limited to local resources

Technology stack

  • Orchestration: Kubernetes
  • CI/CD: Jenkins with Kubernetes agents
  • Artifacts: Nexus Repository Manager
  • Auth: Dex (OIDC)
  • Database: PostgreSQL
  • Container Build: Kaniko (no Docker socket)
  • Storage: local-path-provisioner

Next steps