/ docker / claude.md
claude.md
  1  # docker/
  2  
  3  **Context:** Docker & Kubernetes Deployment
  4  
  5  This directory contains Docker configuration and Kubernetes manifests for deploying ECHO to containerized environments.
  6  
  7  ## Purpose
  8  
  9  Docker support enables:
 10  - **Containerized Deployment** - Package agents and infrastructure in containers
 11  - **Environment Consistency** - Same setup across dev/staging/production
 12  - **Orchestration** - Kubernetes deployment for scalability
 13  - **Easy Setup** - Docker Compose for local development
 14  
 15  ## Directory Structure
 16  
 17  ```
 18  docker/
 19  ├── claude.md                  # This file
 20  ├── docker-compose.yml        # Local development setup
 21  └── [individual Dockerfiles for agents]
 22  ```
 23  
 24  Note: Kubernetes manifests are in `../k8s/` directory
 25  
 26  ## Docker Compose Setup
 27  
 28  **Purpose:** Run entire ECHO system locally with Docker
 29  
 30  **File:** `docker-compose.yml`
 31  
 32  ```yaml
 33  version: '3.8'
 34  
 35  services:
 36    # Infrastructure
 37    postgres:
 38      image: postgres:16-alpine
 39      environment:
 40        POSTGRES_DB: echo_org
 41        POSTGRES_USER: postgres
 42        POSTGRES_PASSWORD: postgres
 43      ports:
 44        - "5432:5432"
 45      volumes:
 46        - postgres_data:/var/lib/postgresql/data
 47      healthcheck:
 48        test: ["CMD-SHELL", "pg_isready -U postgres"]
 49        interval: 10s
 50        timeout: 5s
 51        retries: 5
 52  
 53    redis:
 54      image: redis:7-alpine
 55      ports:
 56        - "6379:6379"
 57      volumes:
 58        - redis_data:/data
 59      healthcheck:
 60        test: ["CMD", "redis-cli", "ping"]
 61        interval: 10s
 62        timeout: 3s
 63        retries: 5
 64  
 65    # Agents
 66    echo-ceo:
 67      build:
 68        context: ../agents/ceo
 69        dockerfile: Dockerfile
 70      depends_on:
 71        postgres:
 72          condition: service_healthy
 73        redis:
 74          condition: service_healthy
 75      environment:
 76        DB_HOST: postgres
 77        DB_NAME: echo_org
 78        REDIS_HOST: redis
 79        OLLAMA_ENDPOINT: http://host.docker.internal:11434
 80      command: ["./ceo", "--autonomous"]
 81  
 82    echo-cto:
 83      build:
 84        context: ../agents/cto
 85        dockerfile: Dockerfile
 86      depends_on:
 87        postgres:
 88          condition: service_healthy
 89        redis:
 90          condition: service_healthy
 91      environment:
 92        DB_HOST: postgres
 93        REDIS_HOST: redis
 94        OLLAMA_ENDPOINT: http://host.docker.internal:11434
 95      command: ["./cto", "--autonomous"]
 96  
 97    # ... (repeat for other 7 agents)
 98  
 99    # Monitor Dashboard
100    monitor:
101      build:
102        context: ../monitor
103        dockerfile: Dockerfile
104      depends_on:
105        postgres:
106          condition: service_healthy
107        redis:
108          condition: service_healthy
109      ports:
110        - "4000:4000"
111      environment:
112        DB_HOST: postgres
113        REDIS_HOST: redis
114        SECRET_KEY_BASE: ${SECRET_KEY_BASE}
115  
116  volumes:
117    postgres_data:
118    redis_data:
119  ```
120  
121  ### Usage
122  
123  ```bash
124  # Start all services
125  docker-compose up -d
126  
127  # View logs
128  docker-compose logs -f
129  
130  # Stop all services
131  docker-compose down
132  
133  # Rebuild and restart
134  docker-compose up -d --build
135  
136  # Run database migrations
137  docker-compose exec postgres psql -U postgres -d echo_org < migrations.sql
138  ```
139  
140  ## Agent Dockerfile Template
141  
142  ```dockerfile
143  # Multi-stage build for smaller image
144  FROM elixir:1.18-alpine AS builder
145  
146  # Install build dependencies
147  RUN apk add --no-cache build-base git
148  
149  WORKDIR /app
150  
151  # Copy shared library first (dependency)
152  COPY ../../shared /app/shared
153  WORKDIR /app/shared
154  RUN mix local.hex --force && \
155      mix local.rebar --force && \
156      mix deps.get && \
157      mix compile
158  
159  # Copy agent code
160  WORKDIR /app/agent
161  COPY mix.exs mix.lock ./
162  RUN mix deps.get --only prod
163  COPY lib lib
164  COPY config config
165  
166  # Build escript executable
167  RUN MIX_ENV=prod mix escript.build
168  
169  # Runtime stage
170  FROM alpine:latest
171  
172  # Install runtime dependencies
173  RUN apk add --no-cache bash openssl ncurses-libs
174  
175  WORKDIR /app
176  
177  # Copy executable from builder
178  COPY --from=builder /app/agent/agent_name ./agent_name
179  
180  # Create non-root user
181  RUN adduser -D -u 1000 echo && \
182      chown -R echo:echo /app
183  
184  USER echo
185  
186  # Run agent
187  CMD ["./agent_name", "--autonomous"]
188  ```
189  
190  ## Kubernetes Deployment
191  
192  **Location:** `../k8s/` directory
193  
194  ### Architecture
195  
196  ```
197  k8s/
198  ├── namespace.yml              # echo-org namespace
199  ├── postgres.yml               # PostgreSQL StatefulSet
200  ├── redis.yml                  # Redis Deployment
201  ├── agents/
202  │   ├── ceo.yml               # CEO agent Deployment
203  │   ├── cto.yml               # CTO agent Deployment
204  │   └── ... (other agents)
205  └── monitor.yml                # Monitor dashboard Deployment + Service
206  ```
207  
208  ### Namespace
209  
210  ```yaml
211  # k8s/namespace.yml
212  apiVersion: v1
213  kind: Namespace
214  metadata:
215    name: echo-org
216    labels:
217      name: echo-org
218  ```
219  
220  ### PostgreSQL StatefulSet
221  
222  ```yaml
223  # k8s/postgres.yml
224  apiVersion: apps/v1
225  kind: StatefulSet
226  metadata:
227    name: postgres
228    namespace: echo-org
229  spec:
230    serviceName: postgres
231    replicas: 1
232    selector:
233      matchLabels:
234        app: postgres
235    template:
236      metadata:
237        labels:
238          app: postgres
239      spec:
240        containers:
241        - name: postgres
242          image: postgres:16-alpine
243          ports:
244          - containerPort: 5432
245          env:
246          - name: POSTGRES_DB
247            value: echo_org
248          - name: POSTGRES_USER
249            valueFrom:
250              secretKeyRef:
251                name: postgres-secret
252                key: username
253          - name: POSTGRES_PASSWORD
254            valueFrom:
255              secretKeyRef:
256                name: postgres-secret
257                key: password
258          volumeMounts:
259          - name: postgres-storage
260            mountPath: /var/lib/postgresql/data
261    volumeClaimTemplates:
262    - metadata:
263        name: postgres-storage
264      spec:
265        accessModes: ["ReadWriteOnce"]
266        resources:
267          requests:
268            storage: 10Gi
269  ```
270  
271  ### Agent Deployment Template
272  
273  ```yaml
274  # k8s/agents/ceo.yml
275  apiVersion: apps/v1
276  kind: Deployment
277  metadata:
278    name: echo-ceo
279    namespace: echo-org
280  spec:
281    replicas: 1
282    selector:
283      matchLabels:
284        app: echo-ceo
285        role: ceo
286    template:
287      metadata:
288        labels:
289          app: echo-ceo
290          role: ceo
291      spec:
292        containers:
293        - name: ceo
294          image: ghcr.io/your-org/echo-ceo:latest
295          env:
296          - name: DB_HOST
297            value: postgres
298          - name: DB_NAME
299            value: echo_org
300          - name: DB_USER
301            valueFrom:
302              secretKeyRef:
303                name: postgres-secret
304                key: username
305          - name: DB_PASSWORD
306            valueFrom:
307              secretKeyRef:
308                name: postgres-secret
309                key: password
310          - name: REDIS_HOST
311            value: redis
312          - name: OLLAMA_ENDPOINT
313            value: http://ollama-service:11434
314          resources:
315            requests:
316              memory: "256Mi"
317              cpu: "100m"
318            limits:
319              memory: "512Mi"
320              cpu: "500m"
321          livenessProbe:
322            exec:
323              command:
324              - /bin/sh
325              - -c
326              - "pgrep -f ceo"
327            initialDelaySeconds: 30
328            periodSeconds: 30
329          readinessProbe:
330            exec:
331              command:
332              - /bin/sh
333              - -c
334              - "pgrep -f ceo"
335            initialDelaySeconds: 10
336            periodSeconds: 10
337  ```
338  
339  ### Monitor Service
340  
341  ```yaml
342  # k8s/monitor.yml
343  apiVersion: v1
344  kind: Service
345  metadata:
346    name: monitor
347    namespace: echo-org
348  spec:
349    type: LoadBalancer
350    ports:
351    - port: 80
352      targetPort: 4000
353      protocol: TCP
354    selector:
355      app: monitor
356  ---
357  apiVersion: apps/v1
358  kind: Deployment
359  metadata:
360    name: monitor
361    namespace: echo-org
362  spec:
363    replicas: 2
364    selector:
365      matchLabels:
366        app: monitor
367    template:
368      metadata:
369        labels:
370          app: monitor
371      spec:
372        containers:
373        - name: monitor
374          image: ghcr.io/your-org/echo-monitor:latest
375          ports:
376          - containerPort: 4000
377          env:
378          - name: DB_HOST
379            value: postgres
380          - name: REDIS_HOST
381            value: redis
382          - name: SECRET_KEY_BASE
383            valueFrom:
384              secretKeyRef:
385                name: monitor-secret
386                key: secret_key_base
387          resources:
388            requests:
389              memory: "512Mi"
390              cpu: "250m"
391            limits:
392              memory: "1Gi"
393              cpu: "1000m"
394  ```
395  
396  ## Deployment Commands
397  
398  ### Docker Compose
399  
400  ```bash
401  # Quick start for local development
402  ./docker-setup.sh
403  
404  # Or manually:
405  cd docker
406  docker-compose up -d
407  
408  # Check status
409  docker-compose ps
410  
411  # View logs
412  docker-compose logs -f echo-ceo
413  
414  # Restart specific service
415  docker-compose restart echo-cto
416  
417  # Stop everything
418  docker-compose down
419  
420  # Clean up volumes
421  docker-compose down -v
422  ```
423  
424  ### Kubernetes
425  
426  ```bash
427  # Create namespace
428  kubectl apply -f k8s/namespace.yml
429  
430  # Create secrets
431  kubectl create secret generic postgres-secret \
432    --from-literal=username=postgres \
433    --from-literal=password=YOUR_PASSWORD \
434    -n echo-org
435  
436  # Deploy infrastructure
437  kubectl apply -f k8s/postgres.yml
438  kubectl apply -f k8s/redis.yml
439  
440  # Wait for infrastructure to be ready
441  kubectl wait --for=condition=ready pod -l app=postgres -n echo-org --timeout=300s
442  kubectl wait --for=condition=ready pod -l app=redis -n echo-org --timeout=300s
443  
444  # Deploy agents
445  kubectl apply -f k8s/agents/
446  
447  # Deploy monitor
448  kubectl apply -f k8s/monitor.yml
449  
450  # Check status
451  kubectl get pods -n echo-org
452  kubectl get services -n echo-org
453  
454  # View logs
455  kubectl logs -f deployment/echo-ceo -n echo-org
456  
457  # Access monitor dashboard
458  kubectl port-forward service/monitor 4000:80 -n echo-org
459  # Open http://localhost:4000
460  ```
461  
462  ## Building & Pushing Images
463  
464  ### Build Script
465  
466  ```bash
467  #!/bin/bash
468  set -euo pipefail
469  
470  REGISTRY="ghcr.io/your-org"
471  VERSION=$(cat VERSION)
472  
473  # Build all agent images
474  for agent in ceo cto chro operations_head product_manager senior_architect uiux_engineer senior_developer test_lead; do
475    echo "Building echo-$agent:$VERSION..."
476    docker build -t "$REGISTRY/echo-$agent:$VERSION" \
477      -t "$REGISTRY/echo-$agent:latest" \
478      -f "agents/$agent/Dockerfile" \
479      .
480  done
481  
482  # Build monitor image
483  echo "Building echo-monitor:$VERSION..."
484  docker build -t "$REGISTRY/echo-monitor:$VERSION" \
485    -t "$REGISTRY/echo-monitor:latest" \
486    -f "monitor/Dockerfile" \
487    .
488  
489  echo "Build complete!"
490  ```
491  
492  ### Push to Registry
493  
494  ```bash
495  # Login to GitHub Container Registry
496  echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
497  
498  # Push all images
499  for agent in ceo cto chro operations_head product_manager senior_architect uiux_engineer senior_developer test_lead; do
500    docker push "$REGISTRY/echo-$agent:$VERSION"
501    docker push "$REGISTRY/echo-$agent:latest"
502  done
503  
504  docker push "$REGISTRY/echo-monitor:$VERSION"
505  docker push "$REGISTRY/echo-monitor:latest"
506  ```
507  
508  ## Environment Configuration
509  
510  ### Development (.env.dev)
511  
512  ```bash
513  DB_HOST=localhost
514  DB_PORT=5432
515  DB_NAME=echo_org
516  DB_USER=postgres
517  DB_PASSWORD=postgres
518  
519  REDIS_HOST=localhost
520  REDIS_PORT=6379
521  
522  OLLAMA_ENDPOINT=http://localhost:11434
523  ```
524  
525  ### Production (.env.prod)
526  
527  ```bash
528  DB_HOST=postgres.production.internal
529  DB_PORT=5432
530  DB_NAME=echo_org
531  DB_USER=echo_prod
532  DB_PASSWORD=${DB_PASSWORD}  # From secret
533  
534  REDIS_HOST=redis.production.internal
535  REDIS_PORT=6379
536  
537  OLLAMA_ENDPOINT=http://ollama.production.internal:11434
538  ```
539  
540  ## Troubleshooting
541  
542  ### Container won't start
543  
544  **Debug:**
545  ```bash
546  # Check logs
547  docker logs echo-ceo
548  
549  # Interactive shell
550  docker exec -it echo-ceo /bin/sh
551  
552  # Check health
553  docker inspect echo-ceo | grep -A 10 Health
554  ```
555  
556  ### Database connection errors
557  
558  **Debug:**
559  ```bash
560  # Test from container
561  docker exec echo-ceo psql -h postgres -U postgres -d echo_org -c "SELECT 1"
562  
563  # Check network
564  docker network inspect docker_default
565  ```
566  
567  ### Redis connection errors
568  
569  **Debug:**
570  ```bash
571  # Test from container
572  docker exec echo-ceo redis-cli -h redis ping
573  
574  # Check Redis logs
575  docker logs redis
576  ```
577  
578  ### Image size too large
579  
580  **Optimize:**
581  - Use multi-stage builds
582  - Use alpine base images
583  - Clean up build artifacts
584  - Don't copy unnecessary files
585  
586  ## LocalCode for Docker Questions
587  
588  For quick Docker deployment queries, use **LocalCode** (see `../CLAUDE.md` Rule 8):
589  
590  ```bash
591  source ./scripts/llm/localcode_quick.sh
592  lc_start
593  lc_query "How do I build Docker images for ECHO agents?"
594  lc_query "Explain the docker-compose setup"
595  lc_end
596  ```
597  
598  ## Related Documentation
599  
600  - **Parent:** [../CLAUDE.md](../CLAUDE.md) - Project overview
601  - **Quick Start:** [../DOCKER_QUICKSTART.md](../DOCKER_QUICKSTART.md) - Docker setup guide
602  - **Scripts:** [../scripts/claude.md](../scripts/claude.md) - docker-setup.sh details
603  
604  ---
605  
606  **Remember:** Docker is for deployment. For local development, running agents directly is simpler and faster.