backend redesign
This commit is contained in:
@@ -1,38 +0,0 @@
|
||||
FROM python:3.14-alpine
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy requirements first for better caching
|
||||
COPY backend/requirements.txt /app/requirements.txt
|
||||
|
||||
# Install TA-Lib C library and build dependencies, then install Python dependencies and clean up
|
||||
RUN apk add --no-cache --virtual .build-deps \
|
||||
gcc \
|
||||
g++ \
|
||||
make \
|
||||
musl-dev \
|
||||
wget \
|
||||
tar \
|
||||
cargo \
|
||||
rust \
|
||||
&& wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz \
|
||||
&& tar -xzf ta-lib-0.4.0-src.tar.gz \
|
||||
&& cd ta-lib/ \
|
||||
&& ./configure --prefix=/usr \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& cd .. \
|
||||
&& rm -rf ta-lib ta-lib-0.4.0-src.tar.gz \
|
||||
&& pip install --no-cache-dir -r requirements.txt \
|
||||
&& apk del .build-deps \
|
||||
&& rm -rf /var/cache/apk/* /root/.cache /root/.cargo /root/.rustup
|
||||
|
||||
# Copy application code
|
||||
COPY backend/src /app/src
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8000
|
||||
|
||||
# Run the application
|
||||
CMD ["python", "-m", "uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
@@ -1,65 +0,0 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
ARG CONFIG=production
|
||||
|
||||
# Install TA-Lib C library early for better layer caching
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
g++ \
|
||||
make \
|
||||
wget \
|
||||
ca-certificates \
|
||||
&& wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz \
|
||||
&& tar -xzf ta-lib-0.4.0-src.tar.gz \
|
||||
&& cd ta-lib/ \
|
||||
&& ./configure --prefix=/usr \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& cd .. \
|
||||
&& rm -rf ta-lib ta-lib-0.4.0-src.tar.gz \
|
||||
&& apt-get purge -y --auto-remove gcc g++ make wget \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Python build dependencies early for better layer caching
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
g++ \
|
||||
cargo \
|
||||
rustc
|
||||
|
||||
# Install compiled packages - separate layer so requirements.txt changes don't trigger recompilation
|
||||
COPY backend/requirements-pre.txt /app/requirements-pre.txt
|
||||
RUN --mount=type=cache,target=/root/.cache/pip \
|
||||
--mount=type=cache,target=/root/.cargo \
|
||||
pip install --no-cache-dir -r /app/requirements-pre.txt \
|
||||
&& apt-get purge -y --auto-remove gcc g++ cargo rustc \
|
||||
&& rm -rf /var/lib/apt/lists/* /root/.rustup /tmp/*
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy and install remaining requirements
|
||||
COPY backend/requirements.txt /app/requirements.txt
|
||||
|
||||
# Install Python dependencies and clean up
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copy application code
|
||||
COPY backend/src /app/src
|
||||
COPY backend/config*.yaml /tmp/
|
||||
RUN if [ -f /tmp/config-${CONFIG}.yaml ]; then \
|
||||
cp /tmp/config-${CONFIG}.yaml /app/config.yaml; \
|
||||
else \
|
||||
cp /tmp/config.yaml /app/config.yaml; \
|
||||
fi && rm -rf /tmp/config*.yaml
|
||||
|
||||
# Add src to PYTHONPATH for correct module resolution
|
||||
ENV PYTHONPATH=/app/src
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8000
|
||||
|
||||
# Run the application
|
||||
CMD ["python", "-m", "uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
@@ -1,19 +0,0 @@
|
||||
FROM node:20-alpine
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files first for better caching
|
||||
COPY web/package*.json /app/
|
||||
|
||||
# Install dependencies
|
||||
RUN npm install
|
||||
|
||||
# Copy application code
|
||||
COPY web /app/
|
||||
|
||||
# Expose port
|
||||
EXPOSE 5173
|
||||
|
||||
# Run dev server (for development/debug)
|
||||
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ai-ingress
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- dexorder.ai
|
||||
secretName: dexorder-ai-tls
|
||||
rules:
|
||||
- host: dexorder.ai
|
||||
http:
|
||||
paths:
|
||||
- path: /charting_library
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: ai-web
|
||||
port:
|
||||
number: 5173
|
||||
- path: /cryptochimp
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: ai-web
|
||||
port:
|
||||
number: 5173
|
||||
- path: /ws
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: ai-backend
|
||||
port:
|
||||
number: 8000
|
||||
287
deploy/k8s/README.md
Normal file
287
deploy/k8s/README.md
Normal file
@@ -0,0 +1,287 @@
|
||||
# Kubernetes Deployment
|
||||
|
||||
This directory contains Kubernetes manifests using [Kustomize](https://kustomize.io/) for managing dev and production environments.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
deploy/k8s/
|
||||
├── base/ # Base manifests (shared)
|
||||
│ ├── backend.yaml
|
||||
│ ├── web.yaml
|
||||
│ ├── ingress.yaml
|
||||
│ ├── init.yaml
|
||||
│ └── kustomization.yaml
|
||||
├── dev/ # Dev overlay (minikube)
|
||||
│ ├── infrastructure.yaml # Kafka, Postgres, MinIO, Flink, Relay, Ingestor
|
||||
│ ├── ingress-dev.yaml # Dev ingress (dexorder.local)
|
||||
│ ├── patches.yaml # Dev-specific patches
|
||||
│ ├── kustomization.yaml
|
||||
│ └── secrets/
|
||||
│ ├── *.yaml # Actual secrets (gitignored)
|
||||
│ └── *.yaml.example # Templates
|
||||
├── prod/ # Production overlay
|
||||
│ ├── patches.yaml # Prod patches (replicas, resources, gVisor)
|
||||
│ ├── kustomization.yaml
|
||||
│ └── secrets/
|
||||
│ ├── *.yaml # Actual secrets (gitignored)
|
||||
│ └── *.yaml.example # Templates
|
||||
└── configmaps/ # Shared ConfigMaps
|
||||
├── relay-config.yaml
|
||||
├── ingestor-config.yaml
|
||||
└── flink-config.yaml
|
||||
```
|
||||
|
||||
## Dev Environment (Minikube)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- [minikube](https://minikube.sigs.k8s.io/docs/start/)
|
||||
- [kubectl](https://kubernetes.io/docs/tasks/tools/)
|
||||
- Docker
|
||||
|
||||
### Quick Start
|
||||
|
||||
```bash
|
||||
# Start everything
|
||||
bin/dev start
|
||||
|
||||
# Access the application
|
||||
# Web UI: http://dexorder.local/cryptochimp/
|
||||
# Backend: ws://dexorder.local/ws
|
||||
|
||||
# In another terminal, start tunnel for ingress
|
||||
bin/dev tunnel
|
||||
```
|
||||
|
||||
### Managing Dev Environment
|
||||
|
||||
```bash
|
||||
# Rebuild images after code changes
|
||||
bin/dev rebuild
|
||||
|
||||
# Redeploy services
|
||||
bin/dev deploy
|
||||
|
||||
# Full restart (rebuild + redeploy)
|
||||
bin/dev restart
|
||||
|
||||
# View status
|
||||
bin/dev status
|
||||
|
||||
# View logs
|
||||
bin/dev logs relay
|
||||
bin/dev logs ingestor
|
||||
bin/dev logs flink-jobmanager
|
||||
|
||||
# Open shell in pod
|
||||
bin/dev shell relay
|
||||
|
||||
# Clean everything
|
||||
bin/dev clean
|
||||
|
||||
# Stop minikube
|
||||
bin/dev stop
|
||||
```
|
||||
|
||||
### Setting Up Secrets (Dev)
|
||||
|
||||
```bash
|
||||
# Copy example secrets
|
||||
cd deploy/k8s/dev/secrets/
|
||||
cp ai-secrets.yaml.example ai-secrets.yaml
|
||||
cp postgres-secret.yaml.example postgres-secret.yaml
|
||||
cp minio-secret.yaml.example minio-secret.yaml
|
||||
cp ingestor-secrets.yaml.example ingestor-secrets.yaml
|
||||
|
||||
# Edit with actual values
|
||||
vim ai-secrets.yaml # Add your Anthropic API key
|
||||
|
||||
# Apply to cluster
|
||||
bin/secret-update dev
|
||||
|
||||
# Or update a specific secret
|
||||
bin/secret-update dev ai-secrets
|
||||
```
|
||||
|
||||
### Updating Configs (Dev)
|
||||
|
||||
```bash
|
||||
# Edit config files
|
||||
vim deploy/configmaps/relay-config.yaml
|
||||
|
||||
# Apply changes
|
||||
bin/config-update dev
|
||||
|
||||
# Or update specific config
|
||||
bin/config-update dev relay-config
|
||||
```
|
||||
|
||||
### Dev vs Docker Compose
|
||||
|
||||
The minikube dev environment mirrors production more closely than docker-compose:
|
||||
|
||||
| Feature | docker-compose | minikube |
|
||||
|---------|---------------|----------|
|
||||
| Environment parity | ❌ Different from prod | ✅ Same as prod |
|
||||
| Secrets management | `.env` files | K8s Secrets |
|
||||
| Configuration | Volume mounts | ConfigMaps |
|
||||
| Service discovery | DNS by service name | K8s Services |
|
||||
| Ingress/routing | Port mapping | nginx-ingress |
|
||||
| Resource limits | Limited support | Full K8s resources |
|
||||
| Init containers | No | Yes |
|
||||
| Readiness probes | No | Yes |
|
||||
|
||||
## Production Environment
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Access to production Kubernetes cluster
|
||||
- `kubectl` configured with production context
|
||||
- Production secrets prepared
|
||||
|
||||
### Setting Up Secrets (Prod)
|
||||
|
||||
```bash
|
||||
# Copy example secrets
|
||||
cd deploy/k8s/prod/secrets/
|
||||
cp ai-secrets.yaml.example ai-secrets.yaml
|
||||
cp postgres-secret.yaml.example postgres-secret.yaml
|
||||
# ... etc
|
||||
|
||||
# Edit with production values
|
||||
vim ai-secrets.yaml
|
||||
|
||||
# Apply to cluster (will prompt for confirmation)
|
||||
bin/secret-update prod
|
||||
|
||||
# Or update specific secret
|
||||
bin/secret-update prod ai-secrets
|
||||
```
|
||||
|
||||
### Updating Configs (Prod)
|
||||
|
||||
```bash
|
||||
# Edit production configs if needed
|
||||
vim deploy/configmaps/relay-config.yaml
|
||||
|
||||
# Apply changes (will prompt for confirmation)
|
||||
bin/config-update prod
|
||||
```
|
||||
|
||||
### Deploying to Production
|
||||
|
||||
```bash
|
||||
# Verify kubectl context
|
||||
kubectl config current-context
|
||||
|
||||
# Apply manifests
|
||||
kubectl apply -k deploy/k8s/prod/
|
||||
|
||||
# Check rollout status
|
||||
kubectl rollout status statefulset/ai-backend
|
||||
kubectl rollout status deployment/ai-web
|
||||
|
||||
# View status
|
||||
kubectl get pods,svc,ingress
|
||||
```
|
||||
|
||||
## Kustomize Overlays
|
||||
|
||||
### Dev Overlay
|
||||
|
||||
- **imagePullPolicy: Never** - Uses locally built images
|
||||
- **Infrastructure services** - Kafka, Postgres, MinIO, Flink, Relay, Ingestor
|
||||
- **Local ingress** - `dexorder.local` (requires `/etc/hosts` entry)
|
||||
- **No gVisor** - RuntimeClass removed (not available in minikube)
|
||||
- **Single replicas** - Minimal resource usage
|
||||
|
||||
### Prod Overlay
|
||||
|
||||
- **imagePullPolicy: Always** - Pulls from registry
|
||||
- **Multiple replicas** - HA configuration
|
||||
- **Resource limits** - CPU/memory constraints
|
||||
- **gVisor** - Security sandbox via RuntimeClass
|
||||
- **Production ingress** - `dexorder.ai` with TLS
|
||||
|
||||
## Infrastructure Services (Dev Only)
|
||||
|
||||
These services are included in the dev environment but are expected to be managed separately in production:
|
||||
|
||||
- **Kafka** - KRaft mode (no Zookeeper), single broker
|
||||
- **PostgreSQL** - Iceberg catalog metadata
|
||||
- **MinIO** - S3-compatible object storage
|
||||
- **Iceberg REST Catalog** - Table metadata
|
||||
- **Flink** - JobManager + TaskManager
|
||||
- **Relay** - ZMQ message router
|
||||
- **Ingestor** - CCXT data fetcher
|
||||
|
||||
In production, you would typically use:
|
||||
- Managed Kafka (Confluent Cloud, MSK, etc.)
|
||||
- Managed PostgreSQL (RDS, Cloud SQL, etc.)
|
||||
- Object storage (S3, GCS, Azure Blob)
|
||||
- Flink Kubernetes Operator or managed Flink
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Minikube not starting
|
||||
|
||||
```bash
|
||||
minikube delete
|
||||
minikube start --cpus=6 --memory=12g --driver=docker
|
||||
```
|
||||
|
||||
### Images not found
|
||||
|
||||
Make sure you're using minikube's docker daemon:
|
||||
|
||||
```bash
|
||||
eval $(minikube docker-env)
|
||||
bin/dev rebuild
|
||||
```
|
||||
|
||||
### Ingress not working
|
||||
|
||||
Start minikube tunnel in another terminal:
|
||||
|
||||
```bash
|
||||
bin/dev tunnel
|
||||
```
|
||||
|
||||
### Secrets not found
|
||||
|
||||
Create secrets from examples:
|
||||
|
||||
```bash
|
||||
cd deploy/k8s/dev/secrets/
|
||||
cp *.example *.yaml
|
||||
vim ai-secrets.yaml # Edit with actual values
|
||||
bin/secret-update dev
|
||||
```
|
||||
|
||||
### Pods not starting
|
||||
|
||||
Check events and logs:
|
||||
|
||||
```bash
|
||||
kubectl get events --sort-by=.metadata.creationTimestamp
|
||||
kubectl describe pod <pod-name>
|
||||
kubectl logs <pod-name>
|
||||
```
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
For automated deployments, you can use:
|
||||
|
||||
```bash
|
||||
# Build and push images
|
||||
docker build -t registry.example.com/dexorder/ai-web:$TAG .
|
||||
docker push registry.example.com/dexorder/ai-web:$TAG
|
||||
|
||||
# Update kustomization with new tag
|
||||
cd deploy/k8s/prod
|
||||
kustomize edit set image dexorder/ai-web=registry.example.com/dexorder/ai-web:$TAG
|
||||
|
||||
# Deploy
|
||||
kubectl apply -k deploy/k8s/prod/
|
||||
```
|
||||
17
deploy/k8s/base/ingress.yaml
Normal file
17
deploy/k8s/base/ingress.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ai-ingress
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- dexorder.ai
|
||||
secretName: dexorder-ai-tls
|
||||
rules:
|
||||
- host: dexorder.ai
|
||||
http:
|
||||
paths: []
|
||||
9
deploy/k8s/base/init.yaml
Normal file
9
deploy/k8s/base/init.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
apiVersion: node.k8s.io/v1
|
||||
kind: RuntimeClass
|
||||
metadata:
|
||||
name: gvisor
|
||||
handler: gvisor
|
||||
overhead:
|
||||
podFixed:
|
||||
memory: "64Mi"
|
||||
cpu: "0m"
|
||||
5
deploy/k8s/base/kustomization.yaml
Normal file
5
deploy/k8s/base/kustomization.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources: []
|
||||
# ingress.yaml - removed until we have services to expose
|
||||
40
deploy/k8s/dev/configs/flink-config.yaml
Normal file
40
deploy/k8s/dev/configs/flink-config.yaml
Normal file
@@ -0,0 +1,40 @@
|
||||
# Flink Job Configuration
|
||||
|
||||
# ZeroMQ bind address and ports
|
||||
zmq_bind_address: "tcp://*"
|
||||
zmq_ingestor_work_queue_port: 5555
|
||||
zmq_ingestor_response_port: 5556
|
||||
zmq_ingestor_control_port: 5557
|
||||
zmq_market_data_pub_port: 5558
|
||||
zmq_client_request_port: 5559
|
||||
zmq_cep_webhook_port: 5560
|
||||
|
||||
# Notification endpoints
|
||||
# Task managers PUSH to job manager PULL socket at this address
|
||||
notification_publish_endpoint: "tcp://flink-jobmanager:5561"
|
||||
# Job manager binds PULL socket on this port to receive from task managers
|
||||
notification_pull_port: 5561
|
||||
|
||||
# Kafka configuration
|
||||
kafka_bootstrap_servers: "kafka:9092"
|
||||
kafka_tick_topic: "market-tick"
|
||||
kafka_ohlc_topic: "market-ohlc"
|
||||
kafka_topics_file: "/topics-dev.yaml" # Use topics-dev.yaml for single broker dev environment
|
||||
|
||||
# Iceberg catalog
|
||||
iceberg_catalog_uri: "http://iceberg-catalog:8181"
|
||||
iceberg_warehouse: "s3://trading-warehouse/"
|
||||
iceberg_namespace: "trading"
|
||||
iceberg_table_prefix: "market"
|
||||
hadoop_conf_dir: "/etc/hadoop/conf"
|
||||
|
||||
# Flink configuration
|
||||
flink_parallelism: 1
|
||||
flink_checkpoint_interval_ms: 60000
|
||||
|
||||
# Flink memory configuration (required)
|
||||
jobmanager.memory.process.size: 1600m
|
||||
taskmanager.memory.process.size: 1728m
|
||||
taskmanager.numberOfTaskSlots: 2
|
||||
jobmanager.rpc.address: flink-jobmanager
|
||||
jobmanager.rpc.port: 6123
|
||||
24
deploy/k8s/dev/configs/ingestor-config.yaml
Normal file
24
deploy/k8s/dev/configs/ingestor-config.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
# CCXT Ingestor Configuration
|
||||
|
||||
# Relay ZMQ endpoints (relay is the well-known gateway)
|
||||
flink_hostname: relay
|
||||
ingestor_work_port: 5555 # SUB - receives DataRequest with exchange prefix
|
||||
# Note: No response port needed - async architecture via Kafka!
|
||||
|
||||
# Supported exchanges (subscribe to these prefixes)
|
||||
supported_exchanges:
|
||||
- BINANCE
|
||||
- COINBASE
|
||||
- KRAKEN
|
||||
|
||||
# Kafka configuration
|
||||
kafka_brokers:
|
||||
- kafka:9092
|
||||
kafka_topic: market-ohlc
|
||||
|
||||
# Worker configuration
|
||||
max_concurrent: 10
|
||||
poll_interval_ms: 10000
|
||||
|
||||
# Logging
|
||||
log_level: info
|
||||
19
deploy/k8s/dev/configs/relay-config.yaml
Normal file
19
deploy/k8s/dev/configs/relay-config.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
# ZMQ Relay Configuration
|
||||
|
||||
# Bind address for all relay sockets
|
||||
bind_address: "tcp://*"
|
||||
|
||||
# Client-facing ports
|
||||
client_request_port: 5559 # ROUTER - Client historical data requests
|
||||
market_data_pub_port: 5558 # XPUB - Market data fanout to clients
|
||||
|
||||
# Ingestor-facing ports
|
||||
ingestor_work_port: 5555 # PUB - Distribute work with exchange prefix
|
||||
ingestor_response_port: 5556 # ROUTER - Receive responses from ingestors
|
||||
|
||||
# Flink connection
|
||||
flink_market_data_endpoint: "tcp://flink-jobmanager:5558" # XSUB - Subscribe to Flink market data (MARKET_DATA_PUB)
|
||||
|
||||
# Timeouts and limits
|
||||
request_timeout_secs: 30 # Timeout for pending client requests
|
||||
high_water_mark: 10000 # ZMQ high water mark for all sockets
|
||||
519
deploy/k8s/dev/infrastructure.yaml
Normal file
519
deploy/k8s/dev/infrastructure.yaml
Normal file
@@ -0,0 +1,519 @@
|
||||
---
|
||||
# Kafka (KRaft mode - no Zookeeper needed)
|
||||
# Using apache/kafka:3.9.0 instead of confluentinc/cp-kafka because:
|
||||
# - cp-kafka's entrypoint script has issues with KRaft configuration
|
||||
# - apache/kafka allows explicit command configuration
|
||||
# - For production, use Strimzi operator (see kafka/ directory)
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: kafka
|
||||
spec:
|
||||
selector:
|
||||
app: kafka
|
||||
ports:
|
||||
- name: broker
|
||||
protocol: TCP
|
||||
port: 9092
|
||||
targetPort: 9092
|
||||
- name: controller
|
||||
protocol: TCP
|
||||
port: 9093
|
||||
targetPort: 9093
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: kafka
|
||||
spec:
|
||||
serviceName: kafka
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: kafka
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: kafka
|
||||
spec:
|
||||
containers:
|
||||
- name: kafka
|
||||
image: apache/kafka:3.9.0
|
||||
ports:
|
||||
- containerPort: 9092
|
||||
name: broker
|
||||
- containerPort: 9093
|
||||
name: controller
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
CLUSTER_ID="dexorder-dev-cluster"
|
||||
if [ ! -f /var/lib/kafka/data/meta.properties ]; then
|
||||
/opt/kafka/bin/kafka-storage.sh format -t $CLUSTER_ID -c /opt/kafka/config/kraft/server.properties
|
||||
fi
|
||||
/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/kraft/server.properties \
|
||||
--override node.id=1 \
|
||||
--override process.roles=broker,controller \
|
||||
--override listeners=PLAINTEXT://:9092,CONTROLLER://:9093 \
|
||||
--override advertised.listeners=PLAINTEXT://kafka:9092 \
|
||||
--override controller.quorum.voters=1@kafka:9093 \
|
||||
--override controller.listener.names=CONTROLLER \
|
||||
--override listener.security.protocol.map=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT \
|
||||
--override log.dirs=/var/lib/kafka/data \
|
||||
--override offsets.topic.replication.factor=1 \
|
||||
--override transaction.state.log.replication.factor=1 \
|
||||
--override transaction.state.log.min.isr=1
|
||||
env: []
|
||||
volumeMounts:
|
||||
- name: kafka-data
|
||||
mountPath: /var/lib/kafka/data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: kafka-data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
---
|
||||
# PostgreSQL (for Iceberg catalog metadata)
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: postgres
|
||||
spec:
|
||||
selector:
|
||||
app: postgres
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
targetPort: 5432
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: postgres
|
||||
spec:
|
||||
serviceName: postgres
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: postgres
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: postgres
|
||||
spec:
|
||||
containers:
|
||||
- name: postgres
|
||||
image: postgres:15
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
env:
|
||||
- name: POSTGRES_USER
|
||||
value: postgres
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: postgres-secret
|
||||
key: password
|
||||
- name: POSTGRES_DB
|
||||
value: iceberg
|
||||
volumeMounts:
|
||||
- name: postgres-data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: postgres-data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
---
|
||||
# MinIO (S3-compatible object storage)
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: minio
|
||||
spec:
|
||||
selector:
|
||||
app: minio
|
||||
ports:
|
||||
- name: api
|
||||
protocol: TCP
|
||||
port: 9000
|
||||
targetPort: 9000
|
||||
- name: console
|
||||
protocol: TCP
|
||||
port: 9001
|
||||
targetPort: 9001
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: minio
|
||||
spec:
|
||||
serviceName: minio
|
||||
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"
|
||||
ports:
|
||||
- containerPort: 9000
|
||||
name: api
|
||||
- containerPort: 9001
|
||||
name: console
|
||||
env:
|
||||
- name: MINIO_ROOT_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: minio-secret
|
||||
key: root-user
|
||||
- name: MINIO_ROOT_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: minio-secret
|
||||
key: root-password
|
||||
volumeMounts:
|
||||
- name: minio-data
|
||||
mountPath: /data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: minio-data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
---
|
||||
# Iceberg REST Catalog
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: iceberg-catalog
|
||||
spec:
|
||||
selector:
|
||||
app: iceberg-catalog
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8181
|
||||
targetPort: 8181
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: iceberg-catalog
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: iceberg-catalog
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: iceberg-catalog
|
||||
spec:
|
||||
initContainers:
|
||||
- name: wait-for-postgres
|
||||
image: busybox:1.36
|
||||
command: ['sh', '-c', 'until nc -z postgres 5432; do echo waiting for postgres; sleep 2; done;']
|
||||
- name: wait-for-minio
|
||||
image: busybox:1.36
|
||||
command: ['sh', '-c', 'until nc -z minio 9000; do echo waiting for minio; sleep 2; done;']
|
||||
containers:
|
||||
- name: iceberg-catalog
|
||||
image: tabulario/iceberg-rest:latest
|
||||
ports:
|
||||
- containerPort: 8181
|
||||
env:
|
||||
- name: CATALOG_WAREHOUSE
|
||||
value: "s3://warehouse/"
|
||||
- name: CATALOG_IO__IMPL
|
||||
value: "org.apache.iceberg.aws.s3.S3FileIO"
|
||||
- name: CATALOG_S3_ENDPOINT
|
||||
value: "http://minio:9000"
|
||||
- name: CATALOG_S3_ACCESS__KEY__ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: minio-secret
|
||||
key: root-user
|
||||
- name: CATALOG_S3_SECRET__ACCESS__KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: minio-secret
|
||||
key: root-password
|
||||
- name: CATALOG_S3_PATH__STYLE__ACCESS
|
||||
value: "true"
|
||||
- name: AWS_REGION
|
||||
value: "us-east-1"
|
||||
---
|
||||
# Flink JobManager
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: flink-jobmanager
|
||||
spec:
|
||||
selector:
|
||||
app: flink-jobmanager
|
||||
ports:
|
||||
- name: rpc
|
||||
protocol: TCP
|
||||
port: 6123
|
||||
targetPort: 6123
|
||||
- name: ui
|
||||
protocol: TCP
|
||||
port: 8081
|
||||
targetPort: 8081
|
||||
- name: zmq-market-data
|
||||
protocol: TCP
|
||||
port: 5558
|
||||
targetPort: 5558
|
||||
- name: zmq-notif-pull
|
||||
protocol: TCP
|
||||
port: 5561
|
||||
targetPort: 5561
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: flink-jobmanager
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: flink-jobmanager
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: flink-jobmanager
|
||||
spec:
|
||||
initContainers:
|
||||
- name: wait-for-kafka
|
||||
image: busybox:1.36
|
||||
command: ['sh', '-c', 'until nc -z kafka 9092; do echo waiting for kafka; sleep 2; done;']
|
||||
containers:
|
||||
- name: flink-jobmanager
|
||||
image: dexorder/flink:latest
|
||||
imagePullPolicy: Never
|
||||
args: ["standalone-job", "--job-classname", "com.dexorder.flink.TradingFlinkApp"]
|
||||
ports:
|
||||
- containerPort: 6123
|
||||
name: rpc
|
||||
- containerPort: 8081
|
||||
name: ui
|
||||
- containerPort: 5558
|
||||
name: zmq-market-data
|
||||
- containerPort: 5561
|
||||
name: zmq-notif-pull
|
||||
env:
|
||||
- name: JOB_MANAGER_RPC_ADDRESS
|
||||
value: flink-jobmanager
|
||||
- name: AWS_REGION
|
||||
value: us-east-1
|
||||
- name: AWS_ACCESS_KEY_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: flink-secrets
|
||||
key: minio-access-key
|
||||
- name: AWS_SECRET_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: flink-secrets
|
||||
key: minio-secret-key
|
||||
volumeMounts:
|
||||
- name: flink-config
|
||||
mountPath: /etc/config/config.yaml
|
||||
subPath: config.yaml
|
||||
- name: flink-secrets
|
||||
mountPath: /etc/secrets
|
||||
volumes:
|
||||
- name: flink-config
|
||||
configMap:
|
||||
name: flink-config
|
||||
- name: flink-secrets
|
||||
secret:
|
||||
secretName: flink-secrets
|
||||
---
|
||||
# Flink TaskManager
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: flink-taskmanager
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: flink-taskmanager
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: flink-taskmanager
|
||||
spec:
|
||||
initContainers:
|
||||
- name: wait-for-jobmanager
|
||||
image: busybox:1.36
|
||||
command: ['sh', '-c', 'until nc -z flink-jobmanager 6123; do echo waiting for jobmanager; sleep 2; done;']
|
||||
containers:
|
||||
- name: flink-taskmanager
|
||||
image: dexorder/flink:latest
|
||||
imagePullPolicy: Never
|
||||
args: ["taskmanager"]
|
||||
env:
|
||||
- name: JOB_MANAGER_RPC_ADDRESS
|
||||
value: flink-jobmanager
|
||||
- name: AWS_REGION
|
||||
value: us-east-1
|
||||
- name: AWS_ACCESS_KEY_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: flink-secrets
|
||||
key: minio-access-key
|
||||
- name: AWS_SECRET_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: flink-secrets
|
||||
key: minio-secret-key
|
||||
volumeMounts:
|
||||
- name: flink-config
|
||||
mountPath: /etc/config/config.yaml
|
||||
subPath: config.yaml
|
||||
- name: flink-secrets
|
||||
mountPath: /etc/secrets
|
||||
volumes:
|
||||
- name: flink-config
|
||||
configMap:
|
||||
name: flink-config
|
||||
- name: flink-secrets
|
||||
secret:
|
||||
secretName: flink-secrets
|
||||
---
|
||||
# Relay (ZMQ router)
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: relay
|
||||
spec:
|
||||
selector:
|
||||
app: relay
|
||||
ports:
|
||||
- name: work-queue
|
||||
protocol: TCP
|
||||
port: 5555
|
||||
targetPort: 5555
|
||||
- name: responses
|
||||
protocol: TCP
|
||||
port: 5556
|
||||
targetPort: 5556
|
||||
- name: market-data
|
||||
protocol: TCP
|
||||
port: 5558
|
||||
targetPort: 5558
|
||||
- name: client-requests
|
||||
protocol: TCP
|
||||
port: 5559
|
||||
targetPort: 5559
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: relay
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: relay
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: relay
|
||||
spec:
|
||||
containers:
|
||||
- name: relay
|
||||
image: dexorder/relay:latest
|
||||
imagePullPolicy: Never
|
||||
ports:
|
||||
- containerPort: 5555
|
||||
name: work-queue
|
||||
- containerPort: 5556
|
||||
name: responses
|
||||
- containerPort: 5558
|
||||
name: market-data
|
||||
- containerPort: 5559
|
||||
name: client-requests
|
||||
env:
|
||||
- name: RUST_LOG
|
||||
value: relay=info
|
||||
- name: CONFIG_PATH
|
||||
value: /config/config.yaml
|
||||
volumeMounts:
|
||||
- name: relay-config
|
||||
mountPath: /config
|
||||
volumes:
|
||||
- name: relay-config
|
||||
configMap:
|
||||
name: relay-config
|
||||
---
|
||||
# Ingestor (CCXT data fetcher)
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ingestor
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ingestor
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: ingestor
|
||||
spec:
|
||||
initContainers:
|
||||
- name: wait-for-relay
|
||||
image: busybox:1.36
|
||||
command: ['sh', '-c', 'until nc -z relay 5555; do echo waiting for relay; sleep 2; done;']
|
||||
- name: wait-for-kafka
|
||||
image: busybox:1.36
|
||||
command: ['sh', '-c', 'until nc -z kafka 9092; do echo waiting for kafka; sleep 2; done;']
|
||||
containers:
|
||||
- name: ingestor
|
||||
image: dexorder/ingestor:latest
|
||||
imagePullPolicy: Never
|
||||
env:
|
||||
- name: LOG_LEVEL
|
||||
value: info
|
||||
- name: CONFIG_PATH
|
||||
value: /config/config.yaml
|
||||
volumeMounts:
|
||||
- name: ingestor-config
|
||||
mountPath: /config
|
||||
- name: ingestor-secrets
|
||||
mountPath: /secrets
|
||||
volumes:
|
||||
- name: ingestor-config
|
||||
configMap:
|
||||
name: ingestor-config
|
||||
- name: ingestor-secrets
|
||||
secret:
|
||||
secretName: ingestor-secrets
|
||||
11
deploy/k8s/dev/ingress-dev.yaml
Normal file
11
deploy/k8s/dev/ingress-dev.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ai-ingress
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: dexorder.local
|
||||
http:
|
||||
paths: []
|
||||
32
deploy/k8s/dev/kustomization.yaml
Normal file
32
deploy/k8s/dev/kustomization.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
namespace: default
|
||||
|
||||
# Base resources
|
||||
resources:
|
||||
- ../base
|
||||
- infrastructure.yaml
|
||||
|
||||
# No patches needed currently
|
||||
patches: []
|
||||
# ingress-dev.yaml - removed until we have services to expose
|
||||
|
||||
# ConfigMaps for service configs
|
||||
configMapGenerator:
|
||||
- name: relay-config
|
||||
files:
|
||||
- config.yaml=configs/relay-config.yaml
|
||||
- name: ingestor-config
|
||||
files:
|
||||
- config.yaml=configs/ingestor-config.yaml
|
||||
- name: flink-config
|
||||
files:
|
||||
- config.yaml=configs/flink-config.yaml
|
||||
|
||||
# Secrets (managed via kubectl, not committed)
|
||||
# These are created by bin/secret-update
|
||||
secretGenerator: []
|
||||
|
||||
generatorOptions:
|
||||
disableNameSuffixHash: true
|
||||
7
deploy/k8s/dev/secrets/ai-secrets.yaml.example
Normal file
7
deploy/k8s/dev/secrets/ai-secrets.yaml.example
Normal file
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: ai-secrets
|
||||
type: Opaque
|
||||
stringData:
|
||||
anthropic-api-key: "sk-ant-YOUR_KEY_HERE"
|
||||
9
deploy/k8s/dev/secrets/flink-secrets.yaml.example
Normal file
9
deploy/k8s/dev/secrets/flink-secrets.yaml.example
Normal file
@@ -0,0 +1,9 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: flink-secrets
|
||||
type: Opaque
|
||||
stringData:
|
||||
# MinIO/S3 credentials for Iceberg S3FileIO
|
||||
minio-access-key: "minio"
|
||||
minio-secret-key: "minio123"
|
||||
13
deploy/k8s/dev/secrets/ingestor-secrets.yaml.example
Normal file
13
deploy/k8s/dev/secrets/ingestor-secrets.yaml.example
Normal file
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: ingestor-secrets
|
||||
type: Opaque
|
||||
stringData:
|
||||
# Exchange API keys (if needed for authenticated endpoints)
|
||||
binance-api-key: ""
|
||||
binance-api-secret: ""
|
||||
coinbase-api-key: ""
|
||||
coinbase-api-secret: ""
|
||||
kraken-api-key: ""
|
||||
kraken-api-secret: ""
|
||||
8
deploy/k8s/dev/secrets/minio-secret.yaml.example
Normal file
8
deploy/k8s/dev/secrets/minio-secret.yaml.example
Normal file
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: minio-secret
|
||||
type: Opaque
|
||||
stringData:
|
||||
root-user: "minio"
|
||||
root-password: "minio123"
|
||||
7
deploy/k8s/dev/secrets/postgres-secret.yaml.example
Normal file
7
deploy/k8s/dev/secrets/postgres-secret.yaml.example
Normal file
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: postgres-secret
|
||||
type: Opaque
|
||||
stringData:
|
||||
password: "password"
|
||||
30
deploy/k8s/prod/configs/flink-config.yaml
Normal file
30
deploy/k8s/prod/configs/flink-config.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
# Flink Job Configuration
|
||||
|
||||
# ZeroMQ bind address and ports
|
||||
zmq_bind_address: "tcp://*"
|
||||
zmq_ingestor_work_queue_port: 5555
|
||||
zmq_ingestor_response_port: 5556
|
||||
zmq_ingestor_control_port: 5557
|
||||
zmq_market_data_pub_port: 5558
|
||||
zmq_client_request_port: 5559
|
||||
zmq_cep_webhook_port: 5560
|
||||
|
||||
# Notification publisher endpoint (Flink → Relay)
|
||||
# Relay connects XSUB to this endpoint and proxies to clients
|
||||
notification_publish_endpoint: "tcp://*:5557"
|
||||
|
||||
# Kafka configuration
|
||||
kafka_bootstrap_servers: "kafka:9092"
|
||||
kafka_tick_topic: "market-tick"
|
||||
kafka_ohlc_topic: "market-ohlc"
|
||||
|
||||
# Iceberg catalog
|
||||
iceberg_catalog_uri: "http://iceberg-catalog:8181"
|
||||
iceberg_warehouse: "s3://trading-warehouse/"
|
||||
iceberg_namespace: "trading"
|
||||
iceberg_table_prefix: "market"
|
||||
hadoop_conf_dir: "/etc/hadoop/conf"
|
||||
|
||||
# Flink configuration
|
||||
flink_parallelism: 2
|
||||
flink_checkpoint_interval_ms: 60000
|
||||
24
deploy/k8s/prod/configs/ingestor-config.yaml
Normal file
24
deploy/k8s/prod/configs/ingestor-config.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
# CCXT Ingestor Configuration
|
||||
|
||||
# Relay ZMQ endpoints (relay is the well-known gateway)
|
||||
flink_hostname: relay
|
||||
ingestor_work_port: 5555 # SUB - receives DataRequest with exchange prefix
|
||||
# Note: No response port needed - async architecture via Kafka!
|
||||
|
||||
# Supported exchanges (subscribe to these prefixes)
|
||||
supported_exchanges:
|
||||
- BINANCE
|
||||
- COINBASE
|
||||
- KRAKEN
|
||||
|
||||
# Kafka configuration
|
||||
kafka_brokers:
|
||||
- kafka:9092
|
||||
kafka_topic: market-0
|
||||
|
||||
# Worker configuration
|
||||
max_concurrent: 10
|
||||
poll_interval_ms: 10000
|
||||
|
||||
# Logging
|
||||
log_level: info
|
||||
19
deploy/k8s/prod/configs/relay-config.yaml
Normal file
19
deploy/k8s/prod/configs/relay-config.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
# ZMQ Relay Configuration
|
||||
|
||||
# Bind address for all relay sockets
|
||||
bind_address: "tcp://*"
|
||||
|
||||
# Client-facing ports
|
||||
client_request_port: 5559 # ROUTER - Client historical data requests
|
||||
market_data_pub_port: 5558 # XPUB - Market data fanout to clients
|
||||
|
||||
# Ingestor-facing ports
|
||||
ingestor_work_port: 5555 # PUB - Distribute work with exchange prefix
|
||||
ingestor_response_port: 5556 # ROUTER - Receive responses from ingestors
|
||||
|
||||
# Flink connection
|
||||
flink_market_data_endpoint: "tcp://flink-jobmanager:5557" # XSUB - Subscribe to Flink market data
|
||||
|
||||
# Timeouts and limits
|
||||
request_timeout_secs: 30 # Timeout for pending client requests
|
||||
high_water_mark: 10000 # ZMQ high water mark for all sockets
|
||||
40
deploy/k8s/prod/kustomization.yaml
Normal file
40
deploy/k8s/prod/kustomization.yaml
Normal file
@@ -0,0 +1,40 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
namespace: default
|
||||
|
||||
# Base resources (backend, web, ingress, init/gVisor)
|
||||
resources:
|
||||
- ../base
|
||||
|
||||
# Production patches
|
||||
patches:
|
||||
- path: patches.yaml
|
||||
|
||||
# ConfigMaps for service configs
|
||||
# In production, these might come from external sources
|
||||
# or be managed separately, but we'll include them here for consistency
|
||||
configMapGenerator:
|
||||
- name: relay-config
|
||||
files:
|
||||
- config.yaml=../../configmaps/relay-config.yaml
|
||||
- name: ingestor-config
|
||||
files:
|
||||
- config.yaml=../../configmaps/ingestor-config.yaml
|
||||
- name: flink-config
|
||||
files:
|
||||
- config.yaml=../../configmaps/flink-config.yaml
|
||||
|
||||
# Secrets (managed via kubectl, not committed)
|
||||
# These are created by bin/secret-update prod
|
||||
secretGenerator: []
|
||||
|
||||
generatorOptions:
|
||||
disableNameSuffixHash: true
|
||||
|
||||
# Images
|
||||
images:
|
||||
- name: dexorder/ai-backend
|
||||
newTag: latest
|
||||
- name: dexorder/ai-web
|
||||
newTag: latest
|
||||
52
deploy/k8s/prod/patches.yaml
Normal file
52
deploy/k8s/prod/patches.yaml
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
# Production backend patches
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: ai-backend
|
||||
spec:
|
||||
replicas: 2
|
||||
template:
|
||||
spec:
|
||||
runtimeClassName: gvisor
|
||||
containers:
|
||||
- name: ai-backend
|
||||
image: dexorder/ai-backend:latest
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: CONFIG
|
||||
value: "prod"
|
||||
resources:
|
||||
requests:
|
||||
memory: "2Gi"
|
||||
cpu: "1000m"
|
||||
limits:
|
||||
memory: "4Gi"
|
||||
cpu: "2000m"
|
||||
---
|
||||
# Production web patches
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ai-web
|
||||
spec:
|
||||
replicas: 2
|
||||
template:
|
||||
spec:
|
||||
runtimeClassName: gvisor
|
||||
containers:
|
||||
- name: ai-web
|
||||
image: dexorder/ai-web:latest
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: VITE_BASE_PATH
|
||||
value: "/cryptochimp/"
|
||||
- name: VITE_WS_URL
|
||||
value: "wss://dexorder.ai/ws"
|
||||
resources:
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "1Gi"
|
||||
cpu: "500m"
|
||||
7
deploy/k8s/prod/secrets/ai-secrets.yaml.example
Normal file
7
deploy/k8s/prod/secrets/ai-secrets.yaml.example
Normal file
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: ai-secrets
|
||||
type: Opaque
|
||||
stringData:
|
||||
anthropic-api-key: "sk-ant-YOUR_KEY_HERE"
|
||||
13
deploy/k8s/prod/secrets/ingestor-secrets.yaml.example
Normal file
13
deploy/k8s/prod/secrets/ingestor-secrets.yaml.example
Normal file
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: ingestor-secrets
|
||||
type: Opaque
|
||||
stringData:
|
||||
# Exchange API keys (if needed for authenticated endpoints)
|
||||
binance-api-key: ""
|
||||
binance-api-secret: ""
|
||||
coinbase-api-key: ""
|
||||
coinbase-api-secret: ""
|
||||
kraken-api-key: ""
|
||||
kraken-api-secret: ""
|
||||
8
deploy/k8s/prod/secrets/minio-secret.yaml.example
Normal file
8
deploy/k8s/prod/secrets/minio-secret.yaml.example
Normal file
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: minio-secret
|
||||
type: Opaque
|
||||
stringData:
|
||||
root-user: "CHANGE_THIS_IN_PRODUCTION"
|
||||
root-password: "CHANGE_THIS_IN_PRODUCTION"
|
||||
7
deploy/k8s/prod/secrets/postgres-secret.yaml.example
Normal file
7
deploy/k8s/prod/secrets/postgres-secret.yaml.example
Normal file
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: postgres-secret
|
||||
type: Opaque
|
||||
stringData:
|
||||
password: "CHANGE_THIS_IN_PRODUCTION"
|
||||
Reference in New Issue
Block a user