Skip to content

Commit 0fac5c5

Browse files
committed
tilt
1 parent 2469340 commit 0fac5c5

11 files changed

Lines changed: 913 additions & 0 deletions

File tree

Tiltfile

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
# -*- mode: Python -*-
2+
# Cabotage Local Development with Tilt
3+
#
4+
# Usage:
5+
# tilt up
6+
#
7+
# This Tiltfile sets up the complete Cabotage development environment on OrbStack K8s.
8+
# Hot reload is handled by:
9+
# - hostPath volume mounts (source code mounted directly into pods)
10+
# - Hupper (Python process watcher, auto-reloads on file changes)
11+
12+
# Configuration
13+
k8s_context('orbstack')
14+
load('ext://namespace', 'namespace_create')
15+
16+
# Create namespace
17+
namespace_create('cabotage-dev')
18+
19+
# =============================================================================
20+
# Docker Image Build
21+
# =============================================================================
22+
23+
# Build the development image with DEVEL=yes for dev dependencies
24+
docker_build(
25+
'cabotage-app:dev',
26+
'.',
27+
dockerfile='Dockerfile',
28+
build_args={'DEVEL': 'yes'},
29+
# Since we use hostPath mounts, we don't need live_update for file sync
30+
# Hupper handles process reload automatically
31+
)
32+
33+
# =============================================================================
34+
# Infrastructure Resources
35+
# =============================================================================
36+
37+
# Deploy infrastructure in dependency order
38+
# (namespace already created by namespace_create above)
39+
40+
# =============================================================================
41+
# OrbStack DNS - No Port Conflicts!
42+
# =============================================================================
43+
# All services are accessible via OrbStack's automatic DNS:
44+
# - http://cabotage-app.cabotage-dev.orb.local (web app)
45+
# - db.cabotage-dev.orb.local:5432 (postgres)
46+
# - redis.cabotage-dev.orb.local:6379 (redis)
47+
# - consul.cabotage-dev.orb.local:8500 (consul)
48+
# - vault.cabotage-dev.orb.local:8200 (vault)
49+
# - minio.cabotage-dev.orb.local:9000 (minio)
50+
# - registry.cabotage-dev.orb.local:5001 (registry)
51+
#
52+
# Uncomment port_forwards below if you need localhost access for specific tools.
53+
# =============================================================================
54+
55+
# Postgres - must come first (Vault needs it for DB creds)
56+
k8s_yaml('k8s/dev/infra/postgres.yaml')
57+
k8s_resource(
58+
'postgres',
59+
objects=['postgres-initdb:configmap'],
60+
# port_forwards=['5432:5432'],
61+
labels=['infra'],
62+
)
63+
64+
# Redis
65+
k8s_yaml('k8s/dev/infra/redis.yaml')
66+
k8s_resource(
67+
'redis',
68+
# port_forwards=['6379:6379'],
69+
labels=['infra'],
70+
)
71+
72+
# Consul
73+
k8s_yaml('k8s/dev/infra/consul.yaml')
74+
k8s_resource(
75+
'consul',
76+
# port_forwards=['8500:8500'],
77+
labels=['infra'],
78+
)
79+
80+
# Vault - depends on postgres
81+
k8s_yaml('k8s/dev/infra/vault.yaml')
82+
k8s_resource(
83+
'vault',
84+
objects=['vault-config:configmap'],
85+
# port_forwards=['8200:8200'],
86+
resource_deps=['postgres'],
87+
labels=['infra'],
88+
)
89+
90+
# MinIO (S3-compatible storage for registry)
91+
k8s_yaml('k8s/dev/infra/minio.yaml')
92+
k8s_resource(
93+
'minio',
94+
# port_forwards=['9000:9000', '9001:9001'],
95+
labels=['infra'],
96+
)
97+
98+
# Docker Registry - depends on minio
99+
k8s_yaml('k8s/dev/infra/registry.yaml')
100+
k8s_resource(
101+
'registry',
102+
objects=['registry-config:configmap'],
103+
# port_forwards=['5001:5001'],
104+
resource_deps=['minio'],
105+
labels=['infra'],
106+
)
107+
108+
# BuildKit
109+
k8s_yaml('k8s/dev/infra/buildkit.yaml')
110+
k8s_resource(
111+
'buildkit',
112+
objects=['buildkit-config:configmap'],
113+
# port_forwards=['1234:1234'],
114+
resource_deps=['registry'],
115+
labels=['infra'],
116+
)
117+
118+
# =============================================================================
119+
# Application Resources
120+
# =============================================================================
121+
122+
k8s_yaml('k8s/dev/app.yaml')
123+
k8s_yaml('k8s/dev/ingress.yaml')
124+
125+
# Cabotage Web App
126+
# Access via: http://cabotage.192-168-139-2.nip.io (through nginx ingress)
127+
k8s_resource(
128+
'cabotage-app',
129+
objects=['cabotage-app:ingress'], # Include the ingress with this resource
130+
resource_deps=['postgres', 'redis', 'vault', 'consul'],
131+
labels=['app'],
132+
trigger_mode=TRIGGER_MODE_AUTO,
133+
)
134+
135+
# Cabotage Celery Worker
136+
k8s_resource(
137+
'cabotage-app-worker',
138+
resource_deps=['postgres', 'redis', 'vault', 'consul'],
139+
labels=['app'],
140+
trigger_mode=TRIGGER_MODE_AUTO,
141+
)
142+
143+
# =============================================================================
144+
# Local Commands
145+
# =============================================================================
146+
147+
# Working directory for kubectl exec commands (must cd first, then use python -m)
148+
EXEC_PREFIX = 'kubectl exec -n cabotage-dev deploy/cabotage-app -- sh -c "cd /opt/cabotage-app/src && '
149+
150+
# Run database migrations (auto-runs on startup, safe to run multiple times)
151+
local_resource(
152+
'db-migrate',
153+
cmd=EXEC_PREFIX + 'python3 -m flask db upgrade"',
154+
resource_deps=['cabotage-app'],
155+
labels=['setup'],
156+
auto_init=True,
157+
)
158+
159+
# Create admin user (auto-runs on startup, script should handle existing user)
160+
local_resource(
161+
'create-admin',
162+
cmd=EXEC_PREFIX + 'python3 -m cabotage.scripts.create_admin"',
163+
resource_deps=['db-migrate'],
164+
labels=['setup'],
165+
auto_init=True,
166+
)
167+
168+
# View Flask routes
169+
local_resource(
170+
'routes',
171+
cmd=EXEC_PREFIX + 'python3 -m flask routes"',
172+
resource_deps=['cabotage-app'],
173+
labels=['commands'],
174+
auto_init=False,
175+
trigger_mode=TRIGGER_MODE_MANUAL,
176+
)
177+
178+
# =============================================================================
179+
# Development Workflow
180+
# =============================================================================
181+
182+
# Watch Python files for changes (informational - Hupper handles actual reload)
183+
watch_file('cabotage/')
184+
watch_file('migrations/')
185+
186+
# Watch templates for changes
187+
watch_file('cabotage/client/templates/')
188+
watch_file('cabotage/client/static/')

