diff --git a/Makefile b/Makefile index e61dc82..d4757be 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ -.PHONY: up down seed invoke install logs console clean graphs docs +.PHONY: up down seed invoke install logs console clean graphs docs kind tilt-up tilt-down PY ?= .venv/bin/python PIP ?= .venv/bin/pip +COMPOSE := docker compose -f ctrl/docker-compose.yml DOT_SRC := $(wildcard docs/graphs/*.dot) SVG_OUT := $(DOT_SRC:.dot=.svg) @@ -11,18 +12,27 @@ install: $(PIP) install -r requirements.txt up: - docker compose up -d + $(COMPOSE) up -d @echo "MinIO API: http://localhost:9000" @echo "MinIO console: http://localhost:9001 (minioadmin / minioadmin)" down: - docker compose down + $(COMPOSE) down clean: - docker compose down -v + $(COMPOSE) down -v logs: - docker compose logs -f minio + $(COMPOSE) logs -f minio + +kind: + bash ctrl/kind-config.sh + +tilt-up: + cd ctrl && tilt up --context kind-eth + +tilt-down: + cd ctrl && tilt down --context kind-eth seed: @if [ -z "$$SOURCE_DIR" ]; then echo "set SOURCE_DIR="; exit 2; fi diff --git a/ctrl/Dockerfile.docs b/ctrl/Dockerfile.docs new file mode 100644 index 0000000..fb97550 --- /dev/null +++ b/ctrl/Dockerfile.docs @@ -0,0 +1,3 @@ +FROM nginx:alpine +COPY docs/ /usr/share/nginx/html/ +COPY ctrl/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/ctrl/Dockerfile.lambda b/ctrl/Dockerfile.lambda new file mode 100644 index 0000000..fe7d555 --- /dev/null +++ b/ctrl/Dockerfile.lambda @@ -0,0 +1,10 @@ +FROM python:3.13-slim + +WORKDIR /app + +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt + +COPY lambda_function.py invoke.py seed.py ./ + +CMD ["sleep", "infinity"] diff --git a/ctrl/Tiltfile b/ctrl/Tiltfile new file mode 100644 index 0000000..622428e --- /dev/null +++ b/ctrl/Tiltfile @@ -0,0 +1,50 @@ +# ETH — Tilt development environment +# Usage: cd ctrl && tilt up +# Cluster: kind (name: eth — create via ./kind-config.sh) +# Entry point: http://localhost:8050 (or http://eth.local.ar via Caddy) + +allow_k8s_contexts('kind-eth') + +# Hard guard: Tilt snapshots the kubectl context at startup (before parsing +# this file), so we can't switch it from here. Prefer `tilt up --context +# kind-eth` to bypass the shell's global context entirely. +if k8s_context() != 'kind-eth': + fail("Wrong kubectl context: '%s'. Run with: tilt up --context kind-eth" % k8s_context()) + +local('kubectl --context kind-eth create namespace eth --dry-run=client -o yaml | kubectl --context kind-eth apply -f -') + +k8s_yaml(kustomize('k8s/overlays/dev')) + +# --- Images --- + +docker_build( + 'eth-lambda', + context='..', + dockerfile='Dockerfile.lambda', + ignore=['.git', 'def', '.venv', 'docs', '__pycache__', '.pytest_cache'], + live_update=[ + sync('../lambda_function.py', '/app/lambda_function.py'), + sync('../invoke.py', '/app/invoke.py'), + sync('../seed.py', '/app/seed.py'), + ], +) + +docker_build( + 'eth-docs', + context='..', + dockerfile='Dockerfile.docs', + live_update=[ + sync('../docs', '/usr/share/nginx/html'), + ], +) + +# --- Resources --- + +k8s_resource('minio') +k8s_resource('lambda', resource_deps=['minio']) +k8s_resource('docs') + +k8s_resource( + objects=['eth:namespace', 'eth-config:configmap'], + new_name='infra', +) diff --git a/docker-compose.yml b/ctrl/docker-compose.yml similarity index 100% rename from docker-compose.yml rename to ctrl/docker-compose.yml diff --git a/ctrl/invoke.sh b/ctrl/invoke.sh new file mode 100755 index 0000000..345dd88 --- /dev/null +++ b/ctrl/invoke.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +kubectl --context kind-eth -n eth exec -i deploy/lambda -- python invoke.py "$@" diff --git a/ctrl/k8s/base/configmap.yaml b/ctrl/k8s/base/configmap.yaml new file mode 100644 index 0000000..866d592 --- /dev/null +++ b/ctrl/k8s/base/configmap.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: eth-config + namespace: eth +data: + BUCKET_NAME: "my-company-reports-bucket" + PREFIX: "2026/04/" + URL_EXPIRY_SECONDS: "900" + S3_ENDPOINT_URL: "http://minio:9000" + AWS_ACCESS_KEY_ID: "minioadmin" + AWS_SECRET_ACCESS_KEY: "minioadmin" + AWS_REGION: "us-east-1" + AWS_DEFAULT_REGION: "us-east-1" diff --git a/ctrl/k8s/base/docs.yaml b/ctrl/k8s/base/docs.yaml new file mode 100644 index 0000000..b98158a --- /dev/null +++ b/ctrl/k8s/base/docs.yaml @@ -0,0 +1,44 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: docs + namespace: eth +spec: + replicas: 1 + selector: + matchLabels: + app: docs + template: + metadata: + labels: + app: docs + spec: + containers: + - name: docs + image: eth-docs + ports: + - containerPort: 80 + readinessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 2 + periodSeconds: 10 + resources: + requests: + memory: 32Mi + cpu: 50m + limits: + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: docs + namespace: eth +spec: + selector: + app: docs + ports: + - port: 80 + targetPort: 80 diff --git a/ctrl/k8s/base/kustomization.yaml b/ctrl/k8s/base/kustomization.yaml new file mode 100644 index 0000000..1b4572f --- /dev/null +++ b/ctrl/k8s/base/kustomization.yaml @@ -0,0 +1,11 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: eth + +resources: + - namespace.yaml + - configmap.yaml + - minio.yaml + - lambda.yaml + - docs.yaml diff --git a/ctrl/k8s/base/lambda.yaml b/ctrl/k8s/base/lambda.yaml new file mode 100644 index 0000000..412c667 --- /dev/null +++ b/ctrl/k8s/base/lambda.yaml @@ -0,0 +1,29 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: lambda + namespace: eth +spec: + replicas: 1 + selector: + matchLabels: + app: lambda + template: + metadata: + labels: + app: lambda + spec: + containers: + - name: lambda + image: eth-lambda + command: ["sleep", "infinity"] + workingDir: /app + envFrom: + - configMapRef: + name: eth-config + resources: + requests: + memory: 128Mi + cpu: 100m + limits: + memory: 512Mi diff --git a/ctrl/k8s/base/minio.yaml b/ctrl/k8s/base/minio.yaml new file mode 100644 index 0000000..e5468ad --- /dev/null +++ b/ctrl/k8s/base/minio.yaml @@ -0,0 +1,63 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: minio + namespace: eth +spec: + replicas: 1 + selector: + matchLabels: + app: minio + template: + metadata: + labels: + app: minio + spec: + containers: + - name: minio + image: minio/minio:latest + args: ["server", "/data", "--console-address", ":9001"] + env: + - name: MINIO_ROOT_USER + value: minioadmin + - name: MINIO_ROOT_PASSWORD + value: minioadmin + ports: + - containerPort: 9000 + name: api + - containerPort: 9001 + name: console + readinessProbe: + httpGet: + path: /minio/health/live + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + - name: data + mountPath: /data + resources: + requests: + memory: 128Mi + cpu: 100m + limits: + memory: 512Mi + volumes: + - name: data + emptyDir: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: minio + namespace: eth +spec: + selector: + app: minio + ports: + - name: api + port: 9000 + targetPort: 9000 + - name: console + port: 9001 + targetPort: 9001 diff --git a/ctrl/k8s/base/namespace.yaml b/ctrl/k8s/base/namespace.yaml new file mode 100644 index 0000000..ff22369 --- /dev/null +++ b/ctrl/k8s/base/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: eth diff --git a/ctrl/k8s/kind-config.yaml b/ctrl/k8s/kind-config.yaml new file mode 100644 index 0000000..64cd490 --- /dev/null +++ b/ctrl/k8s/kind-config.yaml @@ -0,0 +1,10 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +name: eth +nodes: + - role: control-plane + extraPortMappings: + - containerPort: 30050 + hostPort: 8050 + listenAddress: "0.0.0.0" + protocol: TCP diff --git a/ctrl/k8s/overlays/dev/kustomization.yaml b/ctrl/k8s/overlays/dev/kustomization.yaml new file mode 100644 index 0000000..7bc417f --- /dev/null +++ b/ctrl/k8s/overlays/dev/kustomization.yaml @@ -0,0 +1,17 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../base + +patches: + - target: + kind: Service + name: docs + patch: | + - op: replace + path: /spec/type + value: NodePort + - op: add + path: /spec/ports/0/nodePort + value: 30050 diff --git a/ctrl/kind-config.sh b/ctrl/kind-config.sh new file mode 100755 index 0000000..12c7058 --- /dev/null +++ b/ctrl/kind-config.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")" + +if kind get clusters 2>/dev/null | grep -qx eth; then + echo "kind cluster 'eth' already exists" +else + echo "creating kind cluster 'eth'..." + kind create cluster --config k8s/kind-config.yaml +fi + +kubectl config use-context kind-eth diff --git a/ctrl/nginx.conf b/ctrl/nginx.conf new file mode 100644 index 0000000..cc24e66 --- /dev/null +++ b/ctrl/nginx.conf @@ -0,0 +1,9 @@ +server { + listen 80; + + location / { + root /usr/share/nginx/html; + index index.html; + try_files $uri $uri/ /index.html; + } +} diff --git a/ctrl/project.json b/ctrl/project.json new file mode 100644 index 0000000..b59df3f --- /dev/null +++ b/ctrl/project.json @@ -0,0 +1,14 @@ +{ + "images": [ + { + "name": "eth/lambda", + "dockerfile": "ctrl/Dockerfile.lambda", + "context": "." + }, + { + "name": "eth/docs", + "dockerfile": "ctrl/Dockerfile.docs", + "context": "." + } + ] +} diff --git a/ctrl/tilt_config.json b/ctrl/tilt_config.json new file mode 100644 index 0000000..addfa72 --- /dev/null +++ b/ctrl/tilt_config.json @@ -0,0 +1,5 @@ +{ + "kind_cluster_name": "eth", + "kind_config": "k8s/kind-config.yaml", + "default_registry": "" +}