Skip to content

Instantly share code, notes, and snippets.

@zrks
Last active April 4, 2025 14:40
Show Gist options
  • Select an option

  • Save zrks/d698f04ed97936e637b615d6a16be6d4 to your computer and use it in GitHub Desktop.

Select an option

Save zrks/d698f04ed97936e637b615d6a16be6d4 to your computer and use it in GitHub Desktop.

Revisions

  1. zrks revised this gist Apr 4, 2025. 3 changed files with 67 additions and 0 deletions.
    15 changes: 15 additions & 0 deletions app-Dockerfile
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    FROM python:3.11-slim

    WORKDIR /app

    # Install dependencies
    RUN pip install flask kubernetes redis

    # Copy files
    COPY watcher.py /app/watcher.py
    COPY web.py /app/web.py

    EXPOSE 5000

    # Run both watcher + web via supervisor or background trick
    CMD ["sh", "-c", "python /app/watcher.py & python /app/web.py"]
    34 changes: 34 additions & 0 deletions app-watcher.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,34 @@
    from kubernetes import client, config, watch # type: ignore
    import redis # type: ignore
    import json
    import os
    import urllib3 # type: ignore
    from urllib3.exceptions import InsecureRequestWarning # type: ignore
    urllib3.disable_warnings(InsecureRequestWarning)


    # Load config, then override
    configuration = client.Configuration()
    config.load_kube_config(client_configuration=configuration)
    configuration.verify_ssl = False

    v1 = client.CoreV1Api(client.ApiClient(configuration))

    r = redis.Redis(host=os.getenv("REDIS_HOST", "localhost"),
    port=int(os.getenv("REDIS_PORT", 6379)),
    decode_responses=True)

    w = watch.Watch()
    for event in w.stream(v1.list_namespace, timeout_seconds=0):
    ns = event['object']
    name = ns.metadata.name
    labels = ns.metadata.labels or {}
    event_type = event['type']

    if not name.startswith("dyn-"):
    continue

    if event_type in ['ADDED', 'MODIFIED']:
    r.hset("namespace_labels", name, json.dumps(labels))
    elif event_type == 'DELETED':
    r.hdel("namespace_labels", name)
    18 changes: 18 additions & 0 deletions app-web.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,18 @@
    from flask import Flask, jsonify
    import redis
    import json
    import os

    app = Flask(__name__)
    r = redis.Redis(host=os.getenv("REDIS_HOST", "localhost"),
    port=int(os.getenv("REDIS_PORT", 6379)),
    decode_responses=True)

    @app.route("/api/namespaces")
    def get_namespace_labels():
    raw = r.hgetall("namespace_labels")
    parsed = {ns: json.loads(label_str) for ns, label_str in raw.items()}
    return jsonify(parsed)

    if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
  2. zrks created this gist Apr 4, 2025.
    31 changes: 31 additions & 0 deletions docker-compose.yaml
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,31 @@
    version: '3.8'

    services:
    redis:
    image: redis:7-alpine
    container_name: redis
    ports:
    - "6379:6379"
    networks:
    - backend

    flask-app:
    build:
    context: ./app
    container_name: flask-k8s-watcher
    ports:
    - "5000:5000"
    depends_on:
    - redis
    environment:
    KUBECONFIG: /root/.kube/config
    REDIS_HOST: redis
    REDIS_PORT: 6379
    volumes:
    - ~/.kube:/root/.kube:ro
    networks:
    - backend

    networks:
    backend:
    driver: bridge