k8s/dev/app.yaml

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
# Cabotage App - Web Server
2+
apiVersion: v1
3+
kind: Service
4+
metadata:
5+
name: cabotage-app
6+
namespace: cabotage-dev
7+
spec:
8+
ports:
9+
- port: 8000
10+
targetPort: 8000
11+
selector:
12+
app: cabotage-app
13+
---
14+
apiVersion: apps/v1
15+
kind: Deployment
16+
metadata:
17+
name: cabotage-app
18+
namespace: cabotage-dev
19+
spec:
20+
replicas: 1
21+
selector:
22+
matchLabels:
23+
app: cabotage-app
24+
template:
25+
metadata:
26+
labels:
27+
app: cabotage-app
28+
spec:
29+
containers:
30+
- name: cabotage-app
31+
image: cabotage-app:dev
32+
command:
33+
- hupper
34+
- -m
35+
- gunicorn.app.wsgiapp
36+
- -c
37+
- gunicorn.conf
38+
- -w
39+
- "2"
40+
- --threads
41+
- "50"
42+
- -b
43+
- 0.0.0.0:8000
44+
- cabotage.server.wsgi:app
45+
ports:
46+
- containerPort: 8000
47+
env:
48+
# Cache directories
49+
- name: PIP_CACHE_DIR
50+
value: /opt/cabotage-app/src/dev/.pip-cache
51+
- name: PIP_TOOLS_CACHE_DIR
52+
value: /opt/cabotage-app/src/dev/.pip-tools-cache
53+
# Application configuration
54+
- name: CABOTAGE_BCRYPT_LOG_ROUNDS
55+
value: "4"
56+
- name: CABOTAGE_DEBUG
57+
value: "True"
58+
- name: CABOTAGE_DEBUG_TB_ENABLED
59+
value: "True"
60+
- name: CABOTAGE_GITHUB_APP_ID
61+
value: ""
62+
- name: CABOTAGE_GITHUB_APP_PRIVATE_KEY
63+
value: ""
64+
- name: CABOTAGE_GITHUB_APP_URL
65+
value: https://github.com/apps/cabotage-local
66+
- name: CABOTAGE_GITHUB_WEBHOOK_SECRET
67+
value: ""
68+
- name: CABOTAGE_KUBERNETES_CONTEXT
69+
value: orbstack
70+
- name: CABOTAGE_KUBERNETES_ENABLED
71+
value: "True"
72+
- name: CABOTAGE_SECURITY_CONFIRMABLE
73+
value: "False"
74+
- name: CABOTAGE_SQLALCHEMY_DATABASE_URI
75+
value: postgresql://postgres@db/cabotage_dev
76+
- name: CABOTAGE_TESTING
77+
value: "True"
78+
- name: CABOTAGE_VAULT_TOKEN
79+
value: deadbeef-dead-beef-dead-beefdeadbeef
80+
- name: CABOTAGE_WTF_CSRF_ENABLED
81+
value: "False"
82+
- name: C_FORCE_ROOT
83+
value: "1"
84+
- name: FLASK_APP
85+
value: cabotage.server.wsgi
86+
- name: KUBECONFIG
87+
value: /var/run/kube/config
88+
volumeMounts:
89+
- name: source-code
90+
mountPath: /opt/cabotage-app/src
91+
- name: kubeconfig
92+
mountPath: /var/run/kube
93+
readOnly: true
94+
resources:
95+
requests:
96+
memory: "256Mi"
97+
cpu: "100m"
98+
limits:
99+
memory: "512Mi"
100+
cpu: "500m"
101+
volumes:
102+
- name: source-code
103+
hostPath:
104+
# OrbStack automatically translates macOS paths
105+
path: /Users/coffee/git/internal/cabotage-app
106+
type: Directory
107+
- name: kubeconfig
108+
hostPath:
109+
path: /Users/coffee/.kube
110+
type: Directory
111+
---
112+
# Cabotage App - Celery Worker
113+
apiVersion: apps/v1
114+
kind: Deployment
115+
metadata:
116+
name: cabotage-app-worker
117+
namespace: cabotage-dev
118+
spec:
119+
replicas: 1
120+
selector:
121+
matchLabels:
122+
app: cabotage-app-worker
123+
template:
124+
metadata:
125+
labels:
126+
app: cabotage-app-worker
127+
spec:
128+
containers:
129+
- name: cabotage-app-worker
130+
image: cabotage-app:dev
131+
command:
132+
- hupper
133+
- -m
134+
- celery
135+
- -A
136+
- cabotage.celery.worker.celery_app
137+
- worker
138+
- -E
139+
- --loglevel=INFO
140+
env:
141+
# Cache directories
142+
- name: PIP_CACHE_DIR
143+
value: /opt/cabotage-app/src/dev/.pip-cache
144+
- name: PIP_TOOLS_CACHE_DIR
145+
value: /opt/cabotage-app/src/dev/.pip-tools-cache
146+
# Application configuration
147+
- name: CABOTAGE_BCRYPT_LOG_ROUNDS
148+
value: "4"
149+
- name: CABOTAGE_DEBUG
150+
value: "True"
151+
- name: CABOTAGE_DEBUG_TB_ENABLED
152+
value: "True"
153+
- name: CABOTAGE_GITHUB_APP_ID
154+
value: ""
155+
- name: CABOTAGE_GITHUB_APP_PRIVATE_KEY
156+
value: ""
157+
- name: CABOTAGE_GITHUB_APP_URL
158+
value: https://github.com/apps/cabotage-local
159+
- name: CABOTAGE_GITHUB_WEBHOOK_SECRET
160+
value: ""
161+
- name: CABOTAGE_KUBERNETES_CONTEXT
162+
value: orbstack
163+
- name: CABOTAGE_KUBERNETES_ENABLED
164+
value: "True"
165+
- name: CABOTAGE_SECURITY_CONFIRMABLE
166+
value: "False"
167+
- name: CABOTAGE_SQLALCHEMY_DATABASE_URI
168+
value: postgresql://postgres@db/cabotage_dev
169+
- name: CABOTAGE_TESTING
170+
value: "True"
171+
- name: CABOTAGE_VAULT_TOKEN
172+
value: deadbeef-dead-beef-dead-beefdeadbeef
173+
- name: CABOTAGE_WTF_CSRF_ENABLED
174+
value: "False"
175+
- name: C_FORCE_ROOT
176+
value: "1"
177+
- name: FLASK_APP
178+
value: cabotage.server.wsgi
179+
- name: KUBECONFIG
180+
value: /var/run/kube/config
181+
volumeMounts:
182+
- name: source-code
183+
mountPath: /opt/cabotage-app/src
184+
- name: kubeconfig
185+
mountPath: /var/run/kube
186+
readOnly: true
187+
resources:
188+
requests:
189+
memory: "256Mi"
190+
cpu: "100m"
191+
limits:
192+
memory: "512Mi"
193+
cpu: "500m"
194+
volumes:
195+
- name: source-code
196+
hostPath:
197+
path: /Users/coffee/git/internal/cabotage-app
198+
type: Directory
199+
- name: kubeconfig
200+
hostPath:
201+
path: /Users/coffee/.kube
202+
type: Directory

0 commit comments

Comments
 (0)