Docs: Add backend deployment constraints and monorepo structure
- Documented Docker/Kubernetes deployment requirements - Added homelab configuration (resource limits, ports) - Configured reverse proxy compatibility - Designed monorepo structure (backend/mobile/web/shared)
This commit is contained in:
parent
1e38fe3ace
commit
1cf927f527
3 changed files with 1232 additions and 79 deletions
786
thoughts/research/2026-02-14-backend-deployment-constraints.md
Normal file
786
thoughts/research/2026-02-14-backend-deployment-constraints.md
Normal file
|
|
@ -0,0 +1,786 @@
|
|||
### /home/asoliver/desarrollo/normogen/thoughts/research/2026-02-14-backend-deployment-constraints.md
|
||||
```markdown
|
||||
1: # Backend Deployment Constraints
|
||||
2:
|
||||
3: ## Deployment Requirements
|
||||
4:
|
||||
5: ### Docker + Docker Compose
|
||||
6: - Backend must be containerized using Docker
|
||||
7: - Use Docker Compose for local development and homelab deployment
|
||||
8: - Multi-stage builds for optimal image size
|
||||
9: - Non-root user for security
|
||||
10:
|
||||
11: ### Kubernetes Compatibility
|
||||
12: - Design for future Kubernetes deployment
|
||||
13: - Use environment-based configuration (env vars)
|
||||
14: - Health check endpoints (`/health`, `/ready`)
|
||||
15: - Graceful shutdown handling
|
||||
16: - Stateless application design
|
||||
17: - ConfigMap and Secret ready
|
||||
18:
|
||||
19: ### One-Command Deployment
|
||||
20: ```bash
|
||||
21: # Clone repository
|
||||
22: git clone https://github.com/yourusername/normogen.git
|
||||
23: cd normogen
|
||||
24:
|
||||
25: # Setup configuration
|
||||
26: cp config/example.env config/.env
|
||||
27: # Edit config/.env with your settings
|
||||
28:
|
||||
29: # Build and run
|
||||
30: docker compose build
|
||||
31: docker compose up -d
|
||||
32: ```
|
||||
33:
|
||||
34: ## Homelab Deployment (Phase 1)
|
||||
35:
|
||||
36: ### Port Configuration
|
||||
37: - **MongoDB**: Standard ports
|
||||
38: - Primary: `27017` (default MongoDB port)
|
||||
39: - This allows connecting with existing MongoDB tools/admin UIs
|
||||
40:
|
||||
41: - **Backend API**: `6000` (homelab range)
|
||||
42: - External: `6000` (host port)
|
||||
43: - Internal: `8000` (container port)
|
||||
44: - Mapped in docker-compose.yml
|
||||
45:
|
||||
46: - **Future Services**: Port range `6000-6999`
|
||||
47: - `6000`: Backend API (current)
|
||||
48: - `6001`: Web UI (future)
|
||||
49: - `6002`: Admin dashboard (future)
|
||||
50: - `6003`: Metrics/monitoring (future)
|
||||
51:
|
||||
52: ### Network Configuration
|
||||
53: - Docker network: `normogen-network`
|
||||
54: - Must communicate with existing Docker services on homelab server
|
||||
55: - MongoDB accessible to host for backup/admin tools
|
||||
56:
|
||||
57: ### Environment Configuration
|
||||
58: ```bash
|
||||
59: # config/.env (gitignored)
|
||||
60: # Server Configuration
|
||||
61: RUST_LOG=info
|
||||
62: SERVER_HOST=0.0.0.0
|
||||
63: SERVER_PORT=8000
|
||||
64: ALLOWED_ORIGINS=http://localhost:3000,http://localhost:6001
|
||||
65:
|
||||
66: # Database Configuration
|
||||
67: MONGODB_URI=mongodb://mongodb:27017/normogen
|
||||
68: MONGODB_DATABASE=normogen
|
||||
69:
|
||||
70: # JWT Configuration
|
||||
71: JWT_SECRET=your-super-secret-jwt-key-here
|
||||
72: JWT_ACCESS_TOKEN_EXPIRY_MINUTES=15
|
||||
73: JWT_REFRESH_TOKEN_EXPIRY_DAYS=30
|
||||
74:
|
||||
75: # Encryption Configuration (for validation only)
|
||||
76: # Actual encryption happens client-side
|
||||
77: ENCRYPTION_ALGORITHM=aes-256-gcm
|
||||
78:
|
||||
79: # Rate Limiting
|
||||
80: RATE_LIMIT_REQUESTS=100
|
||||
81: RATE_LIMIT_DURATION_SECONDS=60
|
||||
82: ```
|
||||
83:
|
||||
84: ### Docker Compose Structure
|
||||
85: ```yaml
|
||||
86: # docker-compose.yml
|
||||
87: version: '3.8'
|
||||
88:
|
||||
89: services:
|
||||
90: backend:
|
||||
91: build:
|
||||
92: context: .
|
||||
93: dockerfile: docker/Dockerfile
|
||||
94: container_name: normogen-backend
|
||||
95: ports:
|
||||
96: - "6000:8000" # Homelab port range
|
||||
97: environment:
|
||||
98: - RUST_LOG=${RUST_LOG:-info}
|
||||
99: - SERVER_PORT=8000
|
||||
100: - MONGODB_URI=mongodb://mongodb:27017/normogen
|
||||
101: - MONGODB_DATABASE=${MONGODB_DATABASE:-normogen}
|
||||
102: - JWT_SECRET=${JWT_SECRET}
|
||||
103: - JWT_ACCESS_TOKEN_EXPIRY_MINUTES=${JWT_ACCESS_TOKEN_EXPIRY_MINUTES:-15}
|
||||
104: - JWT_REFRESH_TOKEN_EXPIRY_DAYS=${JWT_REFRESH_TOKEN_EXPIRY_DAYS:-30}
|
||||
105: env_file:
|
||||
106: - config/.env
|
||||
107: depends_on:
|
||||
108: mongodb:
|
||||
109: condition: service_healthy
|
||||
110: networks:
|
||||
111: - normogen-network
|
||||
112: restart: unless-stopped
|
||||
113: healthcheck:
|
||||
114: test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||
115: interval: 30s
|
||||
116: timeout: 10s
|
||||
117: retries: 3
|
||||
118: start_period: 40s
|
||||
119:
|
||||
120: mongodb:
|
||||
121: image: mongo:6.0
|
||||
122: container_name: normogen-mongodb
|
||||
123: ports:
|
||||
124: - "27017:27017" # Standard MongoDB port
|
||||
125: environment:
|
||||
126: - MONGO_INITDB_DATABASE=${MONGO_DATABASE:-normogen}
|
||||
127: volumes:
|
||||
128: - mongodb_data:/data/db
|
||||
129: - mongodb_config:/data/configdb
|
||||
130: networks:
|
||||
131: - normogen-network
|
||||
132: restart: unless-stopped
|
||||
133: healthcheck:
|
||||
134: test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
|
||||
135: interval: 10s
|
||||
136: timeout: 5s
|
||||
137: retries: 5
|
||||
138: start_period: 10s
|
||||
139:
|
||||
140: volumes:
|
||||
141: mongodb_data:
|
||||
142: driver: local
|
||||
143: mongodb_config:
|
||||
144: driver: local
|
||||
145:
|
||||
146: networks:
|
||||
147: normogen-network:
|
||||
148: driver: bridge
|
||||
149: ```
|
||||
150:
|
||||
151: ## Kubernetes Deployment (Phase 2 - Future)
|
||||
152:
|
||||
153: ### Manifests Structure
|
||||
154: ```
|
||||
155: k8s/
|
||||
156: ├── base/
|
||||
157: │ ├── deployment.yaml
|
||||
158: │ ├── service.yaml
|
||||
159: │ ├── configmap.yaml
|
||||
160: │ ├── secrets.yaml
|
||||
161: │ └── ingress.yaml
|
||||
162: └── overlays/
|
||||
163: ├── homelab/
|
||||
164: │ ├── kustomization.yaml
|
||||
165: │ └── patches/
|
||||
166: └── production/
|
||||
167: ├── kustomization.yaml
|
||||
168: └── patches/
|
||||
169: ```
|
||||
170:
|
||||
171: ### Deployment Configuration
|
||||
172: - **Replicas**: 2-3 for high availability
|
||||
173: - **Liveness Probe**: `/health` (10s interval, 5s timeout)
|
||||
174: - **Readiness Probe**: `/ready` (5s interval, 3s timeout)
|
||||
175: - **Resource Limits**:
|
||||
176: - CPU: 500m-1000m
|
||||
177: - Memory: 256Mi-512Mi
|
||||
178: - **Helm Chart**: Optional for easier deployment
|
||||
179:
|
||||
180: ### Configuration Management
|
||||
181: - **ConfigMap**: Non-sensitive config (log levels, ports)
|
||||
182: - **Secrets**: Sensitive config (JWT secret, DB URI)
|
||||
183: - **Environment Variables**: All configuration via env vars
|
||||
184:
|
||||
185: ## Dockerfile Design
|
||||
186:
|
||||
187: ### Multi-Stage Build
|
||||
188: ```dockerfile
|
||||
189: # docker/Dockerfile
|
||||
190:
|
||||
191: # Build stage
|
||||
192: FROM rust:1.75-alpine AS builder
|
||||
193: WORKDIR /app
|
||||
194:
|
||||
195: # Install build dependencies
|
||||
196: RUN apk add --no-cache musl-dev pkgconf openssl-dev
|
||||
197:
|
||||
198: # Copy manifests
|
||||
199: COPY Cargo.toml Cargo.lock ./
|
||||
200:
|
||||
201: # Create dummy main.rs to build dependencies
|
||||
202: RUN mkdir src && echo "fn main() {}" > src/main.rs
|
||||
203: RUN cargo build --release && rm -rf src
|
||||
204:
|
||||
205: # Copy source code
|
||||
206: COPY src ./src
|
||||
207:
|
||||
208: # Build application
|
||||
209: RUN touch src/main.rs && cargo build --release
|
||||
210:
|
||||
211: # Runtime stage
|
||||
212: FROM alpine:3.18
|
||||
213: WORKDIR /app
|
||||
214:
|
||||
215: # Install runtime dependencies
|
||||
216: RUN apk add --no-cache ca-certificates openssl
|
||||
217:
|
||||
218: # Copy binary from builder
|
||||
219: COPY --from=builder /app/target/release/normogen-backend /app/normogen-backend
|
||||
220:
|
||||
221: # Create non-root user
|
||||
222: RUN addgroup -g 1000 normogen && \
|
||||
223: adduser -D -u 1000 -G normogen normogen && \
|
||||
224: chown -R normogen:normogen /app
|
||||
225:
|
||||
226: USER normogen
|
||||
227:
|
||||
228: # Expose port
|
||||
229: EXPOSE 8000
|
||||
230:
|
||||
231: # Check
|
||||
232: HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||||
233: CMD wget --no-verbose --tries=1 --spider http://localhost:8000/health || exit 1
|
||||
234:
|
||||
235: # Run application
|
||||
236: CMD ["./normogen-backend"]
|
||||
237: ```
|
||||
238:
|
||||
239: ## Configuration Management
|
||||
240:
|
||||
241: ### Environment Variables
|
||||
242: All configuration via environment variables (12-factor app):
|
||||
243: - Database connections
|
||||
244: - JWT secrets
|
||||
245: - API credentials
|
||||
246: - Feature flags
|
||||
247: - Log levels
|
||||
248:
|
||||
249: ### Configuration Files
|
||||
250: ```
|
||||
251: config/
|
||||
252: ├── .env # Gitignored, local dev
|
||||
253: ├── .env.example # Git committed, template
|
||||
254: └── defaults.env # Git committed, defaults
|
||||
255: ```
|
||||
256:
|
||||
257: ### Configuration Validation
|
||||
258: - Validate required env vars on startup
|
||||
259: - Fail fast if misconfigured
|
||||
260: - Log configuration (sanitize secrets)
|
||||
261:
|
||||
262: ## Endpoints
|
||||
263:
|
||||
264: ### Check Endpoints
|
||||
265: ```rust
|
||||
266: // GET /health - Liveness probe
|
||||
267: // Returns: {"status": "ok"}
|
||||
268: // Used by: K8s liveness probe, Docker check
|
||||
269: // Purpose: Is the app running?
|
||||
270:
|
||||
271: // GET /ready - Readiness probe
|
||||
272: // Returns: {"status": "ready", "database": "connected"}
|
||||
273: // Used by: K8s readiness probe
|
||||
274: // Purpose: Is the app ready to serve traffic?
|
||||
275: ```
|
||||
276:
|
||||
277: ## Logging & Observability
|
||||
278:
|
||||
279: ### Structured Logging
|
||||
280: - JSON format for production
|
||||
281: - Log levels: ERROR, WARN, INFO, DEBUG, TRACE
|
||||
282: - Request ID tracing
|
||||
283: - Sensitive data sanitization
|
||||
284:
|
||||
285: ### Metrics (Future)
|
||||
286: - Prometheus endpoint: `/metrics`
|
||||
287: - Request rate, error rate, latency
|
||||
288: - Database connection pool status
|
||||
289:
|
||||
290: ## Security Considerations
|
||||
291:
|
||||
292: ### Container Security
|
||||
293: - Non-root user (UID 1000)
|
||||
294: - Read-only filesystem (except /tmp)
|
||||
295: - Minimal base image (Alpine)
|
||||
296: - No shell in runtime image
|
||||
297: - Security scanning (Trivy, Snyk)
|
||||
298:
|
||||
299: ### Secrets Management
|
||||
300: - Never commit secrets to git
|
||||
301: - Use environment variables
|
||||
302: - K8s: Use secrets, not configmaps
|
||||
303: - Docker: Use env_file or Docker secrets
|
||||
304: - Gitignore: `config/.env`
|
||||
305:
|
||||
306: ## Deployment Checklist
|
||||
307:
|
||||
308: ### Initial Setup
|
||||
309: - [ ] Clone repository
|
||||
310: - [ ] Copy `config/.env.example` to `config/.env`
|
||||
311: - [ ] Configure environment variables
|
||||
312: - [ ] Create Docker network: `docker network create normogen-network`
|
||||
313: - [ ] Generate JWT secret: `openssl rand -base64 32`
|
||||
314:
|
||||
315: ### Build & Run
|
||||
316: - [ ] Build: `docker compose build`
|
||||
317: - [ ] Run: `docker compose up -d`
|
||||
318: - [ ] Check logs: `docker compose logs -f backend`
|
||||
319: - [ ] Check status: `curl http://localhost:6000/health`
|
||||
320: - [ ] Check ready: `curl http://localhost:6000/ready`
|
||||
321:
|
||||
322: ### Verification
|
||||
323: - [ ] Backend responds on port 6000
|
||||
324: - [ ] MongoDB accessible on port 27017
|
||||
325: - [ ] Checks passing
|
||||
326: - [ ] Database connection working
|
||||
327: - [ ] JWT authentication working
|
||||
328:
|
||||
329: ## Questions for Clarification
|
||||
330:
|
||||
331: ### Environment
|
||||
332: 1. **Reverse Proxy**: Will you use a reverse proxy (Nginx, Traefik, Caddy)?
|
||||
333: - If yes, should TLS be handled at proxy or backend?
|
||||
334: - What domain/path for the API?
|
||||
335:
|
||||
336: 2. **MongoDB Deployment**:
|
||||
337: - Is MongoDB already running in your homelab?
|
||||
338: - Or should docker-compose spin up a dedicated MongoDB instance for Normogen?
|
||||
339: - If existing: What's the connection string?
|
||||
340:
|
||||
341: 3. **Resource Limits**:
|
||||
342: - Any CPU/memory constraints for the homelab?
|
||||
343: - Suggested limits: 500m CPU, 512Mi RAM?
|
||||
344:
|
||||
345: 4. **Backup Strategy**:
|
||||
346: - MongoDB backups? (Volume mount, scheduled dump)
|
||||
347: - Configuration backups?
|
||||
348:
|
||||
349: 5. **Monitoring**:
|
||||
350: - Log aggregation? (ELK, Loki, Splunk)
|
||||
351: - Metrics collection? (Prometheus, Grafana)
|
||||
352: - APM? (Datadog, New Relic)
|
||||
353:
|
||||
354: 6. **CI/CD**:
|
||||
355: - Will you use GitHub Actions, GitLab CI, or Jenkins?
|
||||
356: - Auto-deploy on commit to main branch?
|
||||
357: - Automated testing before deploy?
|
||||
358:
|
||||
359: ### Development Workflow
|
||||
360: 7. **Hot Reload**: Development mode with hot reload?
|
||||
361: - Use `cargo-watch` for auto-rebuild on file changes?
|
||||
362:
|
||||
363: 8. **Database Migrations**:
|
||||
364: - Run migrations on startup?
|
||||
365: - Separate migration tool?
|
||||
366:
|
||||
367: 9. **Seed Data**:
|
||||
368: - Seed development database with sample data?
|
||||
369:
|
||||
370: ### Production Readiness
|
||||
371: 10. **Rate Limiting**:
|
||||
372: - Per-IP rate limiting?
|
||||
373: - Per-user rate limiting (after auth)?
|
||||
374:
|
||||
375: 11. **CORS Configuration**:
|
||||
376: - Allowed origins for local dev?
|
||||
377: - Allowed origins for production?
|
||||
378:
|
||||
379: 12. **TLS/HTTPS**:
|
||||
380: - Local dev: HTTP or HTTPS?
|
||||
381: - Production: TLS termination at proxy?
|
||||
382:
|
||||
383: ## Next Steps
|
||||
384:
|
||||
385: Once the above questions are answered, we can proceed with:
|
||||
386:
|
||||
387: 1. **Phase 2.1**: Docker Compose Setup
|
||||
388: - Create Dockerfile (multi-stage build)
|
||||
389: - Create docker-compose.yml
|
||||
390: - Create configuration templates
|
||||
391: - Test local deployment
|
||||
392:
|
||||
393: 2. **Phase 2.2**: Axum Server Setup
|
||||
394: - Initialize Rust project
|
||||
395: - Setup Axum dependencies
|
||||
396: - Create check endpoints
|
||||
397: - Test containerized build
|
||||
398:
|
||||
399: 3. **Phase 2.3**: MongoDB Integration
|
||||
400: - MongoDB connection pooling
|
||||
401: - Readiness check with database
|
||||
402: - Test database connectivity
|
||||
403:
|
||||
404: 4. **Phase 2.4**: Configuration Management
|
||||
405: - Environment variable validation
|
||||
406: - Configuration struct
|
||||
407: - Secret loading
|
||||
408:
|
||||
409: 5. **Phase 2.5**: Deployment Testing
|
||||
410: - Test on homelab server
|
||||
411: - Verify checks
|
||||
412: - Verify database connection
|
||||
413: - Test restart behavior
|
||||
```
|
||||
|
||||
## Deployment Decisions (User Confirmed)
|
||||
|
||||
### 1. MongoDB Deployment
|
||||
✅ **New MongoDB instance in docker-compose**
|
||||
- MongoDB will be spun up as part of docker-compose.yml
|
||||
- Volume mounts for data persistence
|
||||
- Standard port 27017 for admin tool access
|
||||
|
||||
### 2. Reverse Proxy
|
||||
✅ **Using reverse proxy for TLS termination**
|
||||
- Backend handles HTTP only
|
||||
- TLS/HTTPS handled by reverse proxy (Nginx/Traefik/Caddy)
|
||||
- CORS configuration needed for allowed origins
|
||||
|
||||
### 3. Development Workflow
|
||||
✅ **Hot reload for local development**
|
||||
- Use `cargo-watch` for auto-rebuild on file changes
|
||||
- Separate docker-compose.dev.yml for development
|
||||
- Production build without hot reload
|
||||
|
||||
### 4. Resource Limits
|
||||
✅ **Homelab resource constraints**
|
||||
- CPU: 1000m (1 CPU core limit)
|
||||
- Memory: 1000Mi (1GB RAM limit)
|
||||
- Configure in docker-compose.yml
|
||||
- Configure in Kubernetes Deployment for future
|
||||
|
||||
### 5. Repository & CI/CD
|
||||
✅ **Forgejo repository**
|
||||
- Git hosting: Forgejo (self-hosted GitHub-compatible)
|
||||
- CI/CD: Forgejo Actions (GitHub Actions compatible)
|
||||
- Single repository for backend, mobile, web
|
||||
|
||||
## Updated Monorepo Structure
|
||||
|
||||
```
|
||||
normogen/ # Root repository
|
||||
├── backend/ # Rust backend
|
||||
│ ├── src/ # Source code
|
||||
│ │ ├── main.rs
|
||||
│ │ ├── auth/
|
||||
│ │ ├── api/
|
||||
│ │ ├── db/
|
||||
│ │ └── config/
|
||||
│ ├── docker/
|
||||
│ │ └── Dockerfile # Multi-stage build
|
||||
│ ├── Cargo.toml
|
||||
│ ├── Cargo.lock
|
||||
│ ├── docker-compose.yml # Homelab deployment
|
||||
│ ├── docker-compose.dev.yml # Development with hot reload
|
||||
│ ├── config/
|
||||
│ │ ├── .env.example
|
||||
│ │ └── defaults.env
|
||||
│ └── k8s/ # Future Kubernetes manifests
|
||||
│ ├── base/
|
||||
│ └── overlays/
|
||||
│
|
||||
├── mobile/ # React Native (iOS + Android)
|
||||
│ ├── src/ # Source code
|
||||
│ │ ├── components/
|
||||
│ │ ├── screens/
|
||||
│ │ ├── navigation/
|
||||
│ │ ├── store/
|
||||
│ │ ├── services/
|
||||
│ │ └── utils/
|
||||
│ ├── package.json
|
||||
│ ├── tsconfig.json
|
||||
│ ├── App.tsx
|
||||
│ └── android/
|
||||
│ └── ios/
|
||||
│
|
||||
├── web/ # React web app
|
||||
│ ├── src/ # Source code
|
||||
│ │ ├── components/
|
||||
│ │ ├── pages/
|
||||
│ │ ├── store/
|
||||
│ │ ├── services/
|
||||
│ │ └── utils/
|
||||
│ ├── package.json
|
||||
│ ├── tsconfig.json
|
||||
│ └── index.html
|
||||
│
|
||||
├── shared/ # Shared TypeScript code
|
||||
│ ├── src/
|
||||
│ │ ├── types/ # Shared types
|
||||
│ │ ├── validation/ # Zod schemas
|
||||
│ │ ├── encryption/ # Encryption utilities
|
||||
│ │ └── api/ # API client
|
||||
│ └── package.json
|
||||
│
|
||||
├── thoughts/ # Research & design docs
|
||||
│ └── research/
|
||||
│
|
||||
├── .gitignore # Root gitignore
|
||||
├── README.md # Root README
|
||||
└── docker-compose.root.yml # Optional: Run all services
|
||||
```
|
||||
|
||||
### Updated Docker Compose with Resource Limits
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml (production)
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
backend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile
|
||||
container_name: normogen-backend
|
||||
ports:
|
||||
- "6000:8000"
|
||||
environment:
|
||||
- RUST_LOG=${RUST_LOG:-info}
|
||||
- SERVER_PORT=8000
|
||||
- MONGODB_URI=mongodb://mongodb:27017/normogen
|
||||
- MONGODB_DATABASE=${MONGODB_DATABASE:-normogen}
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- JWT_ACCESS_TOKEN_EXPIRY_MINUTES=${JWT_ACCESS_TOKEN_EXPIRY_MINUTES:-15}
|
||||
- JWT_REFRESH_TOKEN_EXPIRY_DAYS=${JWT_REFRESH_TOKEN_EXPIRY_DAYS:-30}
|
||||
env_file:
|
||||
- config/.env
|
||||
depends_on:
|
||||
mongodb:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- normogen-network
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.0' # 1 CPU core
|
||||
memory: 1000M # 1GB RAM
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 256M
|
||||
check:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
mongodb:
|
||||
image: mongo:6.0
|
||||
container_name: normogen-mongodb
|
||||
ports:
|
||||
- "27017:27017"
|
||||
environment:
|
||||
- MONGO_INITDB_DATABASE=${MONGO_DATABASE:-normogen}
|
||||
volumes:
|
||||
- mongodb_data:/data/db
|
||||
- mongodb_config:/data/configdb
|
||||
networks:
|
||||
- normogen-network
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.5'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
check:
|
||||
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
|
||||
volumes:
|
||||
mongodb_data:
|
||||
driver: local
|
||||
mongodb_config:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
normogen-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Development Docker Compose (Hot Reload)
|
||||
|
||||
```yaml
|
||||
# docker-compose.dev.yml (development)
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
backend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile.dev
|
||||
container_name: normogen-backend-dev
|
||||
ports:
|
||||
- "6000:8000"
|
||||
volumes:
|
||||
- ./src:/app/src # Hot reload: Mount source code
|
||||
- ./Cargo.toml:/app/Cargo.toml
|
||||
environment:
|
||||
- RUST_LOG=debug
|
||||
- SERVER_PORT=8000
|
||||
- MONGODB_URI=mongodb://mongodb:27017/normogen
|
||||
- MONGODB_DATABASE=normogen_dev
|
||||
- JWT_SECRET=dev-secret-do-not-use-in-production
|
||||
- CARGO_WATCH=1 # Enable hot reload
|
||||
depends_on:
|
||||
mongodb:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- normogen-network
|
||||
restart: unless-stopped
|
||||
|
||||
mongodb:
|
||||
image: mongo:6.0
|
||||
container_name: normogen-mongodb-dev
|
||||
ports:
|
||||
- "27017:27017"
|
||||
environment:
|
||||
- MONGO_INITDB_DATABASE=normogen_dev
|
||||
volumes:
|
||||
- mongodb_dev_data:/data/db
|
||||
networks:
|
||||
- normogen-network
|
||||
check:
|
||||
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
mongodb_dev_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
normogen-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Development Dockerfile (with cargo-watch)
|
||||
|
||||
```dockerfile
|
||||
# docker/Dockerfile.dev
|
||||
|
||||
FROM rust:1.75-alpine
|
||||
WORKDIR /app
|
||||
|
||||
# Install runtime and build dependencies
|
||||
RUN apk add --no-cache \
|
||||
musl-dev \
|
||||
pkgconf \
|
||||
openssl-dev \
|
||||
curl \
|
||||
wget \
|
||||
git
|
||||
|
||||
# Install cargo-watch for hot reload
|
||||
RUN cargo install cargo-watch
|
||||
|
||||
# Copy manifests
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
|
||||
# Create dummy main.rs to build dependencies
|
||||
RUN mkdir src && echo "fn main() {}" > src/main.rs
|
||||
RUN cargo build && rm -rf src
|
||||
|
||||
# Copy source code (will be mounted as volume in dev)
|
||||
COPY src ./src
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8000
|
||||
|
||||
# Run with hot reload
|
||||
CMD ["cargo-watch", "-x", "run"]
|
||||
```
|
||||
|
||||
### Forgejo CI/CD (Example)
|
||||
|
||||
```yaml
|
||||
# .forgejo/workflows/backend-build.yml
|
||||
name: Build and Test Backend
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
- name: Cache cargo registry
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/registry
|
||||
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Build backend
|
||||
working-directory: ./backend
|
||||
run: cargo build --verbose
|
||||
|
||||
- name: Run tests
|
||||
working-directory: ./backend
|
||||
run: cargo test --verbose
|
||||
|
||||
- name: Build Docker image
|
||||
working-directory: ./backend
|
||||
run: docker build -f docker/Dockerfile -t normogen-backend:${{ github.sha }} .
|
||||
|
||||
deploy-homelab:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/main'
|
||||
steps:
|
||||
- name: Deploy to homelab
|
||||
run: |
|
||||
echo "Deploy to homelab server"
|
||||
# Add deployment script here
|
||||
```
|
||||
|
||||
### CORS Configuration (for Reverse Proxy)
|
||||
|
||||
```rust
|
||||
// src/config/cors.rs
|
||||
use tower_http::cors::{CorsLayer, Any};
|
||||
use axum::http::{HeaderValue, Method};
|
||||
|
||||
pub fn create_cors_layer(allowed_origins: &str) -> CorsLayer {
|
||||
let origins: Vec<&str> = allowed_origins.split(',').map(|s| s.trim()).collect();
|
||||
|
||||
CorsLayer::new()
|
||||
.allow_origin(origins.into_iter().map(|s| {
|
||||
s.parse::<HeaderValue>().unwrap()
|
||||
}).collect::<Vec<_>>())
|
||||
.allow_methods([Method::GET, Method::POST, Method::PUT, Method::PATCH, Method::DELETE, Method::OPTIONS])
|
||||
.allow_headers(Any)
|
||||
.allow_credentials(true)
|
||||
.max_age(3600)
|
||||
}
|
||||
```
|
||||
|
||||
## Updated Deployment Checklist
|
||||
|
||||
### Initial Setup
|
||||
- [ ] Clone repository from Forgejo
|
||||
- [ ] Copy `backend/config/.env.example` to `backend/config/.env`
|
||||
- [ ] Configure environment variables
|
||||
- [ ] Generate JWT secret: `openssl rand -base64 32`
|
||||
- [ ] Set resource limits in docker-compose.yml
|
||||
|
||||
### Development Setup
|
||||
- [ ] Run development: `docker compose -f docker-compose.dev.yml up -d`
|
||||
- [ ] Check logs: `docker compose -f docker-compose.dev.yml logs -f backend`
|
||||
- [ ] Test hot reload: Make changes to src/, verify auto-rebuild
|
||||
|
||||
### Production Deployment
|
||||
- [ ] Run production: `docker compose up -d`
|
||||
- [ ] Check logs: `docker compose logs -f backend`
|
||||
- [ ] Verify resource limits: `docker stats`
|
||||
- [ ] Configure reverse proxy (Nginx/Traefik/Caddy)
|
||||
- [ ] Configure reverse proxy CORS headers
|
||||
- [ ] Test API through reverse proxy
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue