Edit this page on GitHub

Architecture Overview

telectl is a direct-API Kubernetes bot: the binary runs inside (or next to) your cluster and talks to the API server with client-go. No agent pods, no webhook relays, no kubectl subprocesses — every operation is a native Kubernetes API call.

Component Diagram

flowchart TB
    subgraph User["Outside the cluster"]
        U1[Telegram user 1]
        U2[Telegram user 2]
        U3[Telegram user N]
    end

    subgraph Cloud["Telegram"]
        API[Bot API server]
    end

    subgraph K8sCluster["Your Kubernetes cluster"]
        subgraph NS["namespace: telectl"]
            Pod[telectl pod]
            SA[ServiceAccount: telectl]
            Secret[Secret: bot token + user IDs]
            CM[ConfigMap: telectl.yaml]
            ImpCR[ClusterRole: telectl-impersonator]
        end

        APIServer[(API server)]

        ImpUserA[Identity: admin-user<br/>groups: system:masters]
        ImpUserB[Identity: readonly-user<br/>groups: viewers]

        RBAC1[ClusterRoleBinding<br/>readonly-user → viewers]
        RBAC2[ClusterRoleBinding<br/>admin-user → system:masters]
    end

    U1 -->|HTTPS long-poll| API
    U2 -->|HTTPS long-poll| API
    U3 -->|HTTPS long-poll| API
    API -->|getUpdates| Pod

    Pod -->|uses token| SA
    Pod -->|reads| Secret
    Pod -->|reads| CM
    Pod -->|impersonates| APIServer

    APIServer -->|checks| ImpCR
    ImpUserA --> RBAC2
    ImpUserB --> RBAC1

Request Flow (mutating action, e.g. scale)

sequenceDiagram
    participant U as Telegram user
    participant B as telectl bot
    participant K as API server
    participant R as RBAC

    U->>B: tap "Scale to 10" on deployment pane
    B->>B: resolve callback → applyScale
    B->>B: look up user mapping → identity (user + groups)
    B->>K: PATCH deployments/scale as impersonated identity
    K->>R: authorize(user, groups, verb, resource)
    alt allowed
        R-->>K: allow
        K-->>B: 200 OK
        B->>U: re-render detail pane (new replica count)
    else forbidden
        R-->>K: deny
        K-->>B: 403 Forbidden
        B->>U: show Forbidden error in pane
    end

Key Design Decisions

Decision Why
Direct API, no kubectl One binary, no subprocess management, typed clients
Impersonation for per-user RBAC The bot holds one ServiceAccount; each Telegram user is mapped to a k8s identity, and Kubernetes RBAC decides what they may do
Single message pane Menu navigation edits one message in place; verbs render into the pane (TUI-style)
Rich messages with plain fallback Native tables/headings where the Bot API supports them; graceful fallback to text
GHCR multi-arch images linux/amd64 + linux/arm64 built with buildx TARGETARCH

Data Flow for a Typed Command

flowchart LR
    A[/logs pod --tail 50/] --> B[LogsHandler]
    B --> C[parseLogFlags]
    C --> D[getK8sClient session]
    D --> E[GetPodLogs]
    E --> F[FormatPodLogs respects --tail]
    F --> G[SendRich + text fallback]
    G --> H[Telegram]

Package Layout

cmd/telectl/          entrypoint (Cobra CLI)
internal/bot/         bot core: callbacks, panes, detail verbs
internal/handlers/    typed command handlers (logs, exec, scale, restart…)
internal/k8s/         client-go wrapper, impersonated clients
internal/config/      viper config, impersonation mapping
internal/menus/       menu/keyboard builders, callback token store
internal/tg/          Telegram transport, rich messages
internal/types/       shared types, resource map
internal/utils/       formatters, helpers
charts/telectl/       Helm chart

Next: How It Works · Impersonation & RBAC