š MAOS Project Documentation
Complete guide to deploying applications on your dedicated Kubernetes cluster
ā” Quick Start (3 Steps)
Your infrastructure is ready! Deploy your first application in under 5 minutes:
1# 1. Clone your Helm repository (created in your GitHub org)2git clone https://github.com/<your-org>/<project-name>-helm.git3cd <project-name>-helm45# 2. Update image tag in values.yaml6# Change: tag: "bootstrap"7# To: tag: "v1.0.0" # Your actual image tag89# 3. Commit and push10git add values.yaml11git commit -m "Deploy v1.0.0"12git push origin main1314# ArgoCD will automatically deploy your application!
⨠What We've Provisioned for You
- EKS Cluster - Managed Kubernetes in your AWS account
- ECR Repository - Private Docker image registry
- Helm Chart - Ready-to-use deployment templates in your GitHub org
- NGINX Ingress - HTTP routing with automatic SSL
- ArgoCD - GitOps continuous deployment
- Prometheus - Metrics collection and monitoring
- AWS Secrets Manager - Secure credential storage
- Custom Domain - app.<project-name>.maosproject.io
ā ļø Required Endpoints
Your application must implement these two endpoints:
ā¤ļø /healthz
Purpose: Kubernetes health checks
Method: GET
Port: 8080
Response: 200 OK with JSON
/health, /api/health) - just update values.yaml to match.š /metrics
Purpose: Prometheus monitoring
Method: GET
Port: 8080
Format: Prometheus text format
ā¤ļø Health Check Implementation
Simple endpoint that returns 200 OK:
1// ā ļø REQUIRED: Health Check Endpoint2// You can use any path - just update values.yaml to match34// Go (Gin framework)5r.GET("/healthz", func(c *gin.Context) {6 c.JSON(200, gin.H{"status": "healthy"})7})89// Node.js (Express)10app.get('/healthz', (req, res) => {11 res.json({ status: 'healthy' });12});1314// Python (Flask)15@app.route('/healthz')16def health():17 return {'status': 'healthy'}1819// Java (Spring Boot)20@GetMapping("/healthz")21public Map<String, String> health() {22 return Map.of("status", "healthy");23}
š Metrics Endpoint Implementation
Expose metrics for Prometheus to scrape. Choose one example for your language:
Go (net/http)
1// Go (net/http)2import "github.com/prometheus/client_golang/prometheus/promhttp"34http.Handle("/metrics", promhttp.Handler())5http.ListenAndServe(":8080", nil)
Node.js (Express)
Install: npm install prom-client
1// Node.js (Express)2const client = require('prom-client');3client.collectDefaultMetrics();45app.get('/metrics', async (_req, res) => {6 res.set('Content-Type', client.register.contentType);7 res.end(await client.register.metrics());8});
Python (Flask)
Install: pip install prometheus-flask-exporter
1# Python (Flask)2from prometheus_flask_exporter import PrometheusMetrics34app = Flask(__name__)5metrics = PrometheusMetrics(app) # exposes /metrics
š” What you get automatically:
- CPU and memory usage metrics
- HTTP request counts and durations
- Error rates and response codes
- Garbage collection stats (language-specific)
Test locally: curl localhost:8080/metrics
āļø Configuration Guide
Your values.yaml controls your deployment. Here's what you need to know:
1# values.yaml - Configuration for your Kubernetes deployment2# Most settings have sensible defaults - only change what you need34# š§ REQUIRED: Update these for your app5image:6 repository: <account-id>.dkr.ecr.<region>.amazonaws.com/<project-name>7 tag: "bootstrap" # ā ļø Change this to your image tag to deploy (e.g., "v1.0.0")8 pullPolicy: Always910replicaCount: 1 # Number of pod replicas1112# š Environment Variables (Non-Sensitive)13configMap:14 env:15 db_ssl_mode: require16 base_url: http://localhost:8017 smtp_host: localhost18 smtp_port: "1025"19 # Add more env vars as needed20 # api_timeout: "30"21 # log_level: "info"2223# š Secrets Configuration24# ā ļø DO NOT EDIT - Secrets are managed via MAOS dashboard25secrets:26 existingSecret: "app-secrets" # Auto-created, stored in AWS Secrets Manager2728# š¦ Service Configuration29service:30 type: ClusterIP31 port: 8032 targetPort: 8080 # Your application container port33 annotations:34 prometheus.io/scrape: "true"35 prometheus.io/port: "80"36 prometheus.io/path: "/metrics" # ā ļø Your app MUST expose this endpoint3738# š Ingress (Domain & HTTPS)39ingress:40 enabled: true41 className: "nginx"42 annotations:43 kubernetes.io/ingress.class: nginx44 nginx.ingress.kubernetes.io/backend-protocol: HTTP45 nginx.ingress.kubernetes.io/force-ssl-redirect: "false"46 nginx.ingress.kubernetes.io/ssl-redirect: "false"47 nginx.ingress.kubernetes.io/proxy-body-size: 10m48 nginx.ingress.kubernetes.io/proxy-buffer-size: 4k49 # Uncomment for CORS (adjust in production)50 # nginx.ingress.kubernetes.io/enable-cors: "true"51 # nginx.ingress.kubernetes.io/cors-allow-origin: "*"52 hosts:53 - host: app.<project-name>.maosproject.io54 paths:55 - path: /56 pathType: Prefix5758# š¾ Resource Limits (Recommended)59resources:60 limits:61 cpu: 250m # Max CPU62 memory: 1Gi # Max Memory63 requests:64 cpu: 150m # Guaranteed CPU65 memory: 512Mi # Guaranteed Memory6667# ā¤ļø Health Checks68# ā ļø Your app MUST expose /healthz endpoint69livenessProbe:70 httpGet:71 path: /healthz72 port: 808073 initialDelaySeconds: 1574 periodSeconds: 1575 timeoutSeconds: 2076 failureThreshold: 57778readinessProbe:79 httpGet:80 path: /healthz81 port: 808082 initialDelaySeconds: 2083 periodSeconds: 1584 timeoutSeconds: 2085 failureThreshold: 58687# š Auto-Scaling (Optional)88autoscaling:89 enabled: false90 minReplicas: 191 maxReplicas: 392 targetCPUUtilizationPercentage: 809394# š Service Account (IRSA for AWS access)95# ā ļø DO NOT EDIT - Auto-configured for ECR access96serviceAccount:97 create: true98 automount: true99 annotations: {}100 name: ""101102# ā ļø DO NOT EDIT - Auto-configured103imagePullSecrets: [] # IRSA handles ECR authentication104nameOverride: ""105fullnameOverride: ""106podAnnotations: {}107podLabels: {}108podSecurityContext: {}109securityContext: {}110volumes: []111volumeMounts: []112nodeSelector: {}113tolerations: []114affinity: {}
š Key Sections Explained
1. Image Configuration
ā ļø Most Important Setting
Change the image.tag from "bootstrap" to your actual version (e.g., "v1.0.0") to deploy. Every commit to your Helm repo triggers a deployment.
repository- Your ECR repository URL (auto-populated)tag- Image version to deploy (change this to deploy new versions)pullPolicy: Always- Always pull latest image from ECR
2. Environment Variables
Two types of environment variables:
š ConfigMap (Non-Sensitive)
Edit freely in values.yaml
- Database URLs (no passwords)
- API endpoints
- SMTP settings
- Base URLs
š Secrets (Sensitive)
Managed via MAOS dashboard only
- API keys
- Database passwords
- OAuth tokens
- Private keys
3. Service & Prometheus Configuration
š Automatic Metrics Collection
Your service is pre-configured for Prometheus scraping:
annotations: prometheus.io/scrape: "true" # Enable automatic discovery prometheus.io/port: "80" # Service port prometheus.io/path: "/metrics" # Metrics endpoint path
Prometheus automatically discovers and scrapes your /metrics endpoint every 15 seconds.
4. Ingress & Domain
Your app is automatically available at:https://app.<project-name>.maosproject.io
š§ Important Annotations
proxy-body-size: 10m- Max request size (adjust for file uploads)force-ssl-redirect: "false"- HTTP allowed (change to "true" for HTTPS-only)- CORS is commented out - uncomment and configure for production
5. Resource Limits
Configure CPU and memory allocation for your pods:
- Requests - Guaranteed resources (Kubernetes reserves this)
- Limits - Maximum resources (pod gets killed if exceeded)
š” Best Practice
Start with defaults (150m CPU / 512Mi RAM). Monitor actual usage via your/metrics endpoint in Prometheus, then adjust based on real data.
š Secrets Management
Secrets are encrypted and stored in AWS Secrets Manager in your AWS account. They're automatically injected into your pods as environment variables.
ā ļø Do NOT Edit This Block in values.yaml
The secrets.existingSecret: "app-secrets" value is managed by MAOS. Add/update secrets via the dashboard only.
1# In your deployment.yaml template2# Secrets are automatically injected from AWS Secrets Manager34apiVersion: apps/v15kind: Deployment6spec:7 template:8 spec:9 containers:10 - name: {{ .Chart.Name }}11 image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"1213 # š Inject all secrets as environment variables14 envFrom:15 - secretRef:16 name: {{ .Values.secrets.existingSecret }} # References "app-secrets"1718 # š Inject ConfigMap (non-sensitive env vars)19 env:20 {{- range $key, $value := .Values.configMap.env }}21 - name: {{ $key | upper }}22 value: {{ $value | quote }}23 {{- end }}
How to add/update secrets:
- Go to MAOS dashboard ā Your Project ā Secrets
- Add key-value pairs (e.g.,
DATABASE_PASSWORD=mysecret) - Click "Save" - secrets are encrypted and stored in AWS Secrets Manager
- Restart your pods for changes to take effect
š Complete Deployment Workflow
1# š Deployment Workflow231. Build your Docker image with /healthz and /metrics endpoints42. Push image to ECR (your AWS account)5 āā docker push <account-id>.dkr.ecr.<region>.amazonaws.com/<project-name>:v1.0.063. Update Helm values.yaml with new image tag74. Commit and push to Helm repo85. ArgoCD automatically syncs and deploys to EKS96. Prometheus scrapes /metrics every 15s for monitoring1011šÆ Your app is live at: https://app.<project-name>.maosproject.io12š Metrics visible in: Prometheus dashboard (provided in your cluster)
š Common Tasks
Deploy New Version
- Build and push Docker image to ECR with new tag
- Update
image.taginvalues.yaml - Commit and push to Helm repository
- ArgoCD syncs automatically (or click "Sync" in ArgoCD UI)
Scale Application
Change replicaCount in values.yaml:
replicaCount: 3 # Run 3 pods instead of 1
Add Environment Variable
Add to configMap.env section:
configMap:
env:
new_variable: "value"
api_timeout: "30"Enable Auto-Scaling
autoscaling: enabled: true minReplicas: 2 maxReplicas: 10 targetCPUUtilizationPercentage: 70
š§ Troubleshooting
Pods not starting
ā Check image tag is correct and exists in ECR
ā
Verify /healthz endpoint returns 200 OK
ā Check resource limits aren't too low
ā
View logs: kubectl logs <pod-name>
Cannot access application via domain
ā
Check ingress is enabled in values.yaml
ā Wait 2-3 minutes for DNS propagation
ā Verify NGINX ingress controller is running
ā
Check ingress: kubectl get ingress
Secrets not available in pods
ā Verify secrets added via MAOS dashboard
ā
Don't edit secrets.existingSecret value
ā
Check secret exists: kubectl get secret app-secrets
ā Restart pods after updating secrets
Metrics not showing in Prometheus
ā
Verify /metrics endpoint returns data: curl <pod-ip>:8080/metrics
ā
Check service annotations are correct in values.yaml
ā Ensure app is listening on port 8080
ā Wait 15-30 seconds for Prometheus to scrape
High memory/CPU usage
ā Check Prometheus metrics dashboard for usage patterns
ā Increase resource limits if consistently hitting ceiling
ā Enable auto-scaling for traffic spikes
ā Profile your application for optimization
š¬ Need Help?
We're here to help! Reach out if you have questions or run into issues.
- š§ Email: support@maosproject.io
- š¬ Community: Join our Slack/Discord (link in dashboard)