GitOps with ArgoCD for ChatGPT Apps: Continuous Deployment
Deploying ChatGPT apps to production requires robust continuous deployment pipelines that ensure reliability, traceability, and rapid rollback capabilities. GitOps with ArgoCD provides a declarative approach to Kubernetes deployments where Git repositories serve as the single source of truth for your infrastructure and application state.
In this comprehensive guide, you'll learn how to implement production-grade GitOps workflows for ChatGPT apps using ArgoCD. We'll cover application manifests, sync policies, multi-environment management, advanced features like ApplicationSets, and production best practices including secrets management and disaster recovery.
Whether you're deploying a single ChatGPT app or managing dozens of MCP servers across multiple clusters, ArgoCD's automated synchronization, health monitoring, and declarative configuration will transform your deployment workflow. By the end of this guide, you'll have a complete GitOps pipeline that automatically deploys changes from Git to Kubernetes with zero manual intervention.
Ready to automate your ChatGPT app deployments? Let's dive into ArgoCD architecture and start building production-ready GitOps workflows.
ArgoCD Architecture for ChatGPT Apps
ArgoCD is a declarative, GitOps continuous delivery tool for Kubernetes that automates the deployment of applications by synchronizing desired state (defined in Git) with actual state (running in Kubernetes clusters). Understanding ArgoCD's architecture is essential for designing robust deployment pipelines for ChatGPT apps.
Core Components
ArgoCD consists of three primary components that work together to enable GitOps workflows:
1. Application Controller: The brain of ArgoCD that continuously monitors Git repositories for changes and compares the desired state with the actual state in Kubernetes. When it detects drift (differences between desired and actual state), it triggers synchronization to bring the cluster back to the desired state. For ChatGPT apps, this means your MCP server deployments, services, and configurations are automatically updated whenever you push changes to Git.
2. Repo Server: A lightweight component that clones Git repositories, renders Kubernetes manifests (supporting Helm, Kustomize, Jsonnet, and plain YAML), and provides rendered manifests to the Application Controller. The Repo Server caches repository contents to improve performance and reduce Git API rate limits—critical when managing multiple ChatGPT app deployments.
3. API Server: Exposes ArgoCD's functionality via REST/gRPC APIs and serves the web UI. This component handles authentication, authorization (RBAC), and provides the interface for managing applications, viewing sync status, and triggering manual operations. For teams deploying ChatGPT apps, the API Server enables integration with CI/CD pipelines and custom automation workflows.
Sync Strategies for ChatGPT Apps
ArgoCD offers three synchronization strategies that determine how changes are applied to your ChatGPT app deployments:
Automatic Sync: ArgoCD automatically applies changes from Git to Kubernetes as soon as it detects drift. This is ideal for non-production environments where you want rapid iteration and testing of ChatGPT app updates. Enable with syncPolicy.automated.prune: true to automatically delete resources removed from Git.
Manual Sync: Requires explicit approval before applying changes. This provides a safety gate for production ChatGPT apps where you want to review changes, run tests, or coordinate deployments with business requirements. Manual sync is recommended for critical MCP servers serving production traffic.
Sync Waves: Control the order of resource deployment using annotations like argocd.argoproj.io/sync-wave: "1". This is essential for ChatGPT apps with dependencies—for example, deploying ConfigMaps and Secrets (wave 0) before Deployments (wave 1) before Services (wave 2). Sync waves prevent race conditions and ensure proper initialization order.
For production ChatGPT apps, we recommend a hybrid approach: automatic sync for development/staging environments with sync waves for orchestration, and manual sync with approval gates for production environments. This balances speed with safety.
Health Assessment for MCP Servers
ArgoCD continuously monitors the health of deployed resources using Kubernetes health checks and custom health assessment logic. For ChatGPT apps running MCP servers, ArgoCD can detect:
- Deployment health: Checks if desired replicas match available replicas, pods are running, and containers are ready
- Service health: Validates that Services have endpoints and are routing traffic correctly
- Custom resource health: For ChatGPT apps using custom CRDs (e.g., MCP server operators), you can define custom health checks using Lua scripts
- Degraded state detection: Identifies resources stuck in CrashLoopBackOff, ImagePullBackOff, or other error states
This comprehensive health monitoring ensures your ChatGPT apps remain available and performant. When ArgoCD detects unhealthy resources, it updates the application status in the UI and can trigger notifications via Slack, email, or webhooks.
Application Configuration for ChatGPT Apps
ArgoCD applications are defined using Kubernetes custom resources (Application CRD) that specify the Git repository, target cluster, sync policies, and health assessment rules. Here's a production-ready ArgoCD application manifest for deploying a ChatGPT MCP server:
# argocd-application.yaml - Complete ArgoCD Application for ChatGPT MCP Server
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: chatgpt-mcp-server
namespace: argocd
# Finalizer ensures proper cleanup when application is deleted
finalizers:
- resources-finalizer.argocd.argoproj.io
# Labels for organization and filtering
labels:
app.kubernetes.io/name: chatgpt-mcp-server
app.kubernetes.io/component: mcp-server
environment: production
team: platform
spec:
# Git repository containing Kubernetes manifests
source:
repoURL: https://github.com/your-org/chatgpt-apps-gitops
targetRevision: main
path: apps/mcp-server/overlays/production
# Kustomize configuration (alternative to Helm)
kustomize:
# Set common labels on all resources
commonLabels:
app.kubernetes.io/managed-by: argocd
app.kubernetes.io/instance: chatgpt-mcp-server
# Set common annotations
commonAnnotations:
managed-by: argocd
contact: platform-team@company.com
# Image tag override (can be set by CI/CD)
images:
- ghcr.io/your-org/chatgpt-mcp-server:v1.2.3
# Namespace override
namespace: chatgpt-production
# Build options
buildOptions: "--enable-alpha-plugins --load-restrictor=LoadRestrictionsNone"
# Destination cluster and namespace
destination:
server: https://kubernetes.default.svc
namespace: chatgpt-production
# Sync policy - controls how ArgoCD applies changes
syncPolicy:
# Automated sync - apply changes automatically
automated:
# Prune resources that are no longer defined in Git
prune: true
# Self-heal - automatically sync if cluster state drifts from Git
selfHeal: true
# Allow empty - permit sync with zero resources
allowEmpty: false
# Sync options for additional control
syncOptions:
# Create namespace if it doesn't exist
- CreateNamespace=true
# Validate resources against Kubernetes API
- Validate=true
# Use server-side apply (recommended for large resources)
- ServerSideApply=true
# Prune last - delete resources after creating new ones
- PruneLast=true
# Replace resources instead of applying patches
- Replace=false
# Respect ignore differences
- RespectIgnoreDifferences=true
# Retry policy for failed syncs
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
# Ignore differences in specific fields (prevents constant drift)
ignoreDifferences:
# Ignore replicas managed by HPA
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas
# Ignore mutating webhook modifications
- group: ""
kind: Secret
jsonPointers:
- /data
# Only ignore secrets with specific annotation
jqPathExpressions:
- .metadata.annotations."sealedsecrets.bitnami.com/managed"
# Health assessment configuration
revisionHistoryLimit: 10
# Info section - metadata displayed in ArgoCD UI
info:
- name: Environment
value: Production
- name: Team
value: Platform Engineering
- name: Documentation
value: https://docs.company.com/chatgpt-mcp-server
- name: Slack Channel
value: "#chatgpt-ops"
- name: PagerDuty
value: https://company.pagerduty.com/services/chatgpt-mcp
---
# AppProject - RBAC and resource restrictions for ChatGPT apps
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: chatgpt-apps
namespace: argocd
spec:
description: Project for all ChatGPT application deployments
# Source repositories allowed for this project
sourceRepos:
- https://github.com/your-org/chatgpt-apps-gitops
- https://ghcr.io/your-org/*
# Destination clusters and namespaces
destinations:
# Production cluster
- server: https://kubernetes.default.svc
namespace: chatgpt-production
# Staging cluster
- server: https://staging-cluster.company.com
namespace: chatgpt-staging
# Development cluster
- server: https://dev-cluster.company.com
namespace: 'chatgpt-*'
# Cluster resource whitelist (allowed resource types)
clusterResourceWhitelist:
- group: ''
kind: Namespace
- group: rbac.authorization.k8s.io
kind: ClusterRole
- group: rbac.authorization.k8s.io
kind: ClusterRoleBinding
# Namespace resource whitelist
namespaceResourceWhitelist:
- group: apps
kind: Deployment
- group: apps
kind: StatefulSet
- group: ''
kind: Service
- group: ''
kind: ConfigMap
- group: ''
kind: Secret
- group: networking.k8s.io
kind: Ingress
- group: autoscaling
kind: HorizontalPodAutoscaler
# Deny certain resource types (security)
namespaceResourceBlacklist:
- group: ''
kind: ResourceQuota
- group: ''
kind: LimitRange
# RBAC roles for this project
roles:
# Developers - read-only access
- name: developer
description: Read-only access to ChatGPT apps
policies:
- p, proj:chatgpt-apps:developer, applications, get, chatgpt-apps/*, allow
- p, proj:chatgpt-apps:developer, applications, list, chatgpt-apps/*, allow
groups:
- chatgpt-developers
# Operators - full sync/rollback access
- name: operator
description: Full operational access to ChatGPT apps
policies:
- p, proj:chatgpt-apps:operator, applications, *, chatgpt-apps/*, allow
- p, proj:chatgpt-apps:operator, applications, sync, chatgpt-apps/*, allow
- p, proj:chatgpt-apps:operator, applications, override, chatgpt-apps/*, allow
groups:
- chatgpt-operators
- sre-team
This comprehensive application manifest includes sync policies, health checks, RBAC controls, and metadata for effective ChatGPT app management. The AppProject provides multi-tenant isolation and security boundaries for different teams deploying ChatGPT apps.
Diff Customization for Sensitive Data
ChatGPT apps often contain sensitive configuration (API keys, model credentials) that shouldn't appear in ArgoCD diffs. Configure diff customization to prevent credential exposure:
# argocd-cm ConfigMap - Diff customization rules
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
# Ignore differences in Secret data fields
resource.customizations.ignoreDifferences.core_Secret: |
jsonPointers:
- /data
- /stringData
# Custom health check for MCP server Deployment
resource.customizations.health.apps_Deployment: |
hs = {}
if obj.status ~= nil then
if obj.status.conditions ~= nil then
for i, condition in ipairs(obj.status.conditions) do
if condition.type == "Progressing" and condition.reason == "ProgressDeadlineExceeded" then
hs.status = "Degraded"
hs.message = condition.message
return hs
end
if condition.type == "Available" and condition.status == "True" then
hs.status = "Healthy"
hs.message = "Deployment is available"
return hs
end
end
end
end
hs.status = "Progressing"
hs.message = "Waiting for deployment"
return hs
Learn more about monitoring ChatGPT apps in production and Kubernetes security best practices.
Multi-Environment Management with Kustomize
Managing ChatGPT apps across development, staging, and production environments requires a structured approach to configuration management. Kustomize provides a template-free way to customize Kubernetes manifests for different environments while maintaining a single base configuration.
Base Configuration for MCP Servers
The base directory contains common Kubernetes resources shared across all environments:
# apps/mcp-server/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# Common labels applied to all resources
commonLabels:
app.kubernetes.io/name: chatgpt-mcp-server
app.kubernetes.io/component: mcp-server
# Common annotations
commonAnnotations:
managed-by: argocd
# Base resources
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
- hpa.yaml
- ingress.yaml
# ConfigMap generator for environment-agnostic config
configMapGenerator:
- name: mcp-server-config
literals:
- LOG_LEVEL=info
- MCP_PROTOCOL_VERSION=2024-11-05
- HEALTH_CHECK_PATH=/health
- METRICS_PORT=9090
# Secret generator placeholder (override in overlays)
secretGenerator:
- name: mcp-server-secrets
literals:
- OPENAI_API_KEY=placeholder
# Image configuration
images:
- name: mcp-server
newName: ghcr.io/your-org/chatgpt-mcp-server
newTag: latest
---
# apps/mcp-server/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: chatgpt-mcp-server
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: chatgpt-mcp-server
template:
metadata:
labels:
app.kubernetes.io/name: chatgpt-mcp-server
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
spec:
serviceAccountName: chatgpt-mcp-server
# Security context
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: mcp-server
image: mcp-server
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 3000
protocol: TCP
- name: metrics
containerPort: 9090
protocol: TCP
env:
- name: NODE_ENV
value: production
- name: PORT
value: "3000"
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: mcp-server-secrets
key: OPENAI_API_KEY
envFrom:
- configMapRef:
name: mcp-server-config
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: http
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
# Container security context
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /app/.cache
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
# Topology spread for high availability
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/name: chatgpt-mcp-server
Production Overlay with Advanced Configuration
The production overlay customizes base resources with production-specific settings, resource limits, and replica counts:
# apps/mcp-server/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# Reference base configuration
bases:
- ../../base
# Production namespace
namespace: chatgpt-production
# Production-specific labels
commonLabels:
environment: production
team: platform
cost-center: engineering
# Production annotations
commonAnnotations:
managed-by: argocd
contact: platform-team@company.com
documentation: https://docs.company.com/chatgpt-mcp-server
# Replica count for production
replicas:
- name: chatgpt-mcp-server
count: 5
# Production image tag (updated by CI/CD)
images:
- name: mcp-server
newName: ghcr.io/your-org/chatgpt-mcp-server
newTag: v1.2.3
# ConfigMap overrides for production
configMapGenerator:
- name: mcp-server-config
behavior: merge
literals:
- LOG_LEVEL=warn
- REQUEST_TIMEOUT=30s
- MAX_CONNECTIONS=1000
- RATE_LIMIT_RPM=600
- CACHE_TTL=3600
- ENABLE_METRICS=true
- ENABLE_TRACING=true
- TRACING_SAMPLE_RATE=0.1
# Sealed Secrets for production credentials
secretGenerator:
- name: mcp-server-secrets
behavior: replace
files:
- OPENAI_API_KEY=secrets/openai-api-key.txt
- JWT_SECRET=secrets/jwt-secret.txt
- DATABASE_URL=secrets/database-url.txt
# Strategic merge patches
patchesStrategicMerge:
- deployment-patch.yaml
- hpa-patch.yaml
- ingress-patch.yaml
# JSON patches for fine-grained control
patchesJson6902:
# Add production-specific environment variables
- target:
group: apps
version: v1
kind: Deployment
name: chatgpt-mcp-server
patch: |-
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: DD_AGENT_HOST
valueFrom:
fieldRef:
fieldPath: status.hostIP
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: DD_SERVICE
value: chatgpt-mcp-server
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: DD_ENV
value: production
---
# apps/mcp-server/overlays/production/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: chatgpt-mcp-server
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
spec:
# Production-grade resource limits
containers:
- name: mcp-server
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi
# Production health checks with tighter thresholds
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: http
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
# Production affinity rules
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/name: chatgpt-mcp-server
topologyKey: kubernetes.io/hostname
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: node.kubernetes.io/instance-type
operator: In
values:
- c5.2xlarge
- c6i.2xlarge
---
# apps/mcp-server/overlays/production/hpa-patch.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: chatgpt-mcp-server
spec:
minReplicas: 5
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
# Custom metric from Prometheus
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "1000"
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 30
- type: Pods
value: 4
periodSeconds: 30
selectPolicy: Max
This Kustomize structure provides environment-specific configurations while maintaining DRY principles. Development and staging overlays follow the same pattern with adjusted replica counts, resource limits, and configuration values.
Explore more about ChatGPT app scaling strategies and configuration management patterns.
Advanced ArgoCD Features for ChatGPT Apps
Beyond basic application deployment, ArgoCD provides advanced features for managing complex ChatGPT app architectures, multi-cluster deployments, and sophisticated workflows.
App of Apps Pattern for Microservices
The "App of Apps" pattern enables hierarchical application management where a parent ArgoCD application manages child applications. This is ideal for ChatGPT platforms with multiple MCP servers, databases, and supporting services:
# apps/chatgpt-platform/app-of-apps.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: chatgpt-platform
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: chatgpt-apps
source:
repoURL: https://github.com/your-org/chatgpt-apps-gitops
targetRevision: main
path: apps/chatgpt-platform/applications
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# apps/chatgpt-platform/applications/mcp-server-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: mcp-server
namespace: argocd
spec:
project: chatgpt-apps
source:
repoURL: https://github.com/your-org/chatgpt-apps-gitops
targetRevision: main
path: apps/mcp-server/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: chatgpt-production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
# Sync wave - deploy after infrastructure
metadata:
annotations:
argocd.argoproj.io/sync-wave: "2"
---
# apps/chatgpt-platform/applications/database-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: postgres-db
namespace: argocd
spec:
project: chatgpt-apps
source:
repoURL: https://github.com/your-org/chatgpt-apps-gitops
targetRevision: main
path: infrastructure/postgres/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: chatgpt-production
syncPolicy:
automated:
prune: false # Never auto-delete database
selfHeal: true
# Sync wave - deploy before applications
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1"
---
# apps/chatgpt-platform/applications/redis-cache-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: redis-cache
namespace: argocd
spec:
project: chatgpt-apps
source:
repoURL: https://github.com/your-org/chatgpt-apps-gitops
targetRevision: main
path: infrastructure/redis/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: chatgpt-production
syncPolicy:
automated:
prune: true
selfHeal: true
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1"
ApplicationSets for Multi-Cluster Deployments
ApplicationSets automate the creation of ArgoCD applications across multiple clusters and environments. This is essential for ChatGPT apps deployed to multiple regions or customer-specific clusters:
# applicationsets/chatgpt-mcp-multi-cluster.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: chatgpt-mcp-multi-cluster
namespace: argocd
spec:
# Generator creates applications from cluster list
generators:
# List generator - define clusters explicitly
- list:
elements:
- cluster: production-us-east
url: https://prod-us-east.company.com
region: us-east-1
environment: production
replicas: "5"
resources: high
- cluster: production-eu-west
url: https://prod-eu-west.company.com
region: eu-west-1
environment: production
replicas: "5"
resources: high
- cluster: staging-us-east
url: https://staging-us-east.company.com
region: us-east-1
environment: staging
replicas: "2"
resources: medium
- cluster: development
url: https://dev-cluster.company.com
region: us-east-1
environment: development
replicas: "1"
resources: low
# Template for generated applications
template:
metadata:
name: 'chatgpt-mcp-{{cluster}}'
labels:
environment: '{{environment}}'
region: '{{region}}'
annotations:
managed-by: applicationset
cluster: '{{cluster}}'
spec:
project: chatgpt-apps
source:
repoURL: https://github.com/your-org/chatgpt-apps-gitops
targetRevision: main
path: 'apps/mcp-server/overlays/{{environment}}'
# Kustomize with cluster-specific overrides
kustomize:
commonLabels:
cluster: '{{cluster}}'
region: '{{region}}'
# Replica count per cluster
replicas:
- name: chatgpt-mcp-server
count: '{{replicas}}'
# Resource profile per cluster
patches:
- patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: chatgpt-mcp-server
spec:
template:
spec:
containers:
- name: mcp-server
resources:
{{#if (eq resources "high")}}
requests:
cpu: 1000m
memory: 2Gi
limits:
cpu: 4000m
memory: 8Gi
{{else if (eq resources "medium")}}
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi
{{else}}
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 1Gi
{{/if}}
destination:
server: '{{url}}'
namespace: chatgpt-{{environment}}
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
# Progressive sync - wait for health before continuing
syncPolicy:
syncOptions:
- RespectIgnoreDifferences=true
- ApplyOutOfSyncOnly=true
---
# applicationsets/chatgpt-tenant-generator.yaml
# ApplicationSet with Git File generator for per-tenant deployments
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: chatgpt-tenant-apps
namespace: argocd
spec:
generators:
# Git file generator - discover tenants from directory structure
- git:
repoURL: https://github.com/your-org/chatgpt-apps-gitops
revision: main
files:
- path: "tenants/*/config.json"
template:
metadata:
name: 'chatgpt-tenant-{{tenant.name}}'
labels:
tenant: '{{tenant.name}}'
tier: '{{tenant.tier}}'
spec:
project: chatgpt-tenants
source:
repoURL: https://github.com/your-org/chatgpt-apps-gitops
targetRevision: main
path: 'apps/mcp-server/overlays/tenant'
kustomize:
commonLabels:
tenant: '{{tenant.name}}'
# Tenant-specific namespace
namespace: 'chatgpt-tenant-{{tenant.name}}'
# Tenant-specific configuration
patches:
- patch: |-
apiVersion: v1
kind: ConfigMap
metadata:
name: tenant-config
data:
TENANT_ID: "{{tenant.id}}"
TENANT_NAME: "{{tenant.name}}"
API_RATE_LIMIT: "{{tenant.rateLimit}}"
MAX_CONNECTIONS: "{{tenant.maxConnections}}"
destination:
server: https://kubernetes.default.svc
namespace: 'chatgpt-tenant-{{tenant.name}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
ApplicationSets dramatically reduce operational overhead for multi-cluster and multi-tenant ChatGPT deployments, enabling centralized management with cluster-specific customization.
Notification Templates for Deployment Events
ArgoCD integrations with notification systems (Slack, email, PagerDuty) provide real-time alerts for sync status, health changes, and deployment events:
# argocd-notifications-cm.yaml - Notification configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
# Slack service configuration
service.slack: |
token: $slack-token
username: ArgoCD Bot
icon: ":rocket:"
# Email service configuration
service.email.gmail: |
username: $email-username
password: $email-password
host: smtp.gmail.com
port: 587
from: argocd@company.com
# Webhook service for custom integrations
service.webhook.chatgpt-ops: |
url: https://api.company.com/argocd-webhooks
headers:
- name: Authorization
value: Bearer $webhook-token
# Notification templates
template.app-deployed: |
message: |
ChatGPT app {{.app.metadata.name}} deployed successfully!
Environment: {{.app.metadata.labels.environment}}
Version: {{.app.status.sync.revision}}
Sync Status: {{.app.status.sync.status}}
Health Status: {{.app.status.health.status}}
slack:
attachments: |
[{
"title": "{{ .app.metadata.name}}",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#18be52",
"fields": [
{
"title": "Environment",
"value": "{{.app.metadata.labels.environment}}",
"short": true
},
{
"title": "Version",
"value": "{{.app.status.sync.revision}}",
"short": true
},
{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
},
{
"title": "Health",
"value": "{{.app.status.health.status}}",
"short": true
}
]
}]
template.app-health-degraded: |
message: |
⚠️ ChatGPT app {{.app.metadata.name}} health degraded!
Environment: {{.app.metadata.labels.environment}}
Health Status: {{.app.status.health.status}}
Health Message: {{.app.status.health.message}}
slack:
attachments: |
[{
"title": "🚨 {{ .app.metadata.name}} - Health Degraded",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#f4c030",
"fields": [
{
"title": "Environment",
"value": "{{.app.metadata.labels.environment}}",
"short": true
},
{
"title": "Health Status",
"value": "{{.app.status.health.status}}",
"short": true
},
{
"title": "Health Message",
"value": "{{.app.status.health.message}}",
"short": false
}
]
}]
template.app-sync-failed: |
message: |
❌ ChatGPT app {{.app.metadata.name}} sync failed!
Environment: {{.app.metadata.labels.environment}}
Sync Status: {{.app.status.sync.status}}
Error: {{.app.status.operationState.message}}
slack:
attachments: |
[{
"title": "❌ {{ .app.metadata.name}} - Sync Failed",
"title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
"color": "#E96D76",
"fields": [
{
"title": "Environment",
"value": "{{.app.metadata.labels.environment}}",
"short": true
},
{
"title": "Sync Status",
"value": "{{.app.status.sync.status}}",
"short": true
},
{
"title": "Error Message",
"value": "{{.app.status.operationState.message}}",
"short": false
}
]
}]
# Notification triggers
trigger.on-deployed: |
- when: app.status.operationState.phase in ['Succeeded']
send: [app-deployed]
trigger.on-health-degraded: |
- when: app.status.health.status == 'Degraded'
send: [app-health-degraded]
trigger.on-sync-failed: |
- when: app.status.operationState.phase in ['Error', 'Failed']
send: [app-sync-failed]
# Subscription annotations (add to applications)
subscriptions: |
# Production apps notify Slack + PagerDuty
- recipients:
- slack:chatgpt-ops
- webhook:chatgpt-ops
selector: environment=production
triggers:
- on-deployed
- on-health-degraded
- on-sync-failed
# Staging apps notify Slack only
- recipients:
- slack:chatgpt-staging
selector: environment=staging
triggers:
- on-deployed
- on-sync-failed
These notification templates provide real-time visibility into ChatGPT app deployments, enabling rapid response to issues and automated incident management workflows.
Learn more about ChatGPT app observability and incident response automation.
Production Best Practices for ChatGPT Apps
Deploying ChatGPT apps with ArgoCD requires adherence to production best practices covering secrets management, monitoring, backup, and disaster recovery.
Sealed Secrets for Credential Management
Never commit plain-text secrets to Git. Use Sealed Secrets to encrypt sensitive data before committing:
#!/bin/bash
# sealed-secrets-setup.sh - Install and configure Sealed Secrets controller
set -euo pipefail
# Install Sealed Secrets controller
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
# Wait for controller to be ready
kubectl wait --for=condition=ready pod -l name=sealed-secrets-controller -n kube-system --timeout=300s
# Install kubeseal CLI
KUBESEAL_VERSION='0.24.0'
wget "https://github.com/bitnami-labs/sealed-secrets/releases/download/v${KUBESEAL_VERSION}/kubeseal-${KUBESEAL_VERSION}-linux-amd64.tar.gz"
tar -xvzf "kubeseal-${KUBESEAL_VERSION}-linux-amd64.tar.gz" kubeseal
sudo install -m 755 kubeseal /usr/local/bin/kubeseal
# Create sealed secret from plain text
kubectl create secret generic mcp-server-secrets \
--from-literal=OPENAI_API_KEY="sk-..." \
--from-literal=JWT_SECRET="your-jwt-secret" \
--from-literal=DATABASE_URL="postgresql://..." \
--dry-run=client -o yaml | \
kubeseal --controller-name=sealed-secrets-controller \
--controller-namespace=kube-system \
--format yaml > sealed-secret.yaml
# Commit sealed secret to Git (safe - encrypted)
git add sealed-secret.yaml
git commit -m "feat: Add sealed secrets for MCP server"
git push origin main
echo "✅ Sealed Secrets setup complete"
echo "📝 Sealed secret created: sealed-secret.yaml"
echo "🔐 Original secrets are encrypted and safe to commit to Git"
Automated Rollback on Failure
Implement automated rollback policies to revert failed deployments and minimize downtime:
#!/bin/bash
# argocd-rollback-automation.sh - Automated rollback on sync failure
set -euo pipefail
APP_NAME="${1:-chatgpt-mcp-server}"
HEALTH_THRESHOLD=300 # 5 minutes
echo "🔍 Monitoring ArgoCD application: $APP_NAME"
# Function to get app sync status
get_sync_status() {
argocd app get "$APP_NAME" -o json | jq -r '.status.sync.status'
}
# Function to get app health status
get_health_status() {
argocd app get "$APP_NAME" -o json | jq -r '.status.health.status'
}
# Function to get current revision
get_current_revision() {
argocd app get "$APP_NAME" -o json | jq -r '.status.sync.revision'
}
# Function to get previous successful revision
get_previous_revision() {
argocd app get "$APP_NAME" -o json | \
jq -r '.status.history[] | select(.deployedAt != null) | .revision' | \
head -n 2 | tail -n 1
}
# Function to rollback to previous revision
rollback_app() {
local previous_revision=$1
echo "⚠️ Initiating rollback to revision: $previous_revision"
argocd app rollback "$APP_NAME" "$previous_revision" --prune
echo "✅ Rollback initiated"
# Notify Slack about rollback
curl -X POST https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK \
-H 'Content-Type: application/json' \
-d "{
\"text\": \"🔄 ArgoCD Rollback: $APP_NAME\",
\"attachments\": [{
\"color\": \"warning\",
\"fields\": [
{\"title\": \"Application\", \"value\": \"$APP_NAME\", \"short\": true},
{\"title\": \"Revision\", \"value\": \"$previous_revision\", \"short\": true},
{\"title\": \"Reason\", \"value\": \"Health check failed after deployment\", \"short\": false}
]
}]
}"
}
# Monitor sync operation
SYNC_STATUS=$(get_sync_status)
echo "📊 Current sync status: $SYNC_STATUS"
if [ "$SYNC_STATUS" == "Synced" ]; then
echo "✅ Application synced successfully"
# Monitor health for 5 minutes
echo "🏥 Monitoring health status for $HEALTH_THRESHOLD seconds..."
for i in $(seq 1 $((HEALTH_THRESHOLD / 10))); do
HEALTH_STATUS=$(get_health_status)
echo "[$i/30] Health status: $HEALTH_STATUS"
if [ "$HEALTH_STATUS" == "Degraded" ] || [ "$HEALTH_STATUS" == "Missing" ]; then
echo "❌ Health check failed: $HEALTH_STATUS"
PREVIOUS_REVISION=$(get_previous_revision)
if [ -n "$PREVIOUS_REVISION" ]; then
rollback_app "$PREVIOUS_REVISION"
exit 1
else
echo "⚠️ No previous revision found - cannot rollback"
exit 2
fi
fi
if [ "$HEALTH_STATUS" == "Healthy" ]; then
echo "✅ Application is healthy"
# Notify Slack about successful deployment
CURRENT_REVISION=$(get_current_revision)
curl -X POST https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK \
-H 'Content-Type: application/json' \
-d "{
\"text\": \"✅ ArgoCD Deployment Successful: $APP_NAME\",
\"attachments\": [{
\"color\": \"good\",
\"fields\": [
{\"title\": \"Application\", \"value\": \"$APP_NAME\", \"short\": true},
{\"title\": \"Revision\", \"value\": \"$CURRENT_REVISION\", \"short\": true}
]
}]
}"
exit 0
fi
sleep 10
done
echo "⚠️ Health check timeout - manual investigation required"
exit 3
elif [ "$SYNC_STATUS" == "OutOfSync" ]; then
echo "⚠️ Application out of sync - waiting for sync operation..."
sleep 30
exec "$0" "$APP_NAME"
else
echo "❌ Unexpected sync status: $SYNC_STATUS"
exit 4
fi
Disaster Recovery with Backup
Implement regular backups of ArgoCD configuration and application state:
#!/bin/bash
# argocd-backup.sh - Backup ArgoCD applications and configuration
set -euo pipefail
BACKUP_DIR="/backups/argocd/$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"
echo "📦 Starting ArgoCD backup to: $BACKUP_DIR"
# Backup all ArgoCD applications
echo "💾 Backing up applications..."
argocd app list -o json > "$BACKUP_DIR/applications.json"
# Backup each application manifest
argocd app list -o name | while read -r app; do
echo " - Backing up $app"
argocd app get "$app" -o yaml > "$BACKUP_DIR/app-${app}.yaml"
argocd app manifests "$app" > "$BACKUP_DIR/manifests-${app}.yaml"
done
# Backup ArgoCD projects
echo "💾 Backing up projects..."
kubectl get appproject -n argocd -o yaml > "$BACKUP_DIR/projects.yaml"
# Backup ArgoCD configuration
echo "💾 Backing up configuration..."
kubectl get configmap argocd-cm -n argocd -o yaml > "$BACKUP_DIR/argocd-cm.yaml"
kubectl get configmap argocd-rbac-cm -n argocd -o yaml > "$BACKUP_DIR/argocd-rbac-cm.yaml"
kubectl get configmap argocd-notifications-cm -n argocd -o yaml > "$BACKUP_DIR/argocd-notifications-cm.yaml"
# Backup ArgoCD secrets (encrypted)
echo "💾 Backing up secrets..."
kubectl get secret -n argocd -o yaml > "$BACKUP_DIR/secrets.yaml"
# Create tarball
echo "📦 Creating backup archive..."
tar -czf "$BACKUP_DIR.tar.gz" -C /backups/argocd "$(basename "$BACKUP_DIR")"
# Upload to S3 (or your backup storage)
echo "☁️ Uploading to S3..."
aws s3 cp "$BACKUP_DIR.tar.gz" "s3://company-backups/argocd/$(basename "$BACKUP_DIR").tar.gz"
# Cleanup local backup
rm -rf "$BACKUP_DIR"
# Retention policy - keep last 30 days
echo "🗑️ Cleaning up old backups..."
aws s3 ls s3://company-backups/argocd/ | \
awk '{print $4}' | \
sort -r | \
tail -n +31 | \
while read -r file; do
echo " - Deleting $file"
aws s3 rm "s3://company-backups/argocd/$file"
done
echo "✅ Backup complete: $BACKUP_DIR.tar.gz"
echo "📊 Backup size: $(du -h "$BACKUP_DIR.tar.gz" | cut -f1)"
Monitoring Dashboard with Prometheus
Monitor ArgoCD and ChatGPT app metrics with Prometheus and Grafana:
# prometheus-argocd-servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: argocd-metrics
namespace: argocd
spec:
selector:
matchLabels:
app.kubernetes.io/name: argocd-metrics
endpoints:
- port: metrics
interval: 30s
path: /metrics
---
# prometheus-argocd-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: argocd-alerts
namespace: argocd
spec:
groups:
- name: argocd
interval: 30s
rules:
# Alert when app is out of sync for > 5 minutes
- alert: ArgoCDAppOutOfSync
expr: argocd_app_info{sync_status="OutOfSync"} > 0
for: 5m
labels:
severity: warning
component: argocd
annotations:
summary: "ArgoCD app {{ $labels.name }} out of sync"
description: "Application {{ $labels.name }} has been out of sync for more than 5 minutes"
# Alert when app health is degraded
- alert: ArgoCDAppHealthDegraded
expr: argocd_app_info{health_status="Degraded"} > 0
for: 2m
labels:
severity: critical
component: argocd
annotations:
summary: "ArgoCD app {{ $labels.name }} health degraded"
description: "Application {{ $labels.name }} health is degraded"
# Alert when sync operation fails
- alert: ArgoCDSyncFailed
expr: increase(argocd_app_sync_total{phase="Failed"}[5m]) > 0
labels:
severity: warning
component: argocd
annotations:
summary: "ArgoCD sync failed for {{ $labels.name }}"
description: "Sync operation failed for application {{ $labels.name }}"
# Alert when app hasn't synced in 24 hours
- alert: ArgoCDAppNotSynced
expr: (time() - argocd_app_reconcile_timestamp) > 86400
labels:
severity: warning
component: argocd
annotations:
summary: "ArgoCD app {{ $labels.name }} not synced in 24h"
description: "Application {{ $labels.name }} hasn't reconciled in over 24 hours"
These production best practices ensure ChatGPT apps deployed via ArgoCD maintain high availability, security, and operational excellence.
Discover more about ChatGPT app reliability engineering and production readiness checklists.
Conclusion: Transform ChatGPT App Deployments with GitOps
GitOps with ArgoCD revolutionizes ChatGPT app deployments by providing declarative infrastructure, automated synchronization, and comprehensive health monitoring. By treating Git as the single source of truth, you eliminate configuration drift, enable rapid rollbacks, and create auditable deployment histories.
Key takeaways from this guide:
- ArgoCD architecture provides automated sync, health checks, and multi-cluster management for ChatGPT apps
- Kustomize overlays enable environment-specific configurations while maintaining DRY principles
- ApplicationSets automate multi-cluster and multi-tenant deployments with centralized management
- App of Apps pattern orchestrates complex microservices architectures with dependency management
- Production best practices including Sealed Secrets, automated rollback, and disaster recovery ensure operational excellence
With ArgoCD managing your ChatGPT app deployments, you achieve continuous delivery with zero manual intervention, comprehensive observability, and enterprise-grade reliability.
Ready to automate your ChatGPT app deployments? Start building with MakeAIHQ.com and deploy production-ready ChatGPT apps with built-in GitOps workflows, one-click deployment to the ChatGPT App Store, and comprehensive DevOps tooling—no manual Kubernetes configuration required.
Related Resources
- Kubernetes Deployment Strategies for ChatGPT Apps
- CI/CD Pipelines for ChatGPT App Development
- Monitoring ChatGPT Apps in Production
- Kubernetes Security Best Practices
- Multi-Cluster Kubernetes Management
- ChatGPT App Scaling Strategies
- Configuration Management Patterns
- Observability for ChatGPT Apps
- Incident Response Automation
- SRE for ChatGPT Apps
External Resources:
- ArgoCD Documentation - Official ArgoCD documentation and guides
- GitOps Principles - Introduction to GitOps methodology and best practices
- Kustomize Documentation - Kubernetes native configuration management