šŸ“š 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:

terminal
1# 1. Clone your Helm repository (created in your GitHub org)
2git clone https://github.com/<your-org>/<project-name>-helm.git
3cd <project-name>-helm
4
5# 2. Update image tag in values.yaml
6# Change: tag: "bootstrap"
7# To: tag: "v1.0.0" # Your actual image tag
8
9# 3. Commit and push
10git add values.yaml
11git commit -m "Deploy v1.0.0"
12git push origin main
13
14# 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

Critical: Without this, your pods won't start. You can use any path (e.g., /health, /api/health) - just update values.yaml to match.

šŸ“Š /metrics

Purpose: Prometheus monitoring
Method: GET
Port: 8080
Format: Prometheus text format

Important: Enables application performance monitoring

ā¤ļø Health Check Implementation

Simple endpoint that returns 200 OK:

health-check-examples
1// āš ļø REQUIRED: Health Check Endpoint
2// You can use any path - just update values.yaml to match
3
4// Go (Gin framework)
5r.GET("/healthz", func(c *gin.Context) {
6 c.JSON(200, gin.H{"status": "healthy"})
7})
8
9// Node.js (Express)
10app.get('/healthz', (req, res) => {
11 res.json({ status: 'healthy' });
12});
13
14// Python (Flask)
15@app.route('/healthz')
16def health():
17 return {'status': 'healthy'}
18
19// 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)

main.go
1// Go (net/http)
2import "github.com/prometheus/client_golang/prometheus/promhttp"
3
4http.Handle("/metrics", promhttp.Handler())
5http.ListenAndServe(":8080", nil)

Node.js (Express)

Install: npm install prom-client

server.js
1// Node.js (Express)
2const client = require('prom-client');
3client.collectDefaultMetrics();
4
5app.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

app.py
1# Python (Flask)
2from prometheus_flask_exporter import PrometheusMetrics
3
4app = 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:

values.yaml
1# values.yaml - Configuration for your Kubernetes deployment
2# Most settings have sensible defaults - only change what you need
3
4# šŸ”§ REQUIRED: Update these for your app
5image:
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: Always
9
10replicaCount: 1 # Number of pod replicas
11
12# šŸŒ Environment Variables (Non-Sensitive)
13configMap:
14 env:
15 db_ssl_mode: require
16 base_url: http://localhost:80
17 smtp_host: localhost
18 smtp_port: "1025"
19 # Add more env vars as needed
20 # api_timeout: "30"
21 # log_level: "info"
22
23# šŸ”’ Secrets Configuration
24# āš ļø DO NOT EDIT - Secrets are managed via MAOS dashboard
25secrets:
26 existingSecret: "app-secrets" # Auto-created, stored in AWS Secrets Manager
27
28# šŸ“¦ Service Configuration
29service:
30 type: ClusterIP
31 port: 80
32 targetPort: 8080 # Your application container port
33 annotations:
34 prometheus.io/scrape: "true"
35 prometheus.io/port: "80"
36 prometheus.io/path: "/metrics" # āš ļø Your app MUST expose this endpoint
37
38# 🌐 Ingress (Domain & HTTPS)
39ingress:
40 enabled: true
41 className: "nginx"
42 annotations:
43 kubernetes.io/ingress.class: nginx
44 nginx.ingress.kubernetes.io/backend-protocol: HTTP
45 nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
46 nginx.ingress.kubernetes.io/ssl-redirect: "false"
47 nginx.ingress.kubernetes.io/proxy-body-size: 10m
48 nginx.ingress.kubernetes.io/proxy-buffer-size: 4k
49 # 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.io
54 paths:
55 - path: /
56 pathType: Prefix
57
58# šŸ’¾ Resource Limits (Recommended)
59resources:
60 limits:
61 cpu: 250m # Max CPU
62 memory: 1Gi # Max Memory
63 requests:
64 cpu: 150m # Guaranteed CPU
65 memory: 512Mi # Guaranteed Memory
66
67# ā¤ļø Health Checks
68# āš ļø Your app MUST expose /healthz endpoint
69livenessProbe:
70 httpGet:
71 path: /healthz
72 port: 8080
73 initialDelaySeconds: 15
74 periodSeconds: 15
75 timeoutSeconds: 20
76 failureThreshold: 5
77
78readinessProbe:
79 httpGet:
80 path: /healthz
81 port: 8080
82 initialDelaySeconds: 20
83 periodSeconds: 15
84 timeoutSeconds: 20
85 failureThreshold: 5
86
87# šŸ“ˆ Auto-Scaling (Optional)
88autoscaling:
89 enabled: false
90 minReplicas: 1
91 maxReplicas: 3
92 targetCPUUtilizationPercentage: 80
93
94# šŸ” Service Account (IRSA for AWS access)
95# āš ļø DO NOT EDIT - Auto-configured for ECR access
96serviceAccount:
97 create: true
98 automount: true
99 annotations: {}
100 name: ""
101
102# āš ļø DO NOT EDIT - Auto-configured
103imagePullSecrets: [] # IRSA handles ECR authentication
104nameOverride: ""
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.

deployment.yaml
1# In your deployment.yaml template
2# Secrets are automatically injected from AWS Secrets Manager
3
4apiVersion: apps/v1
5kind: Deployment
6spec:
7 template:
8 spec:
9 containers:
10 - name: {{ .Chart.Name }}
11 image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
12
13 # šŸ”’ Inject all secrets as environment variables
14 envFrom:
15 - secretRef:
16 name: {{ .Values.secrets.existingSecret }} # References "app-secrets"
17
18 # šŸŒ 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:

  1. Go to MAOS dashboard → Your Project → Secrets
  2. Add key-value pairs (e.g., DATABASE_PASSWORD=mysecret)
  3. Click "Save" - secrets are encrypted and stored in AWS Secrets Manager
  4. Restart your pods for changes to take effect

šŸš€ Complete Deployment Workflow

deployment-steps
1# šŸš€ Deployment Workflow
2
31. Build your Docker image with /healthz and /metrics endpoints
42. Push image to ECR (your AWS account)
5 └─ docker push <account-id>.dkr.ecr.<region>.amazonaws.com/<project-name>:v1.0.0
63. Update Helm values.yaml with new image tag
74. Commit and push to Helm repo
85. ArgoCD automatically syncs and deploys to EKS
96. Prometheus scrapes /metrics every 15s for monitoring
10
11šŸŽÆ Your app is live at: https://app.<project-name>.maosproject.io
12šŸ“Š Metrics visible in: Prometheus dashboard (provided in your cluster)

šŸ“‹ Common Tasks

Deploy New Version

  1. Build and push Docker image to ECR with new tag
  2. Update image.tag in values.yaml
  3. Commit and push to Helm repository
  4. 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.