American Cloud Deployment & CI/CD Guide¶
Golden Age Hub deploys its production workloads onto the secure, U.S.-sovereign American Cloud Kubernetes Service (ACKS). This document outlines our Kubernetes configuration, A2 Object Storage setups, and CI/CD pipelines, mapping the operational steps required to keep the production stack running.
Live Production Endpoints¶
- Main Caregiver Dashboard: https://dashboard.goldenage.americancloud.com/
- API Ingestion Gateway:
https://api.goldenage.americancloud.com/ - API Swagger Documentation:
https://api.goldenage.americancloud.com/docs
Architecture Overview¶
The deployment architecture consists of: 1. American Cloud Kubernetes Service (ACKS): Orchesrates our API Gateway, Celery Pipeline worker, and Policy service containers. 2. A2 Object Storage (S3-Compatible): HIPAA-compliant, encrypted-at-rest WORM archive for event verification records. 3. GitHub Actions CI/CD Pipeline: Automates building multi-architecture Docker images, provisioning A2 storage resources via Terraform, installing cluster-level ingress/cert-manager controllers, and executing rolling updates in Kubernetes.
Prerequisites¶
1. Cloud Infrastructure¶
Before starting the deployment, ensure the following resources are provisioned on American Cloud:
1. ACKS Cluster: Set up a Kubernetes cluster via the American Cloud CMP portal and download the cluster connection configuration (kube.conf).
2. Managed Database Instances:
- Managed PostgreSQL (with TimescaleDB extensions enabled).
- Managed Redis (for broker queue traffic).
3. Domain Name: A registered domain (e.g., goldenage.com) configured with a DNS A record pointing api.goldenage.yourdomain.com to the public IP of your Kubernetes Ingress LoadBalancer (which is automatically provisioned during the deployment step).
2. Local CLI Tools¶
For manual deployment, local configuration, and Terraform execution: - kubectl: Kubernetes command line tool. - helm: Kubernetes package manager. - Terraform: Required to provision A2 Storage resources.
Installing Terraform on Ubuntu/Debian (Official APT Repository)¶
# Install prerequisites
sudo apt-get update && sudo apt-get install -y gnupg software-properties-common curl
# Add the official HashiCorp GPG key
wget -O- https://apt.releases.hashicorp.com/gpg | \
gpg --dearmor | \
sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null
# Add the official HashiCorp repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/hashicorp.list
# Install Terraform
sudo apt-get update && sudo apt-get install -y terraform
# Verify installation
terraform -version
Alternatively, you can install Terraform via Snap:
Installing Helm on Ubuntu/Debian (Official APT Repository)¶
# Install prerequisites
sudo apt-get update && sudo apt-get install -y curl gpg apt-transport-https
# Add the official Helm GPG key
curl -fsSL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
# Add the official Helm repository
echo "deb [signed-by=/usr/share/keyrings/helm.gpg] https://packages.buildkite.com/helm-linux/helm-debian/any/ any main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
# Install Helm
sudo apt-get update && sudo apt-get install -y helm
# Verify installation
helm version
Alternatively, you can install Helm via Snap:
Database Setup: Kubernetes-based PostgreSQL with TimescaleDB¶
The Golden Age Hub ingestion pipeline relies on the TimescaleDB extension for high-performance storage and query capabilities of time-series event data (e.g., vitals and IMU readings).
Rather than hosting PostgreSQL on a dedicated standalone VM, PostgreSQL is deployed directly inside the ACKS Kubernetes cluster under the goldenage namespace as a StatefulSet with persistent volume storage.
1. StatefulSet Orchestration¶
The database resources are managed using postgres-statefulset.yaml, which:
- Spins up a single replica running timescale/timescaledb-ha:pg17.
- Automatically requests a 10Gi PersistentVolumeClaim for storage persistence at /var/lib/postgresql/data.
- Exposes a cluster-internal headless service (postgres-service) resolving to port 5432 for other pods in the namespace.
2. Automatic Database Initialization¶
When the StatefulSet spins up for the first time, it configures:
- The database name from ConfigMap (POSTGRES_DB).
- The application user (ga_prod_user).
- The connection password from Secret (POSTGRES_PASSWORD).
[!NOTE] Automated Schema Provisioning Once the database is ready, the API Gateway startup script (startup_gateway.sh) will automatically execute the Python script setup_timescale.py upon pod initialization.
This script automatically: 1. Converts the
eventstable to a time-partitioned hypertable. 2. Sets up ordering and index optimizations. 3. Enforces an at-rest compression policy (compressing events older than 7 days). 4. Enforces a WORM retention policy (dropping events only after 7 years for HIPAA auditing compliance).
1. Configure GitHub Repository Secrets¶
The GitHub Actions workflow requires access tokens and connection strings to authenticate with American Cloud and configure application runtimes.
Add the following Secrets to your GitHub repository (Settings -> Secrets and variables -> Actions):
| Secret Name | Description | Example / Target Value |
|---|---|---|
AMERICAN_CLOUD_KUBECONFIG |
The contents of the kube.conf file downloaded from ACKS. |
apiVersion: v1 ... |
AMERICAN_CLOUD_ACCESS_KEY |
Access Key ID for A2 Object Storage. | AKIAIOSFODNN7EXAMPLE |
AMERICAN_CLOUD_SECRET_KEY |
Secret Access Key for A2 Object Storage. | wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY |
PROD_POSTGRES_PASSWORD |
Password for the Managed PostgreSQL service. | secure-db-password |
PROD_REDIS_PASSWORD |
Password for the Managed Redis queue service. | secure-redis-password |
PROD_JWT_SECRET |
Secret key used for signing authentication JWTs. | your-jwt-signing-secret |
PROD_API_KEY |
Secret API key used for internal service-to-service validation. | your-internal-api-key |
PROD_POLICY_ADMIN_TOKEN |
Admin header token for policy service management. | your-policy-admin-token |
PROD_HEALTH_API_KEY |
Secret API key for verifying policy health check endpoints. | your-policy-health-key |
2. CI/CD Deployment Flow¶
Deployments are automated through the Deploy to American Cloud workflow.
Automated Trigger¶
The workflow triggers automatically whenever a new version release tag is pushed to the repository:
Manual Trigger¶
You can trigger a deployment manually at any time:
1. Go to the Actions tab in the GitHub repository.
2. Select the Deploy to American Cloud workflow from the left sidebar.
3. Click the Run workflow dropdown, choose the target branch, choose the environment (production or staging), and click Run workflow.
3. Manual Deployment (Optional / Local Dry-Run)¶
If you need to provision resources or deploy manifests manually from your local command-line interface, follow the steps below:
Step A: Provision A2 Storage with Terraform¶
Initialize and apply the Terraform configuration to create the S3-compatible compliance archive bucket:
cd infra/americancloud/terraform
terraform init
terraform apply \
-var="american_cloud_access_key=$AMERICAN_CLOUD_ACCESS_KEY" \
-var="american_cloud_secret_key=$AMERICAN_CLOUD_SECRET_KEY"
Step B: Configure Kubernetes Access¶
Ensure kubectl is pointing to the ACKS cluster by setting the KUBECONFIG environment variable:
Step C: Apply ConfigMaps & Secrets¶
Create the goldenage namespace and configure application configuration parameters and credentials:
cd ../k8s
# Create namespace
kubectl apply -f namespace.yaml
# Apply ConfigMaps
kubectl apply -f configmap.yaml
# Create Application Secret
export $(grep -v '^#' ../../.env.prod | xargs) && \
kubectl create secret generic app-secrets \
--namespace=goldenage \
--from-literal=POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \
--from-literal=REDIS_PASSWORD="$REDIS_PASSWORD" \
--from-literal=AMERICAN_CLOUD_A2_ACCESS_KEY="$AMERICAN_CLOUD_ACCESS_KEY" \
--from-literal=AMERICAN_CLOUD_A2_SECRET_KEY="$AMERICAN_CLOUD_SECRET_KEY" \
--from-literal=JWT_SECRET="$JWT_SECRET" \
--from-literal=API_KEY="$API_KEY" \
--from-literal=POLICY_ADMIN_TOKEN="$POLICY_ADMIN_TOKEN" \
--from-literal=HEALTH_API_KEY="$HEALTH_API_KEY"
export KUBECONFIG=../kube.conf
export $(grep -v '^#' ../../.env.prod | xargs) && \
kubectl create secret docker-registry registry-credentials \
--namespace=goldenage \
--docker-server=ghcr.io \
--docker-username="$GITHUB_USERNAME" \
--docker-password="$GITHUB_PAT"
Step D: Expose the Cluster (Helm Controllers)¶
Install the ingress controller and cert-manager:
# Ingress Controller
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx --namespace default --set controller.publishService.enabled=true
# Cert-Manager
helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.12.0 --set installCRDs=true
Push Images to github¶
# 1. API Gateway Service
docker build -t ghcr.io/milesgray/goldenage-hub/gateway:latest -f backend/Dockerfile.gateway backend/
docker push ghcr.io/milesgray/goldenage-hub/gateway:latest
# 2. Celery Pipeline Worker
docker build -t ghcr.io/milesgray/goldenage-hub/pipeline:latest -f backend/Dockerfile.pipeline backend/
docker push ghcr.io/milesgray/goldenage-hub/pipeline:latest
# 3. Policy Service
docker build -t ghcr.io/milesgray/goldenage-hub/policy:latest -f backend/Dockerfile.policy .
docker push ghcr.io/milesgray/goldenage-hub/policy:latest
Step E: Apply Services & Deployments¶
Deploy the microservice resources and network policies:
# Network Boundaries
kubectl apply -f networkpolicy.yaml
# PostgreSQL Database (StatefulSet)
kubectl apply -f postgres-statefulset.yaml
kubectl rollout status statefulset/postgres -n goldenage
# Policy Service
kubectl apply -f policy-service.yaml
kubectl apply -f policy-deployment.yaml
# API Gateway Service
kubectl apply -f gateway-service.yaml
kubectl apply -f gateway-deployment.yaml
# Celery Ingestion pipeline
kubectl apply -f pipeline-deployment.yaml
# Cluster SSL Issuer & Ingress Routing
kubectl apply -f letsencrypt-issuer.yaml
kubectl apply -f ingress.yaml
Step F: Verify Deployment Status¶
Verify that all pods have spun up successfully:
kubectl rollout status statefulset/postgres -n goldenage
kubectl rollout status deployment/policy -n goldenage
kubectl rollout status deployment/gateway -n goldenage
kubectl rollout status deployment/pipeline -n goldenage
4. Automatic Scaling & Kubernetes Best Practices (Celery)¶
The ingestion pipeline Celery workers are configured for production-grade reliability and autoscaling:
A. Celery Worker Autoscaling via KEDA¶
We use KEDA (Kubernetes Event-driven Autoscaling) to scale our Celery workers based on Redis queue depth rather than CPU/Memory. This avoids CPU idle-polling issues and ensures we scale out exactly when workload peaks.
Apply the KEDA configuration using:
B. Graceful Shutdown¶
To prevent dropping tasks mid-execution, we use late-acknowledgement (task_acks_late=True in Celery configuration). Kubernetes is configured with a high terminationGracePeriodSeconds: 90 to allow active tasks to finish processing before receiving SIGKILL.
C. Readiness Probes¶
Our readiness probe uses celery inspect ping -d worker@$(HOSTNAME) so that individual workers are only marked ready when they have established a healthy connection with the Redis broker.
5. Manually Triggering Deployments¶
In addition to auto-deploying when a new tag is pushed (e.g., v1.0.0), you can manually trigger a deployment run to production or staging from your local machine using the provided helper script:
# Deploy the current branch to production (default)
./scripts/trigger-deployment.sh
# Deploy the current branch to staging
./scripts/trigger-deployment.sh --environment staging
# Deploy a specific branch/ref to production
./scripts/trigger-deployment.sh --ref feature-branch
gh auth login).`
6. Hosting the Documentation Site on Coolify VM¶
The static Zensical documentation site is hosted on a dedicated Coolify Virtual Machine (IP 50.117.53.134) on American Cloud, accessible at https://docs.goldenage.americancloud.com/.
This isolates the static documentation from the core ACKS Kubernetes cluster, reducing cluster load while serving the documentation under automatic Let's Encrypt SSL/TLS.
Prerequisites & DNS Configuration¶
To route traffic to the documentation site:
1. Ensure you have configured an A Record pointing docs.goldenage.americancloud.com to the Coolify VM's public IP: 50.117.53.134.
2. The VM has ports 80, 443, 8000 (Coolify Console), and 22 (SSH) open to all traffic (0.0.0.0/0) via the American Cloud firewall rules.
Deploying the Documentation¶
There are two primary methods to deploy or update the documentation:
Method A: Automated Deployment Script (Recommended)¶
We provide a bash helper script scripts/deploy-docs.sh that pulls the compiled image from the GitHub Container Registry (GHCR) and runs it on the VM's coolify Docker network with Traefik reverse-proxy labels.
- Ensure the SSH key
~/.ssh/kube-key.pemis present locally. - Run the script:
The script will connect as root@50.117.53.134, stop any existing docs-site container, pull the latest image, and spin it up with the following Traefik labels:
* traefik.enable=true
* traefik.http.routers.docs-site.rule=Host("docs.goldenage.americancloud.com")
* traefik.http.routers.docs-site.entrypoints=https
* traefik.http.routers.docs-site.tls=true
* traefik.http.routers.docs-site.tls.certresolver=letsencrypt
Traefik (the built-in Coolify proxy) will automatically pick up the container, request a Let's Encrypt certificate, and route HTTPS traffic to the container's port 80.
Method B: Coolify Git Integration¶
Alternatively, you can configure Coolify to pull and build the repository automatically:
1. Log in to the Coolify Dashboard at http://50.117.53.134:8000.
2. Add a new Project and select Application -> Private Repository (authenticated via the repository token).
3. Set the Build Pack to Docker and configure the Dockerfile Path to Dockerfile.docs.
4. Under Domains, input https://docs.goldenage.americancloud.com.
5. Deploy the application. Coolify will build the Docker container and configure Traefik routing automatically.