This directory contains deployment configurations for PlayMeme application on GCP using Kubernetes and Helm.
Note: All configuration in this README is for GKE Autopilot clusters. The deployment script automates the deployment process.
deployment/
├── helm/
│ └── playmeme/ # Helm chart
│ ├── Chart.yaml
│ ├── values.yaml
│ └── templates/ # Kubernetes manifests
├── deploy.ps1 # Automated deployment script
├── GCP_SECRETS_SETUP.md # Secret Manager setup guide
├── ARTIFACT_REGISTRY_SETUP.md # Artifact Registry setup guide
└── README.md
- Google Cloud SDK (gcloud) installed
- kubectl installed
- Helm 3.x installed
- Docker installed (for building images)
- GKE Autopilot cluster created (Secret Store CSI Driver is pre-installed)
IMPORTANT: Secrets are stored in Google Cloud Secret Manager, not in Helm charts.
See GCP_SECRETS_SETUP.md for setup instructions.
The deployment process is automated using the deploy.ps1 script. The script automates steps starting from Step 5: Build Docker Images Locally in ARTIFACT_REGISTRY_SETUP.md through the complete Helm deployment.
What the script does:
- Builds Docker images for backend and frontend
- Pushes images to Artifact Registry
- Verifies GCP secrets are set up (with warning if missing)
- Connects to your GKE Autopilot cluster
- Updates Helm values.yaml with correct image paths and project ID
- Deploys/upgrades the Helm chart
- Waits for pods to be ready and shows deployment status
Before running the deployment script, you must manually complete:
-
Artifact Registry Setup: Create repository and configure authentication
- See ARTIFACT_REGISTRY_SETUP.md for Steps 1-4
-
GCP Secrets Setup: Create secrets in Secret Manager
- See GCP_SECRETS_SETUP.md for complete instructions
- Required secrets:
playmeme-postgres-password(PostgreSQL password)playmeme-admin-wallets(Comma-separated admin wallet addresses)
-
GKE Cluster: Create and prepare your Autopilot cluster
- See Creating and Preparing GKE Cluster below
cd deployment
.\deploy.ps1 -ProjectId "your-project-id" `
-Region "us-central1" `
-ClusterName "playmeme-cluster" `
-ImageTag "latest"Parameters:
-ProjectId(required): Your GCP project ID-Region(required): Artifact Registry region (e.g.,us-central1)-ClusterName(required): Your GKE cluster name-ClusterZone(optional): Cluster zone if using zonal cluster (leave empty for regional)-ImageTag(optional): Docker image tag (default:latest)-RepositoryName(optional): Artifact Registry repository name (default:playmeme-repo)
Example with zone:
.\deploy.ps1 -ProjectId "my-project" `
-Region "us-central1" `
-ClusterName "playmeme-cluster" `
-ClusterZone "us-central1-a" `
-ImageTag "v1.0.0"-
Navigate to GKE:
- Go to Google Cloud Console
- Select your project
- Navigate to Kubernetes Engine > Clusters
-
Create Cluster:
- Click "CREATE" or "CREATE CLUSTER"
- Choose "Autopilot"
-
Configure Cluster Basics:
- Name: Enter a cluster name (e.g.,
playmeme-cluster-autopilot) - Location type: Choose "Regional" (recommended) or "Zonal"
- For Regional: Select a region (e.g.,
us-central1) - For Zonal: Select a zone (e.g.,
us-central1-a)
- For Regional: Select a region (e.g.,
- Kubernetes version: Use the latest stable version (Autopilot manages this)
- Name: Enter a cluster name (e.g.,
-
Autopilot Configuration:
- Workload Identity: Enabled by default (no action needed)
- Networking: Use default VPC or select custom VPC
- Release channel: Choose "Regular" (recommended) or "Rapid"
-
Review and Create:
- Review all settings
- Click "CREATE" (Autopilot cluster creation takes 5-10 minutes)
- Note: Autopilot manages nodes automatically - no node pool configuration needed
Before deploying, ensure the following APIs are enabled:
# Enable Kubernetes Engine API
gcloud services enable container.googleapis.com
# Enable Secret Manager API (for secrets)
gcloud services enable secretmanager.googleapis.com
# Enable Compute Engine API (required for GKE)
gcloud services enable compute.googleapis.comOr enable via UI:
- Go to APIs & Services > Library
- Search and enable:
- Kubernetes Engine API
- Secret Manager API
- Compute Engine API
Even though GKE Autopilot has the Secret Store CSI Driver pre-installed, the CRD (Custom Resource Definition) may need to be installed separately. Install it using Helm:
# Add the secrets-store-csi-driver Helm repository
helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
# Update Helm repositories
helm repo update
# Install the Secret Store CSI Driver (this installs the CRD)
helm install csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver \
--namespace kube-system \
--set syncSecret.enabled=trueAlternative: If Helm installation doesn't work, install the CRD directly:
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/secrets-store-csi-driver/main/deploy/crds/secrets-store.csi.x-k8s.io_secretproviderclasses.yamlFor Autopilot Clusters:
- Workload Identity: Enabled by default (no action needed)
- Secret Store CSI Driver: Pre-installed, but CRD may need manual installation (see Step 3 above)
- Artifact Registry Access: Automatically configured (no action needed)
- The deployment script handles cluster connection and verification
Note: See GCP_SECRETS_SETUP.md for IAM setup required for Secret Manager access.
If you're using a GKE Autopilot cluster, be aware of the following:
IMPORTANT: Autopilot requires resource requests and limits to be specified for all containers. The Helm chart includes these in values.yaml:
- Backend: 100m CPU / 128Mi memory (requests), 200m CPU / 256Mi memory (limits)
- Frontend: 100m CPU / 128Mi memory (requests), 200m CPU / 256Mi memory (limits)
- PostgreSQL: 400m CPU / 256Mi memory (requests), 1000m CPU / 512Mi memory (limits)
Do not remove or set these to empty - Autopilot will reject pods without resource specifications.
- Automatic scaling: Nodes scale up/down based on workload
- Cost optimization: Pay only for requested resources
- Security: Enhanced security by default
- Maintenance: Automatic node upgrades and patching
Before deploying, ensure your Helm chart templates comply with Autopilot requirements:
# Check if resources are defined (should show resources for all containers)
helm template ./playmeme | Select-String -Pattern "resources:" -Context 0,10If you prefer to deploy manually, follow the steps in ARTIFACT_REGISTRY_SETUP.md starting from Step 5, then:
- Update
deployment/helm/playmeme/values.yamlwith correct image paths and project ID - Connect to cluster:
gcloud container clusters get-credentials CLUSTER_NAME --region=REGION --project=PROJECT_ID - Deploy:
cd deployment/helm && helm install playmeme ./playmeme(orhelm upgradefor updates)
Note: The automated script is recommended as it handles all these steps automatically.
- Secrets: Loaded from Google Cloud Secret Manager
DB_PASSWORD- PostgreSQL password (fromplaymeme-postgres-passwordsecret)ADMIN_WALLETS- Comma-separated admin wallet addresses (fromplaymeme-admin-walletssecret)- See GCP_SECRETS_SETUP.md for setup instructions
- Non-secrets: Configured in
values.yamlunderbackend.envandfrontend.env - Frontend: Uses Vite, which requires
VITE_prefix for environment variables exposed to the browser
Important: The ADMIN_WALLETS secret must be created in GCP Secret Manager before deployment. Without it, admin panel access will not work.
PostgreSQL is deployed as part of the Helm chart with persistent storage.
Data Persistence:
- PostgreSQL data is stored in a PersistentVolumeClaim (PVC)
- Data persists across deployments - only the PostgreSQL pod restarts, not the volume
- PVC name:
playmeme-postgres-pvc(15Gi storage, configurable invalues.yaml)
Important Notes:
- Running
helm upgradewill restart PostgreSQL but preserves all data - If you need to delete the PVC manually, backup data first as deletion removes all database data
For production, consider using:
- Google Cloud SQL (managed service with automatic backups)
- Managed PostgreSQL service
Update the DB_HOST in values.yaml to point to your managed database.
The deployment script automatically updates image paths in values.yaml with Artifact Registry paths.
kubectl get pods# Backend logs
kubectl logs -l app=playmeme-backend
# Frontend logs
kubectl logs -l app=playmeme-frontend
# PostgreSQL logs
kubectl logs -l app=playmeme-postgres# Get frontend service external IP
kubectl get service playmeme-frontend-service
# Port forward for local access
kubectl port-forward service/playmeme-backend-service 3001:3001-
Check postgres allocated size: $podName = kubectl get pods -l app=playmeme-postgres -o jsonpath='{.items[0].metadata.name}'; kubectl exec $podName -- df -h /data 2>&1
-
Scale all pods down to 0 (stop all services):
kubectl scale deployment playmeme-backend playmeme-frontend --replicas=0
kubectl scale deployment playmeme-postgres --replicas=0- Scale all pods back up to 2:
kubectl scale deployment playmeme-backend --replicas=2
kubectl scale deployment playmeme-frontend --replicas=2