Installation¶
MANA is installed from the Kubernetes manifests in orchestrator/k8s/ or with the Terraform modules in terraform/. There is no Helm chart for MANA itself (Helm is used only to install the monitoring stack and, in scripts/deploy.sh, an optional Redis).
For a guided local walkthrough see the Quick Start.
What Gets Installed¶
| Resource | Namespace | Source |
|---|---|---|
Namespace orchestrator |
orchestrator/k8s/deployment.yaml |
|
Deployment orchestrator (2 replicas) and Service orchestrator-service (8000) |
orchestrator |
orchestrator/k8s/deployment.yaml |
ServiceAccount orchestrator-sa, ClusterRole orchestrator-role, ClusterRoleBinding orchestrator-binding |
cluster-wide | orchestrator/k8s/deployment.yaml |
Deployment redis (1 replica) and Service redis-service (6379) |
orchestrator |
orchestrator/k8s/redis.yaml |
Secret github-token |
orchestrator |
you create it |
Prerequisites¶
- A Kubernetes cluster, v1.23+, and
kubectlaccess with rights to create namespaces and cluster-scoped RBAC - Docker, to build the orchestrator image (or a registry that already hosts it)
- A GitHub token, if you want automatic retries (see Orchestrator Configuration)
Method 1: Manual Manifests¶
1. Get the orchestrator image into the cluster¶
The manifest uses image: orchestrator:latest with imagePullPolicy: IfNotPresent, so the image must exist on the nodes or be pullable under that name.
docker build -t orchestrator:latest orchestrator/
kind load docker-image orchestrator:latest --name <cluster-name>
docker build -t orchestrator:latest orchestrator/
minikube image load orchestrator:latest
docker build -t <registry>/orchestrator:<tag> orchestrator/
docker push <registry>/orchestrator:<tag>
# then edit orchestrator/k8s/deployment.yaml: image: <registry>/orchestrator:<tag>
The CI workflow also publishes ghcr.io/<owner>/<repo>/orchestrator:<version> and :latest on pushes. GHCR packages are private by default, so either make the package public or add an imagePullSecret to the ServiceAccount or pod spec.
2. Create namespaces and the GitHub secret¶
kubectl create namespace orchestrator
kubectl create secret generic github-token \
--from-literal=token="$GITHUB_TOKEN" \
-n orchestrator
The orchestrator Deployment reads GITHUB_TOKEN from this secret, so the pods will not start (CreateContainerConfigError) if it is missing. If you do not want retries, create the secret with any placeholder value; rollbacks do not need GitHub.
3. Set your repository¶
Edit orchestrator/k8s/deployment.yaml:
- name: GITHUB_REPO
value: "your-org/your-repo" # ships as othaime-en/mana
Review the other values in the same env: block (see Configuration).
4. Apply¶
kubectl apply -f orchestrator/k8s/redis.yaml
kubectl apply -f orchestrator/k8s/deployment.yaml
kubectl rollout status deployment/orchestrator -n orchestrator --timeout=180s
(kubectl apply -f orchestrator/k8s/ -n orchestrator applies both files in one go.) The readiness and liveness probes wait 60 seconds before the first check, so allow a minute or two.
5. Deploy your target application¶
For a first test deploy the bundled sample app:
docker build -t sample-app:1.0.0 sample-app/ # and load it as in step 1
kubectl create namespace production
kubectl apply -f sample-app/k8s/ -n production
Method 2: Terraform¶
cd terraform
terraform init
terraform plan -var="environment=local" -var="enable_staging=false"
terraform apply -var="environment=local" -var="enable_staging=false"
This creates all namespaces (production, staging, canary, orchestrator, monitoring), the sample app, the orchestrator with Redis, NetworkPolicies and quotas, and (unless enable_monitoring=false) Prometheus, Grafana and Loki. Terraform expects the images to be available to the cluster as well; set image_registry if they live in a registry.
Differences from the manual manifests:
- Terraform sets only
PORT,REDIS_HOST,REDIS_PORT,MAX_RETRIESandLOG_LEVELon the orchestrator. AddGITHUB_TOKENandGITHUB_REPOyourself to enable retries. - Do not mix
kubectl applyand Terraform on the same resources; pick one to avoid drift. - State is local by default. For teams, switch
backend.tfto the S3 and DynamoDB example it contains.
See the Configuration Reference for all variables.
Method 3: scripts/deploy.sh¶
Runs Terraform, builds and loads images, deploys Redis (via Helm), the orchestrator and the sample app, installs monitoring and runs smoke tests:
./scripts/deploy.sh --skip-monitoring
Read the notes in the CLI Reference first; the script assumes Terraform, Helm and a local cluster, and it creates a Redis the orchestrator does not use by default.
Using an External Redis¶
Point the orchestrator at your own Redis by changing REDIS_HOST and REDIS_PORT, and skip redis.yaml. The client has no password or TLS support yet, so use a network-isolated instance. The bundled Redis uses an emptyDir, so state is lost if its pod is rescheduled; that is acceptable for testing because deployment records expire after 24 hours anyway, but it also loses the last_successful:* rollback targets.
Post-Installation Checks¶
# Pods and services
kubectl -n orchestrator get pods,svc
# API health (Redis + Kubernetes + GitHub integration flag)
kubectl -n orchestrator port-forward svc/orchestrator-service 8000:8000 &
curl -s localhost:8000/health | jq
# Effective configuration
curl -s localhost:8000/config | jq
# RBAC: can the orchestrator patch Deployments in your app namespace?
kubectl auth can-i patch deployments -n production \
--as=system:serviceaccount:orchestrator:orchestrator-sa
Then:
- Make sure your applications follow the conventions.
- Set up CI/CD integration so the pipeline sends webhooks.
- Restrict who can reach the orchestrator (it has no authentication); see Security.
Upgrading¶
git pull
docker build -t orchestrator:latest orchestrator/ # load or push as above
kubectl apply -f orchestrator/k8s/
kubectl rollout restart deployment/orchestrator -n orchestrator
kubectl rollout status deployment/orchestrator -n orchestrator
Restart the pods after any configuration change; settings are read only at startup. Deployment records in Redis expire after 24 hours and are not affected by an upgrade, and last_successful:* keys persist as long as Redis does.
Uninstalling¶
kubectl delete -f orchestrator/k8s/redis.yaml
kubectl delete -f orchestrator/k8s/deployment.yaml
kubectl delete clusterrole orchestrator-role --ignore-not-found
kubectl delete clusterrolebinding orchestrator-binding --ignore-not-found
Delete redis.yaml first: deployment.yaml also defines the orchestrator namespace, so removing it deletes everything inside, including the github-token secret. It also removes the ServiceAccount, ClusterRole and ClusterRoleBinding it defines; the explicit clusterrole commands are a safety net. With Terraform, run terraform destroy (this removes all modules, including your sample apps and monitoring).
Troubleshooting Installation¶
| Symptom | Cause | Fix |
|---|---|---|
ImagePullBackOff / ErrImagePull |
orchestrator:latest is not on the nodes |
Load the image (Kind/Minikube) or push to a registry and edit the image name |
CreateContainerConfigError |
Secret github-token missing |
kubectl create secret generic github-token ... -n orchestrator |
CrashLoopBackOff, logs show Cannot connect to Redis |
Redis not running or wrong REDIS_HOST |
kubectl get pods -n orchestrator -l app=redis; host must be redis-service in-cluster |
CrashLoopBackOff, logs show a ValueError such as max_backoff must be > initial_backoff |
Invalid configuration | Fix the value (see validation errors) |
Pods Running but not Ready for about a minute |
Probes have a 60 s initial delay | Wait |
/health returns degraded |
Redis or the Kubernetes API unreachable | Check Redis pod, ServiceAccount and NetworkPolicies |
kubectl auth can-i returns no |
ClusterRole or binding not applied | Re-apply deployment.yaml |
Useful commands:
kubectl -n orchestrator logs -l app=orchestrator --tail=100
kubectl -n orchestrator describe pod -l app=orchestrator
kubectl -n orchestrator get events --sort-by=.metadata.creationTimestamp
More in the Troubleshooting Guide.