Packaging a Gaia App¶
This page covers everything you need to go from working code to a deployable Cohesity Marketplace bundle: building Docker images, creating the app package, validating the AppSpec, and uploading to the DevPortal.
Prerequisites¶
- Docker installed and running locally
appspec.yamlandapp.jsonwritten for your appappspecvalidator_execbinary (available from the Cohesity DevPortal)
Step 1: Write Your Dockerfile¶
Marketplace apps are standard Docker containers. Use the base image and build approach that fits your app — no Cohesity-specific base image is required.
# Stage 1: Build the React frontend
FROM node:20-slim AS frontend-builder
WORKDIR /frontend
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
RUN npm run build
# Stage 2: Python backend + compiled React
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY main.py settings.py api/ ./
COPY --from=frontend-builder /frontend/dist ./static
COPY wrapper.sh ./
RUN chmod +x wrapper.sh
EXPOSE 8080
CMD ["./wrapper.sh"]
The wrapper.sh Crash-Recovery Loop¶
Include a wrapper.sh in every image to restart the server automatically on crash:
#!/bin/bash
set -e
while true; do
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] Starting server..."
uvicorn main:app --host 0.0.0.0 --port 8080 --workers 1
exit_code=$?
if [ $exit_code -eq 0 ]; then
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] Server exited cleanly."
break
fi
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] Crashed (exit $exit_code). Restarting in 5s..."
sleep 5
done
The outer Kubernetes pod restart policy provides the second layer of crash recovery.
Step 2: Build the Docker Image¶
# Build for the target architecture
docker build -t my-gaia-app:latest .
# Verify the image starts correctly
docker run --rm -p 8080:8080 \
-e GAIA_API_KEY="your-api-key" \
my-gaia-app:latest
Open http://localhost:8080 and confirm the app works before packaging.
Multi-Platform Builds¶
If your development machine uses Apple Silicon (ARM) but the cluster runs x86-64, build for the correct platform:
Step 3: Write appspec.yaml and app.json¶
See AppSpec Reference for the complete field reference.
Minimal app.json for a Gaia app:
{
"name": "My Gaia App",
"description": "Chat with your knowledge bases using Cohesity Gaia",
"version": "1.0.0",
"min_software_version": "7.2",
"unrestricted_app_ui_access": false
}
Set min_software_version to "7.2" for all Gaia applications — Gaia is only available on Cohesity 7.2+.
Step 4: Validate the AppSpec¶
Download appspecvalidator_exec from the DevPortal (or request it from your Cohesity contact), then run:
Common validation errors:
| Error | Fix |
|---|---|
unsupported kind: Deployment | Change kind: Deployment to kind: ReplicaSet |
replicas must be fixed or share | Replace replicas: 1 with replicas: {fixed: 1} |
cohesityTag must be 'ui' or 'cleanup' | Check the tag value in your ports block |
image not found in bundle | Ensure image name matches between appspec and Docker save |
Step 5: Create the App Bundle¶
The Marketplace expects a tar archive containing: 1. appspec.yaml 2. app.json 3. The Docker image saved as a .tar file
# Save the Docker image
docker save my-gaia-app:latest -o my-gaia-app.tar
# Create the bundle
tar -czf my-gaia-app-bundle.tar.gz \
appspec.yaml \
app.json \
my-gaia-app.tar
Bundle size
Docker images can be large. Use python:3.11-slim (not the full python:3.11 image) and avoid installing development tools to keep the image under 500 MB.
Minimizing Image Size¶
# Use slim base images
FROM python:3.11-slim # ~120MB vs ~900MB for full python:3.11
# Combine RUN commands to reduce layers
RUN pip install --no-cache-dir -r requirements.txt \
&& rm -rf /root/.cache
# Use .dockerignore to exclude unnecessary files
Example .dockerignore:
Step 6: Upload to DevPortal¶
- Log in to the Cohesity cluster UI.
- Navigate to Apps → Upload.
- Select your
my-gaia-app-bundle.tar.gzfile. - The platform validates and installs the app.
- Once installed, users can launch it from the Apps dashboard.
Updating an Existing App¶
To update a deployed app:
- Bump the
versioninapp.json(e.g.,"1.0.0"→"1.1.0"). - Rebuild the Docker image with the same tag.
- Re-create the bundle.
- Upload to DevPortal — it will detect the new version and perform a rolling update.
Directory Structure for a Packaged App¶
my-gaia-app/
├── appspec.yaml # Cohesity deployment manifest
├── app.json # App metadata
├── Dockerfile # Image build instructions
├── wrapper.sh # Crash-recovery restart loop
├── main.py # Application entrypoint
├── requirements.txt # Python dependencies
├── .env.example # Template for local development
└── frontend/ # React source (multi-stage builds only)
Next Steps¶
- Single-Container Pattern — React + FastAPI in one image
- MCP Server on the Marketplace — Example 06 walkthrough
- Testing & Submission — Pre-submission checklist