542 lines
14 KiB
YAML
542 lines
14 KiB
YAML
apiVersion: v1
|
|
kind: Namespace
|
|
metadata:
|
|
name: trading
|
|
labels:
|
|
name: trading
|
|
environment: production
|
|
---
|
|
# OPTIONAL: Use this if you want to persist IB Gateway settings/logs
|
|
# across pod restarts. For most use cases, this is NOT needed since
|
|
# IB Gateway is mostly stateless and credentials are in Secrets.
|
|
#
|
|
# Only create this PV/PVC if you need to persist:
|
|
# - TWS session data
|
|
# - Custom workspace layouts
|
|
# - Historical API usage logs
|
|
|
|
apiVersion: v1
|
|
kind: PersistentVolume
|
|
metadata:
|
|
name: ib-gateway-data
|
|
labels:
|
|
type: local
|
|
app: ib-gateway
|
|
spec:
|
|
capacity:
|
|
storage: 5Gi
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
persistentVolumeReclaimPolicy: Retain
|
|
storageClassName: local-storage
|
|
local:
|
|
path: /mnt/local-ssd/ib-gateway # Adjust to your local SSD path
|
|
nodeAffinity:
|
|
required:
|
|
nodeSelectorTerms:
|
|
- matchExpressions:
|
|
- key: kubernetes.io/hostname
|
|
operator: In
|
|
values:
|
|
- hetzner-2
|
|
|
|
---
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: ib-gateway-data
|
|
namespace: trading
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
resources:
|
|
requests:
|
|
storage: 5Gi
|
|
storageClassName: local-storage
|
|
selector:
|
|
matchLabels:
|
|
app: ib-gateway
|
|
|
|
# To use this PVC, add to Deployment volumeMounts:
|
|
# - name: data
|
|
# mountPath: /root/Jts
|
|
# And to volumes:
|
|
# - name: data
|
|
# persistentVolumeClaim:
|
|
# claimName: ib-gateway-data
|
|
---
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: ib-credentials
|
|
namespace: trading
|
|
type: Opaque
|
|
stringData:
|
|
# IMPORTANT: Replace these with your actual IB credentials
|
|
# For paper trading, use your paper trading account
|
|
username: "saladin85"
|
|
password: "3Lcd@05041985"
|
|
# Trading mode: "paper" or "live"
|
|
trading-mode: "paper"
|
|
|
|
# IB Gateway config (jts.ini equivalent)
|
|
# This enables headless mode and configures ports
|
|
ibgateway.conf: |
|
|
[IBGateway]
|
|
TradingMode=paper
|
|
ApiOnly=true
|
|
ReadOnlyApi=false
|
|
TrustedIPs=127.0.0.1
|
|
|
|
[IBGatewayAPI]
|
|
ApiPortNumber=4002
|
|
|
|
[Logon]
|
|
UseRemoteSettings=no
|
|
Locale=en
|
|
ColorPaletteName=dark
|
|
|
|
[Display]
|
|
ShowSplashScreen=no
|
|
---
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: ib-gateway-config
|
|
namespace: trading
|
|
data:
|
|
# Startup script to configure IB Gateway for headless operation
|
|
startup.sh: |
|
|
#!/bin/bash
|
|
set -e
|
|
|
|
echo "Starting IB Gateway in headless mode..."
|
|
echo "Trading Mode: ${TRADING_MODE}"
|
|
echo "Port: ${TWS_PORT}"
|
|
|
|
# Configure based on trading mode
|
|
if [ "${TRADING_MODE}" == "live" ]; then
|
|
export TWS_PORT=4001
|
|
echo "⚠️ LIVE TRADING MODE - USE WITH CAUTION ⚠️"
|
|
else
|
|
export TWS_PORT=4002
|
|
echo "📝 Paper Trading Mode (Safe)"
|
|
fi
|
|
# IMPORTANT: use the env vars provided by the Deployment
|
|
export IB_USERNAME="${TWS_USERID}"
|
|
export IB_PASSWORD="${TWS_PASSWORD}"
|
|
|
|
# Start IB Gateway
|
|
exec /opt/ibgateway/ibgateway-latest-standalone-linux-x64.sh \
|
|
--tws-path=/root/Jts \
|
|
--tws-settings-path=/root \
|
|
--user="${IB_USERNAME}" \
|
|
--pw="${IB_PASSWORD}" \
|
|
--mode="${TRADING_MODE}" \
|
|
--port="${TWS_PORT}"
|
|
|
|
# Health check script
|
|
healthcheck.sh: |
|
|
#!/bin/bash
|
|
# Check if TWS API port is listening
|
|
# PORT=${TWS_PORT:-4002}
|
|
# nc -z localhost $PORT
|
|
# exit $?
|
|
#!/bin/sh
|
|
# Pure-python TCP check (no nc required)
|
|
PORT="${TWS_PORT:-4002}"
|
|
python - <<'PY'
|
|
import os, socket, sys
|
|
port = int(os.environ.get("TWS_PORT", os.environ.get("PORT", "4002")))
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
s.settimeout(2)
|
|
try:
|
|
s.connect(("127.0.0.1", port))
|
|
sys.exit(0)
|
|
except Exception:
|
|
sys.exit(1)
|
|
finally:
|
|
s.close()
|
|
PY
|
|
---
|
|
# apiVersion: apps/v1
|
|
# kind: Deployment
|
|
# metadata:
|
|
# name: ib-gateway
|
|
# namespace: trading
|
|
# labels:
|
|
# app: ib-gateway
|
|
# component: trading-infrastructure
|
|
# spec:
|
|
# replicas: 1 # IB Gateway should only have 1 instance per account
|
|
# strategy:
|
|
# type: Recreate # Avoid multiple simultaneous logins
|
|
# selector:
|
|
# matchLabels:
|
|
# app: ib-gateway
|
|
# template:
|
|
# metadata:
|
|
# labels:
|
|
# app: ib-gateway
|
|
# annotations:
|
|
# prometheus.io/scrape: "false" # No metrics endpoint by default
|
|
# spec:
|
|
# # Pin to hetzner-2 (matches your existing pattern)
|
|
# nodeSelector:
|
|
# kubernetes.io/hostname: hetzner-2
|
|
|
|
# # Security context
|
|
# securityContext:
|
|
# runAsNonRoot: false # IB Gateway requires root for VNC (even if unused)
|
|
# fsGroup: 1000
|
|
|
|
# containers:
|
|
# - name: ib-gateway
|
|
# # Using community-maintained IB Gateway image
|
|
# # Alternative: waytrade/ib-gateway:latest
|
|
# image: ghcr.io/gnzsnz/ib-gateway:stable
|
|
# imagePullPolicy: IfNotPresent
|
|
|
|
# env:
|
|
# - name: TWS_USERID
|
|
# valueFrom:
|
|
# secretKeyRef:
|
|
# name: ib-credentials
|
|
# key: username
|
|
# - name: TWS_PASSWORD
|
|
# valueFrom:
|
|
# secretKeyRef:
|
|
# name: ib-credentials
|
|
# key: password
|
|
# - name: TRADING_MODE
|
|
# valueFrom:
|
|
# secretKeyRef:
|
|
# name: ib-credentials
|
|
# key: trading-mode
|
|
# - name: TWS_PORT
|
|
# value: "4002" # Default to paper trading
|
|
# - name: READ_ONLY_API
|
|
# value: "no"
|
|
|
|
# # Ports
|
|
# ports:
|
|
# - name: paper-trading
|
|
# containerPort: 4002
|
|
# protocol: TCP
|
|
# - name: live-trading
|
|
# containerPort: 4001
|
|
# protocol: TCP
|
|
# - name: vnc
|
|
# containerPort: 5900
|
|
# protocol: TCP # VNC (not exposed externally)
|
|
|
|
# # Resource limits
|
|
# resources:
|
|
# requests:
|
|
# memory: "1Gi"
|
|
# cpu: "500m"
|
|
# limits:
|
|
# memory: "2Gi"
|
|
# cpu: "1000m"
|
|
|
|
# # Liveness probe (check if API port is responsive)
|
|
# startupProbe:
|
|
# tcpSocket:
|
|
# port: 4002
|
|
# initialDelaySeconds: 60 # Wait 60s before first check
|
|
# periodSeconds: 10 # Check every 10s
|
|
# timeoutSeconds: 5
|
|
# failureThreshold: 18 # 60s + (10s * 18) = 240s total startup time
|
|
|
|
# livenessProbe:
|
|
# tcpSocket:
|
|
# port: 4002
|
|
# initialDelaySeconds: 0 # IB Gateway takes time to start
|
|
# periodSeconds: 60
|
|
# timeoutSeconds: 5
|
|
# failureThreshold: 3
|
|
|
|
# # Readiness probe
|
|
# readinessProbe:
|
|
# tcpSocket:
|
|
# port: 4002
|
|
# initialDelaySeconds: 0
|
|
# periodSeconds: 10
|
|
# timeoutSeconds: 5
|
|
# failureThreshold: 2
|
|
|
|
# # Volume mounts for config
|
|
# volumeMounts:
|
|
# - name: ib-config
|
|
# mountPath: /root/Jts/jts.ini
|
|
# subPath: ibgateway.conf
|
|
# - name: startup-script
|
|
# mountPath: /startup.sh
|
|
# subPath: startup.sh
|
|
# - name: data
|
|
# mountPath: /root/Jts
|
|
|
|
# # Logging to stdout (Fluent Bit will collect)
|
|
# # IB Gateway logs go to /root/Jts/log by default
|
|
# lifecycle:
|
|
# postStart:
|
|
# exec:
|
|
# command:
|
|
# - /bin/sh
|
|
# - -c
|
|
# - |
|
|
# mkdir -p /root/Jts/log
|
|
# ln -sf /dev/stdout /root/Jts/log/ibgateway.log || true
|
|
|
|
# volumes:
|
|
# - name: ib-config
|
|
# secret:
|
|
# secretName: ib-credentials
|
|
# defaultMode: 0644
|
|
# - name: startup-script
|
|
# configMap:
|
|
# name: ib-gateway-config
|
|
# defaultMode: 0755
|
|
# - name: data
|
|
# persistentVolumeClaim:
|
|
# claimName: ib-gateway-data
|
|
|
|
# # Restart policy
|
|
# restartPolicy: Always
|
|
|
|
# # DNS policy for internal cluster resolution
|
|
# dnsPolicy: ClusterFirst
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: ib-gateway
|
|
namespace: trading
|
|
labels:
|
|
app: ib-gateway
|
|
component: trading-infrastructure
|
|
spec:
|
|
replicas: 1
|
|
strategy:
|
|
type: Recreate
|
|
selector:
|
|
matchLabels:
|
|
app: ib-gateway
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: ib-gateway
|
|
annotations:
|
|
prometheus.io/scrape: "false"
|
|
spec:
|
|
nodeSelector:
|
|
kubernetes.io/hostname: hetzner-2
|
|
|
|
securityContext:
|
|
runAsNonRoot: false
|
|
fsGroup: 1000
|
|
|
|
# Seed writable jts.ini into the PVC once
|
|
initContainers:
|
|
- name: seed-jts-config
|
|
image: busybox:1.36
|
|
command:
|
|
- sh
|
|
- -c
|
|
- |
|
|
set -e
|
|
mkdir -p /data
|
|
if [ ! -f /data/jts.ini ]; then
|
|
echo "Seeding jts.ini into PVC"
|
|
cp /config/ibgateway.conf /data/jts.ini
|
|
chmod 644 /data/jts.ini
|
|
else
|
|
echo "jts.ini already exists in PVC"
|
|
fi
|
|
volumeMounts:
|
|
- name: ib-config
|
|
mountPath: /config
|
|
readOnly: true
|
|
- name: data
|
|
mountPath: /data
|
|
|
|
containers:
|
|
# ------------------------------------------------------------------
|
|
# IB Gateway
|
|
# ------------------------------------------------------------------
|
|
- name: ib-gateway
|
|
image: ghcr.io/gnzsnz/ib-gateway:stable
|
|
imagePullPolicy: IfNotPresent
|
|
|
|
env:
|
|
- name: TWS_USERID
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: ib-credentials
|
|
key: username
|
|
- name: TWS_PASSWORD
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: ib-credentials
|
|
key: password
|
|
- name: TRADING_MODE
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: ib-credentials
|
|
key: trading-mode
|
|
- name: TWS_PORT
|
|
value: "4002"
|
|
- name: READ_ONLY_API
|
|
value: "no"
|
|
|
|
ports:
|
|
- name: ib-api-local
|
|
containerPort: 4002
|
|
protocol: TCP
|
|
- name: live-trading
|
|
containerPort: 4001
|
|
protocol: TCP
|
|
- name: vnc
|
|
containerPort: 5900
|
|
protocol: TCP
|
|
|
|
resources:
|
|
requests:
|
|
memory: "1Gi"
|
|
cpu: "500m"
|
|
limits:
|
|
memory: "2Gi"
|
|
cpu: "1000m"
|
|
|
|
# IMPORTANT: Probes should check the local IB port (4002)
|
|
startupProbe:
|
|
tcpSocket:
|
|
port: 4002
|
|
initialDelaySeconds: 60
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 18
|
|
|
|
livenessProbe:
|
|
tcpSocket:
|
|
port: 4002
|
|
periodSeconds: 60
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
|
|
readinessProbe:
|
|
tcpSocket:
|
|
port: 4002
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 2
|
|
|
|
volumeMounts:
|
|
- name: data
|
|
mountPath: /root/Jts
|
|
|
|
lifecycle:
|
|
postStart:
|
|
exec:
|
|
command:
|
|
- sh
|
|
- -c
|
|
- |
|
|
mkdir -p /root/Jts/log
|
|
ln -sf /dev/stdout /root/Jts/log/ibgateway.log || true
|
|
|
|
# ------------------------------------------------------------------
|
|
# Sidecar TCP proxy: accepts cluster traffic, forwards to localhost:4002
|
|
# ------------------------------------------------------------------
|
|
- name: ib-api-proxy
|
|
image: alpine/socat:1.8.0.0
|
|
imagePullPolicy: IfNotPresent
|
|
args:
|
|
- "-d"
|
|
- "-d"
|
|
- "TCP-LISTEN:4003,fork,reuseaddr"
|
|
- "TCP:127.0.0.1:4002"
|
|
ports:
|
|
- name: ib-api
|
|
containerPort: 4003
|
|
protocol: TCP
|
|
resources:
|
|
requests:
|
|
memory: "32Mi"
|
|
cpu: "10m"
|
|
limits:
|
|
memory: "128Mi"
|
|
cpu: "100m"
|
|
# basic probe: is proxy listening
|
|
readinessProbe:
|
|
tcpSocket:
|
|
port: 4003
|
|
periodSeconds: 5
|
|
timeoutSeconds: 2
|
|
failureThreshold: 3
|
|
|
|
volumes:
|
|
- name: ib-config
|
|
secret:
|
|
secretName: ib-credentials
|
|
defaultMode: 0644
|
|
|
|
- name: data
|
|
persistentVolumeClaim:
|
|
claimName: ib-gateway-data
|
|
|
|
restartPolicy: Always
|
|
dnsPolicy: ClusterFirst
|
|
|
|
|
|
---
|
|
# apiVersion: v1
|
|
# kind: Service
|
|
# metadata:
|
|
# name: ib-gateway
|
|
# namespace: trading
|
|
# labels:
|
|
# app: ib-gateway
|
|
# spec:
|
|
# type: ClusterIP # Internal-only, not exposed publicly
|
|
# clusterIP: None # Headless service (optional, remove if you want a stable ClusterIP)
|
|
# selector:
|
|
# app: ib-gateway
|
|
# ports:
|
|
# - name: paper-trading
|
|
# port: 4002
|
|
# targetPort: 4002
|
|
# protocol: TCP
|
|
# - name: live-trading
|
|
# port: 4001
|
|
# targetPort: 4001
|
|
# protocol: TCP
|
|
# sessionAffinity: ClientIP # Stick to same pod (important for stateful TWS sessions)
|
|
# sessionAffinityConfig:
|
|
# clientIP:
|
|
# timeoutSeconds: 3600 # 1 hour session stickiness
|
|
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: ib-gateway
|
|
namespace: trading
|
|
labels:
|
|
app: ib-gateway
|
|
spec:
|
|
type: ClusterIP
|
|
selector:
|
|
app: ib-gateway
|
|
ports:
|
|
- name: paper-trading
|
|
port: 4002
|
|
targetPort: 4003 # <-- proxy sidecar, not the gateway directly
|
|
protocol: TCP
|
|
- name: live-trading
|
|
port: 4001
|
|
targetPort: 4001
|
|
protocol: TCP
|
|
sessionAffinity: ClientIP
|
|
sessionAffinityConfig:
|
|
clientIP:
|
|
timeoutSeconds: 3600
|