Kubernetes Deployment¶
Helm Chart (Recommended)¶
Mycel provides an official Helm chart:
Quick Start¶
# Create ConfigMap from local HCL files
kubectl create configmap my-api-config --from-file=./config/
# Create Secret for credentials
kubectl create secret generic my-api-secrets \
--from-literal=PG_PASSWORD=secret \
--from-literal=API_TOKEN=sk-prod-token
# Install
helm install my-api oci://ghcr.io/matutetandil/charts/mycel \
--set existingConfigMap=my-api-config \
--set envFrom[0].secretRef.name=my-api-secrets
Key Values¶
| Value | Default | Description |
|---|---|---|
image.tag |
latest |
Mycel image tag |
existingConfigMap |
"" |
ConfigMap containing HCL files |
env |
{} |
Static environment variables |
envFrom |
[] |
Env from Secrets/ConfigMaps |
replicaCount |
1 |
Number of replicas |
resources.limits.memory |
256Mi |
Memory limit |
resources.requests.cpu |
100m |
CPU request |
autoscaling.enabled |
false |
Enable HPA |
ingress.enabled |
false |
Enable Ingress |
See helm/mycel/README.md for the complete values reference.
Manual Deployment¶
ConfigMap¶
apiVersion: v1
kind: ConfigMap
metadata:
name: my-api-config
data:
config.mycel: |
service {
name = "orders-api"
version = "1.0.0"
}
connectors.mycel: |
connector "api" {
type = "rest"
port = 3000
}
connector "db" {
type = "database"
driver = "postgres"
host = env("PG_HOST")
database = env("PG_DATABASE")
user = env("PG_USER")
password = env("PG_PASSWORD")
}
flows.mycel: |
flow "get_orders" {
from {
connector = "api"
operation = "GET /orders"
}
to {
connector = "db"
target = "orders"
}
}
Secret¶
apiVersion: v1
kind: Secret
metadata:
name: my-api-secrets
stringData:
PG_PASSWORD: "production-password"
JWT_SECRET: "jwt-secret-key"
STRIPE_KEY: "sk_live_..."
Deployment¶
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-api
spec:
replicas: 3
selector:
matchLabels:
app: my-api
template:
metadata:
labels:
app: my-api
spec:
containers:
- name: mycel
image: ghcr.io/matutetandil/mycel:v1.7.0
ports:
- containerPort: 3000
name: http
- containerPort: 9090
name: admin
env:
- name: MYCEL_ENV
value: production
- name: MYCEL_LOG_FORMAT
value: json
- name: PG_HOST
value: postgres.default.svc.cluster.local
- name: PG_DATABASE
value: myapp
- name: PG_USER
value: app
envFrom:
- secretRef:
name: my-api-secrets
volumeMounts:
- name: config
mountPath: /etc/mycel
livenessProbe:
httpGet:
path: /health/live
port: 3000
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /health/ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
volumes:
- name: config
configMap:
name: my-api-config
Service¶
apiVersion: v1
kind: Service
metadata:
name: my-api
spec:
selector:
app: my-api
ports:
- name: http
port: 80
targetPort: 3000
- name: admin
port: 9090
targetPort: 9090
HPA (Horizontal Pod Autoscaling)¶
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-api
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Health Probes¶
For services with a REST connector, use the REST port:
livenessProbe:
httpGet:
path: /health/live
port: 3000
readinessProbe:
httpGet:
path: /health/ready
port: 3000
For services without a REST connector (queue workers, CDC pipelines), use the admin port:
livenessProbe:
httpGet:
path: /health/live
port: 9090
readinessProbe:
httpGet:
path: /health/ready
port: 9090
Prometheus Scraping¶
Add annotations to scrape metrics:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/path: "/metrics"
prometheus.io/port: "3000"